@actuate-media/cms-admin 0.63.2 → 0.64.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 (100) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/design-system/README.md +53 -0
  3. package/design-system/tokens.css +114 -0
  4. package/design-system/tokens.json +149 -0
  5. package/design-system/tokens.scss +108 -0
  6. package/design-system/tokens.tailwind.cjs +80 -0
  7. package/dist/__tests__/layout/primitives.test.js +9 -2
  8. package/dist/__tests__/layout/primitives.test.js.map +1 -1
  9. package/dist/actuate-admin.css +1 -1
  10. package/dist/components/EnabledSwitch.d.ts +2 -5
  11. package/dist/components/EnabledSwitch.d.ts.map +1 -1
  12. package/dist/components/EnabledSwitch.js +4 -7
  13. package/dist/components/EnabledSwitch.js.map +1 -1
  14. package/dist/components/ThemeProvider.d.ts.map +1 -1
  15. package/dist/components/ThemeProvider.js +5 -3
  16. package/dist/components/ThemeProvider.js.map +1 -1
  17. package/dist/components/forms/FieldsPanel.js +2 -2
  18. package/dist/components/forms/FieldsPanel.js.map +1 -1
  19. package/dist/components/forms/NotificationsPanel.js +2 -2
  20. package/dist/components/forms/NotificationsPanel.js.map +1 -1
  21. package/dist/components/forms/WebhooksPanel.d.ts.map +1 -1
  22. package/dist/components/forms/WebhooksPanel.js +2 -2
  23. package/dist/components/forms/WebhooksPanel.js.map +1 -1
  24. package/dist/components/seo/primitives.d.ts.map +1 -1
  25. package/dist/components/seo/primitives.js +2 -1
  26. package/dist/components/seo/primitives.js.map +1 -1
  27. package/dist/components/ui/Button.d.ts +1 -1
  28. package/dist/components/ui/Button.js +1 -1
  29. package/dist/components/ui/Button.js.map +1 -1
  30. package/dist/components/ui/Card.d.ts +6 -5
  31. package/dist/components/ui/Card.d.ts.map +1 -1
  32. package/dist/components/ui/Card.js +20 -18
  33. package/dist/components/ui/Card.js.map +1 -1
  34. package/dist/components/ui/Input.d.ts +2 -1
  35. package/dist/components/ui/Input.d.ts.map +1 -1
  36. package/dist/components/ui/Input.js +9 -8
  37. package/dist/components/ui/Input.js.map +1 -1
  38. package/dist/components/ui/SearchInput.d.ts.map +1 -1
  39. package/dist/components/ui/SearchInput.js +2 -1
  40. package/dist/components/ui/SearchInput.js.map +1 -1
  41. package/dist/components/ui/Select.d.ts.map +1 -1
  42. package/dist/components/ui/Select.js +9 -10
  43. package/dist/components/ui/Select.js.map +1 -1
  44. package/dist/components/ui/Toggle.d.ts +31 -0
  45. package/dist/components/ui/Toggle.d.ts.map +1 -0
  46. package/dist/components/ui/Toggle.js +41 -0
  47. package/dist/components/ui/Toggle.js.map +1 -0
  48. package/dist/components/ui/form-control.d.ts +11 -0
  49. package/dist/components/ui/form-control.d.ts.map +1 -0
  50. package/dist/components/ui/form-control.js +11 -0
  51. package/dist/components/ui/form-control.js.map +1 -0
  52. package/dist/components/ui/index.d.ts +3 -0
  53. package/dist/components/ui/index.d.ts.map +1 -1
  54. package/dist/components/ui/index.js +2 -0
  55. package/dist/components/ui/index.js.map +1 -1
  56. package/dist/layout/Header.d.ts.map +1 -1
  57. package/dist/layout/Header.js +5 -2
  58. package/dist/layout/Header.js.map +1 -1
  59. package/dist/layout/Sidebar.js +1 -1
  60. package/dist/layout/Sidebar.js.map +1 -1
  61. package/dist/layout/primitives/tokens.d.ts +10 -4
  62. package/dist/layout/primitives/tokens.d.ts.map +1 -1
  63. package/dist/layout/primitives/tokens.js +10 -4
  64. package/dist/layout/primitives/tokens.js.map +1 -1
  65. package/dist/views/Forms.js +2 -2
  66. package/dist/views/Forms.js.map +1 -1
  67. package/dist/views/page-builder/BottomBar.d.ts.map +1 -1
  68. package/dist/views/page-builder/BottomBar.js +2 -2
  69. package/dist/views/page-builder/BottomBar.js.map +1 -1
  70. package/dist/views/seo/TechnicalTab.d.ts.map +1 -1
  71. package/dist/views/seo/TechnicalTab.js +2 -2
  72. package/dist/views/seo/TechnicalTab.js.map +1 -1
  73. package/dist/views/settings/components.d.ts.map +1 -1
  74. package/dist/views/settings/components.js +2 -1
  75. package/dist/views/settings/components.js.map +1 -1
  76. package/package.json +8 -3
  77. package/src/__tests__/layout/primitives.test.ts +10 -2
  78. package/src/components/EnabledSwitch.tsx +4 -22
  79. package/src/components/ThemeProvider.tsx +5 -3
  80. package/src/components/forms/FieldsPanel.tsx +4 -6
  81. package/src/components/forms/NotificationsPanel.tsx +2 -9
  82. package/src/components/forms/WebhooksPanel.tsx +4 -6
  83. package/src/components/seo/primitives.tsx +8 -7
  84. package/src/components/ui/Button.tsx +1 -1
  85. package/src/components/ui/Card.tsx +35 -18
  86. package/src/components/ui/Input.tsx +15 -17
  87. package/src/components/ui/SearchInput.tsx +9 -4
  88. package/src/components/ui/Select.tsx +15 -18
  89. package/src/components/ui/Toggle.tsx +85 -0
  90. package/src/components/ui/form-control.ts +12 -0
  91. package/src/components/ui/index.ts +3 -0
  92. package/src/layout/Header.tsx +6 -2
  93. package/src/layout/Sidebar.tsx +3 -3
  94. package/src/layout/primitives/tokens.ts +11 -4
  95. package/src/styles/actuate-tokens.css +97 -0
  96. package/src/styles/theme.css +88 -156
  97. package/src/views/Forms.tsx +4 -6
  98. package/src/views/page-builder/BottomBar.tsx +3 -6
  99. package/src/views/seo/TechnicalTab.tsx +3 -6
  100. package/src/views/settings/components.tsx +11 -10
@@ -3,6 +3,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import * as Dialog from '@radix-ui/react-dialog';
4
4
  import { AlertTriangle, Check, Loader2, Lock } from 'lucide-react';
5
5
  import { useId } from 'react';
6
+ import { Card, CardContent, CardDescription, CardHeader } from '../../components/ui/Card.js';
6
7
  import { adminPortalContainer } from '../../lib/portal-container.js';
7
8
  /**
8
9
  * The canonical Settings section card: a bordered `bg-card` surface with a
@@ -15,7 +16,7 @@ import { adminPortalContainer } from '../../lib/portal-container.js';
15
16
  */
16
17
  export function SettingsCard({ title, description, actions, children, className, headingLevel: Heading = 'h3', }) {
17
18
  const headingId = useId();
18
- return (_jsxs("section", { "aria-labelledby": headingId, className: `border-border bg-card rounded-lg border p-6 ${className ?? ''}`, children: [_jsxs("header", { className: "mb-4 flex items-start justify-between gap-3", children: [_jsxs("div", { className: "min-w-0", children: [_jsx(Heading, { id: headingId, className: "text-foreground text-lg font-medium", children: title }), description && _jsx("p", { className: "text-muted-foreground mt-0.5 text-sm", children: description })] }), actions && _jsx("div", { className: "flex shrink-0 items-center gap-2", children: actions })] }), children] }));
19
+ return (_jsxs(Card, { padding: "none", "aria-labelledby": headingId, role: "region", className: className, children: [_jsxs(CardHeader, { className: "flex items-start justify-between gap-3", children: [_jsxs("div", { className: "min-w-0", children: [_jsx(Heading, { id: headingId, className: "text-[length:var(--fs-card)] font-semibold text-[var(--txt)]", children: title }), description && _jsx(CardDescription, { children: description })] }), actions && _jsx("div", { className: "flex shrink-0 items-center gap-2", children: actions })] }), _jsx(CardContent, { className: "pt-0 text-[var(--txt)]", children: children })] }));
19
20
  }
20
21
  /**
21
22
  * A sub-section inside a {@link SettingsCard}: a top divider plus a
@@ -1 +1 @@
1
- {"version":3,"file":"components.js","sourceRoot":"","sources":["../../../src/views/settings/components.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAA;;AAEZ,OAAO,KAAK,MAAM,MAAM,wBAAwB,CAAA;AAChD,OAAO,EAAE,aAAa,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,cAAc,CAAA;AAClE,OAAO,EAAE,KAAK,EAAkB,MAAM,OAAO,CAAA;AAC7C,OAAO,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAA;AAGpE;;;;;;;;GAQG;AACH,MAAM,UAAU,YAAY,CAAC,EAC3B,KAAK,EACL,WAAW,EACX,OAAO,EACP,QAAQ,EACR,SAAS,EACT,YAAY,EAAE,OAAO,GAAG,IAAI,GAU7B;IACC,MAAM,SAAS,GAAG,KAAK,EAAE,CAAA;IACzB,OAAO,CACL,sCACmB,SAAS,EAC1B,SAAS,EAAE,+CAA+C,SAAS,IAAI,EAAE,EAAE,aAE3E,kBAAQ,SAAS,EAAC,6CAA6C,aAC7D,eAAK,SAAS,EAAC,SAAS,aACtB,KAAC,OAAO,IAAC,EAAE,EAAE,SAAS,EAAE,SAAS,EAAC,qCAAqC,YACpE,KAAK,GACE,EACT,WAAW,IAAI,YAAG,SAAS,EAAC,sCAAsC,YAAE,WAAW,GAAK,IACjF,EACL,OAAO,IAAI,cAAK,SAAS,EAAC,kCAAkC,YAAE,OAAO,GAAO,IACtE,EACR,QAAQ,IACD,CACX,CAAA;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,kBAAkB,CAAC,EACjC,KAAK,EACL,WAAW,EACX,QAAQ,EACR,SAAS,GAMV;IACC,OAAO,CACL,eAAK,SAAS,EAAE,+BAA+B,SAAS,IAAI,EAAE,EAAE,aAC9D,cAAK,SAAS,EAAC,uCAAuC,YAAE,KAAK,GAAO,EACnE,WAAW,IAAI,YAAG,SAAS,EAAC,sCAAsC,YAAE,WAAW,GAAK,EACpF,QAAQ,IACL,CACP,CAAA;AACH,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,kBAAkB,CAAC,EACjC,KAAK,EACL,WAAW,EACX,OAAO,EACP,OAAO,EACP,OAAO,EACP,KAAK,GAAG,QAAQ,EAChB,SAAS,GAaV;IACC,MAAM,UAAU,GAAG,6CAA6C,CAAA;IAChE,OAAO,CACL,eACE,SAAS,EAAE,8BAA8B,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,aAAa,IAAI,SAAS,IAAI,EAAE,EAAE,aAEjH,eAAK,SAAS,EAAC,iCAAiC,aAC7C,OAAO,EACR,eAAK,SAAS,EAAC,SAAS,aACrB,OAAO,CAAC,CAAC,CAAC,CACT,gBAAO,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,UAAU,YAC3C,KAAK,GACA,CACT,CAAC,CAAC,CAAC,CACF,eAAM,SAAS,EAAE,UAAU,YAAG,KAAK,GAAQ,CAC5C,EACA,WAAW,IAAI,YAAG,SAAS,EAAC,sCAAsC,YAAE,WAAW,GAAK,IACjF,IACF,EACN,cAAK,SAAS,EAAC,kCAAkC,YAAE,OAAO,GAAO,IAC7D,CACP,CAAA;AACH,CAAC;AAED,MAAM,YAAY,GAAqD;IACrE,MAAM,EAAE,gBAAgB;IACxB,WAAW,EAAE,qBAAqB;IAClC,QAAQ,EAAE,UAAU;IACpB,MAAM,EAAE,gBAAgB;IACxB,QAAQ,EAAE,UAAU;CACrB,CAAA;AAED,8DAA8D;AAC9D,MAAM,UAAU,mBAAmB,CAAC,EAAE,IAAI,EAAqC;IAC7E,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,MAAM,KAAK,UAAU,IAAI,IAAI,CAAC,QAAQ,CAAC;QAAE,OAAO,IAAI,CAAA;IACvE,MAAM,MAAM,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAA;IAC7B,OAAO,CACL,gBACE,SAAS,EAAC,qHAAqH,EAC/H,KAAK,EAAE,IAAI,CAAC,MAAM,aAEjB,MAAM,IAAI,KAAC,IAAI,IAAC,IAAI,EAAE,EAAE,iBAAc,MAAM,GAAG,EAC/C,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,IACrB,CACR,CAAA;AACH,CAAC;AAED,yEAAyE;AACzE,MAAM,UAAU,iBAAiB,CAAC,EAChC,KAAK,EACL,WAAW,EACX,OAAO,EACP,QAAQ,EACR,QAAQ,GAAG,KAAK,EAChB,KAAK,GAQN;IACC,OAAO,CACL,eAAK,SAAS,EAAC,wCAAwC,aACrD,eAAK,SAAS,EAAC,QAAQ,aACrB,eAAK,SAAS,EAAC,yBAAyB,aACtC,eAAM,SAAS,EAAC,uCAAuC,YAAE,KAAK,GAAQ,EACrE,KAAK,IACF,EACN,YAAG,SAAS,EAAC,sCAAsC,YAAE,WAAW,GAAK,IACjE,EACN,iBACE,IAAI,EAAC,QAAQ,EACb,IAAI,EAAC,QAAQ,kBACC,OAAO,gBACT,KAAK,EACjB,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,EACjC,SAAS,EAAE,4LACT,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,sBACzB,EAAE,YAEF,eACE,SAAS,EAAE,sFACT,OAAO,CAAC,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC,iBACnC,EAAE,GACF,GACK,IACL,CACP,CAAA;AACH,CAAC;AAED,4DAA4D;AAC5D,MAAM,UAAU,yBAAyB,CAAC,EAAE,MAAM,EAAiC;IACjF,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAA;IACpC,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAA;IAC3D,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAA;IAC/D,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,GAAG,CAAC,CAAA;IACjC,OAAO,CACL,eACE,IAAI,EAAC,OAAO,eACF,QAAQ,EAClB,SAAS,EAAE,wDACT,OAAO;YACL,CAAC,CAAC,0DAA0D;YAC5D,CAAC,CAAC,8CACN,EAAE,aAEF,KAAC,aAAa,IAAC,IAAI,EAAE,EAAE,EAAE,SAAS,EAAC,iBAAiB,iBAAa,MAAM,GAAG,EAC1E,cAAK,SAAS,EAAC,WAAW,YACvB,CAAC,GAAG,MAAM,EAAE,GAAG,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC,CAC1C,sBAAgC,KAAK,CAAC,OAAO,IAArC,GAAG,KAAK,CAAC,KAAK,IAAI,CAAC,EAAE,CAAqB,CACnD,CAAC,GACE,IACF,CACP,CAAA;AACH,CAAC;AAED,6DAA6D;AAC7D,MAAM,UAAU,eAAe,CAAC,EAC9B,KAAK,EACL,OAAO,EACP,SAAS,EACT,SAAS,EACT,MAAM,EACN,OAAO,GAQR;IACC,MAAM,MAAM,GAAG,SAAS,KAAK,QAAQ,CAAA;IACrC,OAAO,CACL,eAAK,SAAS,EAAC,qHAAqH,aACjI,SAAS,KAAK,SAAS,IAAI,CAAC,KAAK,IAAI,CACpC,gBAAM,SAAS,EAAC,gDAAgD,eAAW,QAAQ,aACjF,KAAC,KAAK,IAAC,IAAI,EAAE,EAAE,iBAAc,MAAM,GAAG,cACjC,CACR,EACA,KAAK,IAAI,CAAC,MAAM,IAAI,CACnB,eAAM,SAAS,EAAC,+BAA+B,eAAW,QAAQ,gCAE3D,CACR,EACD,iBACE,IAAI,EAAC,QAAQ,EACb,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,CAAC,KAAK,IAAI,MAAM,EAC1B,SAAS,EAAC,8IAA8I,sBAGjJ,EACT,kBACE,IAAI,EAAC,QAAQ,EACb,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,CAAC,OAAO,IAAI,CAAC,KAAK,IAAI,SAAS,IAAI,MAAM,EACnD,SAAS,EAAC,sQAAsQ,aAE/Q,MAAM,IAAI,KAAC,OAAO,IAAC,IAAI,EAAE,EAAE,EAAE,SAAS,EAAC,cAAc,iBAAa,MAAM,GAAG,EAC3E,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,cAAc,IAC7B,IACL,CACP,CAAA;AACH,CAAC;AAED,0DAA0D;AAC1D,MAAM,UAAU,6BAA6B,CAAC,EAC5C,IAAI,EACJ,KAAK,EACL,WAAW,EACX,YAAY,GAAG,UAAU,EACzB,SAAS,EACT,QAAQ,GAQT;IACC,OAAO,CACL,KAAC,MAAM,CAAC,IAAI,IAAC,IAAI,EAAE,IAAI,EAAE,YAAY,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,QAAQ,EAAE,YAC5D,MAAC,MAAM,CAAC,MAAM,IAAC,SAAS,EAAE,oBAAoB,EAAE,aAC9C,KAAC,MAAM,CAAC,OAAO,IAAC,SAAS,EAAC,gCAAgC,GAAG,EAC7D,MAAC,MAAM,CAAC,OAAO,IAAC,SAAS,EAAC,qIAAqI,aAC7J,eAAK,SAAS,EAAC,8BAA8B,aAC3C,eAAM,SAAS,EAAC,kFAAkF,YAChG,KAAC,aAAa,IAAC,IAAI,EAAE,EAAE,iBAAc,MAAM,GAAG,GACzC,EACP,KAAC,MAAM,CAAC,KAAK,IAAC,SAAS,EAAC,qCAAqC,YAAE,KAAK,GAAgB,IAChF,EACN,KAAC,MAAM,CAAC,WAAW,IAAC,SAAS,EAAC,oCAAoC,YAC/D,WAAW,GACO,EACrB,eAAK,SAAS,EAAC,qCAAqC,aAClD,iBACE,IAAI,EAAC,QAAQ,EACb,OAAO,EAAE,QAAQ,EACjB,SAAS,EAAC,uGAAuG,uBAG1G,EACT,iBACE,IAAI,EAAC,QAAQ,EACb,OAAO,EAAE,SAAS,EAClB,SAAS,EAAC,2HAA2H,YAEpI,YAAY,GACN,IACL,IACS,IACH,GACJ,CACf,CAAA;AACH,CAAC"}
1
+ {"version":3,"file":"components.js","sourceRoot":"","sources":["../../../src/views/settings/components.tsx"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@actuate-media/cms-admin",
3
- "version": "0.63.2",
3
+ "version": "0.64.0",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/actuate-media/actuatecms.git",
@@ -20,9 +20,14 @@
20
20
  },
21
21
  "./styles": "./src/styles/tailwind.css",
22
22
  "./styles/theme.css": "./src/styles/theme.css",
23
- "./styles/precompiled.css": "./dist/actuate-admin.css"
23
+ "./styles/precompiled.css": "./dist/actuate-admin.css",
24
+ "./design-system/tokens.css": "./design-system/tokens.css",
25
+ "./design-system/tokens.json": "./design-system/tokens.json",
26
+ "./design-system/tokens.scss": "./design-system/tokens.scss",
27
+ "./design-system/tokens.tailwind.cjs": "./design-system/tokens.tailwind.cjs"
24
28
  },
25
29
  "files": [
30
+ "design-system",
26
31
  "dist",
27
32
  "src/styles",
28
33
  "src/**/*.tsx",
@@ -90,7 +95,7 @@
90
95
  "tailwindcss": "^4.0.0",
91
96
  "typescript": "^5.7.0",
92
97
  "vitest": "^4.1.0",
93
- "@actuate-media/cms-core": "0.85.1",
98
+ "@actuate-media/cms-core": "0.85.2",
94
99
  "@actuate-media/component-blocks": "0.2.1"
95
100
  },
96
101
  "scripts": {
@@ -12,8 +12,16 @@ describe('layout primitive tokens', () => {
12
12
 
13
13
  it('exposes the canonical radius scale', () => {
14
14
  expect(tokens.radius.none).toBe(0)
15
- expect(tokens.radius.md).toBe(6)
16
- expect(tokens.radius.full).toBe(9999)
15
+ expect(tokens.radius.sm).toBe(6)
16
+ expect(tokens.radius.md).toBe(8)
17
+ expect(tokens.radius.lg).toBe(10)
18
+ expect(tokens.radius.full).toBe(99)
19
+ })
20
+
21
+ it('exposes layout dimensions from the design system', () => {
22
+ expect(tokens.layout.sidebarWidth).toBe(224)
23
+ expect(tokens.layout.sidebarWidthCollapsed).toBe(60)
24
+ expect(tokens.layout.topbarHeight).toBe(56)
17
25
  })
18
26
 
19
27
  it('exposes the canonical breakpoint scale', () => {
@@ -1,6 +1,6 @@
1
1
  'use client'
2
2
 
3
- import * as Switch from '@radix-ui/react-switch'
3
+ import { Toggle } from './ui/Toggle.js'
4
4
 
5
5
  export interface EnabledSwitchProps {
6
6
  checked: boolean
@@ -10,25 +10,7 @@ export interface EnabledSwitchProps {
10
10
  'aria-label': string
11
11
  }
12
12
 
13
- /**
14
- * On/off switch with explicit green (on) and red (off) track colors so state
15
- * is obvious at a glance in admin tables.
16
- */
17
- export function EnabledSwitch({
18
- checked,
19
- onCheckedChange,
20
- disabled,
21
- 'aria-label': ariaLabel,
22
- }: EnabledSwitchProps) {
23
- return (
24
- <Switch.Root
25
- checked={checked}
26
- onCheckedChange={onCheckedChange}
27
- disabled={disabled}
28
- aria-label={ariaLabel}
29
- className="bg-destructive data-[state=checked]:bg-success focus-visible:ring-ring relative inline-flex h-[22px] w-11 shrink-0 rounded-full transition-colors focus-visible:ring-2 focus-visible:outline-none disabled:opacity-50"
30
- >
31
- <Switch.Thumb className="bg-background block h-[18px] w-[18px] translate-x-0.5 rounded-full shadow-sm transition-transform data-[state=checked]:translate-x-[22px]" />
32
- </Switch.Root>
33
- )
13
+ /** Enable/disable toggle — design-system track + success green when on. */
14
+ export function EnabledSwitch(props: EnabledSwitchProps) {
15
+ return <Toggle {...props} variant="enabled" />
34
16
  }
@@ -89,7 +89,7 @@ const ThemeContext = createContext<ThemeContextValue>({
89
89
  setAccent: () => {},
90
90
  density: 'default',
91
91
  setDensity: () => {},
92
- font: 'DM Sans',
92
+ font: 'System UI',
93
93
  setFont: () => {},
94
94
  reduceMotion: false,
95
95
  setReduceMotion: () => {},
@@ -126,6 +126,8 @@ function applyColorMode(resolved: 'light' | 'dark') {
126
126
  const el = adminRootEl()
127
127
  if (!el) return
128
128
  el.classList.toggle('dark', resolved === 'dark')
129
+ // Mirror handoff tokens.css selector so unscoped handoff styles can target the admin root.
130
+ el.setAttribute('data-theme', resolved)
129
131
  }
130
132
 
131
133
  function applyAccent(accent: string, resolved: 'light' | 'dark') {
@@ -166,7 +168,7 @@ export function ThemeProvider({ children, defaultDarkMode }: ThemeProviderProps)
166
168
  const [resolvedTheme, setResolvedTheme] = useState<'light' | 'dark'>('light')
167
169
  const [accent, setAccentState] = useState('purple')
168
170
  const [density, setDensityState] = useState<SidebarDensity>('default')
169
- const [font, setFontState] = useState('DM Sans')
171
+ const [font, setFontState] = useState('System UI')
170
172
  const [reduceMotion, setReduceMotionState] = useState(false)
171
173
  const [adminBrand, setAdminBrandState] = useState<AdminBrandCache>(DEFAULT_BRAND)
172
174
 
@@ -187,7 +189,7 @@ export function ThemeProvider({ children, defaultDarkMode }: ThemeProviderProps)
187
189
 
188
190
  const storedAccent = localStorage.getItem(KEY_ACCENT) || 'purple'
189
191
  const storedDensity = (localStorage.getItem(KEY_DENSITY) as SidebarDensity | null) || 'default'
190
- const storedFont = localStorage.getItem(KEY_FONT) || 'DM Sans'
192
+ const storedFont = localStorage.getItem(KEY_FONT) || 'System UI'
191
193
  const storedMotion = localStorage.getItem(KEY_MOTION) === 'true'
192
194
  let storedBrand = DEFAULT_BRAND
193
195
  try {
@@ -23,7 +23,7 @@ import {
23
23
  } from '@dnd-kit/sortable'
24
24
  import { CSS } from '@dnd-kit/utilities'
25
25
  import { ChevronDown, GripVertical, Plus, Trash2 } from 'lucide-react'
26
- import * as Switch from '@radix-ui/react-switch'
26
+ import { Toggle } from '../ui/Toggle.js'
27
27
  import { useId, useState } from 'react'
28
28
  import type { FormField, FormFieldType } from '../../lib/forms-service.js'
29
29
  import { FieldTypeBadge, FormsEmptyState } from './primitives.js'
@@ -353,14 +353,12 @@ function FieldEditor({
353
353
  <label htmlFor={reqId} className="text-foreground text-sm font-medium">
354
354
  Required
355
355
  </label>
356
- <Switch.Root
356
+ <Toggle
357
357
  id={reqId}
358
358
  checked={field.required}
359
359
  onCheckedChange={(v) => onUpdate({ required: v })}
360
- className="bg-input-background data-[state=checked]:bg-primary focus-visible:ring-ring relative h-[18px] w-8 shrink-0 rounded-full transition-colors focus-visible:ring-2 focus-visible:outline-none"
361
- >
362
- <Switch.Thumb className="bg-background block h-3.5 w-3.5 translate-x-0.5 rounded-full shadow-sm transition-transform data-[state=checked]:translate-x-[14px]" />
363
- </Switch.Root>
360
+ aria-labelledby={reqId}
361
+ />
364
362
  </div>
365
363
  </div>
366
364
  )
@@ -6,7 +6,7 @@
6
6
  * autoresponder). Email delivery uses the configured email adapter when enabled.
7
7
  */
8
8
  import { useEffect, useState } from 'react'
9
- import * as Switch from '@radix-ui/react-switch'
9
+ import { Toggle } from '../ui/Toggle.js'
10
10
  import { toast } from 'sonner'
11
11
  import {
12
12
  fetchNotificationSettings,
@@ -210,14 +210,7 @@ function ToggleRow({
210
210
  <span className="text-foreground block text-sm font-medium">{label}</span>
211
211
  <span className="text-muted-foreground block text-sm">{help}</span>
212
212
  </span>
213
- <Switch.Root
214
- checked={checked}
215
- onCheckedChange={onChange}
216
- aria-label={label}
217
- className="bg-destructive data-[state=checked]:bg-success focus-visible:ring-ring relative h-[18px] w-8 shrink-0 rounded-full transition-colors focus-visible:ring-2 focus-visible:outline-none"
218
- >
219
- <Switch.Thumb className="bg-background block h-3.5 w-3.5 translate-x-0.5 rounded-full shadow-sm transition-transform data-[state=checked]:translate-x-[14px]" />
220
- </Switch.Root>
213
+ <Toggle checked={checked} onCheckedChange={onChange} aria-label={label} />
221
214
  </div>
222
215
  )
223
216
  }
@@ -5,7 +5,7 @@
5
5
  * (Zapier Catch Hook, Make, custom CRM endpoints) and guides editors through
6
6
  * the default Zapier → Webhooks by Zapier → Catch Hook setup.
7
7
  */
8
- import * as Switch from '@radix-ui/react-switch'
8
+ import { Toggle } from '../ui/Toggle.js'
9
9
  import { ExternalLink, Loader2, Plus, Trash2, Zap } from 'lucide-react'
10
10
  import { useEffect, useState } from 'react'
11
11
  import { toast } from 'sonner'
@@ -265,14 +265,12 @@ export function WebhooksPanel({ formId, formSlug }: { formId: string; formSlug:
265
265
  </p>
266
266
  </div>
267
267
  <div className="flex shrink-0 flex-wrap items-center gap-2">
268
- <Switch.Root
268
+ <Toggle
269
269
  checked={webhook.enabled}
270
270
  onCheckedChange={(v) => void toggleEnabled(webhook, v)}
271
271
  aria-label={`Enable webhook ${webhook.url}`}
272
- className="bg-destructive data-[state=checked]:bg-success focus-visible:ring-ring relative h-[18px] w-8 rounded-full transition-colors focus-visible:ring-2 focus-visible:outline-none"
273
- >
274
- <Switch.Thumb className="bg-background block h-3.5 w-3.5 translate-x-0.5 rounded-full shadow-sm transition-transform data-[state=checked]:translate-x-[14px]" />
275
- </Switch.Root>
272
+ variant="enabled"
273
+ />
276
274
  <button
277
275
  type="button"
278
276
  className={btnSecondary}
@@ -7,6 +7,7 @@
7
7
  */
8
8
  import type { ReactNode } from 'react'
9
9
  import { AlertTriangle, Loader2 } from 'lucide-react'
10
+ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '../ui/Card.js'
10
11
  import type { SeoGrade, SeoSeverity } from '../../lib/seo-service.js'
11
12
 
12
13
  // ─── Grade + severity styling ────────────────────────────────────────
@@ -159,18 +160,18 @@ export function SectionCard({
159
160
  className?: string
160
161
  }) {
161
162
  return (
162
- <section className={`border-border bg-card rounded-lg border ${className}`}>
163
+ <Card padding="none" className={className} role="region">
163
164
  {(title || action) && (
164
- <header className="border-border flex items-center justify-between gap-3 border-b px-4 py-3">
165
+ <CardHeader className="flex items-center justify-between gap-3">
165
166
  <div className="min-w-0">
166
- {title && <h3 className="text-foreground text-base font-medium">{title}</h3>}
167
- {description && <p className="text-muted-foreground mt-0.5 text-sm">{description}</p>}
167
+ {title && <CardTitle>{title}</CardTitle>}
168
+ {description && <CardDescription>{description}</CardDescription>}
168
169
  </div>
169
170
  {action}
170
- </header>
171
+ </CardHeader>
171
172
  )}
172
- <div className="p-4">{children}</div>
173
- </section>
173
+ <CardContent className={title || action ? 'pt-0' : ''}>{children}</CardContent>
174
+ </Card>
174
175
  )
175
176
  }
176
177
 
@@ -5,7 +5,7 @@ import { cv, type VariantProps } from '../../lib/cv.js'
5
5
 
6
6
  const button = cv(
7
7
  // Base classes apply to every variant.
8
- 'focus-visible:ring-offset-background inline-flex items-center justify-center gap-2 rounded-[var(--radius)] font-medium transition-colors focus-visible:ring-2 focus-visible:ring-[var(--ring)] focus-visible:ring-offset-2 focus-visible:outline-none disabled:pointer-events-none disabled:opacity-50',
8
+ 'focus-visible:ring-offset-background inline-flex items-center justify-center gap-2 rounded-[var(--r-control)] font-medium transition-colors duration-[var(--motion-fast)] focus-visible:ring-2 focus-visible:ring-[var(--ring)] focus-visible:ring-offset-2 focus-visible:outline-none disabled:pointer-events-none disabled:opacity-50',
9
9
  {
10
10
  variants: {
11
11
  variant: {
@@ -2,29 +2,31 @@ import { forwardRef, type HTMLAttributes, type ReactNode } from 'react'
2
2
  import { cv, type VariantProps } from '../../lib/cv.js'
3
3
 
4
4
  const card = cv(
5
- 'rounded-[var(--radius)] border border-[var(--border)] bg-[var(--card)] text-[var(--card-foreground)]',
5
+ 'overflow-hidden rounded-[var(--r)] border border-[var(--bdr)] bg-[var(--card)] text-[var(--txt)]',
6
6
  {
7
7
  variants: {
8
8
  padding: {
9
9
  none: 'p-0',
10
- sm: 'p-4',
11
- md: 'p-6',
12
- lg: 'p-8',
10
+ /** Stat / compact surfaces (`.dstat`). */
11
+ sm: 'px-4 py-3.5',
12
+ /** Simple padded panel (`.dcard-b`). */
13
+ md: 'px-[18px] py-4',
14
+ lg: 'px-[18px] py-6',
13
15
  },
14
16
  elevation: {
15
17
  flat: 'shadow-none',
16
- sm: 'shadow-sm',
17
- md: 'shadow-md',
18
- lg: 'shadow-lg',
18
+ resting: 'shadow-[var(--shd)]',
19
+ elevated: 'shadow-[var(--shd2)]',
19
20
  },
20
21
  },
21
- defaultVariants: { padding: 'md', elevation: 'sm' },
22
+ defaultVariants: { padding: 'none', elevation: 'resting' },
22
23
  },
23
24
  )
24
25
 
25
26
  export type CardVariants = VariantProps<typeof card>
26
27
 
27
- const INTERACTIVE_CLASS = 'transition-shadow hover:shadow-md focus-within:shadow-md'
28
+ const INTERACTIVE_CLASS =
29
+ 'motion-safe:transition-shadow motion-safe:duration-[var(--motion-fast)] hover:shadow-[var(--shd2)] focus-within:shadow-[var(--shd2)]'
28
30
 
29
31
  export interface CardProps extends HTMLAttributes<HTMLDivElement>, CardVariants {
30
32
  /** Apply hover/focus elevation transitions (e.g. for clickable cards). */
@@ -44,12 +46,20 @@ export const Card = forwardRef<HTMLDivElement, CardProps>(function Card(
44
46
  )
45
47
  })
46
48
 
47
- /**
48
- * Header slot — sits at the top of a card. Pair with CardTitle / CardDescription.
49
- */
50
- export function CardHeader({ className = '', children, ...rest }: HTMLAttributes<HTMLDivElement>) {
49
+ /** Header slot — `.dcard-h` in the design system handoff. */
50
+ export function CardHeader({
51
+ className = '',
52
+ bordered = true,
53
+ children,
54
+ ...rest
55
+ }: HTMLAttributes<HTMLDivElement> & { bordered?: boolean }) {
51
56
  return (
52
- <div className={`flex flex-col space-y-1.5 ${className}`} {...rest}>
57
+ <div
58
+ className={[bordered ? 'border-b border-[var(--bdr)] px-[18px] py-[14px]' : '', className]
59
+ .filter(Boolean)
60
+ .join(' ')}
61
+ {...rest}
62
+ >
53
63
  {children}
54
64
  </div>
55
65
  )
@@ -62,7 +72,7 @@ export function CardTitle({
62
72
  }: HTMLAttributes<HTMLHeadingElement>) {
63
73
  return (
64
74
  <h3
65
- className={`text-lg leading-tight font-medium tracking-tight text-[var(--card-foreground)] ${className}`}
75
+ className={`text-[length:var(--fs-card)] font-semibold text-[var(--txt)] ${className}`}
66
76
  {...rest}
67
77
  >
68
78
  {children}
@@ -76,15 +86,19 @@ export function CardDescription({
76
86
  ...rest
77
87
  }: HTMLAttributes<HTMLParagraphElement>) {
78
88
  return (
79
- <p className={`text-sm text-[var(--muted-foreground)] ${className}`} {...rest}>
89
+ <p className={`mt-px text-[length:var(--fs-hint)] text-[var(--muted)] ${className}`} {...rest}>
80
90
  {children}
81
91
  </p>
82
92
  )
83
93
  }
84
94
 
95
+ /** Body slot — `.dcard-b` in the design system handoff. */
85
96
  export function CardContent({ className = '', children, ...rest }: HTMLAttributes<HTMLDivElement>) {
86
97
  return (
87
- <div className={className} {...rest}>
98
+ <div
99
+ className={`px-[18px] py-4 text-[length:var(--fs-body)] leading-[1.55] text-[var(--sub)] ${className}`}
100
+ {...rest}
101
+ >
88
102
  {children}
89
103
  </div>
90
104
  )
@@ -92,7 +106,10 @@ export function CardContent({ className = '', children, ...rest }: HTMLAttribute
92
106
 
93
107
  export function CardFooter({ className = '', children, ...rest }: HTMLAttributes<HTMLDivElement>) {
94
108
  return (
95
- <div className={`flex items-center justify-end gap-2 pt-4 ${className}`} {...rest}>
109
+ <div
110
+ className={`flex items-center justify-end gap-2 border-t border-[var(--bdr)] px-[18px] py-3 ${className}`}
111
+ {...rest}
112
+ >
96
113
  {children}
97
114
  </div>
98
115
  )
@@ -1,24 +1,22 @@
1
1
  import { forwardRef, type InputHTMLAttributes } from 'react'
2
2
  import { cv, type VariantProps } from '../../lib/cv.js'
3
+ import { formControlBase, formControlState } from './form-control.js'
3
4
 
4
- const input = cv(
5
- 'focus-visible:ring-offset-background flex w-full rounded-[var(--radius)] border bg-[var(--background)] text-[var(--foreground)] file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-[var(--muted-foreground)] focus-visible:ring-2 focus-visible:ring-[var(--ring)] focus-visible:ring-offset-2 focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50',
6
- {
7
- variants: {
8
- size: {
9
- sm: 'h-8 px-2.5 text-xs',
10
- md: 'h-9 px-3 text-sm',
11
- lg: 'h-10 px-4 text-base',
12
- },
13
- state: {
14
- default: 'border-[var(--border)]',
15
- invalid: 'border-[var(--destructive)] focus-visible:ring-[var(--destructive)]',
16
- valid: 'border-emerald-500 focus-visible:ring-emerald-500',
17
- },
5
+ const input = cv(formControlBase, {
6
+ variants: {
7
+ size: {
8
+ sm: 'py-1.5 text-[length:var(--fs-sub)]',
9
+ md: '',
10
+ lg: 'py-2.5 text-[length:var(--fs-body)]',
11
+ },
12
+ state: {
13
+ default: formControlState.default,
14
+ invalid: formControlState.invalid,
15
+ valid: formControlState.valid,
18
16
  },
19
- defaultVariants: { size: 'md', state: 'default' },
20
17
  },
21
- )
18
+ defaultVariants: { size: 'md', state: 'default' },
19
+ })
22
20
 
23
21
  export type InputVariants = VariantProps<typeof input>
24
22
 
@@ -32,4 +30,4 @@ export const Input = forwardRef<HTMLInputElement, InputProps>(function Input(
32
30
  return <input ref={ref} className={input({ size, state, class: className })} {...rest} />
33
31
  })
34
32
 
35
- export { input as inputVariants }
33
+ export { input as inputVariants, formControlBase, formControlState }
@@ -1,5 +1,7 @@
1
1
  'use client'
2
2
 
3
+ import { inputVariants } from './Input.js'
4
+
3
5
  export interface SearchInputProps {
4
6
  value: string
5
7
  onChange: (value: string) => void
@@ -10,11 +12,12 @@ export function SearchInput({ value, onChange, placeholder = 'Search...' }: Sear
10
12
  return (
11
13
  <div className="relative flex-1">
12
14
  <svg
13
- className="absolute top-1/2 left-3 h-4 w-4 -translate-y-1/2 text-[var(--muted-foreground)]"
15
+ className="absolute top-1/2 left-3 h-4 w-4 -translate-y-1/2 text-[var(--muted)]"
14
16
  fill="none"
15
17
  viewBox="0 0 24 24"
16
18
  stroke="currentColor"
17
19
  strokeWidth={2}
20
+ aria-hidden
18
21
  >
19
22
  <path
20
23
  strokeLinecap="round"
@@ -27,12 +30,13 @@ export function SearchInput({ value, onChange, placeholder = 'Search...' }: Sear
27
30
  value={value}
28
31
  onChange={(e) => onChange(e.target.value)}
29
32
  placeholder={placeholder}
30
- className="w-full rounded-md border border-[var(--border)] bg-[var(--input-background)] py-2 pr-8 pl-9 text-sm outline-none focus:ring-2 focus:ring-[var(--ring)]"
33
+ className={inputVariants({ class: 'py-2 pr-8 pl-9' })}
31
34
  />
32
35
  {value && (
33
36
  <button
37
+ type="button"
34
38
  onClick={() => onChange('')}
35
- className="absolute top-1/2 right-2 -translate-y-1/2 rounded p-0.5 text-[var(--muted-foreground)] hover:text-[var(--foreground)]"
39
+ className="absolute top-1/2 right-2 -translate-y-1/2 rounded p-0.5 text-[var(--muted)] hover:text-[var(--txt)]"
36
40
  aria-label="Clear search"
37
41
  >
38
42
  <svg
@@ -41,12 +45,13 @@ export function SearchInput({ value, onChange, placeholder = 'Search...' }: Sear
41
45
  viewBox="0 0 24 24"
42
46
  stroke="currentColor"
43
47
  strokeWidth={2}
48
+ aria-hidden
44
49
  >
45
50
  <path strokeLinecap="round" strokeLinejoin="round" d="M6 18L18 6M6 6l12 12" />
46
51
  </svg>
47
52
  </button>
48
53
  )}
49
- <kbd className="pointer-events-none absolute top-1/2 right-8 hidden -translate-y-1/2 rounded border border-[var(--border)] px-1.5 py-0.5 text-[10px] text-[var(--muted-foreground)] sm:inline-block">
54
+ <kbd className="pointer-events-none absolute top-1/2 right-8 hidden -translate-y-1/2 rounded border border-[var(--bdr)] px-1.5 py-0.5 text-[10px] text-[var(--muted)] sm:inline-block">
50
55
  ⌘K
51
56
  </kbd>
52
57
  </div>
@@ -1,25 +1,22 @@
1
1
  import { forwardRef, type SelectHTMLAttributes, type ReactNode } from 'react'
2
2
  import { cv, type VariantProps } from '../../lib/cv.js'
3
+ import { formControlBase, formControlState } from './form-control.js'
3
4
 
4
- const select = cv(
5
- // Shares geometry with Input so they line up in forms.
6
- 'focus-visible:ring-offset-background flex w-full appearance-none rounded-[var(--radius)] border bg-[var(--background)] pr-8 text-[var(--foreground)] focus-visible:ring-2 focus-visible:ring-[var(--ring)] focus-visible:ring-offset-2 focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50',
7
- {
8
- variants: {
9
- size: {
10
- sm: 'h-8 pr-7 pl-2.5 text-xs',
11
- md: 'h-9 pr-8 pl-3 text-sm',
12
- lg: 'h-10 pr-9 pl-4 text-base',
13
- },
14
- state: {
15
- default: 'border-[var(--border)]',
16
- invalid: 'border-[var(--destructive)] focus-visible:ring-[var(--destructive)]',
17
- valid: 'border-emerald-500 focus-visible:ring-emerald-500',
18
- },
5
+ const select = cv(`${formControlBase} appearance-none pr-8`, {
6
+ variants: {
7
+ size: {
8
+ sm: 'py-1.5 pr-7 pl-3 text-[length:var(--fs-sub)]',
9
+ md: '',
10
+ lg: 'py-2.5 pr-9 pl-3',
11
+ },
12
+ state: {
13
+ default: formControlState.default,
14
+ invalid: formControlState.invalid,
15
+ valid: formControlState.valid,
19
16
  },
20
- defaultVariants: { size: 'md', state: 'default' },
21
17
  },
22
- )
18
+ defaultVariants: { size: 'md', state: 'default' },
19
+ })
23
20
 
24
21
  export type SelectVariants = VariantProps<typeof select>
25
22
 
@@ -39,7 +36,7 @@ export const Select = forwardRef<HTMLSelectElement, SelectProps>(function Select
39
36
  </select>
40
37
  <svg
41
38
  aria-hidden
42
- className="pointer-events-none absolute top-1/2 right-2 h-4 w-4 -translate-y-1/2 text-[var(--muted-foreground)]"
39
+ className="pointer-events-none absolute top-1/2 right-2 h-4 w-4 -translate-y-1/2 text-[var(--muted)]"
43
40
  viewBox="0 0 20 20"
44
41
  fill="currentColor"
45
42
  >
@@ -0,0 +1,85 @@
1
+ 'use client'
2
+
3
+ import * as Switch from '@radix-ui/react-switch'
4
+ import { cv, type VariantProps } from '../../lib/cv.js'
5
+
6
+ const toggleTrack = cv(
7
+ 'relative inline-flex shrink-0 cursor-pointer rounded-[var(--r-pill)] transition-colors duration-[var(--motion-base)] focus-visible:ring-2 focus-visible:ring-[var(--ring)] focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50',
8
+ {
9
+ variants: {
10
+ variant: {
11
+ /** Design system default — accent when on. */
12
+ accent: 'bg-[var(--bdr)] data-[state=checked]:bg-[var(--acc)]',
13
+ /** Semantic enable/disable — success green when on (tables, script tags). */
14
+ enabled: 'bg-[var(--bdr)] data-[state=checked]:bg-[var(--suc)]',
15
+ },
16
+ size: {
17
+ /** Matches `.tog-track` in the design system handoff (38×21). */
18
+ md: 'h-[21px] w-[38px]',
19
+ },
20
+ },
21
+ defaultVariants: {
22
+ variant: 'accent',
23
+ size: 'md',
24
+ },
25
+ },
26
+ )
27
+
28
+ const toggleThumb = cv(
29
+ 'pointer-events-none block rounded-full bg-white shadow-[0_1px_3px_rgba(0,0,0,0.2)] transition-transform duration-[var(--motion-base)]',
30
+ {
31
+ variants: {
32
+ size: {
33
+ md: 'h-4 w-4 translate-x-0.5 data-[state=checked]:translate-x-[17.5px]',
34
+ },
35
+ },
36
+ defaultVariants: {
37
+ size: 'md',
38
+ },
39
+ },
40
+ )
41
+
42
+ export type ToggleVariants = VariantProps<typeof toggleTrack>
43
+
44
+ export interface ToggleProps extends ToggleVariants {
45
+ checked: boolean
46
+ onCheckedChange: (checked: boolean) => void
47
+ disabled?: boolean
48
+ id?: string
49
+ 'aria-label'?: string
50
+ 'aria-labelledby'?: string
51
+ 'aria-describedby'?: string
52
+ }
53
+
54
+ /**
55
+ * Design-system toggle (`.tog-track` / `.tog-thumb`). Use `variant="enabled"`
56
+ * for on/off tables where green communicates active state.
57
+ */
58
+ export function Toggle({
59
+ checked,
60
+ onCheckedChange,
61
+ disabled,
62
+ variant,
63
+ size,
64
+ id,
65
+ 'aria-label': ariaLabel,
66
+ 'aria-labelledby': ariaLabelledBy,
67
+ 'aria-describedby': ariaDescribedBy,
68
+ }: ToggleProps) {
69
+ return (
70
+ <Switch.Root
71
+ id={id}
72
+ checked={checked}
73
+ onCheckedChange={onCheckedChange}
74
+ disabled={disabled}
75
+ aria-label={ariaLabel}
76
+ aria-labelledby={ariaLabelledBy}
77
+ aria-describedby={ariaDescribedBy}
78
+ className={toggleTrack({ variant, size })}
79
+ >
80
+ <Switch.Thumb className={toggleThumb({ size })} />
81
+ </Switch.Root>
82
+ )
83
+ }
84
+
85
+ export { toggleTrack as toggleTrackVariants, toggleThumb as toggleThumbVariants }