From 632a5873ab623968c8c16fa08bc540d806c0e8ed Mon Sep 17 00:00:00 2001 From: Rohan Chakraborty Date: Wed, 28 Jan 2026 09:59:30 +0530 Subject: [PATCH 1/2] feat: migrate checkbox to base ui --- .../components/checkbox/checkbox.module.css | 125 +++++++------- .../raystack/components/checkbox/checkbox.tsx | 77 ++------- .../raystack/components/checkbox/index.tsx | 2 +- packages/raystack/package.json | 3 +- pnpm-lock.yaml | 161 ++++++++++++++---- 5 files changed, 214 insertions(+), 154 deletions(-) diff --git a/packages/raystack/components/checkbox/checkbox.module.css b/packages/raystack/components/checkbox/checkbox.module.css index 8a8e3c303..4dc65bc52 100644 --- a/packages/raystack/components/checkbox/checkbox.module.css +++ b/packages/raystack/components/checkbox/checkbox.module.css @@ -1,66 +1,65 @@ .checkbox { - all: unset; - box-sizing: border-box; - display: inline-flex; - align-items: center; - justify-content: center; - width: var(--rs-space-5); - height: var(--rs-space-5); - min-width: var(--rs-space-5); - min-height: var(--rs-space-5); - border-radius: var(--rs-radius-1); - background: var(--rs-color-background-base-primary); - border: 1px solid var(--rs-color-border-base-secondary); - cursor: pointer; - flex-shrink: 0; - } - - .checkbox:hover { - background: var(--rs-color-background-base-primary-hover); - border-color: var(--rs-color-border-base-focus); - } - - .checkbox[data-state="checked"] { - background: var(--rs-color-background-accent-emphasis); - border: none; - } - - .checkbox[data-state="checked"]:hover { - background: var(--rs-color-background-accent-emphasis-hover); - } + all: unset; + box-sizing: border-box; + display: inline-flex; + align-items: center; + justify-content: center; + width: var(--rs-space-5); + height: var(--rs-space-5); + min-width: var(--rs-space-5); + min-height: var(--rs-space-5); + border-radius: var(--rs-radius-1); + background: var(--rs-color-background-base-primary); + border: 1px solid var(--rs-color-border-base-secondary); + cursor: pointer; + flex-shrink: 0; +} - /* Indeterminate state */ - .checkbox-indeterminate[data-state="checked"] { - background: var(--rs-color-background-neutral-tertiary); - border: none; - } +.checkbox:hover { + background: var(--rs-color-background-base-primary-hover); + border-color: var(--rs-color-border-base-focus); +} - .checkbox-indeterminate[data-state="checked"]:hover { - background: var(--rs-color-background-neutral-tertiary); - border: none; - } - - .checkbox-disabled { - opacity: 0.5; - cursor: not-allowed; - } - - .checkbox-disabled:hover { - background: var(--rs-color-background-base-primary); - border-color: var(--rs-color-border-base-primary); - } - - .indicator { - display: flex; - align-items: center; - justify-content: center; - width: 100%; - height: 100%; - color: var(--rs-color-foreground-accent-emphasis); - } - - .icon { - width: var(--rs-space-5); - height: var(--rs-space-5); - } - \ No newline at end of file +.checkbox[data-checked] { + background: var(--rs-color-background-accent-emphasis); + border: none; +} + +.checkbox[data-checked]:hover { + background: var(--rs-color-background-accent-emphasis-hover); +} + +/* Indeterminate state */ +.checkbox[data-indeterminate] { + background: var(--rs-color-background-neutral-tertiary); + border: none; +} + +.checkbox[data-indeterminate]:hover { + background: var(--rs-color-background-neutral-tertiary); + border: none; +} + +.checkbox[data-disabled] { + opacity: 0.5; + cursor: not-allowed; +} + +.checkbox[data-disabled]:hover { + background: var(--rs-color-background-base-primary); + border-color: var(--rs-color-border-base-primary); +} + +.indicator { + display: flex; + align-items: center; + justify-content: center; + width: 100%; + height: 100%; + color: var(--rs-color-foreground-accent-emphasis); +} + +.icon { + width: var(--rs-space-5); + height: var(--rs-space-5); +} diff --git a/packages/raystack/components/checkbox/checkbox.tsx b/packages/raystack/components/checkbox/checkbox.tsx index 2a1e086f6..d67664c78 100644 --- a/packages/raystack/components/checkbox/checkbox.tsx +++ b/packages/raystack/components/checkbox/checkbox.tsx @@ -1,8 +1,8 @@ 'use client'; -import { VariantProps, cva, cx } from 'class-variance-authority'; -import { Checkbox as CheckboxPrimitive } from 'radix-ui'; -import { ComponentPropsWithoutRef, ElementRef, forwardRef } from 'react'; +import { Checkbox as CheckboxPrimitive } from '@base-ui/react/checkbox'; +import { cx } from 'class-variance-authority'; +import { ElementRef, forwardRef } from 'react'; import styles from './checkbox.module.css'; @@ -42,63 +42,22 @@ const IndeterminateIcon = () => ( ); -const checkbox = cva(styles.checkbox); - -type CheckboxVariants = VariantProps; -type CheckedState = boolean | 'indeterminate'; - -export interface CheckboxProps - extends Omit< - ComponentPropsWithoutRef, - keyof CheckboxVariants - >, - CheckboxVariants { - checked?: CheckedState; - defaultChecked?: CheckedState; - onCheckedChange?: (checked: CheckedState) => void; -} - export const Checkbox = forwardRef< ElementRef, - CheckboxProps ->( - ( - { className, disabled, checked, defaultChecked, onCheckedChange, ...props }, - forwardedRef - ) => { - const isIndeterminate = - checked === 'indeterminate' || defaultChecked === 'indeterminate'; - - return ( - { - if (onCheckedChange) { - // If it's currently indeterminate, next state will be unchecked - if (checked === 'indeterminate') { - onCheckedChange(false); - } else { - onCheckedChange(value); - } - } - }} - disabled={disabled} - ref={forwardedRef} - {...props} - > - - {isIndeterminate ? : } - - - ); - } -); + CheckboxPrimitive.Root.Props +>(({ className, indeterminate, ...props }, ref) => { + return ( + + + {indeterminate ? : } + + + ); +}); Checkbox.displayName = 'Checkbox'; diff --git a/packages/raystack/components/checkbox/index.tsx b/packages/raystack/components/checkbox/index.tsx index 2d4f967d9..83a0ba15d 100644 --- a/packages/raystack/components/checkbox/index.tsx +++ b/packages/raystack/components/checkbox/index.tsx @@ -1 +1 @@ -export { Checkbox } from "./checkbox"; +export { Checkbox } from './checkbox'; diff --git a/packages/raystack/package.json b/packages/raystack/package.json index d86e1689c..35527459d 100644 --- a/packages/raystack/package.json +++ b/packages/raystack/package.json @@ -80,6 +80,7 @@ "license": "ISC", "devDependencies": { "@figma/code-connect": "^1.3.5", + "@raystack/tools-config": "workspace:*", "@rollup/plugin-commonjs": "^25.0.2", "@rollup/plugin-image": "^3.0.2", "@rollup/plugin-node-resolve": "^15.1.0", @@ -107,13 +108,13 @@ "rollup-plugin-postcss": "^4.0.2", "rollup-plugin-preserve-directives": "^0.4.0", "rollup-plugin-tsconfig-paths": "^1.5.2", - "@raystack/tools-config": "workspace:*", "semver": "^7.6.0", "typescript": "~5.4.3", "vitest": "^3.2.4" }, "dependencies": { "@ariakit/react": "^0.4.16", + "@base-ui/react": "^1.1.0", "@radix-ui/react-icons": "^1.3.2", "@tanstack/match-sorter-utils": "^8.8.4", "@tanstack/react-table": "^8.9.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 50068f491..d10663bd6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -175,6 +175,9 @@ importers: '@ariakit/react': specifier: ^0.4.16 version: 0.4.16(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@base-ui/react': + specifier: ^1.1.0 + version: 1.1.0(@types/react@19.1.9)(react-dom@19.2.1(react@19.2.1))(react@19.2.1) '@radix-ui/react-icons': specifier: ^1.3.2 version: 1.3.2(react@19.2.1) @@ -965,14 +968,14 @@ packages: resolution: {integrity: sha512-5F7SDGs1T72ZczbRwbGO9lQi0NLjQxzl6i4lJxLxfW9U5UluCSyEJeniWvnhl3/euNiqQVbo8zruhsDfid0esA==} engines: {node: '>=6.9.0'} - '@babel/runtime@7.26.9': - resolution: {integrity: sha512-aA63XwOkcl4xxQa3HjPMqOP6LiK0ZDv3mUPYEFXkpHbaFjtGggE1A61FjFzJnB+p7/oy2gA8E+rcBNl/zC1tMg==} - engines: {node: '>=6.9.0'} - '@babel/runtime@7.27.0': resolution: {integrity: sha512-VtPOkrdPHZsKc/clNqyi9WUA8TINkZ4cGk63UUE3u4pmB2k+ZMQRDuIOagv8UVd6j7k0T3+RRIb7beKTebNbcw==} engines: {node: '>=6.9.0'} + '@babel/runtime@7.28.6': + resolution: {integrity: sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==} + engines: {node: '>=6.9.0'} + '@babel/template@7.25.9': resolution: {integrity: sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg==} engines: {node: '>=6.9.0'} @@ -997,6 +1000,27 @@ packages: resolution: {integrity: sha512-vN5p+1kl59GVKMvTHt55NzzmYVxprfJD+ql7U9NFIfKCBkYE55LYtS+WtPlaYOyzydrKI8Nezd+aZextrd+FMA==} engines: {node: '>=6.9.0'} + '@base-ui/react@1.1.0': + resolution: {integrity: sha512-ikcJRNj1mOiF2HZ5jQHrXoVoHcNHdBU5ejJljcBl+VTLoYXR6FidjTN86GjO6hyshi6TZFuNvv0dEOgaOFv6Lw==} + engines: {node: '>=14.0.0'} + peerDependencies: + '@types/react': ^17 || ^18 || ^19 + react: ^17 || ^18 || ^19 + react-dom: ^17 || ^18 || ^19 + peerDependenciesMeta: + '@types/react': + optional: true + + '@base-ui/utils@0.2.4': + resolution: {integrity: sha512-smZwpMhjO29v+jrZusBSc5T+IJ3vBb9cjIiBjtKcvWmRj9Z4DWGVR3efr1eHR56/bqY5a4qyY9ElkOY5ljo3ng==} + peerDependencies: + '@types/react': ^17 || ^18 || ^19 + react: ^17 || ^18 || ^19 + react-dom: ^17 || ^18 || ^19 + peerDependenciesMeta: + '@types/react': + optional: true + '@bconnorwhite/module@2.0.2': resolution: {integrity: sha512-ck1me5WMgZKp06gnJrVKEkytpehTTQbvsAMbF1nGPeHri/AZNhj87++PSE2LOxmZqM0EtGMaqeLdx7Lw7SUnTA==} @@ -1450,15 +1474,30 @@ packages: '@floating-ui/core@1.6.4': resolution: {integrity: sha512-a4IowK4QkXl4SCWTGUR0INAfEOX3wtsYw3rKK5InQEHMGObkR8Xk44qYQD9P4r6HHw0iIfK6GUKECmY8sTkqRA==} + '@floating-ui/core@1.7.3': + resolution: {integrity: sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==} + '@floating-ui/dom@1.6.7': resolution: {integrity: sha512-wmVfPG5o2xnKDU4jx/m4w5qva9FWHcnZ8BvzEe90D/RpwsJaTAVYPEPdQ8sbr/N8zZTAHlZUTQdqg8ZUbzHmng==} + '@floating-ui/dom@1.7.4': + resolution: {integrity: sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA==} + '@floating-ui/react-dom@2.1.1': resolution: {integrity: sha512-4h84MJt3CHrtG18mGsXuLCHMrug49d7DFkU0RMIyshRveBeyV2hmV/pDaF2Uxtu8kgq5r46llp5E5FQiR0K2Yg==} peerDependencies: react: '>=16.8.0' react-dom: '>=16.8.0' + '@floating-ui/react-dom@2.1.6': + resolution: {integrity: sha512-4JX6rEatQEvlmgU80wZyq9RT96HZJa88q8hp0pBd+LrczeDI4o6uA2M+uvxngVHo4Ihr8uibXxH6+70zhAFrVw==} + peerDependencies: + react: '>=16.8.0' + react-dom: '>=16.8.0' + + '@floating-ui/utils@0.2.10': + resolution: {integrity: sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==} + '@floating-ui/utils@0.2.4': resolution: {integrity: sha512-dWO2pw8hhi+WrXq1YJy2yCuWoL20PddgGaqTgVe4cOS9Q6qklXCiA1tJEqX6BEwRNSCP84/afac9hd4MS+zEUA==} @@ -7999,6 +8038,9 @@ packages: requires-port@1.0.0: resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==} + reselect@5.1.1: + resolution: {integrity: sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w==} + resolve-alpn@1.2.1: resolution: {integrity: sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==} @@ -8499,6 +8541,9 @@ packages: symbol-tree@3.2.4: resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} + tabbable@6.4.0: + resolution: {integrity: sha512-05PUHKSNE8ou2dwIxTngl4EzcnsCDZGJ/iCLtDflR/SHB/ny14rXc+qU5P4mG9JkusiV7EivzY9Mhm55AzAvCg==} + table@6.9.0: resolution: {integrity: sha512-9kY+CygyYM6j02t5YFHbNz2FN5QmYGv9zAjVp4lCDjlCw7amdckXlEt/bjMhUIfj4ThGRE4gCUH5+yGnNuPo5A==} engines: {node: '>=10.0.0'} @@ -8935,6 +8980,11 @@ packages: peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + use-sync-external-store@1.6.0: + resolution: {integrity: sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + usehooks-ts@2.9.1: resolution: {integrity: sha512-2FAuSIGHlY+apM9FVlj8/oNhd+1y+Uwv5QNkMQz1oSfdHk4PXo1qoCw9I5M7j0vpH8CSWFJwXbVPeYDjLCx9PA==} engines: {node: '>=16.15.0', npm: '>=8'} @@ -10120,14 +10170,12 @@ snapshots: dependencies: regenerator-runtime: 0.14.1 - '@babel/runtime@7.26.9': - dependencies: - regenerator-runtime: 0.14.1 - '@babel/runtime@7.27.0': dependencies: regenerator-runtime: 0.14.1 + '@babel/runtime@7.28.6': {} + '@babel/template@7.25.9': dependencies: '@babel/code-frame': 7.26.2 @@ -10174,6 +10222,31 @@ snapshots: '@babel/helper-string-parser': 7.25.9 '@babel/helper-validator-identifier': 7.25.9 + '@base-ui/react@1.1.0(@types/react@19.1.9)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + dependencies: + '@babel/runtime': 7.28.6 + '@base-ui/utils': 0.2.4(@types/react@19.1.9)(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@floating-ui/react-dom': 2.1.6(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@floating-ui/utils': 0.2.10 + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) + reselect: 5.1.1 + tabbable: 6.4.0 + use-sync-external-store: 1.6.0(react@19.2.1) + optionalDependencies: + '@types/react': 19.1.9 + + '@base-ui/utils@0.2.4(@types/react@19.1.9)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + dependencies: + '@babel/runtime': 7.28.6 + '@floating-ui/utils': 0.2.10 + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) + reselect: 5.1.1 + use-sync-external-store: 1.6.0(react@19.2.1) + optionalDependencies: + '@types/react': 19.1.9 + '@bconnorwhite/module@2.0.2': dependencies: find-up: 5.0.0 @@ -10249,7 +10322,7 @@ snapshots: '@emotion/babel-plugin@11.11.0': dependencies: '@babel/helper-module-imports': 7.25.9 - '@babel/runtime': 7.26.9 + '@babel/runtime': 7.27.0 '@emotion/hash': 0.9.1 '@emotion/memoize': 0.8.1 '@emotion/serialize': 1.1.4 @@ -10276,7 +10349,7 @@ snapshots: '@emotion/react@11.11.4(@types/react@18.2.12)(react@18.3.1)': dependencies: - '@babel/runtime': 7.26.9 + '@babel/runtime': 7.27.0 '@emotion/babel-plugin': 11.11.0 '@emotion/cache': 11.11.0 '@emotion/serialize': 1.1.4 @@ -10499,11 +10572,20 @@ snapshots: dependencies: '@floating-ui/utils': 0.2.4 + '@floating-ui/core@1.7.3': + dependencies: + '@floating-ui/utils': 0.2.10 + '@floating-ui/dom@1.6.7': dependencies: '@floating-ui/core': 1.6.4 '@floating-ui/utils': 0.2.4 + '@floating-ui/dom@1.7.4': + dependencies: + '@floating-ui/core': 1.7.3 + '@floating-ui/utils': 0.2.10 + '@floating-ui/react-dom@2.1.1(react-dom@19.2.1(react@18.3.1))(react@18.3.1)': dependencies: '@floating-ui/dom': 1.6.7 @@ -10516,6 +10598,14 @@ snapshots: react: 19.2.1 react-dom: 19.2.1(react@19.2.1) + '@floating-ui/react-dom@2.1.6(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + dependencies: + '@floating-ui/dom': 1.7.4 + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) + + '@floating-ui/utils@0.2.10': {} + '@floating-ui/utils@0.2.4': {} '@formatjs/intl-localematcher@0.6.2': @@ -11248,6 +11338,7 @@ snapshots: '@parcel/types': 2.12.0(@parcel/core@2.12.0) transitivePeerDependencies: - '@parcel/core' + - '@swc/helpers' '@parcel/plugin@2.9.2(@parcel/core@2.12.0)': dependencies: @@ -11666,6 +11757,8 @@ snapshots: '@parcel/types': 2.12.0(@parcel/core@2.12.0) '@parcel/utils': 2.12.0 nullthrows: 1.1.1 + transitivePeerDependencies: + - '@swc/helpers' '@parcel/workers@2.9.2(@parcel/core@2.12.0)': dependencies: @@ -11708,7 +11801,7 @@ snapshots: '@radix-ui/primitive@1.0.0': dependencies: - '@babel/runtime': 7.26.9 + '@babel/runtime': 7.27.0 '@radix-ui/primitive@1.1.2': {} @@ -11968,7 +12061,7 @@ snapshots: '@radix-ui/react-compose-refs@1.0.0(react@18.3.1)': dependencies: - '@babel/runtime': 7.26.9 + '@babel/runtime': 7.27.0 react: 18.3.1 '@radix-ui/react-compose-refs@1.1.2(@types/react@18.2.12)(react@18.3.1)': @@ -12005,7 +12098,7 @@ snapshots: '@radix-ui/react-context@1.0.0(react@18.3.1)': dependencies: - '@babel/runtime': 7.26.9 + '@babel/runtime': 7.27.0 react: 18.3.1 '@radix-ui/react-context@1.1.2(@types/react@18.2.12)(react@18.3.1)': @@ -12028,7 +12121,7 @@ snapshots: '@radix-ui/react-dialog@1.0.0(@types/react@18.2.12)(react-dom@19.2.1(react@18.3.1))(react@18.3.1)': dependencies: - '@babel/runtime': 7.26.9 + '@babel/runtime': 7.27.0 '@radix-ui/primitive': 1.0.0 '@radix-ui/react-compose-refs': 1.0.0(react@18.3.1) '@radix-ui/react-context': 1.0.0(react@18.3.1) @@ -12134,7 +12227,7 @@ snapshots: '@radix-ui/react-dismissable-layer@1.0.0(react-dom@19.2.1(react@18.3.1))(react@18.3.1)': dependencies: - '@babel/runtime': 7.26.9 + '@babel/runtime': 7.27.0 '@radix-ui/primitive': 1.0.0 '@radix-ui/react-compose-refs': 1.0.0(react@18.3.1) '@radix-ui/react-primitive': 1.0.0(react-dom@19.2.1(react@18.3.1))(react@18.3.1) @@ -12214,7 +12307,7 @@ snapshots: '@radix-ui/react-focus-guards@1.0.0(react@18.3.1)': dependencies: - '@babel/runtime': 7.26.9 + '@babel/runtime': 7.27.0 react: 18.3.1 '@radix-ui/react-focus-guards@1.1.2(@types/react@18.2.12)(react@18.3.1)': @@ -12237,7 +12330,7 @@ snapshots: '@radix-ui/react-focus-scope@1.0.0(react-dom@19.2.1(react@18.3.1))(react@18.3.1)': dependencies: - '@babel/runtime': 7.26.9 + '@babel/runtime': 7.27.0 '@radix-ui/react-compose-refs': 1.0.0(react@18.3.1) '@radix-ui/react-primitive': 1.0.0(react-dom@19.2.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-use-callback-ref': 1.0.0(react@18.3.1) @@ -12318,7 +12411,7 @@ snapshots: '@radix-ui/react-id@1.0.0(react@18.3.1)': dependencies: - '@babel/runtime': 7.26.9 + '@babel/runtime': 7.27.0 '@radix-ui/react-use-layout-effect': 1.0.0(react@18.3.1) react: 18.3.1 @@ -12627,7 +12720,7 @@ snapshots: '@radix-ui/react-portal@1.0.0(react-dom@19.2.1(react@18.3.1))(react@18.3.1)': dependencies: - '@babel/runtime': 7.26.9 + '@babel/runtime': 7.27.0 '@radix-ui/react-primitive': 1.0.0(react-dom@19.2.1(react@18.3.1))(react@18.3.1) react: 18.3.1 react-dom: 19.2.1(react@18.3.1) @@ -12664,7 +12757,7 @@ snapshots: '@radix-ui/react-presence@1.0.0(react-dom@19.2.1(react@18.3.1))(react@18.3.1)': dependencies: - '@babel/runtime': 7.26.9 + '@babel/runtime': 7.27.0 '@radix-ui/react-compose-refs': 1.0.0(react@18.3.1) '@radix-ui/react-use-layout-effect': 1.0.0(react@18.3.1) react: 18.3.1 @@ -12702,7 +12795,7 @@ snapshots: '@radix-ui/react-primitive@1.0.0(react-dom@19.2.1(react@18.3.1))(react@18.3.1)': dependencies: - '@babel/runtime': 7.26.9 + '@babel/runtime': 7.27.0 '@radix-ui/react-slot': 1.0.0(react@18.3.1) react: 18.3.1 react-dom: 19.2.1(react@18.3.1) @@ -12998,7 +13091,7 @@ snapshots: '@radix-ui/react-slot@1.0.0(react@18.3.1)': dependencies: - '@babel/runtime': 7.26.9 + '@babel/runtime': 7.27.0 '@radix-ui/react-compose-refs': 1.0.0(react@18.3.1) react: 18.3.1 @@ -13230,7 +13323,7 @@ snapshots: '@radix-ui/react-use-callback-ref@1.0.0(react@18.3.1)': dependencies: - '@babel/runtime': 7.26.9 + '@babel/runtime': 7.27.0 react: 18.3.1 '@radix-ui/react-use-callback-ref@1.1.1(@types/react@18.2.12)(react@18.3.1)': @@ -13253,7 +13346,7 @@ snapshots: '@radix-ui/react-use-controllable-state@1.0.0(react@18.3.1)': dependencies: - '@babel/runtime': 7.26.9 + '@babel/runtime': 7.27.0 '@radix-ui/react-use-callback-ref': 1.0.0(react@18.3.1) react: 18.3.1 @@ -13304,7 +13397,7 @@ snapshots: '@radix-ui/react-use-escape-keydown@1.0.0(react@18.3.1)': dependencies: - '@babel/runtime': 7.26.9 + '@babel/runtime': 7.27.0 '@radix-ui/react-use-callback-ref': 1.0.0(react@18.3.1) react: 18.3.1 @@ -13345,7 +13438,7 @@ snapshots: '@radix-ui/react-use-layout-effect@1.0.0(react@18.3.1)': dependencies: - '@babel/runtime': 7.26.9 + '@babel/runtime': 7.27.0 react: 18.3.1 '@radix-ui/react-use-layout-effect@1.1.1(@types/react@18.2.12)(react@18.3.1)': @@ -14538,7 +14631,7 @@ snapshots: babel-plugin-macros@3.1.0: dependencies: - '@babel/runtime': 7.26.9 + '@babel/runtime': 7.27.0 cosmiconfig: 7.1.0 resolve: 1.22.8 @@ -15325,7 +15418,7 @@ snapshots: dom-helpers@5.2.1: dependencies: - '@babel/runtime': 7.26.9 + '@babel/runtime': 7.27.0 csstype: 3.1.3 dom-serializer@1.4.1: @@ -18752,7 +18845,7 @@ snapshots: react-transition-group@4.4.5(react-dom@19.2.1(react@18.3.1))(react@18.3.1): dependencies: - '@babel/runtime': 7.26.9 + '@babel/runtime': 7.27.0 dom-helpers: 5.2.1 loose-envify: 1.4.0 prop-types: 15.8.1 @@ -18855,7 +18948,7 @@ snapshots: regenerator-transform@0.15.2: dependencies: - '@babel/runtime': 7.26.9 + '@babel/runtime': 7.27.0 regex-recursion@6.0.2: dependencies: @@ -18983,6 +19076,8 @@ snapshots: requires-port@1.0.0: {} + reselect@5.1.1: {} + resolve-alpn@1.2.1: {} resolve-cwd@3.0.0: @@ -19550,6 +19645,8 @@ snapshots: symbol-tree@3.2.4: {} + tabbable@6.4.0: {} + table@6.9.0: dependencies: ajv: 8.17.1 @@ -20028,6 +20125,10 @@ snapshots: dependencies: react: 19.2.1 + use-sync-external-store@1.6.0(react@19.2.1): + dependencies: + react: 19.2.1 + usehooks-ts@2.9.1(react-dom@19.2.1(react@18.3.1))(react@18.3.1): dependencies: react: 18.3.1 From ac925a7eacd258982cf834831e584bf94e2d821b Mon Sep 17 00:00:00 2001 From: Rohan Chakraborty Date: Wed, 28 Jan 2026 14:28:44 +0530 Subject: [PATCH 2/2] feat: update checkbox tests and docs --- .../content/docs/components/checkbox/demo.ts | 15 ++++-- .../content/docs/components/checkbox/props.ts | 11 +++-- .../checkbox/__tests__/checkbox.test.tsx | 49 +++++++++---------- 3 files changed, 41 insertions(+), 34 deletions(-) diff --git a/apps/www/src/content/docs/components/checkbox/demo.ts b/apps/www/src/content/docs/components/checkbox/demo.ts index 3cc2a5765..505412262 100644 --- a/apps/www/src/content/docs/components/checkbox/demo.ts +++ b/apps/www/src/content/docs/components/checkbox/demo.ts @@ -13,9 +13,14 @@ export const playground = { type: 'playground', controls: { checked: { - type: 'select', - options: ['true', 'false', 'indeterminate'], - initialValue: 'true' + type: 'checkbox', + initialValue: false, + defaultValue: false + }, + indeterminate: { + type: 'checkbox', + initialValue: false, + defaultValue: false }, disabled: { type: 'checkbox', @@ -34,11 +39,11 @@ export const statesExamples = { }, { name: 'Checked', - code: `` + code: `` }, { name: 'Indeterminate', - code: `` + code: `` }, { name: 'Disabled', diff --git a/apps/www/src/content/docs/components/checkbox/props.ts b/apps/www/src/content/docs/components/checkbox/props.ts index 1d2a70bc7..220c452ac 100644 --- a/apps/www/src/content/docs/components/checkbox/props.ts +++ b/apps/www/src/content/docs/components/checkbox/props.ts @@ -2,17 +2,22 @@ export interface CheckboxProps { /** * The controlled state of the checkbox */ - checked?: boolean | 'indeterminate'; + checked?: boolean; /** * The default state when initially rendered */ - defaultChecked?: boolean | 'indeterminate'; + defaultChecked?: boolean; /** * Event handler called when the state changes */ - onCheckedChange?: (checked: boolean | 'indeterminate') => void; + onCheckedChange?: (checked: boolean) => void; + + /** + * When true, the checkbox is in an indeterminate state + */ + indeterminate?: boolean; /** * When true, prevents the user from interacting with the checkbox diff --git a/packages/raystack/components/checkbox/__tests__/checkbox.test.tsx b/packages/raystack/components/checkbox/__tests__/checkbox.test.tsx index 0cac22f06..eec6d6147 100644 --- a/packages/raystack/components/checkbox/__tests__/checkbox.test.tsx +++ b/packages/raystack/components/checkbox/__tests__/checkbox.test.tsx @@ -73,28 +73,25 @@ describe('Checkbox', () => { }); describe('Indeterminate State', () => { - it('applies indeterminate class', () => { - render(); + it('has data-indeterminate attribute when indeterminate', () => { + render(); const checkbox = screen.getByRole('checkbox'); - expect(checkbox).toHaveClass(styles['checkbox-indeterminate']); + expect(checkbox).toHaveAttribute('data-indeterminate'); }); - it('renders with defaultChecked as indeterminate', () => { - render(); + it('can be both checked and indeterminate', () => { + render(); const checkbox = screen.getByRole('checkbox'); - expect(checkbox).toHaveClass(styles['checkbox-indeterminate']); + expect(checkbox).toHaveAttribute('aria-checked', 'mixed'); + expect(checkbox).toHaveAttribute('data-indeterminate'); }); - it('transitions from indeterminate to unchecked on click', () => { - const handleChange = vi.fn(); - render( - - ); - - const checkbox = screen.getByRole('checkbox'); - fireEvent.click(checkbox); - - expect(handleChange).toHaveBeenCalledWith(false); + it('shows indeterminate icon when indeterminate', () => { + const { container } = render(); + const indicator = container.querySelector(`.${styles.indicator}`); + expect(indicator).toBeInTheDocument(); + const svg = indicator?.querySelector('svg'); + expect(svg).toBeInTheDocument(); }); }); @@ -102,13 +99,13 @@ describe('Checkbox', () => { it('renders as disabled when disabled prop is true', () => { render(); const checkbox = screen.getByRole('checkbox'); - expect(checkbox).toBeDisabled(); + expect(checkbox).toHaveAttribute('aria-disabled', 'true'); }); - it('applies disabled class', () => { + it('has data-disabled attribute when disabled', () => { render(); const checkbox = screen.getByRole('checkbox'); - expect(checkbox).toHaveClass(styles['checkbox-disabled']); + expect(checkbox).toHaveAttribute('data-disabled'); }); it('does not trigger onCheckedChange when disabled', () => { @@ -124,15 +121,15 @@ describe('Checkbox', () => { it('can be disabled while checked', () => { render(); const checkbox = screen.getByRole('checkbox'); - expect(checkbox).toBeDisabled(); + expect(checkbox).toHaveAttribute('aria-disabled', 'true'); expect(checkbox).toBeChecked(); }); it('can be disabled while indeterminate', () => { - render(); + render(); const checkbox = screen.getByRole('checkbox'); - expect(checkbox).toBeDisabled(); - expect(checkbox).toHaveClass(styles['checkbox-indeterminate']); + expect(checkbox).toHaveAttribute('aria-disabled', 'true'); + expect(checkbox).toHaveAttribute('data-indeterminate'); }); }); @@ -145,7 +142,7 @@ describe('Checkbox', () => { fireEvent.click(checkbox); expect(handleChange).toHaveBeenCalledTimes(1); - expect(handleChange).toHaveBeenCalledWith(true); + expect(handleChange).toHaveBeenCalledWith(true, expect.anything()); }); it('toggles from unchecked to checked', () => { @@ -155,7 +152,7 @@ describe('Checkbox', () => { const checkbox = screen.getByRole('checkbox'); fireEvent.click(checkbox); - expect(handleChange).toHaveBeenCalledWith(true); + expect(handleChange).toHaveBeenCalledWith(true, expect.anything()); }); it('toggles from checked to unchecked', () => { @@ -165,7 +162,7 @@ describe('Checkbox', () => { const checkbox = screen.getByRole('checkbox'); fireEvent.click(checkbox); - expect(handleChange).toHaveBeenCalledWith(false); + expect(handleChange).toHaveBeenCalledWith(false, expect.anything()); }); it('supports focus events', () => {