@dowel-ui/react 0.5.0 → 0.7.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 (218) hide show
  1. package/README.md +1 -1
  2. package/dist/blocks/admin-dashboard/meta.js +31 -0
  3. package/dist/blocks/admin-dashboard/meta.js.map +1 -0
  4. package/dist/blocks/agent-console/meta.js +27 -0
  5. package/dist/blocks/agent-console/meta.js.map +1 -0
  6. package/dist/blocks/ai-dashboard/meta.js +25 -0
  7. package/dist/blocks/ai-dashboard/meta.js.map +1 -0
  8. package/dist/blocks/ai-workspace/meta.js +33 -0
  9. package/dist/blocks/ai-workspace/meta.js.map +1 -0
  10. package/dist/blocks/analytics/meta.js +24 -0
  11. package/dist/blocks/analytics/meta.js.map +1 -0
  12. package/dist/blocks/billing/meta.js +25 -0
  13. package/dist/blocks/billing/meta.js.map +1 -0
  14. package/dist/blocks/command-center/meta.js +28 -0
  15. package/dist/blocks/command-center/meta.js.map +1 -0
  16. package/dist/blocks/crm/meta.js +32 -0
  17. package/dist/blocks/crm/meta.js.map +1 -0
  18. package/dist/blocks/onboarding/meta.js +23 -0
  19. package/dist/blocks/onboarding/meta.js.map +1 -0
  20. package/dist/components/accordion/accordion.js +1 -1
  21. package/dist/components/accordion/accordion.js.map +1 -1
  22. package/dist/components/activity-feed/activity-feed.js +1 -1
  23. package/dist/components/activity-feed/activity-feed.js.map +1 -1
  24. package/dist/components/ai-agent-plan/ai-agent-plan.js +1 -1
  25. package/dist/components/ai-agent-plan/ai-agent-plan.js.map +1 -1
  26. package/dist/components/ai-extraction-review/ai-extraction-review.js +1 -1
  27. package/dist/components/ai-extraction-review/ai-extraction-review.js.map +1 -1
  28. package/dist/components/ai-prompt-input/ai-prompt-input.js +1 -1
  29. package/dist/components/ai-prompt-input/ai-prompt-input.js.map +1 -1
  30. package/dist/components/ai-reasoning/ai-reasoning.js +1 -1
  31. package/dist/components/ai-reasoning/ai-reasoning.js.map +1 -1
  32. package/dist/components/ai-response/ai-response.js +2 -2
  33. package/dist/components/ai-response/ai-response.js.map +1 -1
  34. package/dist/components/ai-tool/ai-tool.js +2 -2
  35. package/dist/components/ai-tool/ai-tool.js.map +1 -1
  36. package/dist/components/alert/alert.d.ts +1 -1
  37. package/dist/components/avatar/avatar.d.ts +1 -1
  38. package/dist/components/badge/badge.d.ts +1 -1
  39. package/dist/components/breadcrumb/breadcrumb.d.ts +52 -0
  40. package/dist/components/breadcrumb/breadcrumb.d.ts.map +1 -0
  41. package/dist/components/breadcrumb/breadcrumb.js +141 -0
  42. package/dist/components/breadcrumb/breadcrumb.js.map +1 -0
  43. package/dist/components/breadcrumb/index.d.ts +2 -0
  44. package/dist/components/breadcrumb/index.js +2 -0
  45. package/dist/components/breadcrumb/meta.js +17 -0
  46. package/dist/components/breadcrumb/meta.js.map +1 -0
  47. package/dist/components/button/button.d.ts +1 -1
  48. package/dist/components/calendar/calendar.js +2 -2
  49. package/dist/components/calendar/calendar.js.map +1 -1
  50. package/dist/components/code-block/code-block.js +1 -1
  51. package/dist/components/code-block/code-block.js.map +1 -1
  52. package/dist/components/collapsible/collapsible.d.ts +30 -0
  53. package/dist/components/collapsible/collapsible.d.ts.map +1 -0
  54. package/dist/components/collapsible/collapsible.js +38 -0
  55. package/dist/components/collapsible/collapsible.js.map +1 -0
  56. package/dist/components/collapsible/index.d.ts +2 -0
  57. package/dist/components/collapsible/index.js +2 -0
  58. package/dist/components/collapsible/meta.js +17 -0
  59. package/dist/components/collapsible/meta.js.map +1 -0
  60. package/dist/components/combobox/combobox.js +2 -2
  61. package/dist/components/combobox/combobox.js.map +1 -1
  62. package/dist/components/command/command.js +1 -1
  63. package/dist/components/command/command.js.map +1 -1
  64. package/dist/components/data-table/data-table.d.ts.map +1 -1
  65. package/dist/components/data-table/data-table.js +4 -1
  66. package/dist/components/data-table/data-table.js.map +1 -1
  67. package/dist/components/dialog/dialog.js +2 -2
  68. package/dist/components/dialog/dialog.js.map +1 -1
  69. package/dist/components/diff-viewer/diff-viewer.js +4 -4
  70. package/dist/components/diff-viewer/diff-viewer.js.map +1 -1
  71. package/dist/components/direction/direction.d.ts +35 -0
  72. package/dist/components/direction/direction.d.ts.map +1 -0
  73. package/dist/components/direction/direction.js +14 -0
  74. package/dist/components/direction/direction.js.map +1 -0
  75. package/dist/components/direction/index.d.ts +2 -0
  76. package/dist/components/direction/index.js +2 -0
  77. package/dist/components/direction/meta.js +17 -0
  78. package/dist/components/direction/meta.js.map +1 -0
  79. package/dist/components/drawer/drawer.js +1 -1
  80. package/dist/components/drawer/drawer.js.map +1 -1
  81. package/dist/components/dropdown-menu/dropdown-menu.d.ts.map +1 -1
  82. package/dist/components/dropdown-menu/dropdown-menu.js +9 -8
  83. package/dist/components/dropdown-menu/dropdown-menu.js.map +1 -1
  84. package/dist/components/input/input.js +1 -1
  85. package/dist/components/input/input.js.map +1 -1
  86. package/dist/components/log-viewer/log-viewer.js +2 -2
  87. package/dist/components/log-viewer/log-viewer.js.map +1 -1
  88. package/dist/components/meter/meter.js +1 -1
  89. package/dist/components/meter/meter.js.map +1 -1
  90. package/dist/components/pagination/pagination.d.ts.map +1 -1
  91. package/dist/components/pagination/pagination.js +3 -2
  92. package/dist/components/pagination/pagination.js.map +1 -1
  93. package/dist/components/permission-matrix/permission-matrix.js +3 -3
  94. package/dist/components/permission-matrix/permission-matrix.js.map +1 -1
  95. package/dist/components/progress/progress.d.ts +1 -1
  96. package/dist/components/record-diff/record-diff.js +4 -4
  97. package/dist/components/record-diff/record-diff.js.map +1 -1
  98. package/dist/components/select/select.js +2 -2
  99. package/dist/components/select/select.js.map +1 -1
  100. package/dist/components/sheet/sheet.d.ts.map +1 -1
  101. package/dist/components/sheet/sheet.js +2 -2
  102. package/dist/components/sheet/sheet.js.map +1 -1
  103. package/dist/components/sidebar/index.d.ts +2 -0
  104. package/dist/components/sidebar/index.js +2 -0
  105. package/dist/components/sidebar/meta.js +17 -0
  106. package/dist/components/sidebar/meta.js.map +1 -0
  107. package/dist/components/sidebar/sidebar.d.ts +69 -0
  108. package/dist/components/sidebar/sidebar.d.ts.map +1 -0
  109. package/dist/components/sidebar/sidebar.js +256 -0
  110. package/dist/components/sidebar/sidebar.js.map +1 -0
  111. package/dist/components/spinner/spinner.d.ts +1 -1
  112. package/dist/components/table/table.js +2 -2
  113. package/dist/components/table/table.js.map +1 -1
  114. package/dist/components/tags-input/tags-input.js +1 -1
  115. package/dist/components/tags-input/tags-input.js.map +1 -1
  116. package/dist/components/textarea/index.d.ts +2 -0
  117. package/dist/components/textarea/index.js +2 -0
  118. package/dist/components/textarea/meta.js +17 -0
  119. package/dist/components/textarea/meta.js.map +1 -0
  120. package/dist/components/textarea/textarea.d.ts +43 -0
  121. package/dist/components/textarea/textarea.d.ts.map +1 -0
  122. package/dist/components/textarea/textarea.js +119 -0
  123. package/dist/components/textarea/textarea.js.map +1 -0
  124. package/dist/components/time-range-picker/time-range-picker.js +3 -3
  125. package/dist/components/time-range-picker/time-range-picker.js.map +1 -1
  126. package/dist/components/toast/toast.d.ts +1 -1
  127. package/dist/components/toast/toast.d.ts.map +1 -1
  128. package/dist/components/toast/toast.js +2 -2
  129. package/dist/components/toast/toast.js.map +1 -1
  130. package/dist/index.d.ts +12 -2
  131. package/dist/index.js +7 -2
  132. package/dist/lib/styles.d.ts +16 -1
  133. package/dist/lib/styles.d.ts.map +1 -1
  134. package/dist/lib/styles.js +16 -1
  135. package/dist/lib/styles.js.map +1 -1
  136. package/dist/registry/blocks.d.ts.map +1 -1
  137. package/dist/registry/blocks.js +27 -9
  138. package/dist/registry/blocks.js.map +1 -1
  139. package/dist/registry/components.d.ts.map +1 -1
  140. package/dist/registry/components.js +60 -50
  141. package/dist/registry/components.js.map +1 -1
  142. package/dist/registry/schema.d.ts +8 -0
  143. package/dist/registry/schema.d.ts.map +1 -1
  144. package/dist/registry/schema.js.map +1 -1
  145. package/package.json +5 -4
  146. package/src/components/accordion/accordion.tsx +1 -1
  147. package/src/components/activity-feed/activity-feed.tsx +1 -1
  148. package/src/components/ai-agent-plan/ai-agent-plan.tsx +0 -0
  149. package/src/components/ai-extraction-review/ai-extraction-review.tsx +1 -1
  150. package/src/components/ai-prompt-input/ai-prompt-input.tsx +1 -1
  151. package/src/components/ai-reasoning/ai-reasoning.tsx +1 -1
  152. package/src/components/ai-response/ai-response.tsx +2 -2
  153. package/src/components/ai-tool/ai-tool.tsx +2 -2
  154. package/src/components/breadcrumb/breadcrumb.tsx +157 -0
  155. package/src/components/breadcrumb/index.ts +10 -0
  156. package/src/components/breadcrumb/meta.ts +19 -0
  157. package/src/components/calendar/calendar.tsx +2 -2
  158. package/src/components/code-block/code-block.tsx +1 -1
  159. package/src/components/collapsible/collapsible.tsx +63 -0
  160. package/src/components/collapsible/index.ts +6 -0
  161. package/src/components/collapsible/meta.ts +16 -0
  162. package/src/components/combobox/combobox.tsx +2 -2
  163. package/src/components/command/command.tsx +1 -1
  164. package/src/components/data-table/data-table.tsx +14 -3
  165. package/src/components/dialog/dialog.tsx +2 -2
  166. package/src/components/diff-viewer/diff-viewer.tsx +4 -4
  167. package/src/components/direction/direction.tsx +38 -0
  168. package/src/components/direction/index.ts +1 -0
  169. package/src/components/direction/meta.ts +19 -0
  170. package/src/components/drawer/drawer.tsx +1 -1
  171. package/src/components/dropdown-menu/dropdown-menu.tsx +14 -8
  172. package/src/components/input/input.tsx +1 -1
  173. package/src/components/log-viewer/log-viewer.tsx +2 -2
  174. package/src/components/meter/meter.tsx +1 -1
  175. package/src/components/pagination/pagination.tsx +13 -2
  176. package/src/components/permission-matrix/permission-matrix.tsx +4 -4
  177. package/src/components/record-diff/record-diff.tsx +4 -4
  178. package/src/components/select/select.tsx +2 -2
  179. package/src/components/sheet/sheet.tsx +8 -4
  180. package/src/components/sidebar/index.ts +19 -0
  181. package/src/components/sidebar/meta.ts +25 -0
  182. package/src/components/sidebar/sidebar.tsx +374 -0
  183. package/src/components/table/table.tsx +3 -3
  184. package/src/components/tags-input/tags-input.tsx +1 -1
  185. package/src/components/textarea/index.ts +1 -0
  186. package/src/components/textarea/meta.ts +21 -0
  187. package/src/components/textarea/textarea.tsx +210 -0
  188. package/src/components/time-range-picker/time-range-picker.tsx +3 -3
  189. package/src/components/toast/toast.tsx +14 -6
  190. package/src/index.ts +5 -0
  191. package/src/lib/styles.ts +16 -0
  192. package/src/registry/blocks.ts +18 -0
  193. package/src/registry/components.ts +10 -0
  194. package/src/registry/schema.ts +8 -0
  195. package/src/blocks/admin-users/admin-users.tsx +0 -251
  196. package/src/blocks/admin-users/index.ts +0 -1
  197. package/src/blocks/admin-users/meta.ts +0 -27
  198. package/src/blocks/ai-chat/ai-chat.tsx +0 -280
  199. package/src/blocks/ai-chat/index.ts +0 -7
  200. package/src/blocks/ai-chat/meta.ts +0 -32
  201. package/src/blocks/dashboard/dashboard.tsx +0 -192
  202. package/src/blocks/dashboard/index.ts +0 -6
  203. package/src/blocks/dashboard/meta.ts +0 -18
  204. package/src/blocks/forgot-password/forgot-password.tsx +0 -158
  205. package/src/blocks/forgot-password/index.ts +0 -1
  206. package/src/blocks/forgot-password/meta.ts +0 -18
  207. package/src/blocks/login/index.ts +0 -1
  208. package/src/blocks/login/login.tsx +0 -178
  209. package/src/blocks/login/meta.ts +0 -18
  210. package/src/blocks/pricing/index.ts +0 -1
  211. package/src/blocks/pricing/meta.ts +0 -18
  212. package/src/blocks/pricing/pricing.tsx +0 -176
  213. package/src/blocks/settings/index.ts +0 -6
  214. package/src/blocks/settings/meta.ts +0 -29
  215. package/src/blocks/settings/settings.tsx +0 -317
  216. package/src/blocks/signup/index.ts +0 -1
  217. package/src/blocks/signup/meta.ts +0 -18
  218. package/src/blocks/signup/signup.tsx +0 -240
@@ -0,0 +1,210 @@
1
+ "use client";
2
+
3
+ import { cva, type VariantProps } from "class-variance-authority";
4
+ import {
5
+ useId,
6
+ useLayoutEffect,
7
+ useRef,
8
+ useState,
9
+ type ChangeEvent,
10
+ type ComponentPropsWithRef,
11
+ } from "react";
12
+
13
+ import { focusRingInset, invalidStyles } from "@/lib/styles";
14
+ import { cn } from "@/lib/utils";
15
+
16
+ const textareaVariants = cva(
17
+ cn(
18
+ "block w-full min-w-0 rounded-md border border-input bg-background text-foreground shadow-xs",
19
+ "transition-[border-color,box-shadow] duration-[var(--duration-fast)] ease-[var(--ease-out-quint)]",
20
+ "placeholder:text-muted-foreground",
21
+ "focus-visible:border-ring",
22
+ "disabled:cursor-not-allowed disabled:opacity-55",
23
+ focusRingInset,
24
+ invalidStyles,
25
+ ),
26
+ {
27
+ variants: {
28
+ textareaSize: {
29
+ sm: "px-2.5 py-1.5 text-sm",
30
+ md: "px-3 py-2 text-sm",
31
+ lg: "px-3.5 py-2.5 text-base",
32
+ },
33
+ /**
34
+ * Vertical only by default.
35
+ *
36
+ * The browser default is `both`, and a textarea dragged wider than its
37
+ * container is a layout broken by a control that was only meant to be
38
+ * made taller.
39
+ */
40
+ resize: {
41
+ none: "resize-none",
42
+ vertical: "resize-y",
43
+ both: "resize",
44
+ },
45
+ },
46
+ defaultVariants: {
47
+ textareaSize: "md",
48
+ resize: "vertical",
49
+ },
50
+ },
51
+ );
52
+
53
+ export interface TextareaProps
54
+ extends
55
+ Omit<ComponentPropsWithRef<"textarea">, "cols">,
56
+ VariantProps<typeof textareaVariants> {
57
+ /**
58
+ * Grows with its content instead of scrolling, up to `maxRows`.
59
+ *
60
+ * Off by default. A field that changes height as you type moves everything
61
+ * below it, which is the right trade for a comment box and the wrong one for
62
+ * a form of twelve fields.
63
+ */
64
+ autoResize?: boolean;
65
+ /** Ceiling for `autoResize`, after which it scrolls. */
66
+ maxRows?: number;
67
+ /**
68
+ * Shows a live character count.
69
+ *
70
+ * Needs `maxLength` to have anything to count against.
71
+ */
72
+ showCount?: boolean;
73
+ }
74
+
75
+ /**
76
+ * Multi-line text field.
77
+ *
78
+ * The visual size prop is `textareaSize`, not `size`, for the same reason
79
+ * Input's is `inputSize`: `size` is a native attribute on form controls, and a
80
+ * prop of that name shadows it.
81
+ *
82
+ * The character count is where this differs from most. A counter wired as a
83
+ * live region announces on every keystroke, which is unusable — a screen
84
+ * reader reads "one hundred and forty-one characters remaining" between every
85
+ * letter. So the count is silent while there is room and only announces once
86
+ * it is nearly gone, which is the point at which it is information rather than
87
+ * chatter.
88
+ */
89
+ export function Textarea({
90
+ className,
91
+ textareaSize,
92
+ resize,
93
+ autoResize = false,
94
+ maxRows = 12,
95
+ showCount = false,
96
+ rows = 3,
97
+ maxLength,
98
+ value,
99
+ defaultValue,
100
+ onChange,
101
+ id,
102
+ "aria-describedby": describedBy,
103
+ ref,
104
+ ...props
105
+ }: TextareaProps) {
106
+ const internalRef = useRef<HTMLTextAreaElement | null>(null);
107
+ const generatedId = useId();
108
+ const countId = `${id ?? generatedId}-count`;
109
+
110
+ const counted = showCount && maxLength !== undefined;
111
+
112
+ /**
113
+ * Both refs, without a library.
114
+ *
115
+ * React 19 passes `ref` as an ordinary prop, so it arrives here and has to be
116
+ * forwarded on deliberately. Auto-resize needs the element too, and silently
117
+ * dropping the caller's ref would break every form library that reaches for
118
+ * the node.
119
+ */
120
+ const setRef = (node: HTMLTextAreaElement | null) => {
121
+ internalRef.current = node;
122
+ if (typeof ref === "function") ref(node);
123
+ else if (ref) (ref as { current: HTMLTextAreaElement | null }).current = node;
124
+ };
125
+
126
+ // Measured after layout, so the height is right on the first paint rather
127
+ // than one frame late and visibly settling.
128
+ useLayoutEffect(() => {
129
+ const textarea = internalRef.current;
130
+ if (!textarea || !autoResize) return;
131
+
132
+ textarea.style.height = "auto";
133
+ const lineHeight = Number.parseFloat(getComputedStyle(textarea).lineHeight) || 20;
134
+ const maxHeight = lineHeight * maxRows;
135
+ textarea.style.height = `${String(Math.min(textarea.scrollHeight, maxHeight))}px`;
136
+ textarea.style.overflowY = textarea.scrollHeight > maxHeight ? "auto" : "hidden";
137
+ });
138
+
139
+ /**
140
+ * The length, for the count.
141
+ *
142
+ * Held in state for the uncontrolled case rather than read off the element
143
+ * during render. Reading the ref looks simpler and does not work: nothing
144
+ * re-renders when an uncontrolled field is typed into, so the count would
145
+ * show whatever it happened to say on first paint and never move again.
146
+ */
147
+ const [uncontrolledLength, setUncontrolledLength] = useState(
148
+ typeof defaultValue === "string" ? defaultValue.length : 0,
149
+ );
150
+
151
+ const length = typeof value === "string" ? value.length : uncontrolledLength;
152
+
153
+ const remaining = maxLength === undefined ? undefined : maxLength - length;
154
+ // Announce only when it starts to matter: a tenth of the budget, or twenty
155
+ // characters, whichever is larger.
156
+ const announceAt = maxLength === undefined ? 0 : Math.max(20, Math.floor(maxLength / 10));
157
+ const nearLimit = remaining !== undefined && remaining <= announceAt;
158
+
159
+ function handleChange(event: ChangeEvent<HTMLTextAreaElement>) {
160
+ if (value === undefined) setUncontrolledLength(event.target.value.length);
161
+ onChange?.(event);
162
+ }
163
+
164
+ return (
165
+ <div className={cn("grid gap-1.5", counted && "w-full")}>
166
+ <textarea
167
+ ref={setRef}
168
+ id={id ?? (counted ? generatedId : undefined)}
169
+ data-slot="textarea"
170
+ rows={rows}
171
+ maxLength={maxLength}
172
+ value={value}
173
+ defaultValue={defaultValue}
174
+ onChange={handleChange}
175
+ aria-describedby={cn(describedBy, counted && countId) || undefined}
176
+ className={cn(
177
+ textareaVariants({ textareaSize, resize: autoResize ? "none" : resize }),
178
+ className,
179
+ )}
180
+ {...props}
181
+ />
182
+
183
+ {counted ? (
184
+ <p
185
+ id={countId}
186
+ data-slot="textarea-count"
187
+ // Polite only once it matters. Left permanently live it reads the
188
+ // count between every keystroke, which is noise, not help.
189
+ aria-live={nearLimit ? "polite" : "off"}
190
+ className={cn(
191
+ "text-xs tabular-nums",
192
+ remaining !== undefined && remaining < 0
193
+ ? "text-destructive"
194
+ : nearLimit
195
+ ? "text-warning"
196
+ : "text-muted-foreground",
197
+ )}
198
+ >
199
+ {/* Words, not "141/200": a bare ratio is read aloud as two numbers
200
+ with no indication of which is which. */}
201
+ {remaining !== undefined && remaining < 0
202
+ ? `${String(Math.abs(remaining))} characters over the limit`
203
+ : `${String(remaining ?? 0)} characters left`}
204
+ </p>
205
+ ) : null}
206
+ </div>
207
+ );
208
+ }
209
+
210
+ export { textareaVariants };
@@ -324,7 +324,7 @@ export function TimeRangePresets({
324
324
  <div
325
325
  data-slot="time-range-presets"
326
326
  className={cn(
327
- "max-h-80 min-w-52 overflow-y-auto border-border p-1.5 sm:border-r",
327
+ "max-h-80 min-w-52 overflow-y-auto border-border p-1.5 sm:border-e",
328
328
  className,
329
329
  )}
330
330
  {...props}
@@ -344,7 +344,7 @@ export function TimeRangePresets({
344
344
  close();
345
345
  }}
346
346
  className={cn(
347
- "flex w-full items-center rounded-md px-2 py-1.5 text-left text-sm transition-colors",
347
+ "flex w-full items-center rounded-md px-2 py-1.5 text-start text-sm transition-colors",
348
348
  preset.expression === value
349
349
  ? "bg-accent font-medium text-accent-foreground"
350
350
  : "hover:bg-accent hover:text-accent-foreground",
@@ -482,7 +482,7 @@ export function TimeRangeCalendar({
482
482
  return (
483
483
  <div
484
484
  data-slot="time-range-calendar"
485
- className={cn("border-t border-border p-1 sm:border-t-0 sm:border-l", className)}
485
+ className={cn("border-t border-border p-1 sm:border-s sm:border-t-0", className)}
486
486
  {...props}
487
487
  >
488
488
  <Calendar
@@ -28,7 +28,7 @@ import {
28
28
  const toastVariants = cva(
29
29
  cn(
30
30
  "group pointer-events-auto relative flex w-full items-start gap-3 overflow-hidden",
31
- "rounded-lg border p-4 pr-10 shadow-lg",
31
+ "rounded-lg border p-4 pe-10 shadow-lg",
32
32
  "[--slide-x:calc(100%+1rem)]",
33
33
  "data-[state=closed]:animate-float-out data-[state=open]:animate-slide-in",
34
34
  "data-[swipe=move]:translate-x-[var(--radix-toast-swipe-move-x)] data-[swipe=move]:transition-none",
@@ -122,7 +122,7 @@ export function ToastClose({
122
122
  data-slot="toast-close"
123
123
  aria-label="Dismiss"
124
124
  className={cn(
125
- "absolute top-3 right-3 grid size-6 place-items-center rounded-md text-muted-foreground",
125
+ "absolute end-3 top-3 grid size-6 place-items-center rounded-md text-muted-foreground",
126
126
  "transition-colors duration-[var(--duration-fast)] hover:bg-accent hover:text-foreground",
127
127
  focusRing,
128
128
  className,
@@ -144,13 +144,21 @@ export function ToastClose({
144
144
  export type ToastPosition =
145
145
  "top-left" | "top-center" | "top-right" | "bottom-left" | "bottom-center" | "bottom-right";
146
146
 
147
+ /*
148
+ rtl-ok: the positions are *named* left and right, so they stay physical. A
149
+ toast asked for at `bottom-right` that appears bottom-left in Arabic is the
150
+ same lie as a Sheet asked for on the left that opens on the right — and it is
151
+ worse here, because the slide-in comes from the right edge and the toast would
152
+ fly across the screen to reach the other one. The logical version of this is a
153
+ `bottom-end` position, which is a rename rather than a restyle.
154
+ */
147
155
  const viewportPositions: Record<ToastPosition, string> = {
148
- "top-left": "top-0 left-0 sm:flex-col-reverse",
156
+ "top-left": "top-0 left-0 sm:flex-col-reverse", // rtl-ok: named position
149
157
  "top-center": "top-0 left-1/2 -translate-x-1/2 sm:flex-col-reverse",
150
- "top-right": "top-0 right-0 sm:flex-col-reverse",
151
- "bottom-left": "bottom-0 left-0",
158
+ "top-right": "top-0 right-0 sm:flex-col-reverse", // rtl-ok: named position
159
+ "bottom-left": "bottom-0 left-0", // rtl-ok: named position
152
160
  "bottom-center": "bottom-0 left-1/2 -translate-x-1/2",
153
- "bottom-right": "bottom-0 right-0",
161
+ "bottom-right": "bottom-0 right-0", // rtl-ok: named position
154
162
  };
155
163
 
156
164
  export interface ToasterProps {
package/src/index.ts CHANGED
@@ -21,11 +21,13 @@ export * from "./components/ai-tool";
21
21
  export * from "./components/alert";
22
22
  export * from "./components/avatar";
23
23
  export * from "./components/badge";
24
+ export * from "./components/breadcrumb";
24
25
  export * from "./components/button";
25
26
  export * from "./components/calendar";
26
27
  export * from "./components/card";
27
28
  export * from "./components/checkbox";
28
29
  export * from "./components/code-block";
30
+ export * from "./components/collapsible";
29
31
  export * from "./components/combobox";
30
32
  export * from "./components/command";
31
33
  export * from "./components/confirm-typed";
@@ -33,6 +35,7 @@ export * from "./components/cron-editor";
33
35
  export * from "./components/data-table";
34
36
  export * from "./components/date-picker";
35
37
  export * from "./components/dialog";
38
+ export * from "./components/direction";
36
39
  export * from "./components/diff-viewer";
37
40
  export * from "./components/dns-record";
38
41
  export * from "./components/drawer";
@@ -56,6 +59,7 @@ export * from "./components/select";
56
59
  export * from "./components/separator";
57
60
  export * from "./components/session-expiry";
58
61
  export * from "./components/sheet";
62
+ export * from "./components/sidebar";
59
63
  export * from "./components/shortcut-recorder";
60
64
  export * from "./components/skeleton";
61
65
  export * from "./components/slider";
@@ -66,6 +70,7 @@ export * from "./components/table";
66
70
  export * from "./components/tabs";
67
71
  export * from "./components/tags-input";
68
72
  export * from "./components/time-range-picker";
73
+ export * from "./components/textarea";
69
74
  export * from "./components/toast";
70
75
  export * from "./components/tooltip";
71
76
 
package/src/lib/styles.ts CHANGED
@@ -24,3 +24,19 @@ export const invalidStyles =
24
24
  /** Sizes any icon rendered as a direct child of a control. */
25
25
  export const iconSlot =
26
26
  "[&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4";
27
+
28
+ /**
29
+ * Mirrors an icon that points along the reading direction.
30
+ *
31
+ * A chevron meaning "forward" points right in English and left in Arabic.
32
+ * Logical CSS does not help here: the glyph is drawn, not laid out, so the
33
+ * class list mirrors the box while the arrow inside it goes on pointing the
34
+ * wrong way. The result is a fully mirrored page whose "next" button points
35
+ * back the way you came.
36
+ *
37
+ * Only for icons whose meaning is directional. A chevron pointing *down* to
38
+ * open a select means down in every language, and flipping it horizontally
39
+ * would be flipping a thing that was never sided. Nor is a tick, a cross or a
40
+ * spinner.
41
+ */
42
+ export const mirrorForDirection = "rtl:-scale-x-100";
@@ -1,10 +1,19 @@
1
1
  import type { ComponentMeta } from "./schema";
2
2
 
3
+ import { meta as adminDashboardMeta } from "@/blocks/admin-dashboard/meta";
3
4
  import { meta as adminUsersMeta } from "@/blocks/admin-users/meta";
5
+ import { meta as agentConsoleMeta } from "@/blocks/agent-console/meta";
4
6
  import { meta as aiChatMeta } from "@/blocks/ai-chat/meta";
7
+ import { meta as aiDashboardMeta } from "@/blocks/ai-dashboard/meta";
8
+ import { meta as aiWorkspaceMeta } from "@/blocks/ai-workspace/meta";
9
+ import { meta as analyticsMeta } from "@/blocks/analytics/meta";
10
+ import { meta as billingMeta } from "@/blocks/billing/meta";
11
+ import { meta as commandCenterMeta } from "@/blocks/command-center/meta";
12
+ import { meta as crmMeta } from "@/blocks/crm/meta";
5
13
  import { meta as dashboardMeta } from "@/blocks/dashboard/meta";
6
14
  import { meta as forgotPasswordMeta } from "@/blocks/forgot-password/meta";
7
15
  import { meta as loginMeta } from "@/blocks/login/meta";
16
+ import { meta as onboardingMeta } from "@/blocks/onboarding/meta";
8
17
  import { meta as pricingMeta } from "@/blocks/pricing/meta";
9
18
  import { meta as settingsMeta } from "@/blocks/settings/meta";
10
19
  import { meta as signupMeta } from "@/blocks/signup/meta";
@@ -19,11 +28,20 @@ import { meta as signupMeta } from "@/blocks/signup/meta";
19
28
  * `meta.test.ts` fails if a block directory exists that is missing from here.
20
29
  */
21
30
  export const blockMetas: ComponentMeta[] = [
31
+ adminDashboardMeta,
22
32
  adminUsersMeta,
33
+ agentConsoleMeta,
23
34
  aiChatMeta,
35
+ aiDashboardMeta,
36
+ aiWorkspaceMeta,
37
+ analyticsMeta,
38
+ billingMeta,
39
+ commandCenterMeta,
40
+ crmMeta,
24
41
  dashboardMeta,
25
42
  forgotPasswordMeta,
26
43
  loginMeta,
44
+ onboardingMeta,
27
45
  pricingMeta,
28
46
  settingsMeta,
29
47
  signupMeta,
@@ -23,17 +23,20 @@ import { meta as aiToolMeta } from "@/components/ai-tool/meta";
23
23
  import { meta as alertMeta } from "@/components/alert/meta";
24
24
  import { meta as avatarMeta } from "@/components/avatar/meta";
25
25
  import { meta as badgeMeta } from "@/components/badge/meta";
26
+ import { meta as breadcrumbMeta } from "@/components/breadcrumb/meta";
26
27
  import { meta as buttonMeta } from "@/components/button/meta";
27
28
  import { meta as calendarMeta } from "@/components/calendar/meta";
28
29
  import { meta as cardMeta } from "@/components/card/meta";
29
30
  import { meta as checkboxMeta } from "@/components/checkbox/meta";
30
31
  import { meta as codeBlockMeta } from "@/components/code-block/meta";
32
+ import { meta as collapsibleMeta } from "@/components/collapsible/meta";
31
33
  import { meta as comboboxMeta } from "@/components/combobox/meta";
32
34
  import { meta as commandMeta } from "@/components/command/meta";
33
35
  import { meta as confirmTypedMeta } from "@/components/confirm-typed/meta";
34
36
  import { meta as cronEditorMeta } from "@/components/cron-editor/meta";
35
37
  import { meta as dataTableMeta } from "@/components/data-table/meta";
36
38
  import { meta as datePickerMeta } from "@/components/date-picker/meta";
39
+ import { meta as directionMeta } from "@/components/direction/meta";
37
40
  import { meta as dialogMeta } from "@/components/dialog/meta";
38
41
  import { meta as diffViewerMeta } from "@/components/diff-viewer/meta";
39
42
  import { meta as dnsRecordMeta } from "@/components/dns-record/meta";
@@ -57,6 +60,7 @@ import { meta as secretFieldMeta } from "@/components/secret-field/meta";
57
60
  import { meta as selectMeta } from "@/components/select/meta";
58
61
  import { meta as separatorMeta } from "@/components/separator/meta";
59
62
  import { meta as sessionExpiryMeta } from "@/components/session-expiry/meta";
63
+ import { meta as sidebarMeta } from "@/components/sidebar/meta";
60
64
  import { meta as sheetMeta } from "@/components/sheet/meta";
61
65
  import { meta as shortcutRecorderMeta } from "@/components/shortcut-recorder/meta";
62
66
  import { meta as skeletonMeta } from "@/components/skeleton/meta";
@@ -68,6 +72,7 @@ import { meta as tableMeta } from "@/components/table/meta";
68
72
  import { meta as tabsMeta } from "@/components/tabs/meta";
69
73
  import { meta as tagsInputMeta } from "@/components/tags-input/meta";
70
74
  import { meta as timeRangePickerMeta } from "@/components/time-range-picker/meta";
75
+ import { meta as textareaMeta } from "@/components/textarea/meta";
71
76
  import { meta as toastMeta } from "@/components/toast/meta";
72
77
  import { meta as tooltipMeta } from "@/components/tooltip/meta";
73
78
 
@@ -106,11 +111,13 @@ export const componentMetas: ComponentMeta[] = [
106
111
  alertMeta,
107
112
  avatarMeta,
108
113
  badgeMeta,
114
+ breadcrumbMeta,
109
115
  buttonMeta,
110
116
  calendarMeta,
111
117
  cardMeta,
112
118
  checkboxMeta,
113
119
  codeBlockMeta,
120
+ collapsibleMeta,
114
121
  comboboxMeta,
115
122
  commandMeta,
116
123
  confirmTypedMeta,
@@ -118,6 +125,7 @@ export const componentMetas: ComponentMeta[] = [
118
125
  dataTableMeta,
119
126
  datePickerMeta,
120
127
  dialogMeta,
128
+ directionMeta,
121
129
  diffViewerMeta,
122
130
  dnsRecordMeta,
123
131
  drawerMeta,
@@ -141,6 +149,7 @@ export const componentMetas: ComponentMeta[] = [
141
149
  separatorMeta,
142
150
  sessionExpiryMeta,
143
151
  sheetMeta,
152
+ sidebarMeta,
144
153
  shortcutRecorderMeta,
145
154
  skeletonMeta,
146
155
  sliderMeta,
@@ -151,6 +160,7 @@ export const componentMetas: ComponentMeta[] = [
151
160
  tabsMeta,
152
161
  tagsInputMeta,
153
162
  timeRangePickerMeta,
163
+ textareaMeta,
154
164
  toastMeta,
155
165
  tooltipMeta,
156
166
  ];
@@ -50,6 +50,14 @@ export interface ComponentMeta {
50
50
  files: string[];
51
51
  /** Accessibility notes surfaced on the docs page. */
52
52
  a11y?: string;
53
+ /**
54
+ * Whether the source is public.
55
+ *
56
+ * Omitted means `free`, and free is a promise: an item that has shipped
57
+ * installable without a licence stays that way. Marking an existing component
58
+ * `pro` breaks every project that already installs it.
59
+ */
60
+ access?: "free" | "pro";
53
61
  }
54
62
 
55
63
  /** Identity helper that gives editors autocomplete inside `meta.ts`. */