Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds set and get initial tweaks data from the url hash #33

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions example/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import * as THREE from 'three'
import React, { Suspense, useRef } from 'react'
import { Canvas, useFrame } from 'react-three-fiber'
import { OrbitControls, ContactShadows, useGLTF, useCubeTexture, Octahedron } from '@react-three/drei'
import { useTweaks, makeFolder, makeSeparator, makeButton } from 'use-tweaks'
import { useTweaks, makeFolder, makeSeparator, makeButton } from '../../src'

import Badge from './Badge'

Expand All @@ -20,7 +20,7 @@ function Suzanne(props) {
scale: { value: 1, max: 3 },
...makeButton('Log Console', () => console.log('something in the console ' + Date.now())),
}),
})
}, { setGetFromUrl: true })

return (
<mesh {...props} position-x={position.x} position-y={position.y} scale={[scale, scale, scale]}>
Expand All @@ -32,7 +32,7 @@ function Suzanne(props) {

function Octa({ envMap }) {
const mesh = useRef()
const { move } = useTweaks('Octa', { move: true })
const { move } = useTweaks('Octa', { move: true }, { setGetFromUrl: true }, )

useFrame(({ clock }) => {
if (move) {
Expand All @@ -52,7 +52,7 @@ function Scene() {

const { model } = useTweaks({
model: { value: 'Suzanne', options: ['suzanne', 'Octahedron'] },
})
}, { setGetFromUrl: true })

return (
<Suspense fallback={null}>
Expand All @@ -63,7 +63,7 @@ function Scene() {

export default function App() {
const ref = React.useRef<HTMLDivElement>(null)
const { color } = useTweaks({ color: { value: '#f2f2f2', label: 'background' } }, { container: ref })
const { color } = useTweaks({ color: { value: '#f2f2f2', label: 'background' } }, { container: ref, setGetFromUrl: true })

return (
<>
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@
],
"dependencies": {
"get-value": "^3.0.1",
"query-string": "^6.13.6",
"set-value": "^3.0.2"
}
}
5 changes: 4 additions & 1 deletion src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@ export interface Schema {
[name: string]: InputtableOutType | InputConstructor | Folder | Separator
}

export type Settings = Omit<TweakpaneConfig, 'container'> & { container?: React.RefObject<HTMLElement> }
export type Settings = Omit<TweakpaneConfig, 'container'> & {
container?: React.RefObject<HTMLElement>
setGetFromUrl?: boolean
}

export interface Folder<T extends Schema = Schema> {
type: SpecialInputTypes
Expand Down
20 changes: 14 additions & 6 deletions src/useTweaks.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { useState, useLayoutEffect, useRef } from 'react'
import { useState, useLayoutEffect, useRef, useEffect } from 'react'
import Tweakpane from 'tweakpane'

import { getData, buildPane } from './data'
import { buildPane, getData } from './data'
import { Schema, Settings, UseTweaksValues } from './types'
import { getInitialDataFromUrl, setUrlFromData } from './utils'

let ROOTPANE: Tweakpane | undefined

Expand All @@ -13,11 +14,18 @@ export function useTweaks<T extends Schema>(
): UseTweaksValues<T> {
const _name = typeof nameOrSchema === 'string' ? nameOrSchema : undefined
const _rootKey = typeof nameOrSchema === 'string' ? 'root.' + nameOrSchema : 'root'
const _settings = useRef(typeof nameOrSchema === 'string' ? settings : (schemaOrSettings as Settings))
const _schema = useRef(typeof nameOrSchema === 'string' ? (schemaOrSettings as T) : nameOrSchema)

const rawSettings = typeof nameOrSchema === 'string' ? settings : (schemaOrSettings as Settings)
const { setGetFromUrl, ...remainingSettings } = rawSettings || {}
const _settings = useRef(remainingSettings)

const rawSchema = typeof nameOrSchema === 'string' ? (schemaOrSettings as T) : nameOrSchema
const _schema = useRef(setGetFromUrl ? getInitialDataFromUrl(rawSchema, _rootKey) : rawSchema)

const [data, set] = useState(() => getData(_schema.current, _rootKey))


useEffect(() => void (setGetFromUrl && setUrlFromData(data, _rootKey)), [setGetFromUrl, data, _rootKey])

useLayoutEffect(() => {
ROOTPANE = ROOTPANE || new Tweakpane({ ..._settings, container: _settings.current?.container?.current! })
const isRoot = _name === undefined
Expand All @@ -33,4 +41,4 @@ export function useTweaks<T extends Schema>(
}, [_name, _rootKey])

return data as UseTweaksValues<T>
}
}
53 changes: 53 additions & 0 deletions src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,56 @@
import queryString from "query-string"

import { Schema } from "./types";

export function uuid(): string {
return `${Math.floor((new Date().getTime() * Math.random()) / 1000)}`
}

export function isJson(str: string) : boolean {
try {
JSON.parse(str);
} catch (e) {
return false;
}
return true;
}

export function setUrlFromData(data : any, rootKey : string) {
const parsed = queryString.parse(document.location.hash);
const reducedData = Object.entries(data).reduce((acc: any, [key, val]) => {
if (typeof val !== "undefined") {
acc[`${rootKey}$${key}`] = typeof val === "object" ? JSON.stringify(val) : val
}
return acc
}, parsed)
const stringified = queryString.stringify(reducedData);
document.location.hash = `#${stringified}`;
}

export function getInitialDataFromUrl(schema : Schema, rootKey : string) {
const parsed = queryString.parse(document.location.hash);
return Object.entries(parsed).reduce((acc, [key, val]:[string, any]) => {
const splittedKey = key.split("$")
if (splittedKey[0] === rootKey) {
setValueInSchema(acc, splittedKey[1], val)
}
return acc
}, schema)
}

function setValueInSchema(schema : any, key : string, value : any) {
const correctValue = isJson(value) ? JSON.parse(value) : value
if (schema[key]) {
if (schema[key].value) {
schema[key].value = correctValue
} else {
schema[key] = correctValue
}
} else if (typeof schema === "object") {
Object.entries(schema).forEach(([_, subSchema] : [string, any]) => {
if (subSchema?.type === 1) {
setValueInSchema(subSchema.schema, key, value)
}
})
}
}
19 changes: 19 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -7157,6 +7157,15 @@ qs@~6.5.2:
resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36"
integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==

query-string@^6.13.6:
version "6.13.6"
resolved "https://registry.yarnpkg.com/query-string/-/query-string-6.13.6.tgz#e5ac7c74f2a5da43fbca0b883b4f0bafba439966"
integrity sha512-/WWZ7d9na6s2wMEGdVCVgKWE9Rt7nYyNIf7k8xmHXcesPMlEzicWo3lbYwHyA4wBktI2KrXxxZeACLbE84hvSQ==
dependencies:
decode-uri-component "^0.2.0"
split-on-first "^1.0.0"
strict-uri-encode "^2.0.0"

querystring-es3@^0.2.0:
version "0.2.1"
resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73"
Expand Down Expand Up @@ -8025,6 +8034,11 @@ spdx-license-ids@^3.0.0:
resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.6.tgz#c80757383c28abf7296744998cbc106ae8b854ce"
integrity sha512-+orQK83kyMva3WyPf59k1+Y525csj5JejicWut55zeTWANuN17qSiSLUXWtzHeNWORSvT7GLDJ/E/XiIWoXBTw==

split-on-first@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/split-on-first/-/split-on-first-1.1.0.tgz#f610afeee3b12bce1d0c30425e76398b78249a5f"
integrity sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw==

split-string@^3.0.1, split-string@^3.0.2:
version "3.1.0"
resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2"
Expand Down Expand Up @@ -8119,6 +8133,11 @@ stream-shift@^1.0.0:
resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.1.tgz#d7088281559ab2778424279b0877da3c392d5a3d"
integrity sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==

strict-uri-encode@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz#b9c7330c7042862f6b142dc274bbcc5866ce3546"
integrity sha1-ucczDHBChi9rFC3CdLvMWGbONUY=

string-length@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/string-length/-/string-length-3.1.0.tgz#107ef8c23456e187a8abd4a61162ff4ac6e25837"
Expand Down