@overdoser/react-toolkit 0.1.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/AGENTS.md +26 -0
  2. package/CHANGELOG.md +151 -0
  3. package/README.md +43 -1
  4. package/components/Alert/Alert.d.ts +34 -0
  5. package/components/Alert/index.d.ts +2 -0
  6. package/components/Avatar/Avatar.d.ts +36 -0
  7. package/components/Avatar/index.d.ts +2 -0
  8. package/components/Badge/Badge.d.ts +25 -0
  9. package/components/Badge/index.d.ts +2 -0
  10. package/components/Breadcrumbs/Breadcrumbs.d.ts +44 -0
  11. package/components/Breadcrumbs/index.d.ts +2 -0
  12. package/components/Divider/Divider.d.ts +28 -0
  13. package/components/Divider/index.d.ts +2 -0
  14. package/components/Draggable/Draggable.d.ts +50 -0
  15. package/components/Draggable/index.d.ts +2 -0
  16. package/components/Drawer/Drawer.d.ts +65 -0
  17. package/components/Drawer/index.d.ts +2 -0
  18. package/components/Dropzone/Dropzone.d.ts +50 -0
  19. package/components/Dropzone/index.d.ts +2 -0
  20. package/components/Pagination/Pagination.d.ts +48 -0
  21. package/components/Pagination/index.d.ts +4 -0
  22. package/components/Pagination/paginationRange.d.ts +8 -0
  23. package/components/Skeleton/Skeleton.d.ts +28 -0
  24. package/components/Skeleton/index.d.ts +2 -0
  25. package/components/Spinner/Spinner.d.ts +29 -0
  26. package/components/Spinner/index.d.ts +2 -0
  27. package/components/Tabs/Tabs.d.ts +66 -0
  28. package/components/Tabs/index.d.ts +2 -0
  29. package/components/Timer/Timer.d.ts +103 -0
  30. package/components/Timer/index.d.ts +2 -0
  31. package/components/Toast/Toast.d.ts +82 -0
  32. package/components/Toast/index.d.ts +2 -0
  33. package/components/Toast/toastStore.d.ts +28 -0
  34. package/components/Tooltip/Tooltip.d.ts +38 -0
  35. package/components/Tooltip/index.d.ts +2 -0
  36. package/components/inputs/Checkbox/Checkbox.d.ts +11 -1
  37. package/components/inputs/DatePicker/DatePicker.d.ts +58 -0
  38. package/components/inputs/DatePicker/dateUtils.d.ts +16 -0
  39. package/components/inputs/DatePicker/index.d.ts +2 -0
  40. package/components/inputs/NumberInput/NumberInput.d.ts +41 -0
  41. package/components/inputs/NumberInput/index.d.ts +2 -0
  42. package/components/inputs/Slider/Slider.d.ts +44 -0
  43. package/components/inputs/Slider/index.d.ts +2 -0
  44. package/index.css +1 -1
  45. package/index.d.ts +36 -0
  46. package/index.js +4956 -2805
  47. package/index.layered.css +1 -1
  48. package/llms.txt +275 -1
  49. package/manifest.json +548 -1
  50. package/package.json +1 -1
package/llms.txt CHANGED
@@ -317,6 +317,278 @@ Example:
317
317
  </Modal>
318
318
  ```
319
319
 
320
+ ### Draggable
321
+ Import: `import { Draggable } from '@overdoser/react-toolkit'`
322
+ Element: a `<div>` (forwards ref) that wraps arbitrary children. Free-move container — position is a `translate(x, y)` offset from the element's natural layout position, so it stays in flow until dragged.
323
+
324
+ Compound: `Draggable.Handle` — place inside to restrict the grab area (e.g. a title bar). Without a handle, the whole surface drags. A focused handle is also keyboard-movable (arrow keys).
325
+
326
+ `DraggableProps` (extends native `div` props except `onDrag`):
327
+ - `defaultPosition?: { x: number; y: number }` — uncontrolled initial offset. Default `{ x: 0, y: 0 }`.
328
+ - `position?: { x: number; y: number }` — controlled offset; pair with `onDrag` to update it.
329
+ - `axis?: 'both' | 'x' | 'y'` — default `'both'`.
330
+ - `bounds?: 'viewport' | 'parent' | 'none'` — default `'viewport'`. Clamps movement to the viewport / parent element, or unconstrained.
331
+ - `keyboardStep?: number` — px per arrow-key press on a focused handle. Default `10`.
332
+ - `disabled?: boolean` — default `false`.
333
+ - `onDragStart?(pos)`, `onDrag?(pos)`, `onDragEnd?(pos)` — each receives `{ x, y }`.
334
+ - `classes?: Partial<DraggableClasses>` where `DraggableClasses = { root, handle }`.
335
+
336
+ Example:
337
+ ```tsx
338
+ <Draggable defaultPosition={{ x: 40, y: 40 }} bounds="viewport">
339
+ <Draggable.Handle>⠿ Drag me</Draggable.Handle>
340
+ <div>Any content here</div>
341
+ </Draggable>
342
+ ```
343
+
344
+ ### Toast (ToastProvider + toast + useToast)
345
+ Import: `import { ToastProvider, toast, useToast } from '@overdoser/react-toolkit'`
346
+
347
+ Imperative notification system backed by a global store. Mount `ToastProvider` **once** (it renders a portal at `document.body` and is the only thing that draws toasts — do NOT render toast elements yourself). Then trigger toasts either way:
348
+ - **Standalone `toast(options)`** — importable, no hook/context needed (works from event handlers, utilities, outside React). Also `toast.dismiss(id)` and `toast.dismissAll()`.
349
+ - **`useToast()`** — returns `{ toast, dismiss, dismissAll }` (the same functions) for callers who prefer a hook. It does NOT require being under the provider and never throws.
350
+
351
+ If `toast()` fires while no `ToastProvider` is mounted, it warns (dev) and renders nothing.
352
+
353
+ `ToastProviderProps`:
354
+ - `children: ReactNode` — required.
355
+ - `position?: 'top-left' | 'top-center' | 'top-right' | 'bottom-left' | 'bottom-center' | 'bottom-right'` — default `'top-right'`.
356
+ - `duration?: number` — default auto-dismiss ms. Default `5000`.
357
+ - `max?: number` — max simultaneously-visible toasts (older dropped). Default `5`.
358
+ - `classes?: Partial<ToastClasses>` where `ToastClasses = { viewport, toast, icon, content, title, description, close }`.
359
+
360
+ `toast(options: ToastOptions): string` — standalone; show a toast, returns its id. Methods: `toast.dismiss(id)`, `toast.dismissAll()`.
361
+
362
+ `useToast(): ToastApi` — `{ toast, dismiss, dismissAll }` (identical functions; provided for hook-style ergonomics).
363
+
364
+ `ToastOptions`:
365
+ - `title?: ReactNode`
366
+ - `description?: ReactNode`
367
+ - `variant?: 'neutral' | 'info' | 'success' | 'warning' | 'danger'` — default `'neutral'`.
368
+ - `duration?: number` — override the provider default; `0` or `Infinity` = persist until dismissed.
369
+
370
+ Behavior: auto-dismiss pauses while hovered and resumes on leave. `danger`/`warning` use `role="alert"` (assertive); others use `role="status"` (polite).
371
+
372
+ Example:
373
+ ```tsx
374
+ import { ToastProvider, toast } from '@overdoser/react-toolkit';
375
+
376
+ function App() {
377
+ return <ToastProvider position="bottom-right"><Page /></ToastProvider>;
378
+ }
379
+ function Page() {
380
+ // No hook needed — call toast() directly.
381
+ return <Button onClick={() => toast({ variant: 'success', title: 'Saved' })}>Save</Button>;
382
+ }
383
+ ```
384
+
385
+ ### Tabs (Tabs.List / Tabs.Tab / Tabs.Panel)
386
+ Import: `import { Tabs } from '@overdoser/react-toolkit'`
387
+ Element: a `<div>` (forwards ref) wrapping a `role="tablist"` and panels.
388
+
389
+ Compound: `Tabs.List`, `Tabs.Tab` (needs `value`), `Tabs.Panel` (needs `value`). A tab and its panel are linked by matching `value`. Keyboard: arrow keys (orientation-aware) + Home/End move and activate; roving tabindex; automatic activation on focus.
390
+
391
+ `TabsProps`:
392
+ - `value?: string` — controlled active tab.
393
+ - `defaultValue?: string` — uncontrolled initial active tab.
394
+ - `onValueChange?: (value: string) => void`
395
+ - `orientation?: 'horizontal' | 'vertical'` — default `'horizontal'`.
396
+ - `variant?: 'line' | 'solid' | 'pill'` — default `'line'`.
397
+ - `size?: 'sm' | 'md' | 'lg'` — default `'md'`.
398
+ - `classes?: Partial<TabsClasses>` where `TabsClasses = { root, list, tab, panel }`.
399
+
400
+ `Tabs.Tab` props: `value: string` (required), `disabled?: boolean`, plus native button props.
401
+ `Tabs.Panel` props: `value: string` (required), `keepMounted?: boolean` (default `false` — keep inactive panels mounted but hidden), plus native div props.
402
+
403
+ Example:
404
+ ```tsx
405
+ <Tabs defaultValue="overview" variant="pill">
406
+ <Tabs.List aria-label="Sections">
407
+ <Tabs.Tab value="overview">Overview</Tabs.Tab>
408
+ <Tabs.Tab value="activity">Activity</Tabs.Tab>
409
+ </Tabs.List>
410
+ <Tabs.Panel value="overview">Overview content</Tabs.Panel>
411
+ <Tabs.Panel value="activity">Activity content</Tabs.Panel>
412
+ </Tabs>
413
+ ```
414
+
415
+ ### Alert
416
+ Import: `import { Alert } from '@overdoser/react-toolkit'`
417
+ Element: a `<div role="alert">` (forwards ref). Inline, persistent status message.
418
+
419
+ `AlertProps` (extends native `div` props, omits `title`):
420
+ - `variant?: 'info' | 'success' | 'warning' | 'danger'` — default `'info'`.
421
+ - `title?: ReactNode` — optional bold heading.
422
+ - `icon?: ReactNode | boolean` — default `true` (variant icon). Pass a node to override, `false` to hide.
423
+ - `onClose?: () => void` — when set, renders a dismiss button.
424
+ - `closeLabel?: string` — default `'Dismiss'`.
425
+ - `classes?: Partial<AlertClasses>` where `AlertClasses = { root, icon, content, title, message, close }`.
426
+ - children = message body.
427
+
428
+ Example:
429
+ ```tsx
430
+ <Alert variant="success" title="Saved" onClose={() => setShown(false)}>Your changes were saved.</Alert>
431
+ ```
432
+
433
+ ### Badge
434
+ Import: `import { Badge } from '@overdoser/react-toolkit'`
435
+ Element: a `<span>` (forwards ref). Small inline status pill.
436
+
437
+ `BadgeProps` (extends native `span` props):
438
+ - `variant?: 'neutral' | 'primary' | 'success' | 'warning' | 'danger'` — default `'neutral'`.
439
+ - `appearance?: 'soft' | 'solid' | 'outline'` — default `'soft'`.
440
+ - `size?: 'sm' | 'md' | 'lg'` — default `'md'`.
441
+ - `dot?: boolean` — leading status dot. Default `false`.
442
+ - `classes?: Partial<BadgeClasses>` where `BadgeClasses = { root, dot }`.
443
+
444
+ Example:
445
+ ```tsx
446
+ <Badge variant="success" dot>Active</Badge>
447
+ <Badge variant="primary" appearance="solid">3</Badge>
448
+ ```
449
+
450
+ ### Spinner
451
+ Import: `import { Spinner } from '@overdoser/react-toolkit'`
452
+ Element: a `<span role="status">` (forwards ref). Indeterminate loading spinner; inherits `currentColor`.
453
+
454
+ `SpinnerProps` (extends native `span` props):
455
+ - `size?: 'sm' | 'md' | 'lg'` — default `'md'`.
456
+ - `color?: string` — overrides `currentColor`.
457
+ - `label?: string` — visually-hidden a11y label. Default `'Loading'`; pass `''` to omit when an adjacent element already labels the busy state.
458
+ - `classes?: Partial<SpinnerClasses>` where `SpinnerClasses = { root, circle, label }`.
459
+
460
+ Example:
461
+ ```tsx
462
+ <Spinner size="lg" />
463
+ ```
464
+
465
+ ### Skeleton
466
+ Import: `import { Skeleton } from '@overdoser/react-toolkit'`
467
+ Element: a `<div aria-hidden>` (forwards ref). Decorative loading placeholder.
468
+
469
+ `SkeletonProps` (extends native `div` props, omits `children`):
470
+ - `variant?: 'text' | 'circle' | 'rect'` — default `'text'`.
471
+ - `width?: number | string` — number → px. Defaults to `100%`.
472
+ - `height?: number | string` — number → px. Defaults per variant.
473
+ - `animation?: 'pulse' | 'wave' | 'none'` — default `'pulse'`.
474
+ - `lines?: number` — for `variant="text"`, render N stacked bars (last is shorter). Default `1`.
475
+ - `classes?: Partial<SkeletonClasses>` where `SkeletonClasses = { root, line }`.
476
+
477
+ Example:
478
+ ```tsx
479
+ <Skeleton variant="text" lines={3} />
480
+ <Skeleton variant="circle" width={40} height={40} />
481
+ ```
482
+
483
+ ### Drawer (Drawer.Header / Drawer.Body / Drawer.Footer)
484
+ Import: `import { Drawer } from '@overdoser/react-toolkit'`
485
+ Off-canvas panel sliding from a screen edge. Portal at `document.body`, focus trap, body scroll lock, Escape/backdrop close. Same family as `Modal` but anchored to a side.
486
+
487
+ `DrawerProps`:
488
+ - `open: boolean` — required.
489
+ - `onClose: () => void` — required (backdrop, Escape, header button).
490
+ - `side?: 'left' | 'right' | 'top' | 'bottom'` — default `'right'`. Left/right span full height (partial width); top/bottom span full width (partial height).
491
+ - `size?: 'sm' | 'md' | 'lg' | 'full'` — default `'md'` (width for left/right, height for top/bottom).
492
+ - `variant?: 'temporary' | 'persistent'` — default `'temporary'`. `temporary` overlays a dimmed scrim and is modal (scrim/Escape close). `persistent` shows no scrim and leaves the page interactive (a fixed side panel).
493
+ - `closeOnBackdrop?: boolean` — default `true` (temporary only). `closeOnEscape?: boolean` — default `true`.
494
+
495
+ Slides in/out with a drawer easing (panel translate + scrim fade); stays mounted through the close transition.
496
+ - `aria-label?` / `aria-labelledby?` — if neither, `Drawer.Header` is auto-wired as the label.
497
+ - `classes?: Partial<DrawerClasses>` = `{ backdrop, drawer, header, closeButton, body, footer }`.
498
+
499
+ `Drawer.Header` takes `onClose?` (renders an × button). `Drawer.Body`/`Drawer.Footer` take `children`.
500
+
501
+ ### Tooltip
502
+ Import: `import { Tooltip } from '@overdoser/react-toolkit'`
503
+ Lightweight text label on hover/focus after a delay. Wraps the trigger in an inline span and portals the bubble. For interactive/click content use `Popover`.
504
+
505
+ `TooltipProps`:
506
+ - `content: ReactNode` — the label (nullish/empty → never shows).
507
+ - `children: ReactNode` — the trigger.
508
+ - `placement?: 'top' | 'bottom' | 'left' | 'right'` — default `'top'` (flips on overflow).
509
+ - `delay?: number` — open delay ms, default `300`. `closeDelay?: number` — default `0`.
510
+ - `disabled?: boolean`, `hideArrow?: boolean`.
511
+ - `classes?: Partial<TooltipClasses>` = `{ wrapper, tooltip, arrow }`.
512
+ Closes on Escape; wires `aria-describedby` while open.
513
+
514
+ ### Avatar
515
+ Import: `import { Avatar } from '@overdoser/react-toolkit'`
516
+ Element: `<span>` (forwards ref). Image with initials/icon fallback.
517
+
518
+ `AvatarProps` (extends `span`): `src?`, `alt?`, `name?` (→ initials), `fallback?: ReactNode`, `size?: 'xs'|'sm'|'md'|'lg'|'xl'` (default `'md'`), `shape?: 'circle'|'square'` (default `'circle'`), `status?: 'online'|'offline'|'away'|'busy'`, `classes?` = `{ root, image, fallback, status }`. Falls back to initials (or a user icon) if `src` is missing or errors.
519
+
520
+ ### Divider
521
+ Import: `import { Divider } from '@overdoser/react-toolkit'`
522
+ Element: `<div role="separator">` (forwards ref). `orientation?: 'horizontal'|'vertical'` (default horizontal), `variant?: 'solid'|'dashed'|'dotted'`, `label?: ReactNode` (horizontal only), `labelPosition?: 'start'|'center'|'end'`, `classes?` = `{ root, line, label }`.
523
+
524
+ ### Breadcrumbs (Breadcrumbs.Item)
525
+ Import: `import { Breadcrumbs } from '@overdoser/react-toolkit'`
526
+ `<nav><ol>` (forwards ref). Children are `Breadcrumbs.Item`; separators auto-inserted; the last item defaults to `current`.
527
+
528
+ `BreadcrumbsProps`: `separator?: ReactNode` (default `'/'`), `label?: string` (default `'Breadcrumb'`), `classes?` = `{ root, list, item, link, current, separator }`.
529
+ `Breadcrumbs.Item` props: `href?` (omit for plain text), `current?: boolean` (→ `aria-current="page"`, no link).
530
+
531
+ ### Pagination
532
+ Import: `import { Pagination } from '@overdoser/react-toolkit'`
533
+ `<nav>` (forwards ref). Windowed page list with ellipses, e.g. `1 … 6 7 8 9 10 … 99`.
534
+
535
+ `PaginationProps`:
536
+ - `count?: number` (total pages) OR `total?: number` + `pageSize?: number` (default 10) to derive it.
537
+ - `page?: number` (controlled, 1-based) / `defaultPage?: number` (default 1) / `onChange?: (page) => void`.
538
+ - `siblingCount?: number` — default `2` (→ at most 9 chips). `boundaryCount?: number` — default `1`.
539
+ - `showPrevNext?: boolean` (default true), `showFirstLast?: boolean` (default false).
540
+ - `size?: 'sm'|'md'|'lg'`, `disabled?: boolean`, `label?: string`.
541
+ - `classes?` = `{ root, list, item, active, ellipsis, control }`.
542
+ Also exports `paginationRange(page, count, boundaryCount?, siblingCount?): (number | 'ellipsis')[]`.
543
+
544
+ ### Slider
545
+ Import: `import { Slider } from '@overdoser/react-toolkit'`
546
+ Element: `<div>` (forwards ref) containing `role="slider"` thumb(s). A tuple `value` makes it a range (two thumbs). Pointer drag + keyboard (arrows, Home/End, PageUp/Down).
547
+
548
+ `SliderProps`: `value?: number | [number, number]`, `defaultValue?`, `onChange?(value)`, `onChangeEnd?(value)`, `min?` (0), `max?` (100), `step?` (1), `disabled?`, `aria-label?`/`aria-labelledby?`, `formatValue?(n): string` (for `aria-valuetext`), `classes?` = `{ root, track, range, thumb }`.
549
+
550
+ ### NumberInput
551
+ Import: `import { NumberInput } from '@overdoser/react-toolkit'`
552
+ Element: `<div>` wrapping `<input>` (forwards ref to the input) + stepper buttons. Emits `onChange(value: number | null)`, so it binds in `FormField`.
553
+
554
+ `NumberInputProps`: `value?: number | null`, `defaultValue?`, `onChange?(value)`, `min?`, `max?`, `step?` (1), `precision?` (decimal places), `inputSize?: 'sm'|'md'|'lg'`, `error?`, `hideControls?`, `disabled?`, `classes?` = `{ root, input, controls, increment, decrement }`. Arrow keys step; values clamp on blur; buttons disable at min/max.
555
+
556
+ ### DatePicker
557
+ Import: `import { DatePicker } from '@overdoser/react-toolkit'`
558
+ Element: `<div>` wrapping a read-only `<input>` (forwards ref) + a calendar popover. Single date; binds in `FormField` (`value: Date | null`).
559
+
560
+ `DatePickerProps`: `value?: Date | null`, `defaultValue?`, `onChange?(date)`, `min?: Date`, `max?: Date`, `disabledDate?(date): boolean`, `weekStartsOn?: number` (0 = Sun), `locale?: string`, `format?(date): string`, `placeholder?` (default `'Select date'`), `inputSize?: 'sm'|'md'|'lg'`, `error?`, `disabled?`, `portal?` (default true), `classes?` = `{ root, input, icon, popover, header, nav, grid, day, daySelected, dayToday, dayOutside }`. Keyboard: arrows move days, PageUp/Down change month, Home/End week ends, Enter selects, Esc closes.
561
+
562
+ ### Dropzone
563
+ Import: `import { Dropzone } from '@overdoser/react-toolkit'`
564
+ Element: `<div role="button">` (forwards ref to a hidden file `<input>`). Drag-drop or click to browse; emits files, leaves list UI to you.
565
+
566
+ `DropzoneProps`: `onFiles?(files: File[])`, `onReject?(rejections: { file, reason: 'type'|'size'|'multiple' }[])`, `accept?` (comma list of extensions/MIME patterns), `multiple?` (default false), `maxSize?` (bytes), `disabled?`, `label?`, `hint?`, `children?: ReactNode | (state: { isDragging }) => ReactNode` (custom content), `classes?` = `{ root, input, content, icon, label, hint }`.
567
+
568
+ ### Timer
569
+ Import: `import { Timer } from '@overdoser/react-toolkit'`
570
+ Element: `<div role="timer">`. Forwards a `TimerHandle` ref (not a DOM node): `{ start, pause, reset, restart, getTime(): number, isRunning }`.
571
+
572
+ `TimerProps`:
573
+ - `mode?: 'countdown' | 'stopwatch'` — default `'countdown'`.
574
+ - `duration?: number` — seconds (countdown length / stopwatch cap; drives ring progress).
575
+ - `to?: Date | number` — absolute countdown target (overrides `duration`/pause).
576
+ - `value?: number` — controlled seconds → display-only (no internal clock).
577
+ - `autoStart?: boolean` (default true), `running?: boolean` (controlled run state), `interval?: number` ms (default 1000).
578
+ - `variant?: 'digital' | 'ring' | 'segments'` (default `'digital'`), `size?: 'sm'|'md'|'lg'`.
579
+ - `format?(seconds): ReactNode` (digital/ring only; default `MM:SS` / `H:MM:SS` / `Dd HH:MM:SS`).
580
+ - `label?: ReactNode`, `labelPlacement?: 'top'|'bottom'|'left'|'right'` (default `'bottom'`).
581
+ - `onComplete?()` (countdown hits 0), `onTick?(seconds)`.
582
+ - `classes?` = `{ root, display, label, ringTrack, ringProgress, segments, segment, segmentValue, segmentLabel }`.
583
+
584
+ Segments variant (`variant="segments"`) — one cell per unit, with the unit label under each number:
585
+ - `units?: ('days'|'hours'|'minutes'|'seconds')[]` — which cells to show. Default: smallest set that fits the duration (the leading unit absorbs overflow, e.g. `units={['minutes','seconds']}` on 1h shows `61 : 00`).
586
+ - `unitFormat?: 'long' | 'short'` (default `'short'` → `d/h/m/s`; `'long'` → `days/hours/minutes/seconds`, fixed — no singular/plural switching).
587
+ - `unitLabels?: Partial<Record<TimerUnit, ReactNode | ((value: number) => ReactNode)>>` — override labels per unit.
588
+ - `segmentVariant?: 'boxed' | 'plain'` (default `'boxed'` — a square with the number and the unit below).
589
+ - `renderSegment?: (segment: TimerSegment, index: number) => ReactNode` — fully custom per-cell rendering (`TimerSegment = { unit, value, text, label }`). Overrides `segmentVariant`.
590
+ - `segmentSeparator?: ReactNode` — content between cells (e.g. `':'`).
591
+
320
592
  ### Form / FormField / FormRow
321
593
  Requires `react-hook-form` peer dependency.
322
594
 
@@ -441,12 +713,14 @@ Element: `<input type="checkbox">` wrapped in a `<label>` (forwards ref to the i
441
713
 
442
714
  Props (extends native input props):
443
715
  - `label?: ReactNode`
444
- - `indeterminate?: boolean` — default `false`. Sets the DOM `indeterminate` property; visually distinct.
716
+ - `variant?: 'checkbox' | 'switch'` — default `'checkbox'`. `'switch'` renders a sliding toggle; the underlying `<input type="checkbox">` (a11y + form behavior) is identical.
717
+ - `indeterminate?: boolean` — default `false`. Sets the DOM `indeterminate` property; visually distinct. Ignored when `variant="switch"`.
445
718
  - `classes?: Partial<CheckboxClasses>` where `CheckboxClasses = { root, input, label }`
446
719
 
447
720
  Example:
448
721
  ```tsx
449
722
  <Checkbox label="Remember me" checked={remember} onChange={(e) => setRemember(e.target.checked)} />
723
+ <Checkbox variant="switch" label="Notifications" defaultChecked />
450
724
  ```
451
725
 
452
726
  ### CheckboxGroup