diff --git a/.husky/pre-commit b/.husky/pre-commit index 9928bf8..53e20b0 100644 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -1 +1,14 @@ -pnpm run --filter=./apps/www build:registry && pnpm prettier +#!/bin/sh +. "$(dirname "$0")/_/husky.sh" + +echo "Running pre-commit hook..." +if ! pnpm run --filter=./apps/www build:registry; then + echo "Error: Failed to build registry. Commit aborted." + exit 1 +fi +echo "Registry built successfully. Running Prettier..." +if ! pnpm prettier; then + echo "Error: Prettier formatting failed. Commit aborted." + exit 1 +fi +echo "Pre-commit hook completed successfully." diff --git a/apps/www/components/SwitchEvent.tsx b/apps/www/components/SwitchEvent.tsx index 4b38674..cacfa69 100644 --- a/apps/www/components/SwitchEvent.tsx +++ b/apps/www/components/SwitchEvent.tsx @@ -3,17 +3,17 @@ import React, { useState } from "react"; import { Switch } from "ruru-ui/components/switch"; -const SwiychEvent = (): React.ReactNode => { +const SwitchEvent = (): React.ReactNode => { const [value, setValue] = useState(false); return (
- setValue(e)} id="toggle-animation" /> - + setValue(e)} id="toggle-value" /> +

{String(value)}

); }; -export default SwiychEvent; +export default SwitchEvent; diff --git a/apps/www/content/docs/components/switch.mdx b/apps/www/content/docs/components/switch.mdx index 6f0c8aa..363a93d 100644 --- a/apps/www/content/docs/components/switch.mdx +++ b/apps/www/content/docs/components/switch.mdx @@ -7,7 +7,7 @@ preview: switch import { Tabs, Tab } from "fumadocs-ui/components/tabs"; import { Switch } from "ruru-ui/components/switch"; import { Tabs as Rutabs, Tab as Rutab } from "ruru-ui/components/tabs"; -import SwiychEvent from "../../../components/SwitchEvent.tsx"; +import SwitchEvent from "../../../components/SwitchEvent.tsx"; ## Installation @@ -55,8 +55,7 @@ import SwiychEvent from "../../../components/SwitchEvent.tsx"; ```tsx -// [!code word:Switch] -import { Switch } from "your-ui-library/components/switch"; +import { Switch } from "ruru-ui/components/switch"; export function Demo() { return ; @@ -76,7 +75,7 @@ export function Demo() { ```tsx // [!code word:disabled] -import { Switch } from "your-ui-library/components/switch"; +import { Switch } from "ruru-ui/components/switch"; export function SwitchDemo() { return ; @@ -86,13 +85,6 @@ export function SwitchDemo() { -## Props - -| Name | Type | Default | Description | -| ------------- | ------- | ------- | -------------------------------------- | -| **className** | **string** | `"" ` | Additional class names for the switch. | -| **disabled** | **boolean** | `false` | Flag to disable the switch. | - ## Examples ### Switch with lables @@ -100,16 +92,14 @@ export function SwitchDemo() {
- - + +
```tsx // [!code word:airplane-mode] -// [!code word:id] -// [!code word:htmlFor] -import { Switch } from "your-ui-library/components/switch"; +import { Switch } from "ruru-ui/components/switch"; export function Demo() { return ( @@ -134,7 +124,7 @@ export function Demo() { ```tsx // [!code word:defaultChecked] -import { Switch } from "your-ui-library/components/switch"; +import { Switch } from "ruru-ui/components/switch"; export function SwitchDemo() { return ; @@ -148,7 +138,7 @@ export function SwitchDemo() { - + ```tsx @@ -179,3 +169,13 @@ export default SwiychDemo; +## Props + +| Name | Type | Default | Description | +| ------------------- | ------------------------ | ----------- | ------------------------------------------------------------ | +| **className** | **string** | `"" ` | Additional class names for the switch. | +| **disabled** | **boolean** | `false` | Flag to disable the switch. | +| **id** | **string** | `""` | Id for the switch. | +| **defaultChecked** | **boolean** | `false` | Flag to set the switch to checked by default. | +| **checked** | **boolean** | `false` | Flag to set the switch to checked. | +| **onCheckedChange** | **(e: boolean) => void** | `undefined` | Callback function that is called when the switch is toggled. | diff --git a/apps/www/public/registry/components/switch.json b/apps/www/public/registry/components/switch.json index 7e31764..2d666e3 100644 --- a/apps/www/public/registry/components/switch.json +++ b/apps/www/public/registry/components/switch.json @@ -1,10 +1,9 @@ { "name": "switch", - "dependencies": ["@radix-ui/react-switch"], "files": [ { "name": "switch.tsx", - "content": "import * as React from \"react\";\nimport * as SwitchPrimitives from \"@radix-ui/react-switch\";\n\nimport { cn } from \"@/utils/cn\";\n\nconst Switch = React.forwardRef<\n React.ElementRef,\n React.ComponentPropsWithoutRef\n>(({ className, ...props }, ref) => (\n \n \n \n));\nSwitch.displayName = SwitchPrimitives.Root.displayName;\n\nexport { Switch };\n" + "content": "\"use client\";\n\nimport * as React from \"react\";\nimport { cn } from \"@/utils/cn\";\n\ninterface SwitchProps extends React.ComponentPropsWithoutRef<\"button\"> {\n checked?: boolean;\n onCheckedChange?: (checked: boolean) => void;\n defaultChecked?: boolean;\n}\n\n\nconst Switch = React.forwardRef(\n (\n { className, checked, onCheckedChange, defaultChecked = false, ...props },\n ref,\n ) => {\n const [isCheckedInternal, setIsCheckedInternal] =\n React.useState(defaultChecked);\n\n const isControlled = checked !== undefined;\n const isCheckedValue = isControlled ? checked : isCheckedInternal;\n\n const handleClick = () => {\n const newChecked = !isCheckedValue;\n if (!isControlled) {\n setIsCheckedInternal(newChecked);\n }\n if (onCheckedChange) {\n onCheckedChange(newChecked);\n }\n };\n\n return (\n \n \n \n );\n },\n);\n\nSwitch.displayName = \"Switch\";\n\nexport { Switch };\n" } ], "type": "components:ui" diff --git a/apps/www/public/registry/index.json b/apps/www/public/registry/index.json index 4342b6a..96599b3 100644 --- a/apps/www/public/registry/index.json +++ b/apps/www/public/registry/index.json @@ -40,7 +40,6 @@ }, { "name": "switch", - "dependencies": ["@radix-ui/react-switch"], "files": ["switch.tsx"], "type": "components:ui" }, diff --git a/apps/www/registry/ui.ts b/apps/www/registry/ui.ts index f06892f..dac3732 100644 --- a/apps/www/registry/ui.ts +++ b/apps/www/registry/ui.ts @@ -43,7 +43,6 @@ export const ui: Registry = [ { name: "switch", type: "components:ui", - dependencies: ["@radix-ui/react-switch"], files: ["switch.tsx"], }, { diff --git a/packages/ui/package.json b/packages/ui/package.json index 7477387..02d6f64 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -1,6 +1,6 @@ { "name": "ruru-ui", - "version": "2.2.4", + "version": "2.2.5", "description": "Ruru UI Components", "publishConfig": { "access": "public" @@ -95,7 +95,6 @@ "@radix-ui/react-icons": "^1.3.0", "@radix-ui/react-select": "^2.1.1", "@radix-ui/react-slot": "^1.1.0", - "@radix-ui/react-switch": "^1.1.0", "@radix-ui/react-tabs": "^1.1.0", "@radix-ui/react-tooltip": "^1.1.2", "@swc/core": "^1.6.13", diff --git a/packages/ui/src/components/switch.tsx b/packages/ui/src/components/switch.tsx index 2761d2f..c688876 100644 --- a/packages/ui/src/components/switch.tsx +++ b/packages/ui/src/components/switch.tsx @@ -1,12 +1,22 @@ -import * as React from "react"; -import * as SwitchPrimitives from "@radix-ui/react-switch"; +"use client"; +import * as React from "react"; import { cn } from "@/utils/cn"; + +interface SwitchProps extends React.ComponentPropsWithoutRef<"button"> { + checked?: boolean; + onCheckedChange?: (checked: boolean) => void; + defaultChecked?: boolean; +} + /** * Switch component * * @param {string} className - Additional class names for the switch. - * @param {React.Ref>} ref - Forwarded ref. + * @param {boolean} checked - Whether the switch is checked. + * @param {(checked: boolean) => void} onCheckedChange - Callback when the switch is checked or unchecked. + * @param {boolean} defaultChecked - Whether the switch is checked by default. + * @param {React.Ref} ref - Forwarded ref. * * @example * @@ -14,25 +24,52 @@ import { cn } from "@/utils/cn"; * * ``` */ -const Switch = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - - - -)); -Switch.displayName = SwitchPrimitives.Root.displayName; +const Switch = React.forwardRef( + ( + { className, checked, onCheckedChange, defaultChecked = false, ...props }, + ref, + ) => { + const [isCheckedInternal, setIsCheckedInternal] = + React.useState(defaultChecked); + + const isControlled = checked !== undefined; + const isCheckedValue = isControlled ? checked : isCheckedInternal; + + const handleClick = () => { + const newChecked = !isCheckedValue; + if (!isControlled) { + setIsCheckedInternal(newChecked); + } + if (onCheckedChange) { + onCheckedChange(newChecked); + } + }; + + return ( + + ); + }, +); + +Switch.displayName = "Switch"; export { Switch }; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 91a37e6..36c7199 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -320,9 +320,6 @@ importers: '@radix-ui/react-slot': specifier: ^1.1.0 version: 1.1.0(@types/react@18.3.3)(react@18.3.1) - '@radix-ui/react-switch': - specifier: ^1.1.0 - version: 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1)(react@18.3.1) '@radix-ui/react-tabs': specifier: ^1.1.0 version: 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1)(react@18.3.1) @@ -364,7 +361,7 @@ importers: version: 1.0.7(tailwindcss@3.4.4) tsup: specifier: ^8.1.1 - version: 8.1.1(@swc/core@1.6.13)(postcss@8.4.39)(tsx@4.17.0)(typescript@5.5.3) + version: 8.1.1(@swc/core@1.6.13)(postcss@8.4.39)(typescript@5.5.3) zod: specifier: ^3.23.8 version: 3.23.8 @@ -395,7 +392,7 @@ importers: version: 8.4.39 postcss-cli: specifier: ^11.0.0 - version: 11.0.0(postcss@8.4.39)(tsx@4.17.0) + version: 11.0.0(postcss@8.4.39) postcss-lightningcss: specifier: ^1.0.0 version: 1.0.0(postcss@8.4.39) @@ -1077,6 +1074,7 @@ packages: cpu: [ppc64] os: [aix] requiresBuild: true + dev: false optional: true /@esbuild/android-arm64@0.23.0: @@ -1085,6 +1083,7 @@ packages: cpu: [arm64] os: [android] requiresBuild: true + dev: false optional: true /@esbuild/android-arm@0.23.0: @@ -1093,6 +1092,7 @@ packages: cpu: [arm] os: [android] requiresBuild: true + dev: false optional: true /@esbuild/android-x64@0.23.0: @@ -1101,6 +1101,7 @@ packages: cpu: [x64] os: [android] requiresBuild: true + dev: false optional: true /@esbuild/darwin-arm64@0.23.0: @@ -1109,6 +1110,7 @@ packages: cpu: [arm64] os: [darwin] requiresBuild: true + dev: false optional: true /@esbuild/darwin-x64@0.23.0: @@ -1117,6 +1119,7 @@ packages: cpu: [x64] os: [darwin] requiresBuild: true + dev: false optional: true /@esbuild/freebsd-arm64@0.23.0: @@ -1125,6 +1128,7 @@ packages: cpu: [arm64] os: [freebsd] requiresBuild: true + dev: false optional: true /@esbuild/freebsd-x64@0.23.0: @@ -1133,6 +1137,7 @@ packages: cpu: [x64] os: [freebsd] requiresBuild: true + dev: false optional: true /@esbuild/linux-arm64@0.23.0: @@ -1141,6 +1146,7 @@ packages: cpu: [arm64] os: [linux] requiresBuild: true + dev: false optional: true /@esbuild/linux-arm@0.23.0: @@ -1149,6 +1155,7 @@ packages: cpu: [arm] os: [linux] requiresBuild: true + dev: false optional: true /@esbuild/linux-ia32@0.23.0: @@ -1157,6 +1164,7 @@ packages: cpu: [ia32] os: [linux] requiresBuild: true + dev: false optional: true /@esbuild/linux-loong64@0.23.0: @@ -1165,6 +1173,7 @@ packages: cpu: [loong64] os: [linux] requiresBuild: true + dev: false optional: true /@esbuild/linux-mips64el@0.23.0: @@ -1173,6 +1182,7 @@ packages: cpu: [mips64el] os: [linux] requiresBuild: true + dev: false optional: true /@esbuild/linux-ppc64@0.23.0: @@ -1181,6 +1191,7 @@ packages: cpu: [ppc64] os: [linux] requiresBuild: true + dev: false optional: true /@esbuild/linux-riscv64@0.23.0: @@ -1189,6 +1200,7 @@ packages: cpu: [riscv64] os: [linux] requiresBuild: true + dev: false optional: true /@esbuild/linux-s390x@0.23.0: @@ -1197,6 +1209,7 @@ packages: cpu: [s390x] os: [linux] requiresBuild: true + dev: false optional: true /@esbuild/linux-x64@0.23.0: @@ -1205,6 +1218,7 @@ packages: cpu: [x64] os: [linux] requiresBuild: true + dev: false optional: true /@esbuild/netbsd-x64@0.23.0: @@ -1213,6 +1227,7 @@ packages: cpu: [x64] os: [netbsd] requiresBuild: true + dev: false optional: true /@esbuild/openbsd-arm64@0.23.0: @@ -1221,6 +1236,7 @@ packages: cpu: [arm64] os: [openbsd] requiresBuild: true + dev: false optional: true /@esbuild/openbsd-x64@0.23.0: @@ -1229,6 +1245,7 @@ packages: cpu: [x64] os: [openbsd] requiresBuild: true + dev: false optional: true /@esbuild/sunos-x64@0.23.0: @@ -1237,6 +1254,7 @@ packages: cpu: [x64] os: [sunos] requiresBuild: true + dev: false optional: true /@esbuild/win32-arm64@0.23.0: @@ -1245,6 +1263,7 @@ packages: cpu: [arm64] os: [win32] requiresBuild: true + dev: false optional: true /@esbuild/win32-ia32@0.23.0: @@ -1253,6 +1272,7 @@ packages: cpu: [ia32] os: [win32] requiresBuild: true + dev: false optional: true /@esbuild/win32-x64@0.23.0: @@ -1261,6 +1281,7 @@ packages: cpu: [x64] os: [win32] requiresBuild: true + dev: false optional: true /@eslint-community/eslint-utils@4.4.0(eslint@8.57.0): @@ -2631,32 +2652,6 @@ packages: react: 18.3.1 dev: false - /@radix-ui/react-switch@1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1)(react@18.3.1): - resolution: {integrity: sha512-OBzy5WAj641k0AOSpKQtreDMe+isX0MQJ1IVyF03ucdF3DunOnROVrjWs8zsXUxC3zfZ6JL9HFVCUlMghz9dJw==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - dependencies: - '@radix-ui/primitive': 1.1.0 - '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.3)(react@18.3.1) - '@radix-ui/react-context': 1.1.0(@types/react@18.3.3)(react@18.3.1) - '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.3.3)(react@18.3.1) - '@radix-ui/react-use-previous': 1.1.0(@types/react@18.3.3)(react@18.3.1) - '@radix-ui/react-use-size': 1.1.0(@types/react@18.3.3)(react@18.3.1) - '@types/react': 18.3.3 - '@types/react-dom': 18.3.0 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - dev: false - /@radix-ui/react-tabs@1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1)(react@18.3.1): resolution: {integrity: sha512-bZgOKB/LtZIij75FSuPzyEti/XBhJH52ExgtdVqjCIh+Nx/FW+LhnbXtbCzIi34ccyMsyOja8T0thCzoHFXNKA==} peerDependencies: @@ -4984,6 +4979,7 @@ packages: '@esbuild/win32-arm64': 0.23.0 '@esbuild/win32-ia32': 0.23.0 '@esbuild/win32-x64': 0.23.0 + dev: false /escalade@3.1.2: resolution: {integrity: sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==} @@ -8466,7 +8462,7 @@ packages: engines: {node: '>= 0.4'} dev: true - /postcss-cli@11.0.0(postcss@8.4.39)(tsx@4.17.0): + /postcss-cli@11.0.0(postcss@8.4.39): resolution: {integrity: sha512-xMITAI7M0u1yolVcXJ9XTZiO9aO49mcoKQy6pCDFdMh9kGqhzLVpWxeD/32M/QBmkhcGypZFFOLNLmIW4Pg4RA==} engines: {node: '>=18'} hasBin: true @@ -8480,7 +8476,7 @@ packages: globby: 14.0.2 picocolors: 1.0.1 postcss: 8.4.39 - postcss-load-config: 5.1.0(postcss@8.4.39)(tsx@4.17.0) + postcss-load-config: 5.1.0(postcss@8.4.39) postcss-reporter: 7.1.0(postcss@8.4.39) pretty-hrtime: 1.0.3 read-cache: 1.0.0 @@ -8538,7 +8534,7 @@ packages: postcss: 8.4.39 yaml: 2.4.5 - /postcss-load-config@5.1.0(postcss@8.4.39)(tsx@4.17.0): + /postcss-load-config@5.1.0(postcss@8.4.39): resolution: {integrity: sha512-G5AJ+IX0aD0dygOE0yFZQ/huFFMSNneyfp0e3/bT05a8OfPC5FUoZRPfGijUdGOJNMewJiwzcHJXFafFzeKFVA==} engines: {node: '>= 18'} peerDependencies: @@ -8555,10 +8551,31 @@ packages: dependencies: lilconfig: 3.1.2 postcss: 8.4.39 - tsx: 4.17.0 yaml: 2.4.5 dev: true + /postcss-load-config@6.0.1(postcss@8.4.39): + resolution: {integrity: sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==} + engines: {node: '>= 18'} + peerDependencies: + jiti: '>=1.21.0' + postcss: '>=8.0.9' + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + jiti: + optional: true + postcss: + optional: true + tsx: + optional: true + yaml: + optional: true + dependencies: + lilconfig: 3.1.2 + postcss: 8.4.39 + dev: false + /postcss-load-config@6.0.1(postcss@8.4.39)(tsx@4.17.0): resolution: {integrity: sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==} engines: {node: '>= 18'} @@ -10021,7 +10038,7 @@ packages: /tslib@2.6.2: resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} - /tsup@8.1.1(@swc/core@1.6.13)(postcss@8.4.39)(tsx@4.17.0)(typescript@5.5.3): + /tsup@8.1.1(@swc/core@1.6.13)(postcss@8.4.39)(typescript@5.5.3): resolution: {integrity: sha512-lLXP3BshJ6y/32b3tPZUB2siD2mkJ6mLzhbPOShfjogSc3aRw8MhbBV4cPKbqkbXuhsJR+c9B0W9RHMbtbXLMQ==} engines: {node: '>=18'} hasBin: true @@ -10051,7 +10068,7 @@ packages: globby: 11.1.0 joycon: 3.1.1 postcss: 8.4.39 - postcss-load-config: 6.0.1(postcss@8.4.39)(tsx@4.17.0) + postcss-load-config: 6.0.1(postcss@8.4.39) resolve-from: 5.0.0 rollup: 4.18.1 source-map: 0.8.0-beta.0 @@ -10126,6 +10143,7 @@ packages: get-tsconfig: 4.7.5 optionalDependencies: fsevents: 2.3.3 + dev: false /turbo-darwin-64@2.0.9: resolution: {integrity: sha512-owlGsOaExuVGBUfrnJwjkL1BWlvefjSKczEAcpLx4BI7Oh6ttakOi+JyomkPkFlYElRpjbvlR2gP8WIn6M/+xQ==}