@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,366 @@
1
+ 'use strict';
2
+
3
+ var React = require('react');
4
+ var react = require('@phosphor-icons/react');
5
+ var clsx = require('clsx');
6
+ var tailwindMerge = require('tailwind-merge');
7
+ var classVarianceAuthority = require('class-variance-authority');
8
+ var jsxRuntime = require('react/jsx-runtime');
9
+
10
+ function _interopNamespace(e) {
11
+ if (e && e.__esModule) return e;
12
+ var n = Object.create(null);
13
+ if (e) {
14
+ Object.keys(e).forEach(function (k) {
15
+ if (k !== 'default') {
16
+ var d = Object.getOwnPropertyDescriptor(e, k);
17
+ Object.defineProperty(n, k, d.get ? d : {
18
+ enumerable: true,
19
+ get: function () { return e[k]; }
20
+ });
21
+ }
22
+ });
23
+ }
24
+ n.default = e;
25
+ return Object.freeze(n);
26
+ }
27
+
28
+ var React__namespace = /*#__PURE__*/_interopNamespace(React);
29
+
30
+ // src/button/Button.tsx
31
+ function cn(...inputs) {
32
+ return tailwindMerge.twMerge(clsx.clsx(inputs));
33
+ }
34
+ function buildCutPath({
35
+ W,
36
+ H,
37
+ cut,
38
+ rTR,
39
+ rBL,
40
+ rCut,
41
+ ox = 0,
42
+ oy = 0
43
+ }) {
44
+ const rCutSq = rCut / Math.SQRT2;
45
+ const x = (v) => v + ox;
46
+ const y = (v) => v + oy;
47
+ return [
48
+ `M ${x(cut + rCut)} ${y(0)}`,
49
+ `L ${x(W - rTR)} ${y(0)}`,
50
+ `Q ${x(W)} ${y(0)} ${x(W)} ${y(rTR)}`,
51
+ `L ${x(W)} ${y(H - cut - rCut)}`,
52
+ `Q ${x(W)} ${y(H - cut)} ${x(W - rCutSq)} ${y(H - cut + rCutSq)}`,
53
+ `L ${x(W - cut + rCutSq)} ${y(H - rCutSq)}`,
54
+ `Q ${x(W - cut)} ${y(H)} ${x(W - cut - rCut)} ${y(H)}`,
55
+ `L ${x(rBL)} ${y(H)}`,
56
+ `Q ${x(0)} ${y(H)} ${x(0)} ${y(H - rBL)}`,
57
+ `L ${x(0)} ${y(cut + rCut)}`,
58
+ `Q ${x(0)} ${y(cut)} ${x(rCutSq)} ${y(cut - rCutSq)}`,
59
+ `L ${x(cut - rCutSq)} ${y(rCutSq)}`,
60
+ `Q ${x(cut)} ${y(0)} ${x(cut + rCut)} ${y(0)}`,
61
+ `Z`
62
+ ].join(" ");
63
+ }
64
+ function useCutCornerClipPath(cut, {
65
+ radius = 2,
66
+ radiusCuts,
67
+ radiusTopRight,
68
+ radiusBottomLeft,
69
+ outset
70
+ } = {}) {
71
+ const ref = React__namespace.useRef(null);
72
+ const [clipPath, setClipPath] = React__namespace.useState();
73
+ const [pathD, setPathD] = React__namespace.useState();
74
+ const [outsetPathD, setOutsetPathD] = React__namespace.useState();
75
+ React__namespace.useLayoutEffect(() => {
76
+ const el = ref.current;
77
+ if (!el) return;
78
+ const rTR = radiusTopRight ?? radius;
79
+ const rBL = radiusBottomLeft ?? radius;
80
+ const rCut = radiusCuts ?? radius;
81
+ function compute(W, H) {
82
+ const d = buildCutPath({ W, H, cut, rTR, rBL, rCut });
83
+ setClipPath(`path('${d}')`);
84
+ setPathD(d);
85
+ if (outset != null) {
86
+ const g = outset;
87
+ setOutsetPathD(
88
+ buildCutPath({
89
+ W: W + 2 * g,
90
+ H: H + 2 * g,
91
+ cut: cut + (2 - Math.SQRT2) * g,
92
+ rTR: rTR + g,
93
+ rBL: rBL + g,
94
+ rCut: rCut + g,
95
+ ox: -g,
96
+ oy: -g
97
+ })
98
+ );
99
+ }
100
+ }
101
+ const initial = el.getBoundingClientRect();
102
+ compute(initial.width, initial.height);
103
+ const ro = new ResizeObserver((entries) => {
104
+ const box = entries[entries.length - 1]?.borderBoxSize?.[0];
105
+ if (box) {
106
+ compute(box.inlineSize, box.blockSize);
107
+ } else {
108
+ const rect = el.getBoundingClientRect();
109
+ compute(rect.width, rect.height);
110
+ }
111
+ });
112
+ ro.observe(el);
113
+ return () => ro.disconnect();
114
+ }, [cut, radius, radiusCuts, radiusTopRight, radiusBottomLeft, outset]);
115
+ return { ref, clipPath, pathD, outsetPathD };
116
+ }
117
+ var BUTTON_CUT = { cut: 8, radius: 2, radiusCuts: 0 };
118
+ var buttonVariants = classVarianceAuthority.cva(
119
+ [
120
+ // Layout
121
+ "inline-flex shrink-0 items-center justify-center gap-1",
122
+ // Type — the Figma `button-01` text style (Archivo Medium 14/20)
123
+ "button-01",
124
+ // Shape — cut corners are applied as a clip-path in <Button>; keep the box square
125
+ "rounded-none",
126
+ // Transition
127
+ "transition-colors cursor-pointer",
128
+ // Suppress the native ring. The Figma focus ring is drawn OUTSIDE the
129
+ // clip-path (which would swallow an outline here), so cut-corner variants
130
+ // render it on the wrapper in <Button>; ghost renders it directly (below).
131
+ "outline-none",
132
+ // Disabled
133
+ "disabled:pointer-events-none disabled:cursor-not-allowed",
134
+ // Icons
135
+ "[&_svg]:pointer-events-none [&_svg]:shrink-0"
136
+ ],
137
+ {
138
+ variants: {
139
+ variation: {
140
+ primary: [
141
+ "bg-button-primary-background text-button-primary-foreground",
142
+ "hover:bg-button-primary-accent active:bg-button-primary-accent",
143
+ "disabled:bg-button-primary-muted disabled:text-button-primary-foreground-muted"
144
+ ],
145
+ brand: [
146
+ "bg-button-brand-primary-background text-button-brand-primary-foreground",
147
+ "hover:bg-button-brand-primary-accent active:bg-button-brand-primary-accent",
148
+ "disabled:bg-button-primary-muted disabled:text-button-primary-foreground-muted"
149
+ ],
150
+ destructive: [
151
+ "bg-button-destructive-background text-button-destructive-primary-foreground",
152
+ "hover:bg-button-destructive-accent active:bg-button-destructive-accent",
153
+ "disabled:bg-button-primary-muted disabled:text-button-primary-foreground-muted"
154
+ ],
155
+ // Outline — background fill + an SVG stroke border drawn in <Button>.
156
+ secondary: [
157
+ "bg-button-secondary-background text-button-secondary-foreground",
158
+ "hover:text-button-secondary-foreground-accent active:text-button-secondary-foreground-accent",
159
+ "disabled:text-button-secondary-foreground-muted"
160
+ ],
161
+ // No background, no cut corner — so no wrapper; ring on the element.
162
+ // `outline-solid` restores the style that base `outline-none` zeroed.
163
+ ghost: [
164
+ "bg-transparent text-button-secondary-foreground",
165
+ "hover:text-button-secondary-foreground-accent active:text-button-secondary-foreground-accent",
166
+ "disabled:text-button-secondary-foreground-muted",
167
+ // `rounded-xs` (2px) keeps the ghost focus ring as sharp as the other
168
+ // variants' corners (which now use sharp chamfers + 2px square corners).
169
+ "rounded-xs focus-visible:outline-solid focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-focus"
170
+ ]
171
+ },
172
+ size: {
173
+ sm: "h-8 px-2.5 [&_svg:not([class*='size-'])]:size-4",
174
+ md: "h-10 px-2.5 [&_svg:not([class*='size-'])]:size-4",
175
+ lg: "h-12 px-3 [&_svg:not([class*='size-'])]:size-4"
176
+ },
177
+ iconOnly: {
178
+ true: "",
179
+ false: ""
180
+ }
181
+ },
182
+ compoundVariants: [
183
+ // Icon-only: square footprint, no horizontal padding.
184
+ { iconOnly: true, size: "sm", className: "w-8 px-0" },
185
+ { iconOnly: true, size: "md", className: "w-10 px-0" },
186
+ { iconOnly: true, size: "lg", className: "w-12 px-0" },
187
+ // Ghost has no chamfer/background, so it sits flush with no inset padding.
188
+ { variation: "ghost", iconOnly: false, className: "px-0" }
189
+ ],
190
+ defaultVariants: {
191
+ variation: "primary",
192
+ size: "md",
193
+ iconOnly: false
194
+ }
195
+ }
196
+ );
197
+ var FOCUS_RING_GAP = 3;
198
+ var FOCUS_RING_WIDTH = 2;
199
+ function setRef(ref, node) {
200
+ if (typeof ref === "function") ref(node);
201
+ else if (ref) ref.current = node;
202
+ }
203
+ function Button({
204
+ className,
205
+ variation = "primary",
206
+ size = "md",
207
+ iconOnly = false,
208
+ asChild = false,
209
+ loading = false,
210
+ leftSlot,
211
+ rightSlot,
212
+ wrapperClassName,
213
+ disabled,
214
+ style,
215
+ children,
216
+ onClick,
217
+ ref,
218
+ ...props
219
+ }) {
220
+ const {
221
+ ref: cutRef,
222
+ clipPath,
223
+ pathD,
224
+ outsetPathD
225
+ } = useCutCornerClipPath(BUTTON_CUT.cut, {
226
+ radius: BUTTON_CUT.radius,
227
+ radiusCuts: BUTTON_CUT.radiusCuts,
228
+ outset: FOCUS_RING_GAP
229
+ });
230
+ const setRootRef = React__namespace.useCallback(
231
+ (node) => {
232
+ cutRef.current = node;
233
+ setRef(ref, node);
234
+ },
235
+ [cutRef, ref]
236
+ );
237
+ const isDisabled = disabled;
238
+ const hasCutCorner = variation !== "ghost";
239
+ const hasSvgBorder = variation === "secondary";
240
+ const handleClick = loading ? (event) => {
241
+ event.preventDefault();
242
+ event.stopPropagation();
243
+ } : onClick;
244
+ const rootClassName = cn(
245
+ buttonVariants({ variation, size, iconOnly }),
246
+ hasSvgBorder && "border-0",
247
+ loading && "pointer-events-none",
248
+ className
249
+ );
250
+ const rootStyle = hasCutCorner ? { ...style, clipPath } : style;
251
+ const content = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
252
+ loading ? /* @__PURE__ */ jsxRuntime.jsx(react.CircleNotchIcon, { className: "animate-spin", "aria-hidden": "true" }) : leftSlot,
253
+ !iconOnly && children,
254
+ iconOnly && !loading && children,
255
+ !iconOnly && rightSlot
256
+ ] });
257
+ let rootEl;
258
+ if (asChild) {
259
+ if (!React__namespace.isValidElement(children)) {
260
+ throw new Error(
261
+ "Button: `asChild` requires a single React element child"
262
+ );
263
+ }
264
+ const child = children;
265
+ const childProps = child.props;
266
+ const childOnClick = childProps.onClick;
267
+ rootEl = React__namespace.cloneElement(
268
+ child,
269
+ {
270
+ ...props,
271
+ ...childProps,
272
+ "data-slot": "button",
273
+ "data-loading": loading || void 0,
274
+ "aria-busy": loading || void 0,
275
+ "aria-disabled": loading || void 0,
276
+ // Block activation while loading; otherwise run both handlers.
277
+ onClick: loading ? (event) => {
278
+ event.preventDefault();
279
+ event.stopPropagation();
280
+ } : (event) => {
281
+ onClick?.(event);
282
+ childOnClick?.(event);
283
+ },
284
+ ref: (node) => {
285
+ setRootRef(node);
286
+ setRef(childProps.ref, node);
287
+ },
288
+ className: cn(
289
+ rootClassName,
290
+ childProps.className
291
+ ),
292
+ style: {
293
+ ...rootStyle,
294
+ ...childProps.style
295
+ }
296
+ },
297
+ loading ? /* @__PURE__ */ jsxRuntime.jsx(react.CircleNotchIcon, { className: "animate-spin", "aria-hidden": "true" }) : null,
298
+ childProps.children
299
+ );
300
+ } else {
301
+ rootEl = /* @__PURE__ */ jsxRuntime.jsx(
302
+ "button",
303
+ {
304
+ "data-slot": "button",
305
+ "data-loading": loading || void 0,
306
+ "aria-busy": loading || void 0,
307
+ "aria-disabled": loading || void 0,
308
+ className: rootClassName,
309
+ style: rootStyle,
310
+ disabled: isDisabled,
311
+ ...props,
312
+ onClick: handleClick,
313
+ ref: setRootRef,
314
+ children: content
315
+ }
316
+ );
317
+ }
318
+ if (!hasCutCorner) return rootEl;
319
+ return /* @__PURE__ */ jsxRuntime.jsxs("span", { className: cn("group relative inline-block", wrapperClassName), children: [
320
+ rootEl,
321
+ outsetPathD && /* @__PURE__ */ jsxRuntime.jsx(
322
+ "svg",
323
+ {
324
+ className: "pointer-events-none absolute inset-0 h-full w-full overflow-visible opacity-0 group-has-[:focus-visible]:opacity-100",
325
+ "aria-hidden": "true",
326
+ children: /* @__PURE__ */ jsxRuntime.jsx(
327
+ "path",
328
+ {
329
+ d: outsetPathD,
330
+ fill: "none",
331
+ strokeWidth: FOCUS_RING_WIDTH,
332
+ className: "stroke-focus"
333
+ }
334
+ )
335
+ }
336
+ ),
337
+ hasSvgBorder && pathD && /* @__PURE__ */ jsxRuntime.jsx(
338
+ "svg",
339
+ {
340
+ className: "pointer-events-none absolute inset-0 h-full w-full overflow-visible",
341
+ "aria-hidden": "true",
342
+ children: /* @__PURE__ */ jsxRuntime.jsx(
343
+ "path",
344
+ {
345
+ d: pathD,
346
+ fill: "none",
347
+ strokeWidth: 1,
348
+ className: cn(
349
+ // Disabled locks the muted stroke; the hover/active accent
350
+ // classes must not be present at all (a `group-hover:` variant
351
+ // out-specifies the plain muted class, so it would still
352
+ // recolor the border on hover of a disabled button).
353
+ isDisabled ? "stroke-button-secondary-border-muted" : [
354
+ "stroke-button-secondary-border",
355
+ "group-hover:stroke-button-secondary-border-accent group-active:stroke-button-secondary-border-accent"
356
+ ]
357
+ )
358
+ }
359
+ )
360
+ }
361
+ )
362
+ ] });
363
+ }
364
+
365
+ exports.Button = Button;
366
+ exports.buttonVariants = buttonVariants;
@@ -0,0 +1,52 @@
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
+ /**
6
+ * Button styling — mirrors the Figma `button` component set
7
+ * (`variation` × `size` × `state` × `iconOnly`) and binds ONLY to the semantic
8
+ * `--button-*` token layer (never primitives). Theme switching is automatic via
9
+ * the `.dark` class, so no `dark:` variants are needed.
10
+ *
11
+ * Notes on states:
12
+ * - `hover` / `active` are handled by the `:hover` / `:active` utilities here.
13
+ * - `focus` is the shared focus ring (`outline-focus`), applied in the base.
14
+ * - `disabled` is a shared NEUTRAL-muted look for every filled variant (Figma
15
+ * greys out primary/brand/destructive identically), hence they all reuse
16
+ * `button-primary-muted` / `button-primary-foreground-muted`.
17
+ * - `loading` is a runtime prop on <Button>, not a style variant.
18
+ *
19
+ * Shape (cut corners) and the secondary border are handled in <Button>: the
20
+ * chamfer is a measured `clip-path` and the secondary outline is an SVG stroke
21
+ * that follows that shape (a CSS border would clip square across the chamfer).
22
+ */
23
+ declare const buttonVariants: (props?: ({
24
+ variation?: "primary" | "brand" | "destructive" | "secondary" | "ghost" | null | undefined;
25
+ size?: "sm" | "md" | "lg" | null | undefined;
26
+ iconOnly?: boolean | null | undefined;
27
+ } & class_variance_authority_types.ClassProp) | undefined) => string;
28
+ type ButtonVariantsProps = VariantProps<typeof buttonVariants>;
29
+
30
+ interface ButtonProps extends Omit<React.ComponentProps<"button">, "color">, ButtonVariantsProps {
31
+ /**
32
+ * Render the single child element (e.g. an `<a>` / Next `<Link>`) as the root
33
+ * instead of a `<button>`, keeping all button styling. Keeps a button-styled
34
+ * link a real anchor (valid HTML, middle-click, open-in-new-tab).
35
+ */
36
+ asChild?: boolean;
37
+ /**
38
+ * Show a spinner and mark the button busy (`aria-busy`). Keeps the ACTIVE
39
+ * styling (not the greyed disabled look) but is not actionable while busy —
40
+ * clicks and keyboard activation are blocked and it reports `aria-disabled`.
41
+ */
42
+ loading?: boolean;
43
+ /** Leading content (usually a Phosphor icon). Replaced by the spinner when loading. */
44
+ leftSlot?: React.ReactNode;
45
+ /** Trailing content (usually a Phosphor icon). Stays visible when loading (per Figma). */
46
+ rightSlot?: React.ReactNode;
47
+ /** Class names for the outer wrapper span (present only for the secondary border). */
48
+ wrapperClassName?: string;
49
+ }
50
+ declare function Button({ className, variation, size, iconOnly, asChild, loading, leftSlot, rightSlot, wrapperClassName, disabled, style, children, onClick, ref, ...props }: ButtonProps): React.JSX.Element;
51
+
52
+ export { Button, type ButtonProps, type ButtonVariantsProps, buttonVariants };
@@ -0,0 +1,52 @@
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
+ /**
6
+ * Button styling — mirrors the Figma `button` component set
7
+ * (`variation` × `size` × `state` × `iconOnly`) and binds ONLY to the semantic
8
+ * `--button-*` token layer (never primitives). Theme switching is automatic via
9
+ * the `.dark` class, so no `dark:` variants are needed.
10
+ *
11
+ * Notes on states:
12
+ * - `hover` / `active` are handled by the `:hover` / `:active` utilities here.
13
+ * - `focus` is the shared focus ring (`outline-focus`), applied in the base.
14
+ * - `disabled` is a shared NEUTRAL-muted look for every filled variant (Figma
15
+ * greys out primary/brand/destructive identically), hence they all reuse
16
+ * `button-primary-muted` / `button-primary-foreground-muted`.
17
+ * - `loading` is a runtime prop on <Button>, not a style variant.
18
+ *
19
+ * Shape (cut corners) and the secondary border are handled in <Button>: the
20
+ * chamfer is a measured `clip-path` and the secondary outline is an SVG stroke
21
+ * that follows that shape (a CSS border would clip square across the chamfer).
22
+ */
23
+ declare const buttonVariants: (props?: ({
24
+ variation?: "primary" | "brand" | "destructive" | "secondary" | "ghost" | null | undefined;
25
+ size?: "sm" | "md" | "lg" | null | undefined;
26
+ iconOnly?: boolean | null | undefined;
27
+ } & class_variance_authority_types.ClassProp) | undefined) => string;
28
+ type ButtonVariantsProps = VariantProps<typeof buttonVariants>;
29
+
30
+ interface ButtonProps extends Omit<React.ComponentProps<"button">, "color">, ButtonVariantsProps {
31
+ /**
32
+ * Render the single child element (e.g. an `<a>` / Next `<Link>`) as the root
33
+ * instead of a `<button>`, keeping all button styling. Keeps a button-styled
34
+ * link a real anchor (valid HTML, middle-click, open-in-new-tab).
35
+ */
36
+ asChild?: boolean;
37
+ /**
38
+ * Show a spinner and mark the button busy (`aria-busy`). Keeps the ACTIVE
39
+ * styling (not the greyed disabled look) but is not actionable while busy —
40
+ * clicks and keyboard activation are blocked and it reports `aria-disabled`.
41
+ */
42
+ loading?: boolean;
43
+ /** Leading content (usually a Phosphor icon). Replaced by the spinner when loading. */
44
+ leftSlot?: React.ReactNode;
45
+ /** Trailing content (usually a Phosphor icon). Stays visible when loading (per Figma). */
46
+ rightSlot?: React.ReactNode;
47
+ /** Class names for the outer wrapper span (present only for the secondary border). */
48
+ wrapperClassName?: string;
49
+ }
50
+ declare function Button({ className, variation, size, iconOnly, asChild, loading, leftSlot, rightSlot, wrapperClassName, disabled, style, children, onClick, ref, ...props }: ButtonProps): React.JSX.Element;
51
+
52
+ export { Button, type ButtonProps, type ButtonVariantsProps, buttonVariants };
package/dist/button.js ADDED
@@ -0,0 +1,3 @@
1
+ export { Button, buttonVariants } from './chunk-WJFPGGJB.js';
2
+ import './chunk-JIXW3455.js';
3
+ import './chunk-7EOSDFS3.js';
@@ -0,0 +1,74 @@
1
+ 'use strict';
2
+
3
+ var react = require('@phosphor-icons/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
+ // src/checkbox/Checkbox.tsx
10
+ function cn(...inputs) {
11
+ return tailwindMerge.twMerge(clsx.clsx(inputs));
12
+ }
13
+ var checkboxVariants = classVarianceAuthority.cva([
14
+ // Box — 20×20 (`size-5`), 2px radius (Figma `radius/xs`), 1px border.
15
+ // `peer` lets the sibling indicator react to :checked / :disabled.
16
+ "peer size-5 shrink-0 appearance-none rounded-xs border",
17
+ "cursor-pointer transition-colors",
18
+ // Default
19
+ "bg-background border-border",
20
+ // Hover (unselected) — focus keeps the DEFAULT border; only the ring signals
21
+ // focus (so focus doesn't visually read as hover).
22
+ "hover:border-border-accent",
23
+ // Focus ring — suppress the native ring, draw the shared `--focus` ring the
24
+ // same way ghost Button does: 2px stroke, 2px offset (`outline-solid`
25
+ // restores what `outline-none` zeroed).
26
+ "outline-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-solid focus-visible:outline-focus",
27
+ // Selected
28
+ "checked:bg-brand-primary-background checked:border-brand-primary-border",
29
+ "checked:hover:bg-brand-primary-accent checked:hover:border-brand-primary-border",
30
+ "checked:focus-visible:bg-brand-primary-accent checked:focus-visible:border-brand-primary-border",
31
+ // Disabled — shared neutral-muted look whether selected or not (per Figma)
32
+ "disabled:pointer-events-none disabled:cursor-not-allowed disabled:border-border-muted",
33
+ "checked:disabled:bg-background checked:disabled:border-border-muted"
34
+ ]);
35
+ function Checkbox({
36
+ className,
37
+ wrapperClassName,
38
+ onChange,
39
+ onCheckedChange,
40
+ ...props
41
+ }) {
42
+ const handleChange = (event) => {
43
+ onChange?.(event);
44
+ onCheckedChange?.(event.currentTarget.checked);
45
+ };
46
+ return /* @__PURE__ */ jsxRuntime.jsxs("span", { className: cn("relative inline-flex shrink-0", wrapperClassName), children: [
47
+ /* @__PURE__ */ jsxRuntime.jsx(
48
+ "input",
49
+ {
50
+ type: "checkbox",
51
+ "data-slot": "checkbox",
52
+ className: cn(checkboxVariants(), className),
53
+ ...props,
54
+ onChange: handleChange
55
+ }
56
+ ),
57
+ /* @__PURE__ */ jsxRuntime.jsx(
58
+ react.CheckIcon,
59
+ {
60
+ "aria-hidden": "true",
61
+ weight: "regular",
62
+ "data-slot": "checkbox-indicator",
63
+ className: cn(
64
+ "pointer-events-none invisible absolute inset-0 m-auto size-4",
65
+ "text-brand-primary-foreground",
66
+ "peer-checked:visible peer-disabled:text-foreground-muted"
67
+ )
68
+ }
69
+ )
70
+ ] });
71
+ }
72
+
73
+ exports.Checkbox = Checkbox;
74
+ exports.checkboxVariants = checkboxVariants;
@@ -0,0 +1,63 @@
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 CheckboxProps 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 ✓ indicator). */
15
+ wrapperClassName?: string;
16
+ }
17
+ /**
18
+ * Checkbox control — the Figma `checkbox-control` set (node 5066:9964),
19
+ * rendered as a real `<input type="checkbox">` so keyboard (Space), forms,
20
+ * and label association all come from the platform.
21
+ *
22
+ * Ships without a label (the Figma set is the bare 20×20 control): associate
23
+ * one by wrapping in a `<label>` or via `htmlFor`/`id`; icon-style usages
24
+ * need an `aria-label`.
25
+ *
26
+ * The FD Figma set has no indeterminate variant; if a consumer ever needs the
27
+ * native `indeterminate` flag (DOM-only, not an attribute), set it on the
28
+ * node via `ref`.
29
+ */
30
+ declare function Checkbox({ className, wrapperClassName, onChange, onCheckedChange, ...props }: CheckboxProps): React.JSX.Element;
31
+
32
+ /**
33
+ * Checkbox styling — mirrors the Figma `checkbox-control` component set
34
+ * (node 5066:9964: `state` × `selected`, one 20×20 size) and binds ONLY to the
35
+ * semantic token layer (never primitives). Theme switching is automatic via
36
+ * the `.dark` class, so no `dark:` variants are needed.
37
+ *
38
+ * Unlike Button, every Figma axis here is an *interaction* state, so there is
39
+ * no prop-driven variant table: `selected` maps to the native `:checked`
40
+ * pseudo-class and `state` maps to `:hover` / `:focus-visible` / `:disabled`.
41
+ *
42
+ * State → token map (from the Figma variants):
43
+ * - default: `bg-background` + `border-border`
44
+ * - hover (unselected): border strengthens to `border-accent`
45
+ * - focused: border stays at the default; the ring alone marks focus
46
+ * - selected: `bg-brand-primary-background` + `border-brand-primary-border`
47
+ * - selected hover/focused: bg strengthens to `brand-primary-accent`
48
+ * - disabled (either): shared neutral look — `bg-background` + `border-border-muted`
49
+ * - focused additionally draws the shared 2px `--focus` ring, offset 2px from
50
+ * the box — the same treatment as ghost Button (design decision 2026-07-07,
51
+ * overriding the flush ring the Figma node draws).
52
+ *
53
+ * Checked × hover/focus/disabled combinations are written as compound
54
+ * utilities (`checked:hover:`, `checked:disabled:`) so precedence is decided
55
+ * by selector specificity, not by Tailwind's stylesheet ordering.
56
+ *
57
+ * The ✓ indicator is a sibling of the input (an `<input>` can't have
58
+ * children), revealed via `peer-checked:` in <Checkbox>.
59
+ */
60
+ declare const checkboxVariants: (props?: class_variance_authority_types.ClassProp | undefined) => string;
61
+ type CheckboxVariantsProps = VariantProps<typeof checkboxVariants>;
62
+
63
+ export { Checkbox, type CheckboxProps, type CheckboxVariantsProps, checkboxVariants };
@@ -0,0 +1,63 @@
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 CheckboxProps 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 ✓ indicator). */
15
+ wrapperClassName?: string;
16
+ }
17
+ /**
18
+ * Checkbox control — the Figma `checkbox-control` set (node 5066:9964),
19
+ * rendered as a real `<input type="checkbox">` so keyboard (Space), forms,
20
+ * and label association all come from the platform.
21
+ *
22
+ * Ships without a label (the Figma set is the bare 20×20 control): associate
23
+ * one by wrapping in a `<label>` or via `htmlFor`/`id`; icon-style usages
24
+ * need an `aria-label`.
25
+ *
26
+ * The FD Figma set has no indeterminate variant; if a consumer ever needs the
27
+ * native `indeterminate` flag (DOM-only, not an attribute), set it on the
28
+ * node via `ref`.
29
+ */
30
+ declare function Checkbox({ className, wrapperClassName, onChange, onCheckedChange, ...props }: CheckboxProps): React.JSX.Element;
31
+
32
+ /**
33
+ * Checkbox styling — mirrors the Figma `checkbox-control` component set
34
+ * (node 5066:9964: `state` × `selected`, one 20×20 size) and binds ONLY to the
35
+ * semantic token layer (never primitives). Theme switching is automatic via
36
+ * the `.dark` class, so no `dark:` variants are needed.
37
+ *
38
+ * Unlike Button, every Figma axis here is an *interaction* state, so there is
39
+ * no prop-driven variant table: `selected` maps to the native `:checked`
40
+ * pseudo-class and `state` maps to `:hover` / `:focus-visible` / `:disabled`.
41
+ *
42
+ * State → token map (from the Figma variants):
43
+ * - default: `bg-background` + `border-border`
44
+ * - hover (unselected): border strengthens to `border-accent`
45
+ * - focused: border stays at the default; the ring alone marks focus
46
+ * - selected: `bg-brand-primary-background` + `border-brand-primary-border`
47
+ * - selected hover/focused: bg strengthens to `brand-primary-accent`
48
+ * - disabled (either): shared neutral look — `bg-background` + `border-border-muted`
49
+ * - focused additionally draws the shared 2px `--focus` ring, offset 2px from
50
+ * the box — the same treatment as ghost Button (design decision 2026-07-07,
51
+ * overriding the flush ring the Figma node draws).
52
+ *
53
+ * Checked × hover/focus/disabled combinations are written as compound
54
+ * utilities (`checked:hover:`, `checked:disabled:`) so precedence is decided
55
+ * by selector specificity, not by Tailwind's stylesheet ordering.
56
+ *
57
+ * The ✓ indicator is a sibling of the input (an `<input>` can't have
58
+ * children), revealed via `peer-checked:` in <Checkbox>.
59
+ */
60
+ declare const checkboxVariants: (props?: class_variance_authority_types.ClassProp | undefined) => string;
61
+ type CheckboxVariantsProps = VariantProps<typeof checkboxVariants>;
62
+
63
+ export { Checkbox, type CheckboxProps, type CheckboxVariantsProps, checkboxVariants };
@@ -0,0 +1,2 @@
1
+ export { Checkbox, checkboxVariants } from './chunk-SNU4YXOR.js';
2
+ import './chunk-7EOSDFS3.js';