@craftzbay/ui 0.10.0 → 0.11.1

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 (187) hide show
  1. package/README.md +18 -12
  2. package/dist-lib/__tests__/helpers/color.d.ts +9 -0
  3. package/dist-lib/__tests__/helpers/theme.d.ts +18 -0
  4. package/dist-lib/components/ui/Accordion.js +18 -7
  5. package/dist-lib/components/ui/Accordion.js.map +1 -1
  6. package/dist-lib/components/ui/Alert.d.ts +16 -0
  7. package/dist-lib/components/ui/Alert.js +47 -34
  8. package/dist-lib/components/ui/Alert.js.map +1 -1
  9. package/dist-lib/components/ui/Avatar.d.ts +1 -1
  10. package/dist-lib/components/ui/Avatar.js +45 -47
  11. package/dist-lib/components/ui/Avatar.js.map +1 -1
  12. package/dist-lib/components/ui/Badge.d.ts +3 -1
  13. package/dist-lib/components/ui/Badge.js +24 -15
  14. package/dist-lib/components/ui/Badge.js.map +1 -1
  15. package/dist-lib/components/ui/Breadcrumbs.d.ts +2 -0
  16. package/dist-lib/components/ui/Breadcrumbs.js +46 -28
  17. package/dist-lib/components/ui/Breadcrumbs.js.map +1 -1
  18. package/dist-lib/components/ui/Button.d.ts +5 -3
  19. package/dist-lib/components/ui/Button.js +59 -45
  20. package/dist-lib/components/ui/Button.js.map +1 -1
  21. package/dist-lib/components/ui/Calendar.d.ts +1 -1
  22. package/dist-lib/components/ui/Calendar.js +87 -59
  23. package/dist-lib/components/ui/Calendar.js.map +1 -1
  24. package/dist-lib/components/ui/Card.d.ts +2 -0
  25. package/dist-lib/components/ui/Card.js +48 -67
  26. package/dist-lib/components/ui/Card.js.map +1 -1
  27. package/dist-lib/components/ui/Carousel.d.ts +6 -6
  28. package/dist-lib/components/ui/Carousel.js +133 -102
  29. package/dist-lib/components/ui/Carousel.js.map +1 -1
  30. package/dist-lib/components/ui/Chart.d.ts +49 -10
  31. package/dist-lib/components/ui/Chart.js +415 -181
  32. package/dist-lib/components/ui/Chart.js.map +1 -1
  33. package/dist-lib/components/ui/Checkbox.js +42 -28
  34. package/dist-lib/components/ui/Checkbox.js.map +1 -1
  35. package/dist-lib/components/ui/Combobox.d.ts +2 -0
  36. package/dist-lib/components/ui/Combobox.js +142 -111
  37. package/dist-lib/components/ui/Combobox.js.map +1 -1
  38. package/dist-lib/components/ui/CommandPalette.d.ts +6 -3
  39. package/dist-lib/components/ui/CommandPalette.js +92 -87
  40. package/dist-lib/components/ui/CommandPalette.js.map +1 -1
  41. package/dist-lib/components/ui/ContextMenu.d.ts +7 -2
  42. package/dist-lib/components/ui/ContextMenu.js +77 -62
  43. package/dist-lib/components/ui/ContextMenu.js.map +1 -1
  44. package/dist-lib/components/ui/DataGrid.d.ts +17 -4
  45. package/dist-lib/components/ui/DataGrid.js +65 -50
  46. package/dist-lib/components/ui/DataGrid.js.map +1 -1
  47. package/dist-lib/components/ui/DatePicker.js +118 -99
  48. package/dist-lib/components/ui/DatePicker.js.map +1 -1
  49. package/dist-lib/components/ui/DesignSystemProvider.d.ts +94 -40
  50. package/dist-lib/components/ui/DesignSystemProvider.js +111 -55
  51. package/dist-lib/components/ui/DesignSystemProvider.js.map +1 -1
  52. package/dist-lib/components/ui/Dialog.d.ts +18 -3
  53. package/dist-lib/components/ui/Dialog.js +105 -80
  54. package/dist-lib/components/ui/Dialog.js.map +1 -1
  55. package/dist-lib/components/ui/Drawer.d.ts +17 -2
  56. package/dist-lib/components/ui/Drawer.js +89 -55
  57. package/dist-lib/components/ui/Drawer.js.map +1 -1
  58. package/dist-lib/components/ui/DropdownMenu.js +14 -9
  59. package/dist-lib/components/ui/DropdownMenu.js.map +1 -1
  60. package/dist-lib/components/ui/EmptyState.d.ts +2 -0
  61. package/dist-lib/components/ui/EmptyState.js +30 -16
  62. package/dist-lib/components/ui/EmptyState.js.map +1 -1
  63. package/dist-lib/components/ui/ErrorState.d.ts +13 -2
  64. package/dist-lib/components/ui/ErrorState.js +44 -23
  65. package/dist-lib/components/ui/ErrorState.js.map +1 -1
  66. package/dist-lib/components/ui/FileUpload.js +59 -56
  67. package/dist-lib/components/ui/FileUpload.js.map +1 -1
  68. package/dist-lib/components/ui/Form.d.ts +15 -2
  69. package/dist-lib/components/ui/Form.js +97 -71
  70. package/dist-lib/components/ui/Form.js.map +1 -1
  71. package/dist-lib/components/ui/Icon.d.ts +1 -1
  72. package/dist-lib/components/ui/Icon.js +20 -14
  73. package/dist-lib/components/ui/Icon.js.map +1 -1
  74. package/dist-lib/components/ui/IconButton.d.ts +2 -2
  75. package/dist-lib/components/ui/IconButton.js +28 -20
  76. package/dist-lib/components/ui/IconButton.js.map +1 -1
  77. package/dist-lib/components/ui/Input.d.ts +3 -1
  78. package/dist-lib/components/ui/Input.js +102 -79
  79. package/dist-lib/components/ui/Input.js.map +1 -1
  80. package/dist-lib/components/ui/Kbd.js +1 -1
  81. package/dist-lib/components/ui/Kbd.js.map +1 -1
  82. package/dist-lib/components/ui/MultiSelect.js +121 -107
  83. package/dist-lib/components/ui/MultiSelect.js.map +1 -1
  84. package/dist-lib/components/ui/Pagination.js +67 -62
  85. package/dist-lib/components/ui/Pagination.js.map +1 -1
  86. package/dist-lib/components/ui/Popover.js +14 -14
  87. package/dist-lib/components/ui/Popover.js.map +1 -1
  88. package/dist-lib/components/ui/Progress.d.ts +3 -3
  89. package/dist-lib/components/ui/Progress.js +77 -72
  90. package/dist-lib/components/ui/Progress.js.map +1 -1
  91. package/dist-lib/components/ui/RadioGroup.d.ts +1 -1
  92. package/dist-lib/components/ui/RadioGroup.js +69 -52
  93. package/dist-lib/components/ui/RadioGroup.js.map +1 -1
  94. package/dist-lib/components/ui/RelativeTime.d.ts +19 -0
  95. package/dist-lib/components/ui/RelativeTime.js +31 -0
  96. package/dist-lib/components/ui/RelativeTime.js.map +1 -0
  97. package/dist-lib/components/ui/ScrollArea.d.ts +9 -1
  98. package/dist-lib/components/ui/ScrollArea.js +43 -27
  99. package/dist-lib/components/ui/ScrollArea.js.map +1 -1
  100. package/dist-lib/components/ui/Select.d.ts +6 -1
  101. package/dist-lib/components/ui/Select.js +79 -71
  102. package/dist-lib/components/ui/Select.js.map +1 -1
  103. package/dist-lib/components/ui/Separator.js +1 -1
  104. package/dist-lib/components/ui/Separator.js.map +1 -1
  105. package/dist-lib/components/ui/Sheet.d.ts +9 -0
  106. package/dist-lib/components/ui/Sheet.js +69 -46
  107. package/dist-lib/components/ui/Sheet.js.map +1 -1
  108. package/dist-lib/components/ui/Sidebar.d.ts +12 -9
  109. package/dist-lib/components/ui/Sidebar.js +152 -109
  110. package/dist-lib/components/ui/Sidebar.js.map +1 -1
  111. package/dist-lib/components/ui/Skeleton.d.ts +13 -2
  112. package/dist-lib/components/ui/Skeleton.js +15 -14
  113. package/dist-lib/components/ui/Skeleton.js.map +1 -1
  114. package/dist-lib/components/ui/Slider.js +41 -29
  115. package/dist-lib/components/ui/Slider.js.map +1 -1
  116. package/dist-lib/components/ui/Snackbar.js +23 -22
  117. package/dist-lib/components/ui/Snackbar.js.map +1 -1
  118. package/dist-lib/components/ui/Spinner.js +18 -6
  119. package/dist-lib/components/ui/Spinner.js.map +1 -1
  120. package/dist-lib/components/ui/Stepper.d.ts +6 -0
  121. package/dist-lib/components/ui/Stepper.js +71 -48
  122. package/dist-lib/components/ui/Stepper.js.map +1 -1
  123. package/dist-lib/components/ui/Switch.js +46 -43
  124. package/dist-lib/components/ui/Switch.js.map +1 -1
  125. package/dist-lib/components/ui/Table.d.ts +33 -5
  126. package/dist-lib/components/ui/Table.js +141 -119
  127. package/dist-lib/components/ui/Table.js.map +1 -1
  128. package/dist-lib/components/ui/Tabs.js +50 -48
  129. package/dist-lib/components/ui/Tabs.js.map +1 -1
  130. package/dist-lib/components/ui/TagInput.js +45 -45
  131. package/dist-lib/components/ui/TagInput.js.map +1 -1
  132. package/dist-lib/components/ui/Textarea.js +65 -54
  133. package/dist-lib/components/ui/Textarea.js.map +1 -1
  134. package/dist-lib/components/ui/Timeline.js +39 -35
  135. package/dist-lib/components/ui/Timeline.js.map +1 -1
  136. package/dist-lib/components/ui/Toast.js +44 -57
  137. package/dist-lib/components/ui/Toast.js.map +1 -1
  138. package/dist-lib/components/ui/Tooltip.d.ts +4 -1
  139. package/dist-lib/components/ui/Tooltip.js +24 -22
  140. package/dist-lib/components/ui/Tooltip.js.map +1 -1
  141. package/dist-lib/components/ui/TopNav.d.ts +7 -3
  142. package/dist-lib/components/ui/TopNav.js +39 -22
  143. package/dist-lib/components/ui/TopNav.js.map +1 -1
  144. package/dist-lib/components/ui/Tree.d.ts +15 -10
  145. package/dist-lib/components/ui/Tree.js +82 -79
  146. package/dist-lib/components/ui/Tree.js.map +1 -1
  147. package/dist-lib/hooks/use-debounce.d.ts +19 -0
  148. package/dist-lib/hooks/use-debounce.js +36 -0
  149. package/dist-lib/hooks/use-debounce.js.map +1 -0
  150. package/dist-lib/hooks/use-delayed-loading.d.ts +21 -0
  151. package/dist-lib/hooks/use-delayed-loading.js +20 -0
  152. package/dist-lib/hooks/use-delayed-loading.js.map +1 -0
  153. package/dist-lib/hooks/use-field-ids.d.ts +2 -1
  154. package/dist-lib/hooks/use-field-ids.js +9 -9
  155. package/dist-lib/hooks/use-field-ids.js.map +1 -1
  156. package/dist-lib/hooks/use-media-query.d.ts +3 -1
  157. package/dist-lib/hooks/use-media-query.js +16 -12
  158. package/dist-lib/hooks/use-media-query.js.map +1 -1
  159. package/dist-lib/hooks/use-modifier-key.d.ts +13 -0
  160. package/dist-lib/hooks/use-modifier-key.js +19 -0
  161. package/dist-lib/hooks/use-modifier-key.js.map +1 -0
  162. package/dist-lib/hooks/use-toast.d.ts +7 -2
  163. package/dist-lib/hooks/use-toast.js +61 -30
  164. package/dist-lib/hooks/use-toast.js.map +1 -1
  165. package/dist-lib/icons/index.d.ts +9 -0
  166. package/dist-lib/icons/index.js +148 -130
  167. package/dist-lib/icons/index.js.map +1 -1
  168. package/dist-lib/illustrations/index.d.ts +1 -0
  169. package/dist-lib/illustrations/index.js +15 -6
  170. package/dist-lib/illustrations/index.js.map +1 -1
  171. package/dist-lib/index.d.ts +6 -0
  172. package/dist-lib/index.js +280 -260
  173. package/dist-lib/index.js.map +1 -1
  174. package/dist-lib/lib/format.d.ts +65 -0
  175. package/dist-lib/lib/format.js +95 -0
  176. package/dist-lib/lib/format.js.map +1 -0
  177. package/dist-lib/lib/return-focus.d.ts +11 -0
  178. package/dist-lib/lib/return-focus.js +12 -0
  179. package/dist-lib/lib/return-focus.js.map +1 -0
  180. package/dist-lib/lib/strings.d.ts +62 -1
  181. package/dist-lib/lib/strings.js +75 -19
  182. package/dist-lib/lib/strings.js.map +1 -1
  183. package/dist-lib/lib/strings.mn.js +50 -5
  184. package/dist-lib/lib/strings.mn.js.map +1 -1
  185. package/dist-lib/styles.css +1 -1
  186. package/dist-lib/theme.css +141 -78
  187. package/package.json +11 -4
@@ -1,18 +1,20 @@
1
1
  "use client";
2
- import { jsxs as E, jsx as e } from "react/jsx-runtime";
3
- import { forwardRef as K, useRef as Q, useState as I } from "react";
4
- import { X as U, EyeOff as W, Eye as Y, Search as Z } from "../../icons/index.js";
5
- import { cn as a } from "../../lib/utils.js";
6
- import { useStrings as $ } from "../../hooks/use-strings.js";
7
- import { useFieldIds as ee } from "../../hooks/use-field-ids.js";
8
- import { cva as P } from "class-variance-authority";
9
- const te = P(
2
+ import { jsxs as B, jsx as e } from "react/jsx-runtime";
3
+ import { forwardRef as Y, useRef as Z, useState as P } from "react";
4
+ import { X as $, EyeOff as ee, Eye as te, Search as re } from "../../icons/index.js";
5
+ import { cn as s } from "../../lib/utils.js";
6
+ import { useStrings as ne } from "../../hooks/use-strings.js";
7
+ import { useFieldIds as se } from "../../hooks/use-field-ids.js";
8
+ import { cva as j } from "class-variance-authority";
9
+ const ie = j(
10
10
  [
11
11
  "group inline-flex items-center w-full",
12
- "rounded-md border border-input bg-card text-sm",
12
+ "rounded-md border border-border-input bg-card text-sm",
13
13
  "transition-colors duration-[var(--duration-fast)] ease-[var(--ease-out)]",
14
14
  "has-disabled:opacity-50 has-disabled:pointer-events-none",
15
- "focus-within:ring-2 focus-within:ring-offset-2 focus-within:ring-offset-background"
15
+ "focus-within:ring-2 focus-within:ring-offset-2 focus-within:ring-offset-background",
16
+ // Invalid state comes from the input's aria-invalid so Form wiring needs no extra prop.
17
+ "has-aria-invalid:border-danger has-aria-invalid:focus-within:border-danger has-aria-invalid:focus-within:ring-danger"
16
18
  ],
17
19
  {
18
20
  variants: {
@@ -31,105 +33,126 @@ const te = P(
31
33
  tone: "default"
32
34
  }
33
35
  }
34
- ), re = P([
36
+ ), oe = j([
35
37
  "flex-1 min-w-0 bg-transparent outline-none",
38
+ // Fill the field's height so the focusable target is the full control
39
+ // (32/36/40px), not the ~20px text box. Below 24px axe's target-size
40
+ // rule only passes while nothing sits close by, which is a trap for
41
+ // consumers packing a toolbar.
42
+ "self-stretch",
36
43
  "placeholder:text-foreground-subtle",
37
44
  "text-foreground",
38
45
  // 16px below md so iOS Safari does not zoom the page on focus; --text-lg = 1rem.
39
46
  "text-lg md:text-sm",
40
- "disabled:cursor-not-allowed"
41
- ]), se = K(function({
42
- className: S,
43
- type: s = "text",
44
- size: R,
45
- tone: j,
46
- label: x,
47
- helperText: d,
48
- error: c,
49
- prefix: k,
50
- suffix: v,
51
- clearable: B,
52
- onClear: l,
53
- hideLabel: O,
54
- id: F,
55
- disabled: H,
56
- value: u,
57
- defaultValue: n,
47
+ "disabled:cursor-not-allowed",
48
+ // `type="search"` draws a native clear button in WebKit/Chromium. We render
49
+ // our own via `clearable`, so suppress the native one or both show at once.
50
+ "[&::-webkit-search-cancel-button]:appearance-none",
51
+ "[&::-webkit-search-decoration]:appearance-none"
52
+ ]), S = s(
53
+ "text-foreground-subtle hover:text-foreground relative -m-1 flex size-6 shrink-0 items-center justify-center rounded-sm",
54
+ 'before:absolute before:-inset-0.5 before:content-[""]',
55
+ "focus-visible:ring-ring focus-visible:ring-offset-background outline-none focus-visible:ring-2 focus-visible:ring-offset-2",
56
+ "disabled:pointer-events-none"
57
+ ), ae = Y(function({
58
+ className: R,
59
+ type: i = "text",
60
+ size: O,
61
+ tone: F,
62
+ label: v,
63
+ helperText: l,
64
+ error: o,
65
+ prefix: H,
66
+ suffix: w,
67
+ clearable: L,
68
+ onClear: u,
69
+ hideLabel: T,
70
+ id: _,
71
+ disabled: r,
72
+ value: N,
73
+ defaultValue: a,
58
74
  onInput: f,
59
- ...L
60
- }, o) {
61
- const m = $(), p = !!c, { fieldId: w, helperId: T, errorId: _, describedBy: D } = ee(F, {
62
- hasHelper: !!d,
63
- hasError: p
64
- }), r = Q(null), M = (t) => {
65
- r.current = t, typeof o == "function" ? o(t) : o && (o.current = t);
66
- }, [i, V] = I(!1), X = s === "password" ? i ? "text" : "password" : s, q = p ? "error" : j, N = k ?? (s === "search" ? /* @__PURE__ */ e(Z, { className: "text-foreground-subtle size-4", "aria-hidden": !0 }) : null), g = u !== void 0, [A, y] = I(
67
- n == null ? "" : String(n)
68
- ), h = g ? u : A, C = h !== void 0 && h !== "" && h !== null, G = (t) => {
69
- g || y(t.currentTarget.value), f == null || f(t);
70
- }, J = () => {
71
- var t, z;
72
- if (!g && r.current) {
73
- const b = (t = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, "value")) == null ? void 0 : t.set;
74
- b == null || b.call(r.current, ""), r.current.dispatchEvent(new Event("input", { bubbles: !0 })), y("");
75
+ "aria-describedby": D,
76
+ "aria-invalid": p,
77
+ ...M
78
+ }, c) {
79
+ const h = ne(), y = !!o || p === !0 || p === "true", { fieldId: z, helperId: V, errorId: X, describedBy: q } = se(_, {
80
+ hasHelper: !!l,
81
+ hasError: !!o,
82
+ extra: D
83
+ }), m = N === null ? "" : N, n = Z(null), A = (t) => {
84
+ n.current = t, typeof c == "function" ? c(t) : c && (c.current = t);
85
+ }, [d, C] = P(!1), G = i === "password" ? d ? "text" : "password" : i, J = y ? "error" : F, k = H ?? (i === "search" ? /* @__PURE__ */ e(re, { className: "text-foreground-subtle size-4", "aria-hidden": !0 }) : null), b = m !== void 0, [K, E] = P(
86
+ a == null ? "" : String(a)
87
+ ), g = b ? m : K, Q = g !== void 0 && g !== "" && g !== null, U = (t) => {
88
+ b || E(t.currentTarget.value), f == null || f(t);
89
+ }, W = () => {
90
+ var t, I;
91
+ if (!b && n.current) {
92
+ const x = (t = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, "value")) == null ? void 0 : t.set;
93
+ x == null || x.call(n.current, ""), n.current.dispatchEvent(new Event("input", { bubbles: !0 })), E("");
75
94
  }
76
- l == null || l(), (z = r.current) == null || z.focus();
95
+ u == null || u(), (I = n.current) == null || I.focus();
77
96
  };
78
- return /* @__PURE__ */ E("div", { className: a("flex flex-col gap-1.5", S), children: [
79
- x && /* @__PURE__ */ e(
97
+ return /* @__PURE__ */ B("div", { className: s("flex flex-col gap-1.5", R), children: [
98
+ v && /* @__PURE__ */ e(
80
99
  "label",
81
100
  {
82
- htmlFor: w,
83
- className: a("text-foreground text-sm font-medium", O && "sr-only"),
84
- children: x
101
+ htmlFor: z,
102
+ className: s("text-foreground text-sm font-medium", T && "sr-only"),
103
+ children: v
85
104
  }
86
105
  ),
87
- /* @__PURE__ */ E("div", { className: a(te({ size: R, tone: q })), children: [
88
- N && /* @__PURE__ */ e("span", { className: "text-foreground-subtle flex items-center [&_svg]:size-4", children: N }),
106
+ /* @__PURE__ */ B("div", { className: s(ie({ size: O, tone: J })), children: [
107
+ k && /* @__PURE__ */ e("span", { className: "text-foreground-subtle flex items-center [&_svg]:size-4", children: k }),
89
108
  /* @__PURE__ */ e(
90
109
  "input",
91
110
  {
92
- ref: M,
93
- id: w,
94
- type: X,
95
- disabled: H,
96
- value: u,
97
- defaultValue: n,
98
- onInput: G,
99
- "aria-invalid": p || void 0,
100
- "aria-describedby": D,
101
- className: a(re()),
102
- ...L
111
+ ref: A,
112
+ id: z,
113
+ type: G,
114
+ disabled: r,
115
+ value: m,
116
+ defaultValue: a,
117
+ onInput: U,
118
+ "aria-invalid": y ? !0 : p,
119
+ "aria-describedby": q,
120
+ className: s(oe()),
121
+ ...M
103
122
  }
104
123
  ),
105
- B && C && /* @__PURE__ */ e(
124
+ L && Q && /* @__PURE__ */ e(
106
125
  "button",
107
126
  {
108
127
  type: "button",
109
- onClick: J,
110
- "aria-label": m.input.clear,
111
- className: "text-foreground-subtle hover:text-foreground focus-visible:ring-ring flex items-center rounded-sm outline-none focus-visible:ring-2",
112
- children: /* @__PURE__ */ e(U, { className: "size-4", "aria-hidden": !0 })
128
+ onClick: W,
129
+ disabled: r,
130
+ tabIndex: r ? -1 : void 0,
131
+ "aria-label": h.input.clear,
132
+ className: S,
133
+ children: /* @__PURE__ */ e($, { className: "size-4", "aria-hidden": !0 })
113
134
  }
114
135
  ),
115
- s === "password" && /* @__PURE__ */ e(
136
+ i === "password" && /* @__PURE__ */ e(
116
137
  "button",
117
138
  {
118
139
  type: "button",
119
- onClick: () => V((t) => !t),
120
- "aria-label": i ? m.input.hidePassword : m.input.showPassword,
121
- "aria-pressed": i,
122
- className: "text-foreground-subtle hover:text-foreground focus-visible:ring-ring flex items-center rounded-sm outline-none focus-visible:ring-2",
123
- children: i ? /* @__PURE__ */ e(W, { className: "size-4", "aria-hidden": !0 }) : /* @__PURE__ */ e(Y, { className: "size-4", "aria-hidden": !0 })
140
+ onClick: () => C((t) => !t),
141
+ disabled: r,
142
+ tabIndex: r ? -1 : void 0,
143
+ "aria-label": d ? h.input.hidePassword : h.input.showPassword,
144
+ "aria-pressed": d,
145
+ className: S,
146
+ children: d ? /* @__PURE__ */ e(ee, { className: "size-4", "aria-hidden": !0 }) : /* @__PURE__ */ e(te, { className: "size-4", "aria-hidden": !0 })
124
147
  }
125
148
  ),
126
- v && /* @__PURE__ */ e("span", { className: "text-foreground-subtle flex items-center [&_svg]:size-4", children: v })
149
+ w && /* @__PURE__ */ e("span", { className: "text-foreground-subtle flex items-center [&_svg]:size-4", children: w })
127
150
  ] }),
128
- c ? /* @__PURE__ */ e("p", { id: _, role: "alert", className: "text-danger-text text-xs", children: c }) : d ? /* @__PURE__ */ e("p", { id: T, className: "text-foreground-subtle text-xs", children: d }) : null
151
+ o ? /* @__PURE__ */ e("p", { id: X, className: "text-danger-text text-xs", children: o }) : l ? /* @__PURE__ */ e("p", { id: V, className: "text-foreground-subtle text-xs", children: l }) : null
129
152
  ] });
130
153
  });
131
- se.displayName = "Input";
154
+ ae.displayName = "Input";
132
155
  export {
133
- se as Input
156
+ ae as Input
134
157
  };
135
158
  //# sourceMappingURL=Input.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Input.js","sources":["../../../src/components/ui/Input.tsx"],"sourcesContent":["'use client';\n\nimport {\n forwardRef,\n useRef,\n useState,\n type FormEvent,\n type InputHTMLAttributes,\n type ReactNode,\n} from 'react';\nimport { Eye, EyeOff, Search, X } from '@/icons';\nimport { cn } from '@/lib/utils';\nimport { useStrings } from '@/hooks/use-strings';\nimport { cva, type VariantProps } from '@/lib/cva';\nimport { useFieldIds } from '@/hooks/use-field-ids';\n\n/* -----------------------------------------------------------------------------\n * Field-shell variants. The inner <input> is unstyled background and gets all\n * its visual treatment from this wrapper so prefix / suffix / clear slots\n * share the same border + focus state with no double rings.\n * --------------------------------------------------------------------------- */\nconst field = cva(\n [\n 'group inline-flex items-center w-full',\n 'rounded-md border border-input bg-card text-sm',\n 'transition-colors duration-[var(--duration-fast)] ease-[var(--ease-out)]',\n 'has-disabled:opacity-50 has-disabled:pointer-events-none',\n 'focus-within:ring-2 focus-within:ring-offset-2 focus-within:ring-offset-background',\n ],\n {\n variants: {\n size: {\n sm: 'h-8 px-2.5 gap-1.5',\n md: 'h-9 px-3 gap-2',\n lg: 'h-10 px-3.5 gap-2',\n },\n tone: {\n default: 'focus-within:border-accent focus-within:ring-ring',\n error: 'border-danger focus-within:border-danger focus-within:ring-danger',\n },\n },\n defaultVariants: {\n size: 'md',\n tone: 'default',\n },\n },\n);\n\nconst innerInput = cva([\n 'flex-1 min-w-0 bg-transparent outline-none',\n 'placeholder:text-foreground-subtle',\n 'text-foreground',\n // 16px below md so iOS Safari does not zoom the page on focus; --text-lg = 1rem.\n 'text-lg md:text-sm',\n 'disabled:cursor-not-allowed',\n]);\n\ntype InputType = NonNullable<InputHTMLAttributes<HTMLInputElement>['type']>;\n\nexport interface InputProps\n extends\n Omit<InputHTMLAttributes<HTMLInputElement>, 'size' | 'prefix'>,\n VariantProps<typeof field> {\n /** Field type. `password` enables a show/hide toggle; `search` adds a clear button. */\n type?: InputType;\n /** Visible label rendered above the input. */\n label?: ReactNode;\n /** Hint below the input. Hidden while `error` is set. */\n helperText?: ReactNode;\n /** Validation message. Renders in `danger` colour and sets `aria-invalid`. */\n error?: ReactNode;\n /** Content rendered inside the field, before the input — icon or short text. */\n prefix?: ReactNode;\n /** Content rendered inside the field, after the input. */\n suffix?: ReactNode;\n /** Show an inline clear (×) button when the input has a value. */\n clearable?: boolean;\n /**\n * Fires when the clear button is pressed. Controlled inputs own their state\n * and should reset `value` here; uncontrolled inputs are cleared for you.\n */\n onClear?: () => void;\n /** Visually conceal the label while keeping it for screen readers. */\n hideLabel?: boolean;\n}\n\n/**\n * Text-style input with optional label, helper / error, prefix / suffix,\n * clear, and password show-hide. Wraps a single native `<input>` so it works\n * with `react-hook-form` and any controlled / uncontrolled pattern.\n *\n * @example Email with helper\n * <Input type=\"email\" label=\"Work email\" helperText=\"We never share this.\" />\n *\n * @example Password with show/hide\n * <Input type=\"password\" label=\"Password\" autoComplete=\"current-password\" />\n *\n * @example Search with clear\n * <Input type=\"search\" placeholder=\"Search…\" value={q} onChange={…}\n * clearable onClear={() => setQ('')} />\n *\n * @do Always pair an input with a visible label. If space forces hiding it,\n * use `hideLabel` so the label stays in the accessibility tree.\n * @dont Use placeholder as the only label — placeholders disappear on input\n * and fail accessibility.\n */\nexport const Input = forwardRef<HTMLInputElement, InputProps>(function Input(\n {\n className,\n type = 'text',\n size,\n tone,\n label,\n helperText,\n error,\n prefix,\n suffix,\n clearable,\n onClear,\n hideLabel,\n id,\n disabled,\n value,\n defaultValue,\n onInput,\n ...props\n },\n ref,\n) {\n const strings = useStrings();\n const isError = Boolean(error);\n const { fieldId, helperId, errorId, describedBy } = useFieldIds(id, {\n hasHelper: Boolean(helperText),\n hasError: isError,\n });\n const innerRef = useRef<HTMLInputElement | null>(null);\n const setRefs = (el: HTMLInputElement | null) => {\n innerRef.current = el;\n if (typeof ref === 'function') ref(el);\n else if (ref) ref.current = el;\n };\n\n const [showPassword, setShowPassword] = useState(false);\n const effectiveType = type === 'password' ? (showPassword ? 'text' : 'password') : type;\n\n const effectiveTone = isError ? 'error' : tone;\n\n // Pre-fill prefix slot for search type.\n const renderedPrefix =\n prefix ??\n (type === 'search' ? <Search className=\"text-foreground-subtle size-4\" aria-hidden /> : null);\n\n // Track the value of uncontrolled inputs so `clearable` can show/hide the\n // button without the consumer wiring state.\n const isControlled = value !== undefined;\n const [localValue, setLocalValue] = useState<string>(\n defaultValue === undefined || defaultValue === null ? '' : String(defaultValue),\n );\n const current = isControlled ? value : localValue;\n const hasValue = current !== undefined && current !== '' && current !== null;\n\n const handleInput = (e: FormEvent<HTMLInputElement>) => {\n if (!isControlled) setLocalValue(e.currentTarget.value);\n onInput?.(e);\n };\n\n const handleClear = () => {\n if (!isControlled && innerRef.current) {\n // Use the native setter so React's onChange/onInput listeners fire.\n const setter = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, 'value')?.set;\n setter?.call(innerRef.current, '');\n innerRef.current.dispatchEvent(new Event('input', { bubbles: true }));\n setLocalValue('');\n }\n onClear?.();\n innerRef.current?.focus();\n };\n\n return (\n <div className={cn('flex flex-col gap-1.5', className)}>\n {label && (\n <label\n htmlFor={fieldId}\n className={cn('text-foreground text-sm font-medium', hideLabel && 'sr-only')}\n >\n {label}\n </label>\n )}\n\n <div className={cn(field({ size, tone: effectiveTone }))}>\n {renderedPrefix && (\n <span className=\"text-foreground-subtle flex items-center [&_svg]:size-4\">\n {renderedPrefix}\n </span>\n )}\n\n <input\n ref={setRefs}\n id={fieldId}\n type={effectiveType}\n disabled={disabled}\n value={value}\n defaultValue={defaultValue}\n onInput={handleInput}\n aria-invalid={isError || undefined}\n aria-describedby={describedBy}\n className={cn(innerInput())}\n {...props}\n />\n\n {clearable && hasValue && (\n <button\n type=\"button\"\n onClick={handleClear}\n aria-label={strings.input.clear}\n className=\"text-foreground-subtle hover:text-foreground focus-visible:ring-ring flex items-center rounded-sm outline-none focus-visible:ring-2\"\n >\n <X className=\"size-4\" aria-hidden />\n </button>\n )}\n\n {type === 'password' && (\n <button\n type=\"button\"\n onClick={() => setShowPassword((p) => !p)}\n aria-label={showPassword ? strings.input.hidePassword : strings.input.showPassword}\n aria-pressed={showPassword}\n className=\"text-foreground-subtle hover:text-foreground focus-visible:ring-ring flex items-center rounded-sm outline-none focus-visible:ring-2\"\n >\n {showPassword ? (\n <EyeOff className=\"size-4\" aria-hidden />\n ) : (\n <Eye className=\"size-4\" aria-hidden />\n )}\n </button>\n )}\n\n {suffix && (\n <span className=\"text-foreground-subtle flex items-center [&_svg]:size-4\">{suffix}</span>\n )}\n </div>\n\n {error ? (\n <p id={errorId} role=\"alert\" className=\"text-danger-text text-xs\">\n {error}\n </p>\n ) : helperText ? (\n <p id={helperId} className=\"text-foreground-subtle text-xs\">\n {helperText}\n </p>\n ) : null}\n </div>\n );\n});\n\nInput.displayName = 'Input';\n"],"names":["field","cva","innerInput","Input","forwardRef","className","type","size","tone","label","helperText","error","prefix","suffix","clearable","onClear","hideLabel","id","disabled","value","defaultValue","onInput","props","ref","strings","useStrings","isError","fieldId","helperId","errorId","describedBy","useFieldIds","innerRef","useRef","setRefs","el","showPassword","setShowPassword","useState","effectiveType","effectiveTone","renderedPrefix","jsx","Search","isControlled","localValue","setLocalValue","current","hasValue","handleInput","e","handleClear","setter","_a","_b","cn","jsxs","X","p","EyeOff","Eye"],"mappings":"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"}
1
+ {"version":3,"file":"Input.js","sources":["../../../src/components/ui/Input.tsx"],"sourcesContent":["'use client';\n\nimport {\n forwardRef,\n useRef,\n useState,\n type ComponentProps,\n type InputHTMLAttributes,\n type ReactNode,\n} from 'react';\nimport { Eye, EyeOff, Search, X } from '@/icons';\nimport { cn } from '@/lib/utils';\nimport { useStrings } from '@/hooks/use-strings';\nimport { cva, type VariantProps } from '@/lib/cva';\nimport { useFieldIds } from '@/hooks/use-field-ids';\n\n/* -----------------------------------------------------------------------------\n * Field-shell variants. The inner <input> is unstyled background and gets all\n * its visual treatment from this wrapper so prefix / suffix / clear slots\n * share the same border + focus state with no double rings.\n * --------------------------------------------------------------------------- */\nconst field = cva(\n [\n 'group inline-flex items-center w-full',\n 'rounded-md border border-border-input bg-card text-sm',\n 'transition-colors duration-[var(--duration-fast)] ease-[var(--ease-out)]',\n 'has-disabled:opacity-50 has-disabled:pointer-events-none',\n 'focus-within:ring-2 focus-within:ring-offset-2 focus-within:ring-offset-background',\n // Invalid state comes from the input's aria-invalid so Form wiring needs no extra prop.\n 'has-aria-invalid:border-danger has-aria-invalid:focus-within:border-danger has-aria-invalid:focus-within:ring-danger',\n ],\n {\n variants: {\n size: {\n sm: 'h-8 px-2.5 gap-1.5',\n md: 'h-9 px-3 gap-2',\n lg: 'h-10 px-3.5 gap-2',\n },\n tone: {\n default: 'focus-within:border-accent focus-within:ring-ring',\n error: 'border-danger focus-within:border-danger focus-within:ring-danger',\n },\n },\n defaultVariants: {\n size: 'md',\n tone: 'default',\n },\n },\n);\n\nconst innerInput = cva([\n 'flex-1 min-w-0 bg-transparent outline-none',\n // Fill the field's height so the focusable target is the full control\n // (32/36/40px), not the ~20px text box. Below 24px axe's target-size\n // rule only passes while nothing sits close by, which is a trap for\n // consumers packing a toolbar.\n 'self-stretch',\n 'placeholder:text-foreground-subtle',\n 'text-foreground',\n // 16px below md so iOS Safari does not zoom the page on focus; --text-lg = 1rem.\n 'text-lg md:text-sm',\n 'disabled:cursor-not-allowed',\n // `type=\"search\"` draws a native clear button in WebKit/Chromium. We render\n // our own via `clearable`, so suppress the native one or both show at once.\n '[&::-webkit-search-cancel-button]:appearance-none',\n '[&::-webkit-search-decoration]:appearance-none',\n]);\n\ntype InputType = NonNullable<InputHTMLAttributes<HTMLInputElement>['type']>;\n\n// Inline clear / password buttons: 24px box (WCAG 2.5.8 minimum) with a halo\n// that extends the hit area without growing the field.\nconst innerButton = cn(\n 'text-foreground-subtle hover:text-foreground relative -m-1 flex size-6 shrink-0 items-center justify-center rounded-sm',\n 'before:absolute before:-inset-0.5 before:content-[\"\"]',\n 'focus-visible:ring-ring focus-visible:ring-offset-background outline-none focus-visible:ring-2 focus-visible:ring-offset-2',\n 'disabled:pointer-events-none',\n);\n\nexport interface InputProps\n extends\n Omit<InputHTMLAttributes<HTMLInputElement>, 'size' | 'prefix' | 'value'>,\n VariantProps<typeof field> {\n /** Controlled value. `null` is treated as an empty controlled value (no React warning). */\n value?: InputHTMLAttributes<HTMLInputElement>['value'] | null;\n /** Field type. `password` enables a show/hide toggle; `search` adds a clear button. */\n type?: InputType;\n /** Visible label rendered above the input. */\n label?: ReactNode;\n /** Hint below the input. Hidden while `error` is set. */\n helperText?: ReactNode;\n /** Validation message. Renders in `danger` colour and sets `aria-invalid`. */\n error?: ReactNode;\n /** Content rendered inside the field, before the input — icon or short text. */\n prefix?: ReactNode;\n /** Content rendered inside the field, after the input. */\n suffix?: ReactNode;\n /** Show an inline clear (×) button when the input has a value. */\n clearable?: boolean;\n /**\n * Fires when the clear button is pressed. Controlled inputs own their state\n * and should reset `value` here; uncontrolled inputs are cleared for you.\n */\n onClear?: () => void;\n /** Visually conceal the label while keeping it for screen readers. */\n hideLabel?: boolean;\n}\n\n/**\n * Text-style input with optional label, helper / error, prefix / suffix,\n * clear, and password show-hide. Wraps a single native `<input>` so it works\n * with `react-hook-form` and any controlled / uncontrolled pattern.\n *\n * @example Email with helper\n * <Input type=\"email\" label=\"Work email\" helperText=\"We never share this.\" />\n *\n * @example Password with show/hide\n * <Input type=\"password\" label=\"Password\" autoComplete=\"current-password\" />\n *\n * @example Search with clear\n * <Input type=\"search\" placeholder=\"Search…\" value={q} onChange={…}\n * clearable onClear={() => setQ('')} />\n *\n * @do Always pair an input with a visible label. If space forces hiding it,\n * use `hideLabel` so the label stays in the accessibility tree.\n * @dont Use placeholder as the only label — placeholders disappear on input\n * and fail accessibility.\n */\nexport const Input = forwardRef<HTMLInputElement, InputProps>(function Input(\n {\n className,\n type = 'text',\n size,\n tone,\n label,\n helperText,\n error,\n prefix,\n suffix,\n clearable,\n onClear,\n hideLabel,\n id,\n disabled,\n value: valueProp,\n defaultValue,\n onInput,\n 'aria-describedby': ariaDescribedby,\n 'aria-invalid': ariaInvalid,\n ...props\n },\n ref,\n) {\n const strings = useStrings();\n const isError = Boolean(error) || ariaInvalid === true || ariaInvalid === 'true';\n const { fieldId, helperId, errorId, describedBy } = useFieldIds(id, {\n hasHelper: Boolean(helperText),\n hasError: Boolean(error),\n extra: ariaDescribedby,\n });\n // `null` (nullable form state) is a controlled empty value, not \"uncontrolled\".\n const value = valueProp === null ? '' : valueProp;\n const innerRef = useRef<HTMLInputElement | null>(null);\n const setRefs = (el: HTMLInputElement | null) => {\n innerRef.current = el;\n if (typeof ref === 'function') ref(el);\n else if (ref) ref.current = el;\n };\n\n const [showPassword, setShowPassword] = useState(false);\n const effectiveType = type === 'password' ? (showPassword ? 'text' : 'password') : type;\n\n const effectiveTone = isError ? 'error' : tone;\n\n // Pre-fill prefix slot for search type.\n const renderedPrefix =\n prefix ??\n (type === 'search' ? <Search className=\"text-foreground-subtle size-4\" aria-hidden /> : null);\n\n // Track the value of uncontrolled inputs so `clearable` can show/hide the\n // button without the consumer wiring state.\n const isControlled = value !== undefined;\n const [localValue, setLocalValue] = useState<string>(\n defaultValue === undefined || defaultValue === null ? '' : String(defaultValue),\n );\n const current = isControlled ? value : localValue;\n const hasValue = current !== undefined && current !== '' && current !== null;\n\n // React 19 types `onInput` as `InputEventHandler`; `ComponentProps` keeps this portable.\n const handleInput: NonNullable<ComponentProps<'input'>['onInput']> = (e) => {\n if (!isControlled) setLocalValue(e.currentTarget.value);\n onInput?.(e);\n };\n\n const handleClear = () => {\n if (!isControlled && innerRef.current) {\n // Use the native setter so React's onChange/onInput listeners fire.\n const setter = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, 'value')?.set;\n setter?.call(innerRef.current, '');\n innerRef.current.dispatchEvent(new Event('input', { bubbles: true }));\n setLocalValue('');\n }\n onClear?.();\n innerRef.current?.focus();\n };\n\n return (\n <div className={cn('flex flex-col gap-1.5', className)}>\n {label && (\n <label\n htmlFor={fieldId}\n className={cn('text-foreground text-sm font-medium', hideLabel && 'sr-only')}\n >\n {label}\n </label>\n )}\n\n <div className={cn(field({ size, tone: effectiveTone }))}>\n {renderedPrefix && (\n <span className=\"text-foreground-subtle flex items-center [&_svg]:size-4\">\n {renderedPrefix}\n </span>\n )}\n\n <input\n ref={setRefs}\n id={fieldId}\n type={effectiveType}\n disabled={disabled}\n value={value}\n defaultValue={defaultValue}\n onInput={handleInput}\n aria-invalid={isError ? true : ariaInvalid}\n aria-describedby={describedBy}\n className={cn(innerInput())}\n {...props}\n />\n\n {clearable && hasValue && (\n <button\n type=\"button\"\n onClick={handleClear}\n disabled={disabled}\n tabIndex={disabled ? -1 : undefined}\n aria-label={strings.input.clear}\n className={innerButton}\n >\n <X className=\"size-4\" aria-hidden />\n </button>\n )}\n\n {type === 'password' && (\n <button\n type=\"button\"\n onClick={() => setShowPassword((p) => !p)}\n disabled={disabled}\n tabIndex={disabled ? -1 : undefined}\n aria-label={showPassword ? strings.input.hidePassword : strings.input.showPassword}\n aria-pressed={showPassword}\n className={innerButton}\n >\n {showPassword ? (\n <EyeOff className=\"size-4\" aria-hidden />\n ) : (\n <Eye className=\"size-4\" aria-hidden />\n )}\n </button>\n )}\n\n {suffix && (\n <span className=\"text-foreground-subtle flex items-center [&_svg]:size-4\">{suffix}</span>\n )}\n </div>\n\n {error ? (\n <p id={errorId} className=\"text-danger-text text-xs\">\n {error}\n </p>\n ) : helperText ? (\n <p id={helperId} className=\"text-foreground-subtle text-xs\">\n {helperText}\n </p>\n ) : null}\n </div>\n );\n});\n\nInput.displayName = 'Input';\n"],"names":["field","cva","innerInput","innerButton","cn","Input","forwardRef","className","type","size","tone","label","helperText","error","prefix","suffix","clearable","onClear","hideLabel","id","disabled","valueProp","defaultValue","onInput","ariaDescribedby","ariaInvalid","props","ref","strings","useStrings","isError","fieldId","helperId","errorId","describedBy","useFieldIds","value","innerRef","useRef","setRefs","el","showPassword","setShowPassword","useState","effectiveType","effectiveTone","renderedPrefix","jsx","Search","isControlled","localValue","setLocalValue","current","hasValue","handleInput","e","handleClear","setter","_a","_b","jsxs","X","p","EyeOff","Eye"],"mappings":"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"}
@@ -8,7 +8,7 @@ const d = m(function({ size: e = "sm", className: r, ...o }, t) {
8
8
  {
9
9
  ref: t,
10
10
  className: s(
11
- "inline-flex items-center justify-center rounded-sm border border-border bg-background-subtle font-mono",
11
+ "border-border bg-background-subtle inline-flex items-center justify-center rounded-sm border font-mono",
12
12
  "text-foreground-muted shadow-xs",
13
13
  e === "sm" ? "h-5 min-w-5 px-1 text-xs" : "h-6 min-w-6 px-1.5 text-xs",
14
14
  r
@@ -1 +1 @@
1
- {"version":3,"file":"Kbd.js","sources":["../../../src/components/ui/Kbd.tsx"],"sourcesContent":["'use client';\n\nimport { forwardRef, type HTMLAttributes } from 'react';\nimport { cn } from '@/lib/utils';\n\nexport interface KbdProps extends HTMLAttributes<HTMLElement> {\n /** Visual size — match the surrounding text. */\n size?: 'sm' | 'md';\n}\n\n/**\n * Stylised keyboard shortcut indicator. Compose multiple `<Kbd>` for chords.\n *\n * @example\n * Press <Kbd>⌘</Kbd>+<Kbd>K</Kbd> to open the command palette.\n *\n * @do Use OS-conventional symbols (⌘ ⇧ ⌥ ⌃ ⏎) — keep visuals consistent\n * across the app.\n * @dont Use Kbd for clickable buttons — it implies a real keyboard input.\n */\nexport const Kbd = forwardRef<HTMLElement, KbdProps>(function Kbd(\n { size = 'sm', className, ...props },\n ref,\n) {\n return (\n <kbd\n ref={ref}\n className={cn(\n 'inline-flex items-center justify-center rounded-sm border border-border bg-background-subtle font-mono',\n 'text-foreground-muted shadow-xs',\n size === 'sm' ? 'h-5 min-w-5 px-1 text-xs' : 'h-6 min-w-6 px-1.5 text-xs',\n className,\n )}\n {...props}\n />\n );\n});\nKbd.displayName = 'Kbd';\n"],"names":["Kbd","forwardRef","size","className","props","ref","jsx","cn"],"mappings":";;;;AAoBO,MAAMA,IAAMC,EAAkC,SACnD,EAAE,MAAAC,IAAO,MAAM,WAAAC,GAAW,GAAGC,EAAA,GAC7BC,GACA;AACA,SACE,gBAAAC;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,KAAAD;AAAA,MACA,WAAWE;AAAA,QACT;AAAA,QACA;AAAA,QACAL,MAAS,OAAO,6BAA6B;AAAA,QAC7CC;AAAA,MAAA;AAAA,MAED,GAAGC;AAAA,IAAA;AAAA,EAAA;AAGV,CAAC;AACDJ,EAAI,cAAc;"}
1
+ {"version":3,"file":"Kbd.js","sources":["../../../src/components/ui/Kbd.tsx"],"sourcesContent":["'use client';\n\nimport { forwardRef, type HTMLAttributes } from 'react';\nimport { cn } from '@/lib/utils';\n\nexport interface KbdProps extends HTMLAttributes<HTMLElement> {\n /** Visual size — match the surrounding text. */\n size?: 'sm' | 'md';\n}\n\n/**\n * Stylised keyboard shortcut indicator. Compose multiple `<Kbd>` for chords.\n *\n * @example\n * Press <Kbd>⌘</Kbd>+<Kbd>K</Kbd> to open the command palette.\n *\n * @do Use OS-conventional symbols (⌘ ⇧ ⌥ ⌃ ⏎) — keep visuals consistent\n * across the app.\n * @dont Use Kbd for clickable buttons — it implies a real keyboard input.\n */\nexport const Kbd = forwardRef<HTMLElement, KbdProps>(function Kbd(\n { size = 'sm', className, ...props },\n ref,\n) {\n return (\n <kbd\n ref={ref}\n className={cn(\n 'border-border bg-background-subtle inline-flex items-center justify-center rounded-sm border font-mono',\n 'text-foreground-muted shadow-xs',\n size === 'sm' ? 'h-5 min-w-5 px-1 text-xs' : 'h-6 min-w-6 px-1.5 text-xs',\n className,\n )}\n {...props}\n />\n );\n});\nKbd.displayName = 'Kbd';\n"],"names":["Kbd","forwardRef","size","className","props","ref","jsx","cn"],"mappings":";;;;AAoBO,MAAMA,IAAMC,EAAkC,SACnD,EAAE,MAAAC,IAAO,MAAM,WAAAC,GAAW,GAAGC,EAAA,GAC7BC,GACA;AACA,SACE,gBAAAC;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,KAAAD;AAAA,MACA,WAAWE;AAAA,QACT;AAAA,QACA;AAAA,QACAL,MAAS,OAAO,6BAA6B;AAAA,QAC7CC;AAAA,MAAA;AAAA,MAED,GAAGC;AAAA,IAAA;AAAA,EAAA;AAGV,CAAC;AACDJ,EAAI,cAAc;"}