├── .all-contributorsrc ├── .changeset ├── README.md ├── config.json └── light-tigers-explode.md ├── .codesandbox └── ci.json ├── .eslintignore ├── .eslintrc.json ├── .github └── workflows │ ├── main.yml │ └── release.yml ├── .gitignore ├── .husky ├── .gitignore └── pre-commit ├── .prettierignore ├── .storybook ├── main.js ├── manager.js └── preview.js ├── .vscode └── settings.json ├── .yarn ├── plugins │ └── @yarnpkg │ │ ├── plugin-interactive-tools.cjs │ │ ├── plugin-version.cjs │ │ └── plugin-workspace-tools.cjs └── releases │ └── yarn-sources.cjs ├── .yarnrc.yml ├── LICENSE ├── README.md ├── babel.config.js ├── code_of_conduct.md ├── contributing.md ├── cypress.json ├── cypress ├── fixtures │ └── example.json ├── integration │ └── spec.js ├── plugins │ └── index.js └── support │ ├── commands.js │ └── index.js ├── demo ├── index.html ├── package.json ├── serve.json ├── src │ ├── App.jsx │ ├── index.css │ ├── index.jsx │ ├── sandboxes │ │ ├── leva-advanced-panels │ │ │ ├── package.json │ │ │ ├── public │ │ │ │ └── index.html │ │ │ └── src │ │ │ │ ├── App.jsx │ │ │ │ ├── index.css │ │ │ │ └── index.jsx │ │ ├── leva-busy │ │ │ ├── package.json │ │ │ ├── public │ │ │ │ └── index.html │ │ │ └── src │ │ │ │ ├── App.tsx │ │ │ │ ├── index.css │ │ │ │ ├── index.tsx │ │ │ │ └── styles.module.css │ │ ├── leva-custom-plugin │ │ │ ├── package.json │ │ │ ├── public │ │ │ │ └── index.html │ │ │ └── src │ │ │ │ ├── App.tsx │ │ │ │ ├── index.css │ │ │ │ └── index.tsx │ │ ├── leva-minimal │ │ │ ├── package.json │ │ │ ├── public │ │ │ │ └── index.html │ │ │ └── src │ │ │ │ ├── App.jsx │ │ │ │ ├── index.css │ │ │ │ └── index.jsx │ │ ├── leva-plugin-bezier │ │ │ ├── package.json │ │ │ ├── public │ │ │ │ └── index.html │ │ │ └── src │ │ │ │ ├── App.tsx │ │ │ │ ├── index.css │ │ │ │ ├── index.tsx │ │ │ │ └── style.css │ │ ├── leva-plugin-dates │ │ │ ├── package.json │ │ │ ├── public │ │ │ │ └── index.html │ │ │ └── src │ │ │ │ ├── App.tsx │ │ │ │ ├── index.css │ │ │ │ └── index.tsx │ │ ├── leva-plugin-plot │ │ │ ├── package.json │ │ │ ├── public │ │ │ │ └── index.html │ │ │ └── src │ │ │ │ ├── App.tsx │ │ │ │ ├── index.css │ │ │ │ └── index.tsx │ │ ├── leva-plugin-spring │ │ │ ├── package.json │ │ │ ├── public │ │ │ │ └── index.html │ │ │ └── src │ │ │ │ ├── App.tsx │ │ │ │ ├── index.css │ │ │ │ └── index.tsx │ │ ├── leva-scroll │ │ │ ├── package.json │ │ │ ├── public │ │ │ │ └── index.html │ │ │ └── src │ │ │ │ ├── App.jsx │ │ │ │ ├── index.css │ │ │ │ └── index.jsx │ │ ├── leva-theme │ │ │ ├── package.json │ │ │ ├── public │ │ │ │ └── index.html │ │ │ └── src │ │ │ │ ├── App.jsx │ │ │ │ ├── index.css │ │ │ │ └── index.jsx │ │ ├── leva-transient │ │ │ ├── package.json │ │ │ ├── public │ │ │ │ └── index.html │ │ │ └── src │ │ │ │ ├── App.jsx │ │ │ │ ├── index.css │ │ │ │ └── index.jsx │ │ └── leva-ui │ │ │ ├── package.json │ │ │ ├── public │ │ │ └── index.html │ │ │ └── src │ │ │ ├── App.jsx │ │ │ ├── index.css │ │ │ ├── index.jsx │ │ │ └── styles.css │ └── styles.module.css ├── tsconfig.json └── vite.config.js ├── docs ├── advanced │ ├── circle-drag.gif │ ├── controlled-inputs.md │ └── creating-plugins.md ├── configuration.md ├── getting-started.md ├── inputs.md ├── plugins.md ├── special-inputs.md ├── styling.md └── typescript.md ├── hero.png ├── package.json ├── packages ├── leva │ ├── .npmignore │ ├── CHANGELOG.md │ ├── README.md │ ├── package.json │ ├── plugin │ │ └── package.json │ ├── src │ │ ├── components │ │ │ ├── Boolean │ │ │ │ ├── Boolean.tsx │ │ │ │ ├── StyledBoolean.ts │ │ │ │ ├── boolean-plugin.ts │ │ │ │ ├── boolean-types.ts │ │ │ │ └── index.ts │ │ │ ├── Button │ │ │ │ ├── Button.tsx │ │ │ │ ├── StyledButton.ts │ │ │ │ └── index.ts │ │ │ ├── ButtonGroup │ │ │ │ ├── ButtonGroup.tsx │ │ │ │ ├── StyledButtonGroup.tsx │ │ │ │ ├── StyledButtonGroupButton.ts │ │ │ │ └── index.ts │ │ │ ├── Color │ │ │ │ ├── Color.tsx │ │ │ │ ├── StyledColor.ts │ │ │ │ ├── color-plugin.ts │ │ │ │ ├── color-types.ts │ │ │ │ └── index.ts │ │ │ ├── Control │ │ │ │ ├── Control.tsx │ │ │ │ ├── ControlInput.tsx │ │ │ │ └── index.ts │ │ │ ├── Folder │ │ │ │ ├── Folder.tsx │ │ │ │ ├── FolderTitle.tsx │ │ │ │ ├── StyledFolder.ts │ │ │ │ └── index.ts │ │ │ ├── Image │ │ │ │ ├── Image.tsx │ │ │ │ ├── StyledImage.ts │ │ │ │ ├── image-plugin.ts │ │ │ │ ├── image-types.ts │ │ │ │ └── index.ts │ │ │ ├── Interval │ │ │ │ ├── Interval.tsx │ │ │ │ ├── index.ts │ │ │ │ ├── interval-plugin.ts │ │ │ │ └── interval-types.ts │ │ │ ├── Leva │ │ │ │ ├── Filter.tsx │ │ │ │ ├── Leva.tsx │ │ │ │ ├── LevaPanel.tsx │ │ │ │ ├── LevaRoot.tsx │ │ │ │ ├── StyledFilter.ts │ │ │ │ ├── StyledRoot.ts │ │ │ │ ├── index.ts │ │ │ │ └── tree.ts │ │ │ ├── Monitor │ │ │ │ ├── Monitor.tsx │ │ │ │ ├── StyledMonitor.ts │ │ │ │ └── index.ts │ │ │ ├── Number │ │ │ │ ├── Number.tsx │ │ │ │ ├── RangeSlider.tsx │ │ │ │ ├── StyledNumber.ts │ │ │ │ ├── StyledRange.ts │ │ │ │ ├── index.ts │ │ │ │ ├── number-plugin.ts │ │ │ │ └── number-types.ts │ │ │ ├── Select │ │ │ │ ├── Select.tsx │ │ │ │ ├── StyledSelect.ts │ │ │ │ ├── index.ts │ │ │ │ ├── select-plugin.ts │ │ │ │ └── select-types.ts │ │ │ ├── String │ │ │ │ ├── String.tsx │ │ │ │ ├── index.ts │ │ │ │ ├── string-plugin.ts │ │ │ │ └── string-types.ts │ │ │ ├── UI │ │ │ │ ├── Chevron.tsx │ │ │ │ ├── Label.tsx │ │ │ │ ├── Misc.tsx │ │ │ │ ├── Row.tsx │ │ │ │ ├── StyledUI.ts │ │ │ │ └── index.ts │ │ │ ├── ValueInput │ │ │ │ ├── StyledInput.ts │ │ │ │ ├── ValueInput.tsx │ │ │ │ └── index.ts │ │ │ ├── Vector │ │ │ │ ├── Vector.tsx │ │ │ │ ├── index.ts │ │ │ │ ├── vector-plugin.ts │ │ │ │ ├── vector-types.ts │ │ │ │ └── vector-utils.ts │ │ │ ├── Vector2d │ │ │ │ ├── Joystick.tsx │ │ │ │ ├── StyledJoystick.ts │ │ │ │ ├── Vector2d.tsx │ │ │ │ ├── index.ts │ │ │ │ └── vector2d-types.ts │ │ │ └── Vector3d │ │ │ │ ├── Vector3d.tsx │ │ │ │ ├── index.ts │ │ │ │ └── vector3d-types.ts │ │ ├── context.tsx │ │ ├── eventEmitter.ts │ │ ├── helpers │ │ │ ├── button.ts │ │ │ ├── buttonGroup.ts │ │ │ ├── folder.ts │ │ │ ├── index.ts │ │ │ └── monitor.ts │ │ ├── hooks │ │ │ ├── index.ts │ │ │ ├── useCanvas.ts │ │ │ ├── useCompareMemoize.ts │ │ │ ├── useDeepMemo.ts │ │ │ ├── useDrag.ts │ │ │ ├── useInput.ts │ │ │ ├── useInputSetters.ts │ │ │ ├── usePopin.ts │ │ │ ├── useShallowMemo.ts │ │ │ ├── useToggle.ts │ │ │ ├── useTransform.ts │ │ │ ├── useValue.ts │ │ │ ├── useValuesForPath.ts │ │ │ └── useVisiblePaths.ts │ │ ├── index.ts │ │ ├── plugin.ts │ │ ├── plugin │ │ │ └── index.ts │ │ ├── store.ts │ │ ├── styles │ │ │ ├── index.ts │ │ │ └── stitches.config.ts │ │ ├── types │ │ │ ├── index.ts │ │ │ ├── internal.ts │ │ │ ├── public.test.ts │ │ │ ├── public.ts │ │ │ ├── utils.ts │ │ │ └── v8n.d.ts │ │ ├── useControls.ts │ │ └── utils │ │ │ ├── data.ts │ │ │ ├── event.ts │ │ │ ├── fn.ts │ │ │ ├── index.ts │ │ │ ├── input.ts │ │ │ ├── log.ts │ │ │ ├── math.ts │ │ │ ├── object.ts │ │ │ ├── path.ts │ │ │ └── react.ts │ └── stories │ │ ├── Folder.stories.tsx │ │ ├── caching.stories.tsx │ │ ├── components │ │ └── decorator-reset.tsx │ │ ├── controlled-inputs.stories.tsx │ │ ├── hook-dependencies.stories.tsx │ │ ├── input-options.stories.tsx │ │ ├── inputs │ │ ├── Boolean.stories.tsx │ │ ├── Button.stories.tsx │ │ ├── ButtonGroup.stories.tsx │ │ ├── Color.stories.tsx │ │ ├── Image.stories.tsx │ │ ├── Interval.stories.tsx │ │ ├── Number.stories.tsx │ │ ├── Select.stories.tsx │ │ ├── String.stories.tsx │ │ └── Vector.stories.tsx │ │ └── panel-options.stories.tsx ├── plugin-bezier │ ├── CHANGELOG.md │ ├── README.md │ ├── package.json │ └── src │ │ ├── Bezier.stories.css │ │ ├── Bezier.stories.tsx │ │ ├── Bezier.tsx │ │ ├── BezierPreview.tsx │ │ ├── BezierSvg.tsx │ │ ├── StyledBezier.ts │ │ ├── bezier-plugin.ts │ │ ├── bezier-types.ts │ │ ├── bezier-utils.ts │ │ └── index.ts ├── plugin-dates │ ├── CHANGELOG.md │ ├── README.md │ ├── package.json │ └── src │ │ ├── Date.stories.tsx │ │ ├── Date.tsx │ │ ├── StyledDate.ts │ │ ├── date-plugin.ts │ │ ├── date-types.ts │ │ ├── date-utils.ts │ │ └── index.ts ├── plugin-plot │ ├── CHANGELOG.md │ ├── README.md │ ├── package.json │ └── src │ │ ├── Plot.stories.tsx │ │ ├── Plot.tsx │ │ ├── PlotCanvas.tsx │ │ ├── StyledPlot.ts │ │ ├── index.ts │ │ ├── plot-plugin.ts │ │ ├── plot-types.ts │ │ └── plot-utils.ts └── plugin-spring │ ├── CHANGELOG.md │ ├── README.md │ ├── package.json │ └── src │ ├── Spring.stories.tsx │ ├── Spring.tsx │ ├── SpringCanvas.tsx │ ├── StyledSpring.ts │ ├── index.ts │ ├── math.ts │ ├── spring-plugin.ts │ └── spring-types.ts ├── tsconfig.json └── yarn.lock /.changeset/README.md: -------------------------------------------------------------------------------- 1 | # Changesets 2 | 3 | Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works 4 | with multi-package repos, or single-package repos to help you version and publish your code. You can 5 | find the full documentation for it [in our repository](https://github.com/changesets/changesets) 6 | 7 | We have a quick list of common questions to get you started engaging with this project in 8 | [our documentation](https://github.com/changesets/changesets/blob/master/docs/common-questions.md) 9 | -------------------------------------------------------------------------------- /.changeset/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://unpkg.com/@changesets/config@1.6.0/schema.json", 3 | "changelog": "@changesets/cli/changelog", 4 | "commit": false, 5 | "access": "public", 6 | "baseBranch": "main", 7 | "updateInternalDependencies": "patch", 8 | "ignore": ["demo"] 9 | } 10 | -------------------------------------------------------------------------------- /.changeset/light-tigers-explode.md: -------------------------------------------------------------------------------- 1 | --- 2 | "leva": patch 3 | --- 4 | 5 | `@radix-ui/*` upgrades to prevent peerDeps warnings with React 19 6 | -------------------------------------------------------------------------------- /.codesandbox/ci.json: -------------------------------------------------------------------------------- 1 | { 2 | "packages": [ 3 | "packages/*" 4 | ], 5 | "sandboxes": [ 6 | "/demo/src/sandboxes/leva-minimal", 7 | "/demo/src/sandboxes/leva-busy", 8 | "/demo/src/sandboxes/leva-scroll", 9 | "/demo/src/sandboxes/leva-advanced-panels", 10 | "/demo/src/sandboxes/leva-ui", 11 | "/demo/src/sandboxes/leva-theme", 12 | "/demo/src/sandboxes/leva-transient", 13 | "/demo/src/sandboxes/leva-plugin-plot", 14 | "/demo/src/sandboxes/leva-plugin-bezier", 15 | "/demo/src/sandboxes/leva-plugin-spring", 16 | "/demo/src/sandboxes/leva-plugin-dates", 17 | "/demo/src/sandboxes/leva-custom-plugin" 18 | ], 19 | "node": "14" 20 | } 21 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | node_modules/ 3 | .yarn/ -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "react-app", 3 | "rules": { 4 | "no-console": "warn" 5 | }, 6 | "plugins": ["cypress"], 7 | "env": { 8 | "cypress/globals": true 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: 3 | push: 4 | paths: 5 | - '.github/**' 6 | - 'packages/**' 7 | - 'package.json' 8 | - 'yarn.lock' 9 | - '!demo/**' 10 | - '!docs/**' 11 | - '!**.md' 12 | - '!.changeset/**' 13 | jobs: 14 | build: 15 | name: Build, lint, and test 16 | runs-on: ubuntu-latest 17 | 18 | steps: 19 | - name: Checkout repo 20 | uses: actions/checkout@v3 21 | 22 | - name: Use Node 23 | uses: actions/setup-node@v3 24 | with: 25 | node-version: '18' 26 | 27 | - name: Get yarn cache directory path 28 | id: yarn-cache-dir-path 29 | run: echo "::set-output name=dir::$(yarn config get cacheFolder)" 30 | 31 | - uses: actions/cache@v3 32 | id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`) 33 | with: 34 | path: ${{ steps.yarn-cache-dir-path.outputs.dir }} 35 | key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} 36 | restore-keys: | 37 | ${{ runner.os }}-yarn- 38 | 39 | - name: Install dependencies 40 | run: yarn --silent 41 | 42 | - name: Check types 43 | run: yarn tsc 44 | 45 | - name: Check formatting 46 | run: yarn prettier 47 | 48 | - name: Lint files 49 | run: yarn lint:full 50 | 51 | - uses: actions/cache@v3 52 | name: Setup Yarn build cache 53 | id: yarn-build-cache 54 | with: 55 | path: packages/**/dist 56 | key: ${{ runner.os }}-yarn-build-${{ hashFiles('packages/**') }} 57 | restore-keys: | 58 | ${{ runner.os }}-yarn-build- 59 | 60 | - name: Yarn build without cache 61 | if: steps.yarn-build-cache.outputs.cache-hit != 'true' 62 | run: yarn build 63 | 64 | - name: Cypress run 65 | run: yarn ci:test 66 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | paths: 8 | - '**/package.json' 9 | - '.changeset/**' 10 | - '.github/workflows/release.yml' 11 | 12 | jobs: 13 | release: 14 | name: Release 15 | runs-on: ubuntu-latest 16 | steps: 17 | - name: Checkout Repo 18 | uses: actions/checkout@v3 19 | with: 20 | # This makes Actions fetch all Git history so that Changesets can generate changelogs with the correct commits 21 | fetch-depth: 0 22 | 23 | - name: Use Node 24 | uses: actions/setup-node@v3 25 | with: 26 | node-version: '18' 27 | 28 | - name: Get yarn cache directory path 29 | id: yarn-cache-dir-path 30 | run: echo "::set-output name=dir::$(yarn config get cacheFolder)" 31 | 32 | - uses: actions/cache@v3 33 | id: yarn-cache 34 | with: 35 | path: ${{ steps.yarn-cache-dir-path.outputs.dir }} 36 | key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} 37 | restore-keys: | 38 | ${{ runner.os }}-yarn- 39 | 40 | - name: Install dependencies 41 | run: yarn install --silent 42 | 43 | - name: Create Release Pull Request or Publish to npm 44 | id: changesets 45 | uses: changesets/action@v1 46 | with: 47 | version: yarn ci:version 48 | publish: yarn ci:release 49 | commit: 'chore(release): update monorepo packages versions' 50 | title: 'Upcoming Release Changes' 51 | env: 52 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 53 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }} 54 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | node_modules/ 5 | .yarn/* 6 | !.yarn/releases 7 | !.yarn/plugins 8 | !.yarn/sdks 9 | !.yarn/versions 10 | .pnp.* 11 | 12 | # testing 13 | /coverage 14 | 15 | # production 16 | build/ 17 | dist/ 18 | .cache/ 19 | .parcel-cache/ 20 | 21 | # misc 22 | .DS_Store 23 | .env.local 24 | .env.development.local 25 | .env.test.local 26 | .env.production.local 27 | 28 | npm-debug.log* 29 | yarn-debug.log* 30 | yarn-error.log* 31 | 32 | storybook-static/ 33 | .idea 34 | cypress/screenshots 35 | -------------------------------------------------------------------------------- /.husky/.gitignore: -------------------------------------------------------------------------------- 1 | _ 2 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | npm run lint 5 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | .changeset/ 2 | .codesandbox/ 3 | .github/ 4 | .husky/ 5 | .storybook/ 6 | .vscode/ 7 | .yarn/ 8 | dist/ 9 | node_modules/ 10 | patches/ 11 | storybook-static/ 12 | -------------------------------------------------------------------------------- /.storybook/main.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | 3 | module.exports = { 4 | stories: ['../packages/**/*.stories.mdx', '../packages/**/*.stories.@(js|jsx|ts|tsx)'], 5 | addons: ['@storybook/addon-links', '@storybook/addon-essentials', '@storybook/addon-storysource'], 6 | webpackFinal: async (config, { configType }) => { 7 | // `configType` has a value of 'DEVELOPMENT' or 'PRODUCTION' 8 | // You can change the configuration based on that. 9 | // 'PRODUCTION' is used when building the static version of storybook. 10 | 11 | // manually resolve packages from other repos so that vercel builds properly 12 | if (configType === 'PRODUCTION') { 13 | config.resolve.alias['leva'] = path.resolve(__dirname, '../packages/leva/') 14 | } 15 | // Return the altered config 16 | return config 17 | }, 18 | typescript: { 19 | reactDocgen: 'none', // temp fix for TS 4.3.2 20 | }, 21 | } 22 | -------------------------------------------------------------------------------- /.storybook/manager.js: -------------------------------------------------------------------------------- 1 | import { addons } from '@storybook/addons'; 2 | import { themes } from '@storybook/theming'; 3 | 4 | addons.setConfig({ 5 | theme: themes.dark, 6 | }); -------------------------------------------------------------------------------- /.storybook/preview.js: -------------------------------------------------------------------------------- 1 | 2 | export const parameters = { 3 | actions: { argTypesRegex: "^on[A-Z].*" }, 4 | "previewTabs": { 5 | 'storybook/docs/panel': { hidden: true } 6 | }, 7 | options: { 8 | storySort: { 9 | order: ["Inputs", ["String", "Boolean", "Number", "Interval"], "Misc", "Plugins"] 10 | } 11 | }, 12 | } 13 | 14 | export const decorators = [(Story) =>
] 15 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "typescript.tsdk": "node_modules/typescript/lib" 3 | } -------------------------------------------------------------------------------- /.yarnrc.yml: -------------------------------------------------------------------------------- 1 | nodeLinker: node-modules 2 | 3 | plugins: 4 | - path: .yarn/plugins/@yarnpkg/plugin-version.cjs 5 | spec: '@yarnpkg/plugin-version' 6 | - path: .yarn/plugins/@yarnpkg/plugin-interactive-tools.cjs 7 | spec: '@yarnpkg/plugin-interactive-tools' 8 | - path: .yarn/plugins/@yarnpkg/plugin-workspace-tools.cjs 9 | spec: '@yarnpkg/plugin-workspace-tools' 10 | 11 | yarnPath: .yarn/releases/yarn-sources.cjs 12 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Poimandres 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | comments: false, 3 | presets: [ 4 | [ 5 | '@babel/preset-env', 6 | { 7 | bugfixes: true, 8 | targets: { 9 | esmodules: true, 10 | }, 11 | }, 12 | ], 13 | '@babel/preset-react', 14 | '@babel/preset-typescript', 15 | ], 16 | } 17 | -------------------------------------------------------------------------------- /contributing.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | ## What we are looking for 4 | 5 | - Input Suggestions 6 | - Plugin Suggestions 7 | - Alternative Themes 8 | - Unit Tests 9 | - Docs 10 | -------------------------------------------------------------------------------- /cypress.json: -------------------------------------------------------------------------------- 1 | { 2 | "baseUrl": "http://localhost:5000", 3 | "defaultCommandTimeout": 10000, 4 | "video": false 5 | } 6 | -------------------------------------------------------------------------------- /cypress/fixtures/example.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Using fixtures to represent data", 3 | "email": "hello@cypress.io", 4 | "body": "Fixtures are a great way to mock data for responses to routes" 5 | } 6 | -------------------------------------------------------------------------------- /cypress/integration/spec.js: -------------------------------------------------------------------------------- 1 | describe('Number', () => { 2 | it('Works.', () => { 3 | cy.visit('/leva-minimal') 4 | cy.findByLabelText(/number/).should('exist') 5 | 6 | cy.findByLabelText(/number/) 7 | .clear() 8 | .type(123) 9 | .blur() 10 | // expect 123 to be the value 11 | cy.findByLabelText(/number/).should('have.value', 123) 12 | // expect previous value when empty string is used 13 | cy.findByLabelText(/number/) 14 | .focus() 15 | .clear() 16 | .blur() 17 | }) 18 | 19 | it("Doesn't accept non-numbers.", () => { 20 | cy.visit('/leva-minimal') 21 | 22 | // expect previous value when typing invalid characters 23 | cy.findByLabelText(/number/) 24 | .clear() 25 | .type('ABC') 26 | .blur() 27 | cy.findByLabelText(/number/).should('have.value', 10) 28 | }) 29 | }) 30 | 31 | describe('MinMax', () => { 32 | it('Works.', () => { 33 | cy.visit('/leva-minimal') 34 | cy.findByLabelText(/minmax/).should('exist') 35 | 36 | cy.findByLabelText(/number/) 37 | .clear() 38 | .type(13) 39 | .blur() 40 | cy.findByLabelText(/number/).should('have.value', 13) 41 | // expect previous value when empty string is used 42 | cy.findByLabelText(/number/) 43 | .focus() 44 | .clear() 45 | .blur() 46 | }) 47 | 48 | it("Doesn't go over.", () => { 49 | cy.visit('/leva-minimal') 50 | 51 | // since value is over max, it should reset to max 52 | cy.findByLabelText(/minmax/) 53 | .clear() 54 | .type(123) 55 | .blur() 56 | cy.findByLabelText(/minmax/).should('have.value', 30.5) 57 | }) 58 | 59 | it("Doesn't go under.", () => { 60 | cy.visit('/leva-minimal') 61 | 62 | // since value is under min, it should reset to initial 63 | cy.findByLabelText(/minmax/) 64 | .clear() 65 | .type(1) 66 | .blur() 67 | cy.findByLabelText(/minmax/).should('have.value', 5.5) 68 | }) 69 | }) 70 | -------------------------------------------------------------------------------- /cypress/plugins/index.js: -------------------------------------------------------------------------------- 1 | /// 2 | // *********************************************************** 3 | // This example plugins/index.js can be used to load plugins 4 | // 5 | // You can change the location of this file or turn off loading 6 | // the plugins file with the 'pluginsFile' configuration option. 7 | // 8 | // You can read more here: 9 | // https://on.cypress.io/plugins-guide 10 | // *********************************************************** 11 | 12 | // This function is called when a project is opened or re-opened (e.g. due to 13 | // the project's config changing) 14 | 15 | /** 16 | * @type {Cypress.PluginConfig} 17 | */ 18 | module.exports = (on, config) => { 19 | // `on` is used to hook into various events Cypress emits 20 | // `config` is the resolved Cypress config 21 | } 22 | -------------------------------------------------------------------------------- /cypress/support/commands.js: -------------------------------------------------------------------------------- 1 | import '@testing-library/cypress/add-commands' 2 | -------------------------------------------------------------------------------- /cypress/support/index.js: -------------------------------------------------------------------------------- 1 | // *********************************************************** 2 | // This example support/index.js is processed and 3 | // loaded automatically before your test files. 4 | // 5 | // This is a great place to put global configuration and 6 | // behavior that modifies Cypress. 7 | // 8 | // You can change the location of this file or turn off 9 | // automatically serving support files with the 10 | // 'supportFile' configuration option. 11 | // 12 | // You can read more here: 13 | // https://on.cypress.io/configuration 14 | // *********************************************************** 15 | 16 | // Import commands.js using ES2015 syntax: 17 | import './commands' 18 | 19 | // Alternatively you can use CommonJS syntax: 20 | // require('./commands') 21 | -------------------------------------------------------------------------------- /demo/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Sandboxes Leva 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /demo/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "demo", 3 | "version": "1.0.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "vite --port 3300 --host", 7 | "build": "vite build", 8 | "serve": "vite preview" 9 | }, 10 | "dependencies": { 11 | "@radix-ui/react-icons": "^1.0.3", 12 | "@react-three/drei": "^8.8.3", 13 | "@react-three/fiber": "^7.0.26", 14 | "@stitches/react": "1.2.8", 15 | "leva": "*", 16 | "noisejs": "^2.1.0", 17 | "react": "^18.0.0", 18 | "react-dom": "^18.0.0", 19 | "react-use": "^17.3.2", 20 | "three": "^0.143.0", 21 | "wouter": "^2.7.5" 22 | }, 23 | "devDependencies": { 24 | "@types/react": "^18.0.0", 25 | "@types/react-dom": "^18.0.0", 26 | "@vitejs/plugin-react-refresh": "^1.3.6", 27 | "typescript": "^4.5.5", 28 | "vite": "2.7.13" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /demo/serve.json: -------------------------------------------------------------------------------- 1 | { 2 | "rewrites": [{ "source": "/*", "destination": "/index.html" }] 3 | } 4 | -------------------------------------------------------------------------------- /demo/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: system-ui, sans-serif; 3 | min-height: 100vh; 4 | background: linear-gradient(140deg, rgb(165, 142, 251), rgb(233, 191, 248)); 5 | margin: 0; 6 | } 7 | 8 | *, 9 | *:after, 10 | *:before { 11 | box-sizing: border-box; 12 | } 13 | 14 | pre { 15 | max-width: 720px; 16 | margin: 20px; 17 | padding: 20px; 18 | border: 10px solid black; 19 | } 20 | -------------------------------------------------------------------------------- /demo/src/index.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom' 3 | import App from './App' 4 | 5 | import './index.css' 6 | 7 | const rootElement = document.getElementById('root') 8 | ReactDOM.render( 9 | 10 | 11 | , 12 | rootElement 13 | ) 14 | -------------------------------------------------------------------------------- /demo/src/sandboxes/leva-advanced-panels/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "leva-advanced-panels", 3 | "version": "1.0.0", 4 | "main": "src/index.jsx", 5 | "dependencies": { 6 | "leva": "*", 7 | "react": "^18.0.0", 8 | "react-dom": "^18.0.0", 9 | "react-scripts": "4.0.3" 10 | }, 11 | "scripts": { 12 | "start": "react-scripts start", 13 | "build": "react-scripts build", 14 | "test": "react-scripts test --env=jsdom", 15 | "eject": "react-scripts eject" 16 | }, 17 | "browserslist": [ 18 | ">0.2%", 19 | "not dead", 20 | "not ie <= 11", 21 | "not op_mini all" 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /demo/src/sandboxes/leva-advanced-panels/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 11 | 12 | 13 | 22 | Leva Sandbox 23 | 24 | 25 | 26 | 27 |
28 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /demo/src/sandboxes/leva-advanced-panels/src/App.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { useControls, useStoreContext, useCreateStore, LevaPanel, LevaStoreProvider } from 'leva' 3 | 4 | function MyComponent() { 5 | const store = useStoreContext() 6 | useControls({ point: [0, 0] }, { store }) 7 | return null 8 | } 9 | 10 | export default function App() { 11 | const store1 = useCreateStore() 12 | const store2 = useCreateStore() 13 | useControls({ color: '#fff' }, { store: store1 }) 14 | useControls({ boolean: true }, { store: store2 }) 15 | return ( 16 |
24 | 25 | 26 | 27 | 28 | 29 |
30 | ) 31 | } 32 | -------------------------------------------------------------------------------- /demo/src/sandboxes/leva-advanced-panels/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: system-ui, sans-serif; 3 | min-height: 100vh; 4 | background: linear-gradient(140deg, rgb(165, 142, 251), rgb(233, 191, 248)); 5 | margin: 0; 6 | } 7 | 8 | *, 9 | *:after, 10 | *:before { 11 | box-sizing: border-box; 12 | } 13 | 14 | pre { 15 | max-width: 720px; 16 | margin: 20px; 17 | padding: 20px; 18 | border: 10px solid black; 19 | } 20 | -------------------------------------------------------------------------------- /demo/src/sandboxes/leva-advanced-panels/src/index.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom' 3 | import App from './App' 4 | 5 | import './index.css' 6 | 7 | const rootElement = document.getElementById('root') 8 | ReactDOM.render( 9 | 10 | 11 | , 12 | rootElement 13 | ) 14 | -------------------------------------------------------------------------------- /demo/src/sandboxes/leva-busy/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "leva-busy", 3 | "main": "src/index.jsx", 4 | "version": "1.0.0", 5 | "dependencies": { 6 | "@radix-ui/react-icons": "^1.0.2", 7 | "leva": "*", 8 | "noisejs": "2.1.0", 9 | "react": "^18.0.0", 10 | "react-dom": "^18.0.0", 11 | "react-scripts": "4.0.3", 12 | "react-use": "^17.2.4" 13 | }, 14 | "scripts": { 15 | "start": "react-scripts start", 16 | "build": "react-scripts build", 17 | "test": "react-scripts test --env=jsdom", 18 | "eject": "react-scripts eject" 19 | }, 20 | "browserslist": [ 21 | ">0.2%", 22 | "not dead", 23 | "not ie <= 11", 24 | "not op_mini all" 25 | ], 26 | "devDependencies": { 27 | "@types/react": "^18.0.0", 28 | "@types/react-dom": "^18.0.0", 29 | "typescript": "^4.1.5" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /demo/src/sandboxes/leva-busy/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 11 | 12 | 13 | 22 | Leva Sandbox 23 | 24 | 25 | 26 | 27 |
28 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /demo/src/sandboxes/leva-busy/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: system-ui, sans-serif; 3 | min-height: 100vh; 4 | background: linear-gradient(140deg, rgb(165, 142, 251), rgb(233, 191, 248)); 5 | margin: 0; 6 | } 7 | 8 | *, 9 | *:after, 10 | *:before { 11 | box-sizing: border-box; 12 | } 13 | 14 | pre { 15 | max-width: 720px; 16 | margin: 20px; 17 | padding: 20px; 18 | border: 10px solid black; 19 | } 20 | -------------------------------------------------------------------------------- /demo/src/sandboxes/leva-busy/src/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom' 3 | import App from './App' 4 | 5 | import './index.css' 6 | 7 | const rootElement = document.getElementById('root') 8 | ReactDOM.render( 9 | 10 | 11 | , 12 | rootElement 13 | ) 14 | -------------------------------------------------------------------------------- /demo/src/sandboxes/leva-busy/src/styles.module.css: -------------------------------------------------------------------------------- 1 | .buttons { 2 | display: flex; 3 | font-size: 14px; 4 | padding: 10px; 5 | align-items: center; 6 | } 7 | 8 | .buttons > * { 9 | margin-left: 4px; 10 | } 11 | -------------------------------------------------------------------------------- /demo/src/sandboxes/leva-custom-plugin/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "leva-custom-plugin", 3 | "version": "1.0.0", 4 | "main": "src/index.tsx", 5 | "dependencies": { 6 | "leva": "*", 7 | "react": "^18.0.0", 8 | "react-dom": "^18.0.0", 9 | "react-scripts": "4.0.3" 10 | }, 11 | "devDependencies": { 12 | "@types/react": "^18.0.0", 13 | "@types/react-dom": "^18.0.0", 14 | "typescript": "^4.1.5" 15 | }, 16 | "scripts": { 17 | "start": "react-scripts start", 18 | "build": "react-scripts build", 19 | "test": "react-scripts test --env=jsdom", 20 | "eject": "react-scripts eject" 21 | }, 22 | "browserslist": [ 23 | ">0.2%", 24 | "not dead", 25 | "not ie <= 11", 26 | "not op_mini all" 27 | ] 28 | } 29 | -------------------------------------------------------------------------------- /demo/src/sandboxes/leva-custom-plugin/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 11 | 12 | 13 | 22 | Leva Sandbox 23 | 24 | 25 | 26 | 27 |
28 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /demo/src/sandboxes/leva-custom-plugin/src/App.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Leva, useControls } from 'leva' 3 | import { createPlugin, useInputContext, LevaInputProps, Components } from 'leva/plugin' 4 | 5 | const { Row, Label, String } = Components 6 | 7 | type GreenOrBlueSettings = { alpha?: number } 8 | type GreenOrBlueType = { color?: string; light: boolean } 9 | type GreenOrBlueInput = GreenOrBlueType & GreenOrBlueSettings 10 | 11 | type GreenOrBlueProps = LevaInputProps 12 | 13 | function GreenOrBlue() { 14 | const props = useInputContext() 15 | const { label, displayValue, onUpdate, onChange, settings } = props 16 | const background = displayValue 17 | 18 | return ( 19 | 20 | 21 | 22 | 23 | ) 24 | } 25 | 26 | const normalize = ({ color, light, alpha }: GreenOrBlueInput) => { 27 | return { value: { color, light }, settings: { alpha } } 28 | } 29 | 30 | const sanitize = (v: string): GreenOrBlueType => { 31 | if (!['green', 'blue', 'lightgreen', 'lightblue'].includes(v)) throw Error('Invalid value') 32 | // @ts-ignore 33 | const [, isLight, color] = v.match(/(light)?(.*)/) 34 | return { light: !!isLight, color } 35 | } 36 | 37 | const format = (v: GreenOrBlueType) => (v.light ? 'light' : '') + v.color 38 | 39 | const greenOrBlue = createPlugin({ 40 | sanitize, 41 | format, 42 | normalize, 43 | component: GreenOrBlue, 44 | }) 45 | 46 | export default function App() { 47 | const data = useControls({ 48 | myPlugin: greenOrBlue({ color: 'green', light: true, alpha: 0.5 }), 49 | }) 50 | 51 | return ( 52 | <> 53 | 54 |
{JSON.stringify(data, null, '  ')}
55 | 56 | ) 57 | } 58 | -------------------------------------------------------------------------------- /demo/src/sandboxes/leva-custom-plugin/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: system-ui, sans-serif; 3 | min-height: 100vh; 4 | background: linear-gradient(140deg, rgb(165, 142, 251), rgb(233, 191, 248)); 5 | margin: 0; 6 | } 7 | 8 | *, 9 | *:after, 10 | *:before { 11 | box-sizing: border-box; 12 | } 13 | 14 | pre { 15 | max-width: 720px; 16 | margin: 20px; 17 | padding: 20px; 18 | border: 10px solid black; 19 | } 20 | -------------------------------------------------------------------------------- /demo/src/sandboxes/leva-custom-plugin/src/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom' 3 | import App from './App' 4 | 5 | import './index.css' 6 | 7 | const rootElement = document.getElementById('root') 8 | ReactDOM.render( 9 | 10 | 11 | , 12 | rootElement 13 | ) 14 | -------------------------------------------------------------------------------- /demo/src/sandboxes/leva-minimal/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "leva-minimal", 3 | "version": "1.0.0", 4 | "main": "src/index.jsx", 5 | "dependencies": { 6 | "@radix-ui/react-icons": "^1.0.2", 7 | "leva": "*", 8 | "react": "^18.0.0", 9 | "react-dom": "^18.0.0", 10 | "react-scripts": "4.0.3" 11 | }, 12 | "scripts": { 13 | "start": "react-scripts start", 14 | "build": "react-scripts build", 15 | "test": "react-scripts test --env=jsdom", 16 | "eject": "react-scripts eject" 17 | }, 18 | "browserslist": [ 19 | ">0.2%", 20 | "not dead", 21 | "not ie <= 11", 22 | "not op_mini all" 23 | ] 24 | } 25 | -------------------------------------------------------------------------------- /demo/src/sandboxes/leva-minimal/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 11 | 12 | 13 | 22 | Leva Sandbox 23 | 24 | 25 | 26 | 27 |
28 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /demo/src/sandboxes/leva-minimal/src/App.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { useControls, Leva } from 'leva' 3 | import { Half2Icon } from '@radix-ui/react-icons' 4 | 5 | export default function App() { 6 | const data = useControls({ 7 | number: 10, 8 | minmax: { value: 12.5, min: 5.5, max: 30.5, optional: true }, 9 | printSize: { value: 100, min: 80, max: 140, step: 10 }, 10 | color: { 11 | value: '#f00', 12 | hint: 'Hey, we support icons and hinting values and long text will wrap!', 13 | label: , 14 | }, 15 | }) 16 | 17 | return ( 18 | <> 19 | 20 |
{JSON.stringify(data, null, '  ')}
21 | 22 | ) 23 | } 24 | -------------------------------------------------------------------------------- /demo/src/sandboxes/leva-minimal/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: system-ui, sans-serif; 3 | min-height: 100vh; 4 | background: linear-gradient(140deg, rgb(165, 142, 251), rgb(233, 191, 248)); 5 | margin: 0; 6 | } 7 | 8 | *, 9 | *:after, 10 | *:before { 11 | box-sizing: border-box; 12 | } 13 | 14 | pre { 15 | max-width: 720px; 16 | margin: 20px; 17 | padding: 20px; 18 | border: 10px solid black; 19 | } 20 | -------------------------------------------------------------------------------- /demo/src/sandboxes/leva-minimal/src/index.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom' 3 | import App from './App' 4 | 5 | import './index.css' 6 | 7 | const rootElement = document.getElementById('root') 8 | ReactDOM.render( 9 | 10 | 11 | , 12 | rootElement 13 | ) 14 | -------------------------------------------------------------------------------- /demo/src/sandboxes/leva-plugin-bezier/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "leva-plugin-bezier", 3 | "version": "1.0.0", 4 | "keywords": [], 5 | "main": "src/index.jsx", 6 | "dependencies": { 7 | "@leva-ui/plugin-bezier": "*", 8 | "leva": "*", 9 | "react": "^18.0.0", 10 | "react-dom": "^18.0.0", 11 | "react-scripts": "4.0.3" 12 | }, 13 | "devDependencies": { 14 | "@types/react": "^18.0.0", 15 | "@types/react-dom": "^18.0.0", 16 | "typescript": "^4.1.5" 17 | }, 18 | "scripts": { 19 | "start": "react-scripts start", 20 | "build": "react-scripts build", 21 | "test": "react-scripts test --env=jsdom", 22 | "eject": "react-scripts eject" 23 | }, 24 | "browserslist": [ 25 | ">0.2%", 26 | "not dead", 27 | "not ie <= 11", 28 | "not op_mini all" 29 | ] 30 | } 31 | -------------------------------------------------------------------------------- /demo/src/sandboxes/leva-plugin-bezier/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 11 | 12 | 13 | 22 | Leva Sandbox 23 | 24 | 25 | 26 | 27 |
28 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /demo/src/sandboxes/leva-plugin-bezier/src/App.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { useControls } from 'leva' 3 | import { bezier } from '@leva-ui/plugin-bezier' 4 | import './style.css' 5 | 6 | export default function App() { 7 | const { curve } = useControls({ curve: bezier() }) 8 | 9 | return ( 10 |
11 |
12 |
{JSON.stringify(curve, null, '  ')}
13 |
14 | ) 15 | } 16 | -------------------------------------------------------------------------------- /demo/src/sandboxes/leva-plugin-bezier/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: system-ui, sans-serif; 3 | min-height: 100vh; 4 | background: linear-gradient(140deg, rgb(165, 142, 251), rgb(233, 191, 248)); 5 | margin: 0; 6 | } 7 | 8 | *, 9 | *:after, 10 | *:before { 11 | box-sizing: border-box; 12 | } 13 | 14 | pre { 15 | max-width: 720px; 16 | margin: 20px; 17 | padding: 20px; 18 | border: 10px solid black; 19 | } 20 | -------------------------------------------------------------------------------- /demo/src/sandboxes/leva-plugin-bezier/src/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom' 3 | import App from './App' 4 | 5 | import './index.css' 6 | 7 | const rootElement = document.getElementById('root') 8 | ReactDOM.render( 9 | 10 | 11 | , 12 | rootElement 13 | ) 14 | -------------------------------------------------------------------------------- /demo/src/sandboxes/leva-plugin-bezier/src/style.css: -------------------------------------------------------------------------------- 1 | @keyframes bezierStoryScale { 2 | 0% { 3 | transform: scaleX(0); 4 | } 5 | 6 | 100% { 7 | transform: scaleX(1); 8 | } 9 | } 10 | 11 | .bezier-animated { 12 | height: 10px; 13 | width: 200px; 14 | background: indianred; 15 | transform-origin: left; 16 | animation: bezierStoryScale 1000ms infinite alternate both; 17 | } 18 | -------------------------------------------------------------------------------- /demo/src/sandboxes/leva-plugin-dates/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "leva-plugin-dates", 3 | "version": "1.0.0", 4 | "keywords": [], 5 | "main": "src/index.jsx", 6 | "dependencies": { 7 | "@leva-ui/plugin-dates": "*", 8 | "leva": "*", 9 | "react": "^18.0.0", 10 | "react-dom": "^18.0.0", 11 | "react-scripts": "4.0.3" 12 | }, 13 | "devDependencies": { 14 | "@types/react": "^18.0.0", 15 | "@types/react-dom": "^18.0.0", 16 | "typescript": "^4.1.5" 17 | }, 18 | "scripts": { 19 | "start": "react-scripts start", 20 | "build": "react-scripts build", 21 | "test": "react-scripts test --env=jsdom", 22 | "eject": "react-scripts eject" 23 | }, 24 | "browserslist": [ 25 | ">0.2%", 26 | "not dead", 27 | "not ie <= 11", 28 | "not op_mini all" 29 | ] 30 | } 31 | -------------------------------------------------------------------------------- /demo/src/sandboxes/leva-plugin-dates/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 11 | 12 | 13 | 22 | Leva Sandbox 23 | 24 | 25 | 26 | 27 |
28 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /demo/src/sandboxes/leva-plugin-dates/src/App.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { date } from '@leva-ui/plugin-dates' 3 | import { useControls } from 'leva' 4 | 5 | export default function App() { 6 | const { birthday } = useControls({ 7 | birthday: date({ 8 | date: new Date(), 9 | locale: 'en-UK', 10 | inputFormat: 'dd.MM.yyyy', 11 | }), 12 | }) 13 | 14 | return
{birthday.formattedDate}
15 | } 16 | -------------------------------------------------------------------------------- /demo/src/sandboxes/leva-plugin-dates/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: system-ui, sans-serif; 3 | min-height: 100vh; 4 | background: linear-gradient(140deg, rgb(165, 142, 251), rgb(233, 191, 248)); 5 | margin: 0; 6 | } 7 | 8 | *, 9 | *:after, 10 | *:before { 11 | box-sizing: border-box; 12 | } 13 | 14 | pre { 15 | max-width: 720px; 16 | margin: 20px; 17 | padding: 20px; 18 | border: 10px solid black; 19 | } 20 | -------------------------------------------------------------------------------- /demo/src/sandboxes/leva-plugin-dates/src/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom' 3 | import App from './App' 4 | 5 | import './index.css' 6 | 7 | const rootElement = document.getElementById('root') 8 | ReactDOM.render( 9 | 10 | 11 | , 12 | rootElement 13 | ) 14 | -------------------------------------------------------------------------------- /demo/src/sandboxes/leva-plugin-plot/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "leva-plugin-plot", 3 | "version": "1.0.0", 4 | "keywords": [], 5 | "main": "src/index.jsx", 6 | "dependencies": { 7 | "@leva-ui/plugin-plot": "*", 8 | "leva": "*", 9 | "react": "^18.0.0", 10 | "react-dom": "^18.0.0", 11 | "react-scripts": "4.0.3" 12 | }, 13 | "devDependencies": { 14 | "@types/react": "^18.0.0", 15 | "@types/react-dom": "^18.0.0", 16 | "typescript": "^4.1.5" 17 | }, 18 | "scripts": { 19 | "start": "react-scripts start", 20 | "build": "react-scripts build", 21 | "test": "react-scripts test --env=jsdom", 22 | "eject": "react-scripts eject" 23 | }, 24 | "browserslist": [ 25 | ">0.2%", 26 | "not dead", 27 | "not ie <= 11", 28 | "not op_mini all" 29 | ] 30 | } 31 | -------------------------------------------------------------------------------- /demo/src/sandboxes/leva-plugin-plot/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 11 | 12 | 13 | 22 | Leva Sandbox 23 | 24 | 25 | 26 | 27 |
28 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /demo/src/sandboxes/leva-plugin-plot/src/App.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { useControls, monitor } from 'leva' 3 | import { plot } from '@leva-ui/plugin-plot' 4 | 5 | export default function App() { 6 | const p = React.useRef(performance.now()) 7 | const values = useControls({ 8 | w: 1, 9 | y1: plot({ expression: 'cos(x*w)', boundsX: [-10, 10] }), 10 | y2: plot({ expression: 'x * y1', boundsX: [-100, 100] }), 11 | y3: plot({ expression: 'tan(y2)', boundsX: [-4, 4], boundsY: [-10, 10] }), 12 | }) 13 | 14 | useControls( 15 | { 16 | 'y1(t)': monitor( 17 | () => { 18 | const t = performance.now() - p.current 19 | return values.y1(t / 100) 20 | }, 21 | { graph: true, interval: 30 } 22 | ), 23 | }, 24 | [values.y1] 25 | ) 26 | 27 | const t1 = values.y1(1) 28 | const t2 = values.y2(1) 29 | const t3 = values.y3(1) 30 | return ( 31 |
32 |
y1(1) = {t1}
33 |
y2(1) = {t2}
34 |
y3(1) = {t3}
35 |
36 | ) 37 | } 38 | -------------------------------------------------------------------------------- /demo/src/sandboxes/leva-plugin-plot/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: system-ui, sans-serif; 3 | min-height: 100vh; 4 | background: linear-gradient(140deg, rgb(165, 142, 251), rgb(233, 191, 248)); 5 | margin: 0; 6 | } 7 | 8 | *, 9 | *:after, 10 | *:before { 11 | box-sizing: border-box; 12 | } 13 | 14 | pre { 15 | max-width: 720px; 16 | margin: 20px; 17 | padding: 20px; 18 | border: 10px solid black; 19 | } 20 | -------------------------------------------------------------------------------- /demo/src/sandboxes/leva-plugin-plot/src/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom' 3 | import App from './App' 4 | 5 | import './index.css' 6 | 7 | const rootElement = document.getElementById('root') 8 | ReactDOM.render( 9 | 10 | 11 | , 12 | rootElement 13 | ) 14 | -------------------------------------------------------------------------------- /demo/src/sandboxes/leva-plugin-spring/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "leva-plugin-spring", 3 | "version": "1.0.0", 4 | "keywords": [], 5 | "main": "src/index.jsx", 6 | "dependencies": { 7 | "@leva-ui/plugin-spring": "*", 8 | "leva": "*", 9 | "react": "^18.0.0", 10 | "react-dom": "^18.0.0", 11 | "react-scripts": "4.0.3" 12 | }, 13 | "devDependencies": { 14 | "@types/react": "^18.0.0", 15 | "@types/react-dom": "^18.0.0", 16 | "typescript": "^4.1.5" 17 | }, 18 | "scripts": { 19 | "start": "react-scripts start", 20 | "build": "react-scripts build", 21 | "test": "react-scripts test --env=jsdom", 22 | "eject": "react-scripts eject" 23 | }, 24 | "browserslist": [ 25 | ">0.2%", 26 | "not dead", 27 | "not ie <= 11", 28 | "not op_mini all" 29 | ] 30 | } 31 | -------------------------------------------------------------------------------- /demo/src/sandboxes/leva-plugin-spring/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 11 | 12 | 13 | 22 | Leva Sandbox 23 | 24 | 25 | 26 | 27 |
28 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /demo/src/sandboxes/leva-plugin-spring/src/App.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { useControls } from 'leva' 3 | import { spring } from '@leva-ui/plugin-spring' 4 | 5 | export default function App() { 6 | const { mySpring } = useControls({ 7 | mySpring: spring({ tension: 100, friction: 30, hint: 'spring to use with react-spring' }), 8 | }) 9 | 10 | return ( 11 |
12 |
{JSON.stringify(mySpring, null, '  ')}
13 |
14 | ) 15 | } 16 | -------------------------------------------------------------------------------- /demo/src/sandboxes/leva-plugin-spring/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: system-ui, sans-serif; 3 | min-height: 100vh; 4 | background: linear-gradient(140deg, rgb(165, 142, 251), rgb(233, 191, 248)); 5 | margin: 0; 6 | } 7 | 8 | *, 9 | *:after, 10 | *:before { 11 | box-sizing: border-box; 12 | } 13 | 14 | pre { 15 | max-width: 720px; 16 | margin: 20px; 17 | padding: 20px; 18 | border: 10px solid black; 19 | } 20 | -------------------------------------------------------------------------------- /demo/src/sandboxes/leva-plugin-spring/src/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom' 3 | import App from './App' 4 | 5 | import './index.css' 6 | 7 | const rootElement = document.getElementById('root') 8 | ReactDOM.render( 9 | 10 | 11 | , 12 | rootElement 13 | ) 14 | -------------------------------------------------------------------------------- /demo/src/sandboxes/leva-scroll/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "leva-scroll", 3 | "version": "1.0.0", 4 | "description": "This sandbox has been generated!", 5 | "keywords": [], 6 | "main": "src/index.jsx", 7 | "dependencies": { 8 | "leva": "*", 9 | "noisejs": "2.1.0", 10 | "react": "^18.0.0", 11 | "react-dom": "^18.0.0", 12 | "react-scripts": "4.0.3" 13 | }, 14 | "scripts": { 15 | "start": "react-scripts start", 16 | "build": "react-scripts build", 17 | "test": "react-scripts test --env=jsdom", 18 | "eject": "react-scripts eject" 19 | }, 20 | "browserslist": [ 21 | ">0.2%", 22 | "not dead", 23 | "not ie <= 11", 24 | "not op_mini all" 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /demo/src/sandboxes/leva-scroll/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 11 | 12 | 13 | 22 | Leva Sandbox 23 | 24 | 25 | 26 | 27 |
28 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /demo/src/sandboxes/leva-scroll/src/App.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { useControls, folder, button, monitor, Leva } from 'leva' 3 | import { Noise } from 'noisejs' 4 | 5 | const noise = new Noise(Math.random()) 6 | 7 | function frame() { 8 | const t = Date.now() 9 | return noise.simplex2(t / 1000, t / 100) 10 | } 11 | 12 | export default function App() { 13 | const data = useControls({ 14 | first: { value: 0, min: -10, max: 10 }, 15 | image: { image: undefined }, 16 | select: { options: ['x', 'y', ['x', 'y']] }, 17 | interval: { min: -100, max: 100, value: [-10, 10] }, 18 | color: '#ffffff', 19 | refMonitor: monitor(frame, { graph: true, interval: 30 }), 20 | number: { value: 1000, min: 3 }, 21 | folder2: folder({ 22 | boolean: false, 23 | spring: { tension: 100, friction: 30 }, 24 | folder3: folder( 25 | { 26 | // eslint-disable-next-line no-console 27 | 'Hello Button': button(() => console.log('hello')), 28 | folder4: folder({ 29 | pos2d: { x: 3, y: 4 }, 30 | pos2dArr: [100, 200], 31 | pos3d: { x: 0.3, y: 0.1, z: 0.5 }, 32 | pos3dArr: [Math.PI / 2, 20, 4], 33 | }), 34 | }, 35 | { collapsed: false } 36 | ), 37 | }), 38 | colorObj: { r: 1, g: 2, b: 3 }, 39 | }) 40 | 41 | return ( 42 | <> 43 | 44 | 45 |
46 |
{JSON.stringify(data, null, '  ')}
47 |
48 | 49 | ) 50 | } 51 | -------------------------------------------------------------------------------- /demo/src/sandboxes/leva-scroll/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: system-ui, sans-serif; 3 | min-height: 100vh; 4 | background: linear-gradient(140deg, rgb(165, 142, 251), rgb(233, 191, 248)); 5 | margin: 0; 6 | } 7 | 8 | *, 9 | *:after, 10 | *:before { 11 | box-sizing: border-box; 12 | } 13 | 14 | pre { 15 | max-width: 720px; 16 | margin: 20px; 17 | padding: 20px; 18 | border: 10px solid black; 19 | } 20 | -------------------------------------------------------------------------------- /demo/src/sandboxes/leva-scroll/src/index.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom' 3 | import App from './App' 4 | 5 | import './index.css' 6 | 7 | const rootElement = document.getElementById('root') 8 | ReactDOM.render( 9 | 10 | 11 | , 12 | rootElement 13 | ) 14 | -------------------------------------------------------------------------------- /demo/src/sandboxes/leva-theme/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "leva-theme", 3 | "version": "1.0.0", 4 | "main": "src/index.jsx", 5 | "dependencies": { 6 | "leva": "*", 7 | "@leva-ui/plugin-spring": "*", 8 | "noisejs": "2.1.0", 9 | "react": "^18.0.0", 10 | "react-dom": "^18.0.0", 11 | "react-scripts": "4.0.3" 12 | }, 13 | "scripts": { 14 | "start": "react-scripts start", 15 | "build": "react-scripts build", 16 | "test": "react-scripts test --env=jsdom", 17 | "eject": "react-scripts eject" 18 | }, 19 | "browserslist": [ 20 | ">0.2%", 21 | "not dead", 22 | "not ie <= 11", 23 | "not op_mini all" 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /demo/src/sandboxes/leva-theme/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 11 | 12 | 13 | 22 | Leva Sandbox 23 | 24 | 25 | 26 | 27 |
28 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /demo/src/sandboxes/leva-theme/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: system-ui, sans-serif; 3 | min-height: 100vh; 4 | background: linear-gradient(140deg, rgb(165, 142, 251), rgb(233, 191, 248)); 5 | margin: 0; 6 | } 7 | 8 | *, 9 | *:after, 10 | *:before { 11 | box-sizing: border-box; 12 | } 13 | 14 | pre { 15 | max-width: 720px; 16 | margin: 20px; 17 | padding: 20px; 18 | border: 10px solid black; 19 | } 20 | -------------------------------------------------------------------------------- /demo/src/sandboxes/leva-theme/src/index.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom' 3 | import App from './App' 4 | 5 | import './index.css' 6 | 7 | const rootElement = document.getElementById('root') 8 | ReactDOM.render( 9 | 10 | 11 | , 12 | rootElement 13 | ) 14 | -------------------------------------------------------------------------------- /demo/src/sandboxes/leva-transient/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "leva-transient", 3 | "version": "1.0.0", 4 | "main": "src/index.jsx", 5 | "dependencies": { 6 | "@react-three/drei": "^4.3.3", 7 | "@react-three/fiber": "^6.0.21", 8 | "leva": "*", 9 | "react": "^18.0.0", 10 | "react-dom": "^18.0.0", 11 | "react-scripts": "4.0.3", 12 | "three": "^0.143.0" 13 | }, 14 | "scripts": { 15 | "start": "react-scripts start", 16 | "build": "react-scripts build", 17 | "test": "react-scripts test --env=jsdom", 18 | "eject": "react-scripts eject" 19 | }, 20 | "browserslist": [ 21 | ">0.2%", 22 | "not dead", 23 | "not ie <= 11", 24 | "not op_mini all" 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /demo/src/sandboxes/leva-transient/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 11 | 12 | 13 | 22 | Leva Sandbox 23 | 24 | 25 | 26 | 27 |
28 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /demo/src/sandboxes/leva-transient/src/App.jsx: -------------------------------------------------------------------------------- 1 | import React, { useRef } from 'react' 2 | import { useControls } from 'leva' 3 | import { Canvas } from '@react-three/fiber' 4 | import { OrbitControls } from '@react-three/drei' 5 | 6 | import * as THREE from 'three' 7 | 8 | const torusknot = new THREE.TorusKnotBufferGeometry(3, 0.8, 256, 16) 9 | 10 | const Mesh = () => { 11 | const matRef = useRef() 12 | useControls({ color: { value: 'indianred', onChange: (v) => matRef.current && matRef.current.color.set(v) } }) 13 | return ( 14 | 15 | 16 | 17 | ) 18 | } 19 | 20 | export default function App() { 21 | return ( 22 | 26 | 27 | 28 | 29 | 30 | ) 31 | } 32 | -------------------------------------------------------------------------------- /demo/src/sandboxes/leva-transient/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: system-ui, sans-serif; 3 | min-height: 100vh; 4 | background: linear-gradient(140deg, rgb(165, 142, 251), rgb(233, 191, 248)); 5 | margin: 0; 6 | } 7 | 8 | *, 9 | *:after, 10 | *:before { 11 | box-sizing: border-box; 12 | } 13 | 14 | pre { 15 | max-width: 720px; 16 | margin: 20px; 17 | padding: 20px; 18 | border: 10px solid black; 19 | } 20 | -------------------------------------------------------------------------------- /demo/src/sandboxes/leva-transient/src/index.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom' 3 | import App from './App' 4 | 5 | import './index.css' 6 | 7 | const rootElement = document.getElementById('root') 8 | ReactDOM.render( 9 | 10 | 11 | , 12 | rootElement 13 | ) 14 | -------------------------------------------------------------------------------- /demo/src/sandboxes/leva-ui/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "leva-ui", 3 | "version": "1.0.0", 4 | "description": "This sandbox has been generated!", 5 | "keywords": [], 6 | "main": "src/index.jsx", 7 | "dependencies": { 8 | "leva": "*", 9 | "react": "^18.0.0", 10 | "react-dom": "^18.0.0", 11 | "react-dropzone": "11.3.1", 12 | "react-scripts": "4.0.3", 13 | "react-use-gesture": "^9.0.0" 14 | }, 15 | "scripts": { 16 | "start": "react-scripts start", 17 | "build": "react-scripts build", 18 | "test": "react-scripts test --env=jsdom", 19 | "eject": "react-scripts eject" 20 | }, 21 | "browserslist": [ 22 | ">0.2%", 23 | "not dead", 24 | "not ie <= 11", 25 | "not op_mini all" 26 | ] 27 | } 28 | -------------------------------------------------------------------------------- /demo/src/sandboxes/leva-ui/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 11 | 12 | 13 | 22 | Leva Sandbox 23 | 24 | 25 | 26 | 27 |
28 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /demo/src/sandboxes/leva-ui/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: system-ui, sans-serif; 3 | min-height: 100vh; 4 | background: linear-gradient(140deg, rgb(165, 142, 251), rgb(233, 191, 248)); 5 | margin: 0; 6 | } 7 | 8 | *, 9 | *:after, 10 | *:before { 11 | box-sizing: border-box; 12 | } 13 | 14 | pre { 15 | max-width: 720px; 16 | margin: 20px; 17 | padding: 20px; 18 | border: 10px solid black; 19 | } 20 | -------------------------------------------------------------------------------- /demo/src/sandboxes/leva-ui/src/index.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom' 3 | import App from './App' 4 | 5 | import './index.css' 6 | 7 | const rootElement = document.getElementById('root') 8 | ReactDOM.render( 9 | 10 | 11 | , 12 | rootElement 13 | ) 14 | -------------------------------------------------------------------------------- /demo/src/styles.module.css: -------------------------------------------------------------------------------- 1 | .back { 2 | position: fixed; 3 | left: 10px; 4 | bottom: 10px; 5 | z-index: 100; 6 | padding: 10px; 7 | background: #000; 8 | color: #fff; 9 | font-weight: 500; 10 | font-size: 14px; 11 | text-decoration: none; 12 | border-radius: 2px; 13 | border: 1px solid #333; 14 | } 15 | 16 | .link { 17 | color: inherit; 18 | } 19 | 20 | .linkList { 21 | display: grid; 22 | gap: 10px; 23 | } 24 | -------------------------------------------------------------------------------- /demo/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "lib": ["DOM", "DOM.Iterable", "ESNext"], 5 | "types": ["vite/client"], 6 | "allowJs": true, 7 | "skipLibCheck": false, 8 | "esModuleInterop": false, 9 | "allowSyntheticDefaultImports": true, 10 | "strict": true, 11 | "forceConsistentCasingInFileNames": true, 12 | "module": "ESNext", 13 | "moduleResolution": "node", 14 | "resolveJsonModule": true, 15 | "isolatedModules": true, 16 | "noEmit": true, 17 | "jsx": "react" 18 | }, 19 | "include": ["./src"] 20 | } 21 | -------------------------------------------------------------------------------- /demo/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import reactRefresh from '@vitejs/plugin-react-refresh' 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [reactRefresh()], 7 | }) 8 | -------------------------------------------------------------------------------- /docs/advanced/circle-drag.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pmndrs/leva/72d8e8603f9c3b99497afc738cb412053dc0807f/docs/advanced/circle-drag.gif -------------------------------------------------------------------------------- /docs/advanced/creating-plugins.md: -------------------------------------------------------------------------------- 1 | # Creating Plugins 2 | 3 | @TODO 4 | This page will contain info on how to create custom plugins, 5 | what even qualifies as a plugin, and an idea of what kinds of plugins could be included and maintained in this repo 6 | -------------------------------------------------------------------------------- /docs/configuration.md: -------------------------------------------------------------------------------- 1 | ## Configuration 2 | 3 | You can configure Leva by using the `` component anywhere in your App: 4 | 5 | ```jsx 6 | import { Leva } from 'leva' 7 | 8 | export default function MyApp() { 9 | return ( 10 | <> 11 |