@financedistrict/apps-ui 0.1.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 (136) hide show
  1. package/LICENSE +19 -0
  2. package/README.md +119 -0
  3. package/dist/Radio-BYWz1n7p.d.cts +32 -0
  4. package/dist/Radio-BYWz1n7p.d.ts +32 -0
  5. package/dist/SelectTrigger-By0iPBI3.d.cts +78 -0
  6. package/dist/SelectTrigger-By0iPBI3.d.ts +78 -0
  7. package/dist/accordion.cjs +322 -0
  8. package/dist/accordion.d.cts +156 -0
  9. package/dist/accordion.d.ts +156 -0
  10. package/dist/accordion.js +2 -0
  11. package/dist/apps-ui.umd.js +1 -0
  12. package/dist/button.cjs +366 -0
  13. package/dist/button.d.cts +52 -0
  14. package/dist/button.d.ts +52 -0
  15. package/dist/button.js +3 -0
  16. package/dist/checkbox.cjs +74 -0
  17. package/dist/checkbox.d.cts +63 -0
  18. package/dist/checkbox.d.ts +63 -0
  19. package/dist/checkbox.js +2 -0
  20. package/dist/chunk-3RU7JMFE.js +27 -0
  21. package/dist/chunk-5TWRK4NW.js +783 -0
  22. package/dist/chunk-7EOSDFS3.js +9 -0
  23. package/dist/chunk-AIQ4UOGK.js +142 -0
  24. package/dist/chunk-B3MMGTPV.js +200 -0
  25. package/dist/chunk-DAHQYLUI.js +146 -0
  26. package/dist/chunk-DGBXADSS.js +1 -0
  27. package/dist/chunk-E6KPNTWW.js +295 -0
  28. package/dist/chunk-EOAB6G2D.js +149 -0
  29. package/dist/chunk-FAOVKDVM.js +32 -0
  30. package/dist/chunk-FV76Z4Z2.js +78 -0
  31. package/dist/chunk-GLTLBUZ7.js +285 -0
  32. package/dist/chunk-GTZFV43T.js +154 -0
  33. package/dist/chunk-HRGZNL4A.js +88 -0
  34. package/dist/chunk-IEVN3J2F.js +98 -0
  35. package/dist/chunk-IRS3T6LF.js +352 -0
  36. package/dist/chunk-IYYHCQXG.js +146 -0
  37. package/dist/chunk-JIXW3455.js +89 -0
  38. package/dist/chunk-N4VAP2GB.js +77 -0
  39. package/dist/chunk-SJ2ZRYVV.js +167 -0
  40. package/dist/chunk-SNU4YXOR.js +66 -0
  41. package/dist/chunk-TT6JQATV.js +99 -0
  42. package/dist/chunk-UPQ3ZPCO.js +66 -0
  43. package/dist/chunk-UVUSVFOH.js +264 -0
  44. package/dist/chunk-WJFPGGJB.js +255 -0
  45. package/dist/chunk-WXEBQA7A.js +371 -0
  46. package/dist/chunk-Y2O4YYZQ.js +184 -0
  47. package/dist/cut-corner.cjs +111 -0
  48. package/dist/cut-corner.d.cts +49 -0
  49. package/dist/cut-corner.d.ts +49 -0
  50. package/dist/cut-corner.js +1 -0
  51. package/dist/dialog.cjs +441 -0
  52. package/dist/dialog.d.cts +240 -0
  53. package/dist/dialog.d.ts +240 -0
  54. package/dist/dialog.js +3 -0
  55. package/dist/feature-card.cjs +182 -0
  56. package/dist/feature-card.d.cts +54 -0
  57. package/dist/feature-card.d.ts +54 -0
  58. package/dist/feature-card.js +2 -0
  59. package/dist/filter.cjs +873 -0
  60. package/dist/filter.d.cts +129 -0
  61. package/dist/filter.d.ts +129 -0
  62. package/dist/filter.js +6 -0
  63. package/dist/index.cjs +4583 -0
  64. package/dist/index.d.cts +29 -0
  65. package/dist/index.d.ts +29 -0
  66. package/dist/index.js +27 -0
  67. package/dist/inline-select.cjs +856 -0
  68. package/dist/inline-select.d.cts +92 -0
  69. package/dist/inline-select.d.ts +92 -0
  70. package/dist/inline-select.js +6 -0
  71. package/dist/input.cjs +263 -0
  72. package/dist/input.d.cts +157 -0
  73. package/dist/input.d.ts +157 -0
  74. package/dist/input.js +4 -0
  75. package/dist/panel.cjs +185 -0
  76. package/dist/panel.d.cts +103 -0
  77. package/dist/panel.d.ts +103 -0
  78. package/dist/panel.js +2 -0
  79. package/dist/property-grid.cjs +110 -0
  80. package/dist/property-grid.d.cts +56 -0
  81. package/dist/property-grid.d.ts +56 -0
  82. package/dist/property-grid.js +2 -0
  83. package/dist/radio.cjs +74 -0
  84. package/dist/radio.d.cts +39 -0
  85. package/dist/radio.d.ts +39 -0
  86. package/dist/radio.js +2 -0
  87. package/dist/scrollbar.cjs +34 -0
  88. package/dist/scrollbar.d.cts +35 -0
  89. package/dist/scrollbar.d.ts +35 -0
  90. package/dist/scrollbar.js +1 -0
  91. package/dist/search-bar.cjs +408 -0
  92. package/dist/search-bar.d.cts +42 -0
  93. package/dist/search-bar.d.ts +42 -0
  94. package/dist/search-bar.js +4 -0
  95. package/dist/select.cjs +998 -0
  96. package/dist/select.d.cts +357 -0
  97. package/dist/select.d.ts +357 -0
  98. package/dist/select.js +5 -0
  99. package/dist/selectable-feature-card.cjs +159 -0
  100. package/dist/selectable-feature-card.d.cts +74 -0
  101. package/dist/selectable-feature-card.d.ts +74 -0
  102. package/dist/selectable-feature-card.js +3 -0
  103. package/dist/sidebar-item.cjs +175 -0
  104. package/dist/sidebar-item.d.cts +75 -0
  105. package/dist/sidebar-item.d.ts +75 -0
  106. package/dist/sidebar-item.js +2 -0
  107. package/dist/switch.cjs +86 -0
  108. package/dist/switch.d.cts +72 -0
  109. package/dist/switch.d.ts +72 -0
  110. package/dist/switch.js +2 -0
  111. package/dist/table-cell.cjs +196 -0
  112. package/dist/table-cell.d.cts +76 -0
  113. package/dist/table-cell.d.ts +76 -0
  114. package/dist/table-cell.js +2 -0
  115. package/dist/table-title.cjs +34 -0
  116. package/dist/table-title.d.cts +16 -0
  117. package/dist/table-title.d.ts +16 -0
  118. package/dist/table-title.js +2 -0
  119. package/dist/tabs.cjs +299 -0
  120. package/dist/tabs.d.cts +116 -0
  121. package/dist/tabs.d.ts +116 -0
  122. package/dist/tabs.js +2 -0
  123. package/dist/toast.cjs +87 -0
  124. package/dist/toast.d.cts +48 -0
  125. package/dist/toast.d.ts +48 -0
  126. package/dist/toast.js +2 -0
  127. package/dist/token-input.cjs +415 -0
  128. package/dist/token-input.d.cts +90 -0
  129. package/dist/token-input.d.ts +90 -0
  130. package/dist/token-input.js +3 -0
  131. package/dist/tooltip.cjs +384 -0
  132. package/dist/tooltip.d.cts +142 -0
  133. package/dist/tooltip.d.ts +142 -0
  134. package/dist/tooltip.js +2 -0
  135. package/package.json +200 -0
  136. package/src/fonts.css +33 -0
@@ -0,0 +1,3 @@
1
+ export { SelectableFeatureCard, selectableFeatureCardBottomVariants, selectableFeatureCardRowVariants, selectableFeatureCardTextVariants, selectableFeatureCardTrailingVariants, selectableFeatureCardVariants } from './chunk-HRGZNL4A.js';
2
+ import './chunk-UPQ3ZPCO.js';
3
+ import './chunk-7EOSDFS3.js';
@@ -0,0 +1,175 @@
1
+ 'use strict';
2
+
3
+ var React = require('react');
4
+ var clsx = require('clsx');
5
+ var tailwindMerge = require('tailwind-merge');
6
+ var classVarianceAuthority = require('class-variance-authority');
7
+ var jsxRuntime = require('react/jsx-runtime');
8
+
9
+ function _interopNamespace(e) {
10
+ if (e && e.__esModule) return e;
11
+ var n = Object.create(null);
12
+ if (e) {
13
+ Object.keys(e).forEach(function (k) {
14
+ if (k !== 'default') {
15
+ var d = Object.getOwnPropertyDescriptor(e, k);
16
+ Object.defineProperty(n, k, d.get ? d : {
17
+ enumerable: true,
18
+ get: function () { return e[k]; }
19
+ });
20
+ }
21
+ });
22
+ }
23
+ n.default = e;
24
+ return Object.freeze(n);
25
+ }
26
+
27
+ var React__namespace = /*#__PURE__*/_interopNamespace(React);
28
+
29
+ // src/sidebar-item/SidebarItem.tsx
30
+ function cn(...inputs) {
31
+ return tailwindMerge.twMerge(clsx.clsx(inputs));
32
+ }
33
+ var sidebarItemVariants = classVarianceAuthority.cva(
34
+ [
35
+ "group flex h-9 w-full items-center rounded-xs border-l-2 border-transparent px-3",
36
+ "no-underline transition-colors outline-none"
37
+ ],
38
+ {
39
+ variants: {
40
+ active: {
41
+ true: "bg-brand-background border-brand-border",
42
+ false: ""
43
+ },
44
+ interactive: {
45
+ true: [
46
+ "cursor-pointer",
47
+ // Ring only — no fill/text change on focus (see file docstring).
48
+ "focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-solid focus-visible:outline-focus"
49
+ ],
50
+ false: ""
51
+ }
52
+ },
53
+ compoundVariants: [
54
+ // Hover fill only on a non-active, interactive item.
55
+ { active: false, interactive: true, class: "hover:bg-background" }
56
+ ],
57
+ defaultVariants: { active: false, interactive: false }
58
+ }
59
+ );
60
+ var sidebarItemLabelVariants = classVarianceAuthority.cva(
61
+ ["button-01 min-w-0 flex-1 truncate"],
62
+ {
63
+ variants: {
64
+ active: {
65
+ true: "text-brand-foreground",
66
+ false: "text-foreground-muted"
67
+ },
68
+ interactive: { true: "", false: "" }
69
+ },
70
+ compoundVariants: [
71
+ {
72
+ active: false,
73
+ interactive: true,
74
+ class: "group-hover:text-foreground"
75
+ }
76
+ ],
77
+ defaultVariants: { active: false, interactive: false }
78
+ }
79
+ );
80
+ function setRef(ref, node) {
81
+ if (typeof ref === "function") ref(node);
82
+ else if (ref) ref.current = node;
83
+ }
84
+ function SidebarItem({
85
+ active = false,
86
+ asChild = false,
87
+ href,
88
+ className,
89
+ children,
90
+ ref,
91
+ ...props
92
+ }) {
93
+ const interactive = asChild || href != null;
94
+ const rootClassName = cn(
95
+ sidebarItemVariants({ active, interactive }),
96
+ className
97
+ );
98
+ const label = (labelNode) => /* @__PURE__ */ jsxRuntime.jsx(
99
+ "span",
100
+ {
101
+ "data-slot": "sidebar-item-label",
102
+ className: sidebarItemLabelVariants({ active, interactive }),
103
+ children: labelNode
104
+ }
105
+ );
106
+ const dataState = active ? "active" : void 0;
107
+ const ariaCurrent = active ? "page" : void 0;
108
+ if (asChild) {
109
+ if (!React__namespace.isValidElement(children)) {
110
+ throw new Error(
111
+ "SidebarItem: `asChild` requires a single React element child"
112
+ );
113
+ }
114
+ const child = children;
115
+ const childProps = child.props;
116
+ return React__namespace.cloneElement(
117
+ child,
118
+ {
119
+ ...props,
120
+ ...childProps,
121
+ "data-slot": "sidebar-item",
122
+ "data-state": dataState,
123
+ "aria-current": ariaCurrent,
124
+ className: cn(
125
+ rootClassName,
126
+ childProps.className
127
+ ),
128
+ ref: (node) => {
129
+ setRef(ref, node);
130
+ setRef(childProps.ref, node);
131
+ },
132
+ onClick: (event) => {
133
+ props.onClick?.(event);
134
+ childProps.onClick?.(event);
135
+ },
136
+ style: {
137
+ ...props.style,
138
+ ...childProps.style
139
+ }
140
+ },
141
+ label(childProps.children)
142
+ );
143
+ }
144
+ if (href != null) {
145
+ return /* @__PURE__ */ jsxRuntime.jsx(
146
+ "a",
147
+ {
148
+ "data-slot": "sidebar-item",
149
+ "data-state": dataState,
150
+ "aria-current": ariaCurrent,
151
+ href,
152
+ className: rootClassName,
153
+ ref,
154
+ ...props,
155
+ children: label(children)
156
+ }
157
+ );
158
+ }
159
+ return /* @__PURE__ */ jsxRuntime.jsx(
160
+ "div",
161
+ {
162
+ "data-slot": "sidebar-item",
163
+ "data-state": dataState,
164
+ "aria-current": ariaCurrent,
165
+ className: rootClassName,
166
+ ref,
167
+ ...props,
168
+ children: label(children)
169
+ }
170
+ );
171
+ }
172
+
173
+ exports.SidebarItem = SidebarItem;
174
+ exports.sidebarItemLabelVariants = sidebarItemLabelVariants;
175
+ exports.sidebarItemVariants = sidebarItemVariants;
@@ -0,0 +1,75 @@
1
+ import * as React from 'react';
2
+ import * as class_variance_authority_types from 'class-variance-authority/types';
3
+ import { VariantProps } from 'class-variance-authority';
4
+
5
+ interface SidebarItemProps extends Omit<React.ComponentProps<"a">, "ref"> {
6
+ /**
7
+ * The current-route item — applies the brand-accent treatment (fill + left
8
+ * indicator + brand label) and sets `aria-current="page"`.
9
+ */
10
+ active?: boolean;
11
+ /**
12
+ * Render the single element child as the root (a router `<Link>` / `<a>`),
13
+ * keeping all sidebar-item styling. The child's own children become the
14
+ * label. Requires exactly one valid element child.
15
+ */
16
+ asChild?: boolean;
17
+ /** Ref forwarded to the root element. */
18
+ ref?: React.Ref<HTMLElement>;
19
+ }
20
+ /**
21
+ * A single navigation row for the app sidebar — the Figma `sidebar-item`. A
22
+ * polymorphic navigation control (an `<a>` when `href` is set, `asChild` to
23
+ * compose a router link, otherwise a presentational `<div>`) with a muted,
24
+ * truncating label that recolors on hover. Mark the current route with
25
+ * `active`: it takes the brand fill + left indicator and exposes
26
+ * `aria-current="page"`. Keyboard focus adds only the focus ring and leaves the
27
+ * item's fill and label unchanged.
28
+ */
29
+ declare function SidebarItem({ active, asChild, href, className, children, ref, ...props }: SidebarItemProps): React.JSX.Element;
30
+
31
+ /**
32
+ * SidebarItem styling — the Figma `sidebar-item` set (node `4949:4240`, states
33
+ * default / hover / focused / active). Binds ONLY to the neutral / brand / focus
34
+ * semantic token layer (never primitives / mode plumbing); theme switching is
35
+ * automatic via `.dark`, so no `dark:` variants.
36
+ *
37
+ * `state` in Figma is a mix of two orthogonal concerns, split here per house
38
+ * style (cf. TableCell): the interaction states (hover / focused) are CSS
39
+ * pseudo-classes on the root, not props; `active` — the item for the current
40
+ * route — is the one real prop.
41
+ *
42
+ * **Focus is ring-only.** `focus-visible` adds ONLY the shared focus ring and
43
+ * changes nothing else — the item's fill and label stay exactly as they are in
44
+ * whatever state it's in (default or `active`), so focusing the current-route
45
+ * item keeps its brand treatment. (This diverges from the Figma `focused`
46
+ * variant, which swapped in a white fill — per product direction the element
47
+ * must not change on focus.)
48
+ *
49
+ * The root is a Tailwind `group`; its own fill recolors on `hover:` and via the
50
+ * `active` variant (never on focus), while the label recolors through the same
51
+ * group (see `sidebarItemLabelVariants`). A 2px left border is reserved
52
+ * transparent in every state so selecting an item never shifts the label —
53
+ * `active` just colors it (`brand/border`).
54
+ *
55
+ * Hover / focus affordances are gated to `interactive: true` (an `<a>` / cloned
56
+ * link) so a presentational `<div>` root stays static, and hover is suppressed
57
+ * while `active` so the brand treatment always wins over the hover fill.
58
+ */
59
+ declare const sidebarItemVariants: (props?: ({
60
+ active?: boolean | null | undefined;
61
+ interactive?: boolean | null | undefined;
62
+ } & class_variance_authority_types.ClassProp) | undefined) => string;
63
+ /**
64
+ * The label — `button-01` (Archivo Medium 14/20), truncating. Muted by default;
65
+ * recolors to `foreground` on the root's hover (interactive, non-active only)
66
+ * and to `brand/foreground` while `active`. Focus does not recolor the label —
67
+ * the focus ring is the only focus affordance.
68
+ */
69
+ declare const sidebarItemLabelVariants: (props?: ({
70
+ active?: boolean | null | undefined;
71
+ interactive?: boolean | null | undefined;
72
+ } & class_variance_authority_types.ClassProp) | undefined) => string;
73
+ type SidebarItemVariantsProps = VariantProps<typeof sidebarItemVariants>;
74
+
75
+ export { SidebarItem, type SidebarItemProps, type SidebarItemVariantsProps, sidebarItemLabelVariants, sidebarItemVariants };
@@ -0,0 +1,75 @@
1
+ import * as React from 'react';
2
+ import * as class_variance_authority_types from 'class-variance-authority/types';
3
+ import { VariantProps } from 'class-variance-authority';
4
+
5
+ interface SidebarItemProps extends Omit<React.ComponentProps<"a">, "ref"> {
6
+ /**
7
+ * The current-route item — applies the brand-accent treatment (fill + left
8
+ * indicator + brand label) and sets `aria-current="page"`.
9
+ */
10
+ active?: boolean;
11
+ /**
12
+ * Render the single element child as the root (a router `<Link>` / `<a>`),
13
+ * keeping all sidebar-item styling. The child's own children become the
14
+ * label. Requires exactly one valid element child.
15
+ */
16
+ asChild?: boolean;
17
+ /** Ref forwarded to the root element. */
18
+ ref?: React.Ref<HTMLElement>;
19
+ }
20
+ /**
21
+ * A single navigation row for the app sidebar — the Figma `sidebar-item`. A
22
+ * polymorphic navigation control (an `<a>` when `href` is set, `asChild` to
23
+ * compose a router link, otherwise a presentational `<div>`) with a muted,
24
+ * truncating label that recolors on hover. Mark the current route with
25
+ * `active`: it takes the brand fill + left indicator and exposes
26
+ * `aria-current="page"`. Keyboard focus adds only the focus ring and leaves the
27
+ * item's fill and label unchanged.
28
+ */
29
+ declare function SidebarItem({ active, asChild, href, className, children, ref, ...props }: SidebarItemProps): React.JSX.Element;
30
+
31
+ /**
32
+ * SidebarItem styling — the Figma `sidebar-item` set (node `4949:4240`, states
33
+ * default / hover / focused / active). Binds ONLY to the neutral / brand / focus
34
+ * semantic token layer (never primitives / mode plumbing); theme switching is
35
+ * automatic via `.dark`, so no `dark:` variants.
36
+ *
37
+ * `state` in Figma is a mix of two orthogonal concerns, split here per house
38
+ * style (cf. TableCell): the interaction states (hover / focused) are CSS
39
+ * pseudo-classes on the root, not props; `active` — the item for the current
40
+ * route — is the one real prop.
41
+ *
42
+ * **Focus is ring-only.** `focus-visible` adds ONLY the shared focus ring and
43
+ * changes nothing else — the item's fill and label stay exactly as they are in
44
+ * whatever state it's in (default or `active`), so focusing the current-route
45
+ * item keeps its brand treatment. (This diverges from the Figma `focused`
46
+ * variant, which swapped in a white fill — per product direction the element
47
+ * must not change on focus.)
48
+ *
49
+ * The root is a Tailwind `group`; its own fill recolors on `hover:` and via the
50
+ * `active` variant (never on focus), while the label recolors through the same
51
+ * group (see `sidebarItemLabelVariants`). A 2px left border is reserved
52
+ * transparent in every state so selecting an item never shifts the label —
53
+ * `active` just colors it (`brand/border`).
54
+ *
55
+ * Hover / focus affordances are gated to `interactive: true` (an `<a>` / cloned
56
+ * link) so a presentational `<div>` root stays static, and hover is suppressed
57
+ * while `active` so the brand treatment always wins over the hover fill.
58
+ */
59
+ declare const sidebarItemVariants: (props?: ({
60
+ active?: boolean | null | undefined;
61
+ interactive?: boolean | null | undefined;
62
+ } & class_variance_authority_types.ClassProp) | undefined) => string;
63
+ /**
64
+ * The label — `button-01` (Archivo Medium 14/20), truncating. Muted by default;
65
+ * recolors to `foreground` on the root's hover (interactive, non-active only)
66
+ * and to `brand/foreground` while `active`. Focus does not recolor the label —
67
+ * the focus ring is the only focus affordance.
68
+ */
69
+ declare const sidebarItemLabelVariants: (props?: ({
70
+ active?: boolean | null | undefined;
71
+ interactive?: boolean | null | undefined;
72
+ } & class_variance_authority_types.ClassProp) | undefined) => string;
73
+ type SidebarItemVariantsProps = VariantProps<typeof sidebarItemVariants>;
74
+
75
+ export { SidebarItem, type SidebarItemProps, type SidebarItemVariantsProps, sidebarItemLabelVariants, sidebarItemVariants };
@@ -0,0 +1,2 @@
1
+ export { SidebarItem, sidebarItemLabelVariants, sidebarItemVariants } from './chunk-DAHQYLUI.js';
2
+ import './chunk-7EOSDFS3.js';
@@ -0,0 +1,86 @@
1
+ 'use strict';
2
+
3
+ var clsx = require('clsx');
4
+ var tailwindMerge = require('tailwind-merge');
5
+ var classVarianceAuthority = require('class-variance-authority');
6
+ var jsxRuntime = require('react/jsx-runtime');
7
+
8
+ // src/lib/cn.ts
9
+ function cn(...inputs) {
10
+ return tailwindMerge.twMerge(clsx.clsx(inputs));
11
+ }
12
+ var switchVariants = classVarianceAuthority.cva([
13
+ // Track — 56×24 (`h-6 w-14`), fully round (Figma `radius/full`), 4px inset
14
+ // (`p-1` = Figma `spacing/1`). `appearance-none` strips the native checkbox
15
+ // box; `peer` lets the sibling thumb react to :checked / :disabled.
16
+ "peer inline-flex h-6 w-14 shrink-0 items-center rounded-full border p-1",
17
+ "appearance-none cursor-pointer transition-colors",
18
+ // Off — default
19
+ "bg-button-secondary-background border-button-secondary-border",
20
+ // Off — hover strengthens the border (focused keeps the default border)
21
+ "hover:border-button-secondary-border-accent",
22
+ // Focus ring — suppress the native ring, draw the shared `--focus` ring the
23
+ // same way Checkbox/Radio do: 2px stroke, 2px offset (`outline-solid`
24
+ // restores what `outline-none` zeroed). Circular via the track's rounding.
25
+ "outline-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-solid focus-visible:outline-focus",
26
+ // On — brand fill, border made transparent (kept for a constant box model)
27
+ "checked:bg-brand-primary-background checked:border-transparent",
28
+ "checked:hover:bg-brand-primary-accent",
29
+ // Disabled — off keeps the white track with a muted border; on drops to a
30
+ // neutral muted fill (per Figma). Border transparent when on, muted when off.
31
+ "disabled:pointer-events-none disabled:cursor-not-allowed disabled:border-button-secondary-border-muted",
32
+ "checked:disabled:bg-button-primary-muted checked:disabled:border-transparent"
33
+ ]);
34
+ function Switch({
35
+ className,
36
+ wrapperClassName,
37
+ onChange,
38
+ onCheckedChange,
39
+ ...props
40
+ }) {
41
+ const handleChange = (event) => {
42
+ onChange?.(event);
43
+ onCheckedChange?.(event.currentTarget.checked);
44
+ };
45
+ return /* @__PURE__ */ jsxRuntime.jsxs(
46
+ "span",
47
+ {
48
+ className: cn(
49
+ "relative inline-flex shrink-0 items-center",
50
+ wrapperClassName
51
+ ),
52
+ children: [
53
+ /* @__PURE__ */ jsxRuntime.jsx(
54
+ "input",
55
+ {
56
+ type: "checkbox",
57
+ role: "switch",
58
+ "data-slot": "switch",
59
+ className: cn(switchVariants(), className),
60
+ ...props,
61
+ onChange: handleChange
62
+ }
63
+ ),
64
+ /* @__PURE__ */ jsxRuntime.jsx(
65
+ "span",
66
+ {
67
+ "aria-hidden": "true",
68
+ "data-slot": "switch-thumb",
69
+ className: cn(
70
+ "pointer-events-none absolute left-1 h-4 w-6 rounded-full transition-transform",
71
+ // Off — dark knob at 90% opacity (Figma `opacity/90`)
72
+ "bg-button-secondary-foreground opacity-90",
73
+ "peer-checked:translate-x-5.5 peer-checked:bg-brand-primary-foreground peer-checked:opacity-100",
74
+ // Disabled — muted knob whether on or off (per Figma)
75
+ "peer-disabled:bg-button-secondary-foreground-muted peer-disabled:opacity-100",
76
+ "peer-checked:peer-disabled:bg-button-primary-foreground-muted"
77
+ )
78
+ }
79
+ )
80
+ ]
81
+ }
82
+ );
83
+ }
84
+
85
+ exports.Switch = Switch;
86
+ exports.switchVariants = switchVariants;
@@ -0,0 +1,72 @@
1
+ import * as React from 'react';
2
+ import * as class_variance_authority_types from 'class-variance-authority/types';
3
+ import { VariantProps } from 'class-variance-authority';
4
+
5
+ interface SwitchProps extends Omit<React.ComponentProps<"input">, "type" | "size"> {
6
+ /**
7
+ * Convenience change callback with the next checked state already
8
+ * extracted. Fires alongside (not instead of) the native `onChange`.
9
+ * Controlled/uncontrolled usage is the standard input contract:
10
+ * `defaultChecked` (uncontrolled, the default) or `checked` + a change
11
+ * handler (controlled).
12
+ */
13
+ onCheckedChange?: (checked: boolean) => void;
14
+ /** Class names for the outer wrapper span (positions the sliding thumb). */
15
+ wrapperClassName?: string;
16
+ }
17
+ /**
18
+ * Switch control — the Figma `toggle-switch` set (node 5050:2204), rendered as
19
+ * a real `<input type="checkbox" role="switch">`. A toggle switch is a
20
+ * checkbox semantically (on/off), so the platform gives us Space to toggle,
21
+ * form participation (`FormData`), and label association for free; the `switch`
22
+ * ARIA role only refines the announcement ("on/off" instead of
23
+ * "checked/unchecked"). This is the one difference from Checkbox — otherwise it
24
+ * follows the ADR-0010 form-control conventions exactly (on = `:checked`, zero
25
+ * React state, `onCheckedChange` alongside native `onChange`).
26
+ *
27
+ * The visual is a track (the styled input) plus a sliding thumb (a sibling
28
+ * span, since a void `<input>` can't have children); the thumb slides via
29
+ * `peer-checked:` translate. Ships without a label (the Figma set is the bare
30
+ * 56×24 control): associate one by wrapping in a `<label>` or via
31
+ * `htmlFor`/`id`; icon-style usages need an `aria-label`.
32
+ */
33
+ declare function Switch({ className, wrapperClassName, onChange, onCheckedChange, ...props }: SwitchProps): React.JSX.Element;
34
+
35
+ /**
36
+ * Switch styling — mirrors the Figma `toggle-switch` component set
37
+ * (node 5050:2204: `state` default/hover/focused/disabled × `selected` yes/no,
38
+ * one 56×24 size) and binds ONLY to the semantic token layer (never
39
+ * primitives). Theme switching is automatic via the `.dark` class, so no
40
+ * `dark:` variants are needed.
41
+ *
42
+ * As with Checkbox and Radio (ADR-0010), every Figma axis is an *interaction*
43
+ * state, so there is no prop-driven variant table: `selected` maps to the
44
+ * native `:checked` pseudo-class and `state` maps to `:hover` /
45
+ * `:focus-visible` / `:disabled`. This cva styles the TRACK (the `appearance-
46
+ * none` `<input>` itself); the sliding thumb is a sibling element revealed and
47
+ * translated via `peer-checked:` in <Switch>.
48
+ *
49
+ * Track state → token map (from the Figma variants):
50
+ * - off default: `bg-button-secondary-background` + `border-button-secondary-border`
51
+ * - off hover: border strengthens to `button-secondary-border-accent`
52
+ * - off focused: border stays `button-secondary-border` (+ the shared focus ring)
53
+ * - off disabled: border weakens to `button-secondary-border-muted`
54
+ * - on (default/focused): `bg-brand-primary-background`, border removed
55
+ * - on hover: bg strengthens to `brand-primary-accent`
56
+ * - on disabled: neutral `bg-button-primary-muted`, border removed
57
+ *
58
+ * Checked × hover/disabled combinations are compound utilities
59
+ * (`checked:hover:`, `checked:disabled:`) so precedence rides on selector
60
+ * specificity, not Tailwind's stylesheet order. The border is always declared
61
+ * (`border`) so the track's box model is identical on/off — the on states set
62
+ * `border-transparent` rather than removing the border, keeping the 46px inner
63
+ * track width (and therefore the 22px thumb travel) constant across states.
64
+ *
65
+ * Focus ring: the ADR-0010 system standard (2px `--focus` stroke, 2px offset,
66
+ * `:focus-visible` only), following the track's `rounded-full` radius — the
67
+ * same treatment as Checkbox/Radio, overriding whatever the Figma node draws.
68
+ */
69
+ declare const switchVariants: (props?: class_variance_authority_types.ClassProp | undefined) => string;
70
+ type SwitchVariantsProps = VariantProps<typeof switchVariants>;
71
+
72
+ export { Switch, type SwitchProps, type SwitchVariantsProps, switchVariants };
@@ -0,0 +1,72 @@
1
+ import * as React from 'react';
2
+ import * as class_variance_authority_types from 'class-variance-authority/types';
3
+ import { VariantProps } from 'class-variance-authority';
4
+
5
+ interface SwitchProps extends Omit<React.ComponentProps<"input">, "type" | "size"> {
6
+ /**
7
+ * Convenience change callback with the next checked state already
8
+ * extracted. Fires alongside (not instead of) the native `onChange`.
9
+ * Controlled/uncontrolled usage is the standard input contract:
10
+ * `defaultChecked` (uncontrolled, the default) or `checked` + a change
11
+ * handler (controlled).
12
+ */
13
+ onCheckedChange?: (checked: boolean) => void;
14
+ /** Class names for the outer wrapper span (positions the sliding thumb). */
15
+ wrapperClassName?: string;
16
+ }
17
+ /**
18
+ * Switch control — the Figma `toggle-switch` set (node 5050:2204), rendered as
19
+ * a real `<input type="checkbox" role="switch">`. A toggle switch is a
20
+ * checkbox semantically (on/off), so the platform gives us Space to toggle,
21
+ * form participation (`FormData`), and label association for free; the `switch`
22
+ * ARIA role only refines the announcement ("on/off" instead of
23
+ * "checked/unchecked"). This is the one difference from Checkbox — otherwise it
24
+ * follows the ADR-0010 form-control conventions exactly (on = `:checked`, zero
25
+ * React state, `onCheckedChange` alongside native `onChange`).
26
+ *
27
+ * The visual is a track (the styled input) plus a sliding thumb (a sibling
28
+ * span, since a void `<input>` can't have children); the thumb slides via
29
+ * `peer-checked:` translate. Ships without a label (the Figma set is the bare
30
+ * 56×24 control): associate one by wrapping in a `<label>` or via
31
+ * `htmlFor`/`id`; icon-style usages need an `aria-label`.
32
+ */
33
+ declare function Switch({ className, wrapperClassName, onChange, onCheckedChange, ...props }: SwitchProps): React.JSX.Element;
34
+
35
+ /**
36
+ * Switch styling — mirrors the Figma `toggle-switch` component set
37
+ * (node 5050:2204: `state` default/hover/focused/disabled × `selected` yes/no,
38
+ * one 56×24 size) and binds ONLY to the semantic token layer (never
39
+ * primitives). Theme switching is automatic via the `.dark` class, so no
40
+ * `dark:` variants are needed.
41
+ *
42
+ * As with Checkbox and Radio (ADR-0010), every Figma axis is an *interaction*
43
+ * state, so there is no prop-driven variant table: `selected` maps to the
44
+ * native `:checked` pseudo-class and `state` maps to `:hover` /
45
+ * `:focus-visible` / `:disabled`. This cva styles the TRACK (the `appearance-
46
+ * none` `<input>` itself); the sliding thumb is a sibling element revealed and
47
+ * translated via `peer-checked:` in <Switch>.
48
+ *
49
+ * Track state → token map (from the Figma variants):
50
+ * - off default: `bg-button-secondary-background` + `border-button-secondary-border`
51
+ * - off hover: border strengthens to `button-secondary-border-accent`
52
+ * - off focused: border stays `button-secondary-border` (+ the shared focus ring)
53
+ * - off disabled: border weakens to `button-secondary-border-muted`
54
+ * - on (default/focused): `bg-brand-primary-background`, border removed
55
+ * - on hover: bg strengthens to `brand-primary-accent`
56
+ * - on disabled: neutral `bg-button-primary-muted`, border removed
57
+ *
58
+ * Checked × hover/disabled combinations are compound utilities
59
+ * (`checked:hover:`, `checked:disabled:`) so precedence rides on selector
60
+ * specificity, not Tailwind's stylesheet order. The border is always declared
61
+ * (`border`) so the track's box model is identical on/off — the on states set
62
+ * `border-transparent` rather than removing the border, keeping the 46px inner
63
+ * track width (and therefore the 22px thumb travel) constant across states.
64
+ *
65
+ * Focus ring: the ADR-0010 system standard (2px `--focus` stroke, 2px offset,
66
+ * `:focus-visible` only), following the track's `rounded-full` radius — the
67
+ * same treatment as Checkbox/Radio, overriding whatever the Figma node draws.
68
+ */
69
+ declare const switchVariants: (props?: class_variance_authority_types.ClassProp | undefined) => string;
70
+ type SwitchVariantsProps = VariantProps<typeof switchVariants>;
71
+
72
+ export { Switch, type SwitchProps, type SwitchVariantsProps, switchVariants };
package/dist/switch.js ADDED
@@ -0,0 +1,2 @@
1
+ export { Switch, switchVariants } from './chunk-FV76Z4Z2.js';
2
+ import './chunk-7EOSDFS3.js';