beez-ui 0.6.2 → 0.8.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 (127) hide show
  1. package/CHANGELOG.md +150 -96
  2. package/README.md +33 -6
  3. package/dist/components/account-menu.d.ts +53 -0
  4. package/dist/components/account-menu.js +405 -0
  5. package/dist/components/alert.js +1 -1
  6. package/dist/components/animated-collapse.d.ts +19 -0
  7. package/dist/components/animated-collapse.js +81 -0
  8. package/dist/components/animated-count.d.ts +13 -0
  9. package/dist/components/animated-count.js +105 -0
  10. package/dist/components/animated-list-item.d.ts +25 -0
  11. package/dist/components/animated-list-item.js +132 -0
  12. package/dist/components/avatar.d.ts +2 -1
  13. package/dist/components/avatar.js +4 -3
  14. package/dist/components/bouncing-dots-loader.d.ts +19 -0
  15. package/dist/components/bouncing-dots-loader.js +47 -0
  16. package/dist/components/calendar.js +102 -0
  17. package/dist/components/carousel.js +61 -48
  18. package/dist/components/checkbox.js +1 -1
  19. package/dist/components/confirm-delete-button.d.ts +29 -0
  20. package/dist/components/confirm-delete-button.js +254 -0
  21. package/dist/components/data-table.js +34 -4
  22. package/dist/components/dropdown-menu.js +5 -2
  23. package/dist/components/empty-state.d.ts +24 -0
  24. package/dist/components/empty-state.js +37 -0
  25. package/dist/components/error-state.d.ts +20 -0
  26. package/dist/components/error-state.js +145 -0
  27. package/dist/components/external-browser-handoff.d.ts +27 -0
  28. package/dist/components/external-browser-handoff.js +306 -0
  29. package/dist/components/file-upload.d.ts +78 -0
  30. package/dist/components/file-upload.js +678 -0
  31. package/dist/components/filter-query-bar.js +11 -6
  32. package/dist/components/form.d.ts +5 -0
  33. package/dist/components/form.js +11 -9
  34. package/dist/components/info-popover.d.ts +23 -0
  35. package/dist/components/info-popover.js +158 -0
  36. package/dist/components/input-group.js +1 -1
  37. package/dist/components/input.js +1 -1
  38. package/dist/components/month-calendar-header.d.ts +65 -0
  39. package/dist/components/month-calendar-header.js +337 -0
  40. package/dist/components/month-grid.d.ts +59 -0
  41. package/dist/components/month-grid.js +301 -0
  42. package/dist/components/notification-bell.d.ts +50 -0
  43. package/dist/components/notification-bell.js +338 -0
  44. package/dist/components/notification-panel.d.ts +56 -0
  45. package/dist/components/notification-panel.js +281 -0
  46. package/dist/components/open-in-browser-cta.d.ts +22 -0
  47. package/dist/components/open-in-browser-cta.js +61 -0
  48. package/dist/components/pagination.d.ts +1 -0
  49. package/dist/components/pagination.js +9 -4
  50. package/dist/components/presence-swap.d.ts +22 -0
  51. package/dist/components/presence-swap.js +162 -0
  52. package/dist/components/progress-ring.d.ts +20 -0
  53. package/dist/components/progress-ring.js +53 -0
  54. package/dist/components/pwa-update-control.d.ts +18 -0
  55. package/dist/components/pwa-update-control.js +119 -0
  56. package/dist/components/radio-group.js +1 -1
  57. package/dist/components/reaction-button.d.ts +26 -0
  58. package/dist/components/reaction-button.js +114 -0
  59. package/dist/components/rich-link-editor.d.ts +25 -0
  60. package/dist/components/rich-link-editor.js +320 -0
  61. package/dist/components/rich-markdown-content.d.ts +10 -0
  62. package/dist/components/rich-markdown-content.js +56 -0
  63. package/dist/components/rich-text-content.d.ts +19 -0
  64. package/dist/components/rich-text-content.js +26 -0
  65. package/dist/components/select.js +1 -1
  66. package/dist/components/sheet.js +12 -9
  67. package/dist/components/sidebar.js +9 -5
  68. package/dist/components/skeleton.d.ts +6 -0
  69. package/dist/components/skeleton.js +7 -1
  70. package/dist/components/switch.js +1 -1
  71. package/dist/components/textarea.js +1 -1
  72. package/dist/components/typing-animation.js +42 -15
  73. package/dist/emoji-picker.d.ts +27 -0
  74. package/dist/emoji-picker.js +283 -0
  75. package/dist/hooks/use-horizontal-swipe.d.ts +23 -0
  76. package/dist/hooks/use-horizontal-swipe.js +80 -0
  77. package/dist/hooks/use-is-hydrated.d.ts +6 -0
  78. package/dist/hooks/use-is-hydrated.js +20 -0
  79. package/dist/hooks/use-minute-clock.d.ts +23 -0
  80. package/dist/hooks/use-minute-clock.js +147 -0
  81. package/dist/hooks/use-month-transition-direction.d.ts +21 -0
  82. package/dist/hooks/use-month-transition-direction.js +110 -0
  83. package/dist/hooks/use-rich-link-editor.d.ts +55 -0
  84. package/dist/hooks/use-rich-link-editor.js +515 -0
  85. package/dist/hooks/use-viewer-time-zone.d.ts +6 -0
  86. package/dist/hooks/use-viewer-time-zone.js +20 -0
  87. package/dist/index.d.ts +44 -0
  88. package/dist/index.js +43 -0
  89. package/dist/lib/browser-clipboard.d.ts +13 -0
  90. package/dist/lib/browser-clipboard.js +48 -0
  91. package/dist/lib/browser-navigation.d.ts +21 -0
  92. package/dist/lib/browser-navigation.js +42 -0
  93. package/dist/lib/column-filter-value.d.ts +12 -0
  94. package/dist/lib/column-filter-value.js +52 -0
  95. package/dist/lib/file-acceptance.d.ts +43 -0
  96. package/dist/lib/file-acceptance.js +107 -0
  97. package/dist/lib/format-file-size.d.ts +16 -0
  98. package/dist/lib/format-file-size.js +34 -0
  99. package/dist/lib/fuzzy-search.d.ts +17 -0
  100. package/dist/lib/fuzzy-search.js +183 -0
  101. package/dist/lib/horizontal-swipe.d.ts +23 -0
  102. package/dist/lib/horizontal-swipe.js +29 -0
  103. package/dist/lib/in-app-browser.d.ts +35 -0
  104. package/dist/lib/in-app-browser.js +80 -0
  105. package/dist/lib/month-grid.d.ts +42 -0
  106. package/dist/lib/month-grid.js +74 -0
  107. package/dist/lib/name-initials.d.ts +7 -0
  108. package/dist/lib/name-initials.js +11 -0
  109. package/dist/lib/rich-text/link-markdown-constants.d.ts +147 -0
  110. package/dist/lib/rich-text/link-markdown-constants.js +458 -0
  111. package/dist/lib/rich-text/link-markdown-types.d.ts +53 -0
  112. package/dist/lib/rich-text/link-markdown-types.js +1 -0
  113. package/dist/lib/rich-text/link-markdown.d.ts +193 -0
  114. package/dist/lib/rich-text/link-markdown.js +592 -0
  115. package/dist/lib/rich-text/rich-markdown.d.ts +41 -0
  116. package/dist/lib/rich-text/rich-markdown.js +105 -0
  117. package/dist/lib/rich-text/rich-text-editor-dom.d.ts +26 -0
  118. package/dist/lib/rich-text/rich-text-editor-dom.js +79 -0
  119. package/dist/motion/glide-indicator.d.ts +37 -3
  120. package/dist/motion/glide-indicator.js +37 -3
  121. package/dist/motion/motion-slot.js +47 -18
  122. package/dist/motion/surface-keyframes.js +18 -6
  123. package/dist/motion/tokens.d.ts +41 -2
  124. package/dist/motion/tokens.js +40 -1
  125. package/dist/providers/beez-ui-provider.js +49 -17
  126. package/dist/styles.css +1 -1
  127. package/package.json +212 -2
@@ -0,0 +1,320 @@
1
+ "use client";
2
+ import { c as _c } from "react/compiler-runtime";
3
+ /** `contentEditable` editor for plain text with markdown links, driven by `useRichLinkEditor`. */
4
+ import { useEffect, useRef } from "react";
5
+ import { cn } from "../lib/utils.js";
6
+ import { RICH_LINK_POPOVER_MODE, RICH_TEXT_EDITOR_KEY, RICH_TEXT_SEGMENT_TYPE } from "../lib/rich-text/link-markdown-constants.js";
7
+ import { Button } from "./button.js";
8
+ import { Popover, PopoverContent, PopoverTrigger } from "./popover.js";
9
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
10
+ const BUTTON_TYPE = "button";
11
+ const BUTTON_VARIANT = {
12
+ ghost: "ghost",
13
+ outline: "outline"
14
+ };
15
+ const URL_INPUT_TYPE = "url";
16
+ const LINK_TARGET = "_blank";
17
+ const LINK_REL = "noreferrer";
18
+ /**
19
+ * Presentation of each part. iOS Safari zooms the page when a focused editable region renders
20
+ * text below 16px, so the editor and the inputs are pinned to 1rem on phones.
21
+ */
22
+ const RICH_LINK_EDITOR_CLASS_NAMES = {
23
+ editor: "min-h-28 w-full cursor-text border-0 bg-background p-0 leading-[1.65] whitespace-pre-wrap text-foreground [font:inherit] [overflow-wrap:anywhere] focus:outline-0 empty:before:pointer-events-none empty:before:text-muted-foreground/75 empty:before:content-[attr(data-placeholder)] max-md:text-base",
24
+ editorInvalid: "rounded-[0.35rem] shadow-[inset_0_-2px_0_var(--destructive)] outline-0",
25
+ editorLink: "cursor-pointer rounded-[0.2rem] font-bold text-primary underline decoration-[0.08em] underline-offset-[0.18em] transition-colors hover:text-[color-mix(in_oklab,var(--primary)_72%,var(--foreground))] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring",
26
+ popover: "gap-3",
27
+ editForm: "grid gap-3 animate-in fade-in slide-in-from-bottom-1 duration-200",
28
+ actions: "flex flex-wrap items-center gap-2",
29
+ label: "grid gap-[0.35rem] text-[0.85rem] font-bold text-muted-foreground",
30
+ input: "min-h-8 rounded-lg border border-border/80 bg-background px-[0.65rem] font-normal text-foreground outline-0 transition-[border-color,box-shadow] [font:inherit] focus-visible:border-ring focus-visible:shadow-[0_0_0_3px_color-mix(in_oklab,var(--ring)_35%,transparent)] aria-invalid:border-destructive aria-invalid:focus-visible:shadow-[0_0_0_3px_color-mix(in_oklab,var(--destructive)_25%,transparent)] max-md:text-base"
31
+ };
32
+ const RICH_LINK_EDITOR_DEFAULT_COPY = {
33
+ editAction: "Editar",
34
+ editCancel: "Cancelar",
35
+ editSave: "Guardar",
36
+ popoverTextLabel: "Texto",
37
+ popoverUrlLabel: "Enlace",
38
+ removeAction: "Quitar enlace"
39
+ };
40
+ /**
41
+ * `contentEditable` rich link editor: renders the controller's preview segments,
42
+ * turning each link into a popover that edits or removes it. All state lives in
43
+ * the `useRichLinkEditor` controller; this component is presentation only.
44
+ */
45
+ export function RichLinkEditor(t0) {
46
+ const $ = _c(50);
47
+ const { ariaDescribedBy, ariaLabel, copy: copyOverrides, editor, isDisabled: t1, isInvalid: t2, placeholder } = t0;
48
+ const isDisabled = t1 === undefined ? false : t1;
49
+ const isInvalid = t2 === undefined ? false : t2;
50
+ const { activeLink, closeLinkPopover, handleBeforeInput, handleInput, handleKeyDown, handlePaste, hasContent, hasInvalidLinkUrl, isLinkEditValid, linkTextInput, linkUrlInput, openLinkPopover, popoverMode, removeLink, saveLinkEdit, segments, setEditorElement, setLinkTextInput, setLinkUrlInput, setPopoverMode } = editor;
51
+ let t3;
52
+ if ($[0] !== copyOverrides) {
53
+ t3 = {
54
+ ...RICH_LINK_EDITOR_DEFAULT_COPY,
55
+ ...copyOverrides
56
+ };
57
+ $[0] = copyOverrides;
58
+ $[1] = t3;
59
+ } else {
60
+ t3 = $[1];
61
+ }
62
+ const copy = t3;
63
+ const linkTextInputRef = useRef(null);
64
+ const isEditingLink = popoverMode === RICH_LINK_POPOVER_MODE.edit;
65
+ const t4 = isInvalid && RICH_LINK_EDITOR_CLASS_NAMES.editorInvalid;
66
+ let t5;
67
+ if ($[2] !== t4) {
68
+ t5 = cn(RICH_LINK_EDITOR_CLASS_NAMES.editor, t4);
69
+ $[2] = t4;
70
+ $[3] = t5;
71
+ } else {
72
+ t5 = $[3];
73
+ }
74
+ const editorClassName = t5;
75
+ let t6;
76
+ let t7;
77
+ if ($[4] !== closeLinkPopover || $[5] !== isDisabled) {
78
+ t6 = () => {
79
+ if (isDisabled) {
80
+ closeLinkPopover();
81
+ }
82
+ };
83
+ t7 = [closeLinkPopover, isDisabled];
84
+ $[4] = closeLinkPopover;
85
+ $[5] = isDisabled;
86
+ $[6] = t6;
87
+ $[7] = t7;
88
+ } else {
89
+ t6 = $[6];
90
+ t7 = $[7];
91
+ }
92
+ useEffect(t6, t7);
93
+ let t8;
94
+ if ($[8] !== isEditingLink) {
95
+ t8 = () => {
96
+ if (isEditingLink) {
97
+ linkTextInputRef.current?.focus();
98
+ }
99
+ };
100
+ $[8] = isEditingLink;
101
+ $[9] = t8;
102
+ } else {
103
+ t8 = $[9];
104
+ }
105
+ const t9 = activeLink?.key;
106
+ let t10;
107
+ if ($[10] !== isEditingLink || $[11] !== t9) {
108
+ t10 = [isEditingLink, t9];
109
+ $[10] = isEditingLink;
110
+ $[11] = t9;
111
+ $[12] = t10;
112
+ } else {
113
+ t10 = $[12];
114
+ }
115
+ useEffect(t8, t10);
116
+ let t11;
117
+ if ($[13] !== activeLink || $[14] !== isLinkEditValid || $[15] !== saveLinkEdit) {
118
+ t11 = (event) => {
119
+ if (event.key !== RICH_TEXT_EDITOR_KEY.enter) {
120
+ return;
121
+ }
122
+ event.preventDefault();
123
+ if (activeLink && isLinkEditValid) {
124
+ saveLinkEdit(activeLink);
125
+ }
126
+ };
127
+ $[13] = activeLink;
128
+ $[14] = isLinkEditValid;
129
+ $[15] = saveLinkEdit;
130
+ $[16] = t11;
131
+ } else {
132
+ t11 = $[16];
133
+ }
134
+ const handleEditFieldKeyDown = t11;
135
+ const t12 = !isDisabled;
136
+ let t13;
137
+ if ($[17] !== activeLink || $[18] !== closeLinkPopover || $[19] !== copy || $[20] !== handleEditFieldKeyDown || $[21] !== hasContent || $[22] !== hasInvalidLinkUrl || $[23] !== isDisabled || $[24] !== isLinkEditValid || $[25] !== linkTextInput || $[26] !== linkUrlInput || $[27] !== openLinkPopover || $[28] !== popoverMode || $[29] !== removeLink || $[30] !== saveLinkEdit || $[31] !== segments || $[32] !== setLinkTextInput || $[33] !== setLinkUrlInput || $[34] !== setPopoverMode) {
138
+ t13 = hasContent ? segments.map((segment) => segment.type === RICH_TEXT_SEGMENT_TYPE.link ? isDisabled ? /* @__PURE__ */ _jsx("a", {
139
+ "aria-disabled": true,
140
+ className: RICH_LINK_EDITOR_CLASS_NAMES.editorLink,
141
+ href: segment.url,
142
+ onClick: _temp,
143
+ rel: LINK_REL,
144
+ tabIndex: -1,
145
+ target: LINK_TARGET,
146
+ children: segment.text
147
+ }, segment.key) : /* @__PURE__ */ _jsxs(Popover, {
148
+ onOpenChange: (isOpen) => {
149
+ if (isOpen) {
150
+ openLinkPopover(segment);
151
+ } else {
152
+ if (activeLink?.key === segment.key) {
153
+ closeLinkPopover();
154
+ }
155
+ }
156
+ },
157
+ open: activeLink?.key === segment.key,
158
+ children: [/* @__PURE__ */ _jsx(PopoverTrigger, {
159
+ asChild: true,
160
+ children: /* @__PURE__ */ _jsx("a", {
161
+ className: RICH_LINK_EDITOR_CLASS_NAMES.editorLink,
162
+ href: segment.url,
163
+ onClick: (event_1) => {
164
+ event_1.preventDefault();
165
+ openLinkPopover(segment);
166
+ },
167
+ rel: LINK_REL,
168
+ target: LINK_TARGET,
169
+ children: segment.text
170
+ })
171
+ }), /* @__PURE__ */ _jsx(PopoverContent, {
172
+ className: RICH_LINK_EDITOR_CLASS_NAMES.popover,
173
+ onBeforeInput: _temp2,
174
+ onInput: _temp3,
175
+ onKeyDown: _temp4,
176
+ onPaste: _temp5,
177
+ children: popoverMode === RICH_LINK_POPOVER_MODE.actions ? /* @__PURE__ */ _jsxs("div", {
178
+ className: RICH_LINK_EDITOR_CLASS_NAMES.actions,
179
+ children: [/* @__PURE__ */ _jsx(Button, {
180
+ onClick: () => {
181
+ setPopoverMode(RICH_LINK_POPOVER_MODE.edit);
182
+ },
183
+ type: BUTTON_TYPE,
184
+ variant: BUTTON_VARIANT.ghost,
185
+ children: copy.editAction
186
+ }), /* @__PURE__ */ _jsx(Button, {
187
+ onClick: () => {
188
+ removeLink(segment);
189
+ },
190
+ type: BUTTON_TYPE,
191
+ variant: BUTTON_VARIANT.ghost,
192
+ children: copy.removeAction
193
+ })]
194
+ }) : /* @__PURE__ */ _jsxs("div", {
195
+ className: RICH_LINK_EDITOR_CLASS_NAMES.editForm,
196
+ children: [
197
+ /* @__PURE__ */ _jsxs("label", {
198
+ className: RICH_LINK_EDITOR_CLASS_NAMES.label,
199
+ children: [/* @__PURE__ */ _jsx("span", { children: copy.popoverTextLabel }), /* @__PURE__ */ _jsx("input", {
200
+ className: RICH_LINK_EDITOR_CLASS_NAMES.input,
201
+ onChange: (event_6) => {
202
+ setLinkTextInput(event_6.currentTarget.value);
203
+ },
204
+ onKeyDown: handleEditFieldKeyDown,
205
+ ref: linkTextInputRef,
206
+ value: linkTextInput
207
+ })]
208
+ }),
209
+ /* @__PURE__ */ _jsxs("label", {
210
+ className: RICH_LINK_EDITOR_CLASS_NAMES.label,
211
+ children: [/* @__PURE__ */ _jsx("span", { children: copy.popoverUrlLabel }), /* @__PURE__ */ _jsx("input", {
212
+ "aria-invalid": hasInvalidLinkUrl,
213
+ className: RICH_LINK_EDITOR_CLASS_NAMES.input,
214
+ onChange: (event_7) => {
215
+ setLinkUrlInput(event_7.currentTarget.value);
216
+ },
217
+ onKeyDown: handleEditFieldKeyDown,
218
+ type: URL_INPUT_TYPE,
219
+ value: linkUrlInput
220
+ })]
221
+ }),
222
+ /* @__PURE__ */ _jsxs("div", {
223
+ className: RICH_LINK_EDITOR_CLASS_NAMES.actions,
224
+ children: [/* @__PURE__ */ _jsx(Button, {
225
+ disabled: !isLinkEditValid,
226
+ onClick: () => {
227
+ if (activeLink) {
228
+ saveLinkEdit(activeLink);
229
+ }
230
+ },
231
+ type: BUTTON_TYPE,
232
+ children: copy.editSave
233
+ }), /* @__PURE__ */ _jsx(Button, {
234
+ onClick: closeLinkPopover,
235
+ type: BUTTON_TYPE,
236
+ variant: BUTTON_VARIANT.outline,
237
+ children: copy.editCancel
238
+ })]
239
+ })
240
+ ]
241
+ })
242
+ })]
243
+ }, segment.key) : segment.text) : null;
244
+ $[17] = activeLink;
245
+ $[18] = closeLinkPopover;
246
+ $[19] = copy;
247
+ $[20] = handleEditFieldKeyDown;
248
+ $[21] = hasContent;
249
+ $[22] = hasInvalidLinkUrl;
250
+ $[23] = isDisabled;
251
+ $[24] = isLinkEditValid;
252
+ $[25] = linkTextInput;
253
+ $[26] = linkUrlInput;
254
+ $[27] = openLinkPopover;
255
+ $[28] = popoverMode;
256
+ $[29] = removeLink;
257
+ $[30] = saveLinkEdit;
258
+ $[31] = segments;
259
+ $[32] = setLinkTextInput;
260
+ $[33] = setLinkUrlInput;
261
+ $[34] = setPopoverMode;
262
+ $[35] = t13;
263
+ } else {
264
+ t13 = $[35];
265
+ }
266
+ let t14;
267
+ if ($[36] !== ariaDescribedBy || $[37] !== ariaLabel || $[38] !== editorClassName || $[39] !== handleBeforeInput || $[40] !== handleInput || $[41] !== handleKeyDown || $[42] !== handlePaste || $[43] !== isDisabled || $[44] !== isInvalid || $[45] !== placeholder || $[46] !== setEditorElement || $[47] !== t12 || $[48] !== t13) {
268
+ t14 = /* @__PURE__ */ _jsx("div", {
269
+ "aria-describedby": ariaDescribedBy,
270
+ "aria-disabled": isDisabled,
271
+ "aria-invalid": isInvalid,
272
+ "aria-label": ariaLabel,
273
+ "aria-multiline": true,
274
+ className: editorClassName,
275
+ "data-slot": "rich-link-editor",
276
+ contentEditable: t12,
277
+ "data-placeholder": placeholder,
278
+ onBeforeInput: handleBeforeInput,
279
+ onInput: handleInput,
280
+ onKeyDown: handleKeyDown,
281
+ onPaste: handlePaste,
282
+ ref: setEditorElement,
283
+ role: "textbox",
284
+ suppressContentEditableWarning: true,
285
+ children: t13
286
+ });
287
+ $[36] = ariaDescribedBy;
288
+ $[37] = ariaLabel;
289
+ $[38] = editorClassName;
290
+ $[39] = handleBeforeInput;
291
+ $[40] = handleInput;
292
+ $[41] = handleKeyDown;
293
+ $[42] = handlePaste;
294
+ $[43] = isDisabled;
295
+ $[44] = isInvalid;
296
+ $[45] = placeholder;
297
+ $[46] = setEditorElement;
298
+ $[47] = t12;
299
+ $[48] = t13;
300
+ $[49] = t14;
301
+ } else {
302
+ t14 = $[49];
303
+ }
304
+ return t14;
305
+ }
306
+ function _temp5(event_5) {
307
+ event_5.stopPropagation();
308
+ }
309
+ function _temp4(event_4) {
310
+ event_4.stopPropagation();
311
+ }
312
+ function _temp3(event_3) {
313
+ event_3.stopPropagation();
314
+ }
315
+ function _temp2(event_2) {
316
+ event_2.stopPropagation();
317
+ }
318
+ function _temp(event_0) {
319
+ event_0.preventDefault();
320
+ }
@@ -0,0 +1,10 @@
1
+ export interface RichMarkdownContentProps {
2
+ content: string;
3
+ className?: string;
4
+ }
5
+ /**
6
+ * Parses and renders the content as paragraphs and lists.
7
+ * @param props - Stored content and optional class name.
8
+ * @returns The rendered blocks.
9
+ */
10
+ export declare function RichMarkdownContent({ content, className }: RichMarkdownContentProps): import("react").JSX.Element;
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Renders long-form content with a safe markdown subset: paragraphs, unordered lists, inline
3
+ * bold and the shared link syntax. Raw HTML in the content is never interpreted as markup.
4
+ */
5
+ import { cn } from "../lib/utils.js";
6
+ import { RICH_MARKDOWN_BLOCK_TYPE, RICH_MARKDOWN_INLINE_TYPE, parseRichMarkdownBlocks } from "../lib/rich-text/rich-markdown.js";
7
+ import { RICH_TEXT_LINK_CLASS_NAME } from "./rich-text-content.js";
8
+ import { jsx as _jsx } from "react/jsx-runtime";
9
+ const LINK_TARGET = "_blank";
10
+ const LINK_REL = "noreferrer";
11
+ /**
12
+ * Renders the inline pieces of a paragraph or list item.
13
+ * @param segments - Parsed inline segments.
14
+ * @returns Text, bold runs and links.
15
+ */
16
+ function renderInlineSegments(segments) {
17
+ return segments.map((segment, segmentIndex) => {
18
+ const segmentKey = segment.type + String(segmentIndex);
19
+ if (segment.type === RICH_MARKDOWN_INLINE_TYPE.link) {
20
+ return /* @__PURE__ */ _jsx("a", {
21
+ "data-slot": "rich-text-link",
22
+ className: RICH_TEXT_LINK_CLASS_NAME,
23
+ href: segment.url,
24
+ rel: LINK_REL,
25
+ target: LINK_TARGET,
26
+ children: segment.text
27
+ }, segmentKey);
28
+ }
29
+ if (segment.type === RICH_MARKDOWN_INLINE_TYPE.bold) {
30
+ return /* @__PURE__ */ _jsx("strong", { children: segment.text }, segmentKey);
31
+ }
32
+ return segment.text;
33
+ });
34
+ }
35
+ /**
36
+ * Parses and renders the content as paragraphs and lists.
37
+ * @param props - Stored content and optional class name.
38
+ * @returns The rendered blocks.
39
+ */
40
+ export function RichMarkdownContent({ content, className }) {
41
+ const blocks = parseRichMarkdownBlocks(content);
42
+ return /* @__PURE__ */ _jsx("div", {
43
+ "data-slot": "rich-markdown-content",
44
+ className: cn("grid gap-[0.9rem]", className),
45
+ children: blocks.map((block, blockIndex) => block.type === RICH_MARKDOWN_BLOCK_TYPE.list ? /* @__PURE__ */ _jsx("ul", {
46
+ className: "m-0 grid list-disc gap-[0.35rem] pl-[1.4rem]",
47
+ children: block.items.map((itemSegments, itemIndex) => /* @__PURE__ */ _jsx("li", {
48
+ className: "leading-[1.7] [overflow-wrap:anywhere] marker:text-muted-foreground",
49
+ children: renderInlineSegments(itemSegments)
50
+ }, block.type + String(blockIndex) + String(itemIndex)))
51
+ }, block.type + String(blockIndex)) : /* @__PURE__ */ _jsx("p", {
52
+ className: "m-0 leading-[1.7] whitespace-pre-wrap [overflow-wrap:anywhere]",
53
+ children: renderInlineSegments(block.segments)
54
+ }, block.type + String(blockIndex)))
55
+ });
56
+ }
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Renders persisted rich text (markdown links plus auto-detected URLs) as plain text interleaved
3
+ * with safe `<a>` links. Raw HTML in the content is never interpreted as markup.
4
+ */
5
+ import type { MouseEvent } from "react";
6
+ /** Shared look of links inside rendered rich text. */
7
+ export declare const RICH_TEXT_LINK_CLASS_NAME = "rounded-[0.2rem] text-primary underline decoration-primary/45 underline-offset-[0.18em] transition-[color,text-decoration-color] [word-break:break-word] hover:text-[color-mix(in_oklab,var(--primary)_72%,var(--foreground))] hover:decoration-current focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring";
8
+ export interface RichTextContentProps {
9
+ content: string;
10
+ onLinkClick?: (event: MouseEvent<HTMLAnchorElement>) => void;
11
+ linkClassName?: string;
12
+ }
13
+ /**
14
+ * Renders an inline fragment instead of a wrapper element, so it composes inside any container
15
+ * without altering layout-sensitive behavior such as `line-clamp` on an ancestor.
16
+ * @param props - Stored content, optional link click handler and link class name.
17
+ * @returns Text and links.
18
+ */
19
+ export declare function RichTextContent({ content, onLinkClick, linkClassName }: RichTextContentProps): import("react").JSX.Element;
@@ -0,0 +1,26 @@
1
+ import { cn } from "../lib/utils.js";
2
+ import { RICH_TEXT_SEGMENT_TYPE } from "../lib/rich-text/link-markdown-constants.js";
3
+ import { parseRichTextSegments } from "../lib/rich-text/link-markdown.js";
4
+ import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
5
+ const LINK_TARGET = "_blank";
6
+ const LINK_REL = "noreferrer";
7
+ /** Shared look of links inside rendered rich text. */
8
+ export const RICH_TEXT_LINK_CLASS_NAME = "rounded-[0.2rem] text-primary underline decoration-primary/45 underline-offset-[0.18em] transition-[color,text-decoration-color] [word-break:break-word] hover:text-[color-mix(in_oklab,var(--primary)_72%,var(--foreground))] hover:decoration-current focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring";
9
+ /**
10
+ * Renders an inline fragment instead of a wrapper element, so it composes inside any container
11
+ * without altering layout-sensitive behavior such as `line-clamp` on an ancestor.
12
+ * @param props - Stored content, optional link click handler and link class name.
13
+ * @returns Text and links.
14
+ */
15
+ export function RichTextContent({ content, onLinkClick, linkClassName }) {
16
+ const segments = parseRichTextSegments(content);
17
+ return /* @__PURE__ */ _jsx(_Fragment, { children: segments.map((segment, segmentIndex) => segment.type === RICH_TEXT_SEGMENT_TYPE.link ? /* @__PURE__ */ _jsx("a", {
18
+ "data-slot": "rich-text-link",
19
+ className: cn(RICH_TEXT_LINK_CLASS_NAME, "font-bold decoration-[0.08em]", linkClassName),
20
+ href: segment.url,
21
+ onClick: onLinkClick,
22
+ rel: LINK_REL,
23
+ target: LINK_TARGET,
24
+ children: segment.text
25
+ }, segment.type + String(segmentIndex)) : segment.text) });
26
+ }
@@ -116,7 +116,7 @@ function SelectTrigger(t0) {
116
116
  const size = t1 === undefined ? "default" : t1;
117
117
  let t2;
118
118
  if ($[5] !== className) {
119
- t2 = cn("flex w-fit items-center justify-between gap-1.5 rounded-lg border data-[state=open]:*:data-[slot=select-icon]:rotate-180 border-input bg-transparent py-2 pr-2 pl-2.5 text-sm whitespace-nowrap transition-colors outline-none select-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 data-placeholder:text-muted-foreground data-[size=default]:h-8 data-[size=sm]:h-7 data-[size=sm]:rounded-[min(var(--radius-md),10px)] *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-1.5 dark:bg-input/30 dark:hover:bg-input/50 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", className);
119
+ t2 = cn("flex w-fit items-center justify-between gap-1.5 rounded-lg border data-[state=open]:*:data-[slot=select-icon]:rotate-180 border-input bg-transparent py-2 pr-2 pl-2.5 text-sm whitespace-nowrap transition-[color,background-color,border-color,box-shadow] outline-none select-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 data-placeholder:text-muted-foreground data-[size=default]:h-8 data-[size=sm]:h-7 data-[size=sm]:rounded-[min(var(--radius-md),10px)] *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-1.5 dark:bg-input/30 dark:hover:bg-input/50 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", className);
120
120
  $[5] = className;
121
121
  $[6] = t2;
122
122
  } else {
@@ -196,7 +196,7 @@ function SheetContent(t0) {
196
196
  }
197
197
  let t5;
198
198
  if ($[7] !== className) {
199
- t5 = cn("fixed z-50 flex flex-col gap-4 overflow-y-auto overscroll-contain data-[side=bottom]:max-h-dvh data-[side=top]:max-h-dvh bg-background bg-clip-padding text-sm shadow-lg transition ease-in-out data-[side=bottom]:inset-x-0 data-[side=bottom]:bottom-0 data-[side=bottom]:h-auto data-[side=bottom]:border-t data-[side=left]:inset-y-0 data-[side=left]:left-0 data-[side=left]:h-full data-[side=left]:w-3/4 data-[side=left]:border-r data-[side=right]:inset-y-0 data-[side=right]:right-0 data-[side=right]:h-full data-[side=right]:w-3/4 data-[side=right]:border-l data-[side=top]:inset-x-0 data-[side=top]:top-0 data-[side=top]:h-auto data-[side=top]:border-b data-[side=left]:sm:max-w-sm data-[side=right]:sm:max-w-sm ", className);
199
+ t5 = cn("fixed z-50 flex flex-col gap-4 overflow-y-auto overscroll-contain data-[side=bottom]:max-h-dvh data-[side=top]:max-h-dvh bg-background bg-clip-padding text-sm shadow-lg data-[side=bottom]:inset-x-0 data-[side=bottom]:bottom-0 data-[side=bottom]:h-auto data-[side=bottom]:border-t data-[side=left]:inset-y-0 data-[side=left]:left-0 data-[side=left]:h-full data-[side=left]:w-3/4 data-[side=left]:border-r data-[side=right]:inset-y-0 data-[side=right]:right-0 data-[side=right]:h-full data-[side=right]:w-3/4 data-[side=right]:border-l data-[side=top]:inset-x-0 data-[side=top]:top-0 data-[side=top]:h-auto data-[side=top]:border-b data-[side=left]:sm:max-w-sm data-[side=right]:sm:max-w-sm ", className);
200
200
  $[7] = className;
201
201
  $[8] = t5;
202
202
  } else {
@@ -207,14 +207,17 @@ function SheetContent(t0) {
207
207
  t6 = showCloseButton && /* @__PURE__ */ _jsx(SheetPrimitive.Close, {
208
208
  "data-slot": "sheet-close",
209
209
  asChild: true,
210
- children: /* @__PURE__ */ _jsxs(Button, {
211
- variant: "ghost",
212
- className: "absolute top-4 right-4",
213
- size: "icon-sm",
214
- children: [/* @__PURE__ */ _jsx(XIcon, {}), /* @__PURE__ */ _jsx("span", {
215
- className: "sr-only",
216
- children: "Close"
217
- })]
210
+ children: /* @__PURE__ */ _jsx(MotionSlot, {
211
+ kind: "delayed-pop",
212
+ children: /* @__PURE__ */ _jsxs(Button, {
213
+ variant: "ghost",
214
+ className: "absolute top-4 right-4",
215
+ size: "icon-sm",
216
+ children: [/* @__PURE__ */ _jsx(XIcon, {}), /* @__PURE__ */ _jsx("span", {
217
+ className: "sr-only",
218
+ children: "Close"
219
+ })]
220
+ })
218
221
  })
219
222
  });
220
223
  $[9] = showCloseButton;
@@ -7,6 +7,7 @@ import { useIsMobile } from "../hooks/use-mobile.js";
7
7
  import { useSidebarPersistence, saveSidebarPreference } from "../hooks/use-sidebar-persistence.js";
8
8
  import { GlideSlot } from "../motion/glide-slot.js";
9
9
  import { MotionSlot } from "../motion/motion-slot.js";
10
+ import { MOTION_EASE_DRAWER } from "../motion/tokens.js";
10
11
  import { cn } from "../lib/utils.js";
11
12
  import { SIDEBAR_COOKIE_MAX_AGE, SIDEBAR_COOKIE_NAME } from "../constants/sidebar.js";
12
13
  import { Button } from "./button.js";
@@ -21,6 +22,8 @@ const SIDEBAR_WIDTH = "16rem";
21
22
  const SIDEBAR_WIDTH_MOBILE = "18rem";
22
23
  const SIDEBAR_WIDTH_ICON = "3rem";
23
24
  const SIDEBAR_KEYBOARD_SHORTCUT = "b";
25
+ /** Drawer curve shared by the collapse transitions: quick start, long gentle settle. */
26
+ const SIDEBAR_EASE = `cubic-bezier(${MOTION_EASE_DRAWER.join(", ")})`;
24
27
  const SIDEBAR_MENU_SKELETON_TEXT_WIDTH = "70%";
25
28
  function subscribeToClientMount() {
26
29
  return () => {};
@@ -158,6 +161,7 @@ function SidebarProvider(t0) {
158
161
  t7 = {
159
162
  "--sidebar-width": SIDEBAR_WIDTH,
160
163
  "--sidebar-width-icon": SIDEBAR_WIDTH_ICON,
164
+ "--sidebar-ease": SIDEBAR_EASE,
161
165
  ...style
162
166
  };
163
167
  $[26] = style;
@@ -339,7 +343,7 @@ function Sidebar(t0) {
339
343
  const t5 = variant === "floating" || variant === "inset" ? "group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+(--spacing(4)))]" : "group-data-[collapsible=icon]:w-(--sidebar-width-icon)";
340
344
  let t6;
341
345
  if ($[27] !== t5) {
342
- t6 = cn("relative w-(--sidebar-width) bg-transparent transition-[width] duration-200 ease-linear", "group-data-[collapsible=offcanvas]:w-0", "group-data-[side=right]:rotate-180", t5);
346
+ t6 = cn("relative w-(--sidebar-width) bg-transparent transition-[width] duration-300 ease-(--sidebar-ease)", "group-data-[collapsible=offcanvas]:w-0", "group-data-[side=right]:rotate-180", t5);
343
347
  $[27] = t5;
344
348
  $[28] = t6;
345
349
  } else {
@@ -359,7 +363,7 @@ function Sidebar(t0) {
359
363
  const t8 = variant === "floating" || variant === "inset" ? "p-2 group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+(--spacing(4))+2px)]" : "group-data-[collapsible=icon]:w-(--sidebar-width-icon) group-data-[side=left]:border-r group-data-[side=right]:border-l";
360
364
  let t9;
361
365
  if ($[31] !== className || $[32] !== t8) {
362
- t9 = cn("fixed inset-y-0 z-10 hidden h-svh w-(--sidebar-width) transition-[left,right,width] duration-200 ease-linear data-[side=left]:left-0 data-[side=left]:group-data-[collapsible=offcanvas]:left-[calc(var(--sidebar-width)*-1)] data-[side=right]:right-0 data-[side=right]:group-data-[collapsible=offcanvas]:right-[calc(var(--sidebar-width)*-1)] md:flex", t8, className);
366
+ t9 = cn("fixed inset-y-0 z-10 hidden h-svh w-(--sidebar-width) transition-[left,right,width] duration-300 ease-(--sidebar-ease) data-[side=left]:left-0 data-[side=left]:group-data-[collapsible=offcanvas]:left-[calc(var(--sidebar-width)*-1)] data-[side=right]:right-0 data-[side=right]:group-data-[collapsible=offcanvas]:right-[calc(var(--sidebar-width)*-1)] md:flex", t8, className);
363
367
  $[31] = className;
364
368
  $[32] = t8;
365
369
  $[33] = t9;
@@ -507,7 +511,7 @@ function SidebarRail(t0) {
507
511
  const { toggleSidebar } = useSidebar();
508
512
  let t1;
509
513
  if ($[3] !== className) {
510
- t1 = cn("absolute inset-y-0 z-20 hidden w-4 transition-all ease-linear group-data-[side=left]:-right-4 group-data-[side=right]:left-0 after:absolute after:inset-y-0 after:start-1/2 after:w-[2px] hover:after:bg-sidebar-border sm:flex ltr:-translate-x-1/2 rtl:-translate-x-1/2", "in-data-[side=left]:cursor-w-resize in-data-[side=right]:cursor-e-resize", "[[data-side=left][data-state=collapsed]_&]:cursor-e-resize [[data-side=right][data-state=collapsed]_&]:cursor-w-resize", "group-data-[collapsible=offcanvas]:translate-x-0 group-data-[collapsible=offcanvas]:after:left-full hover:group-data-[collapsible=offcanvas]:bg-sidebar", "[[data-side=left][data-collapsible=offcanvas]_&]:-right-2", "[[data-side=right][data-collapsible=offcanvas]_&]:-left-2", className);
514
+ t1 = cn("absolute inset-y-0 z-20 hidden w-4 transition-all duration-300 ease-(--sidebar-ease) group-data-[side=left]:-right-4 group-data-[side=right]:left-0 after:absolute after:inset-y-0 after:start-1/2 after:w-[2px] hover:after:bg-sidebar-border sm:flex ltr:-translate-x-1/2 rtl:-translate-x-1/2", "in-data-[side=left]:cursor-w-resize in-data-[side=right]:cursor-e-resize", "[[data-side=left][data-state=collapsed]_&]:cursor-e-resize [[data-side=right][data-state=collapsed]_&]:cursor-w-resize", "group-data-[collapsible=offcanvas]:translate-x-0 group-data-[collapsible=offcanvas]:after:left-full hover:group-data-[collapsible=offcanvas]:bg-sidebar", "[[data-side=left][data-collapsible=offcanvas]_&]:-right-2", "[[data-side=right][data-collapsible=offcanvas]_&]:-left-2", className);
511
515
  $[3] = className;
512
516
  $[4] = t1;
513
517
  } else {
@@ -812,7 +816,7 @@ function SidebarGroupLabel(t0) {
812
816
  const Comp = asChild ? Slot.Root : "div";
813
817
  let t2;
814
818
  if ($[4] !== className) {
815
- t2 = cn("flex h-8 shrink-0 items-center rounded-md px-2 text-xs font-medium text-sidebar-foreground/70 ring-sidebar-ring outline-hidden transition-[margin,opacity] duration-200 ease-linear group-data-[collapsible=icon]:-mt-8 group-data-[collapsible=icon]:opacity-0 focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0", className);
819
+ t2 = cn("flex h-8 shrink-0 items-center rounded-md px-2 text-xs font-medium text-sidebar-foreground/70 ring-sidebar-ring outline-hidden transition-[margin,opacity] duration-300 ease-(--sidebar-ease) group-data-[collapsible=icon]:-mt-8 group-data-[collapsible=icon]:opacity-0 focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0", className);
816
820
  $[4] = className;
817
821
  $[5] = t2;
818
822
  } else {
@@ -996,7 +1000,7 @@ const sidebarMenuButtonVariants = cva("peer/menu-button group/menu-button flex w
996
1000
  variants: {
997
1001
  variant: {
998
1002
  default: "hover:bg-sidebar-accent hover:text-sidebar-accent-foreground",
999
- outline: "bg-background shadow-[0_0_0_1px_hsl(var(--sidebar-border))] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground hover:shadow-[0_0_0_1px_hsl(var(--sidebar-accent))]"
1003
+ outline: "bg-background shadow-[0_0_0_1px_var(--sidebar-border)] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground hover:shadow-[0_0_0_1px_var(--sidebar-accent)]"
1000
1004
  },
1001
1005
  size: {
1002
1006
  default: "h-8 text-sm",
@@ -1,2 +1,8 @@
1
+ /**
2
+ * Placeholder with a soft shine that sweeps across it while content loads.
3
+ * The shine rests outside the box, so reduced motion shows a plain muted block.
4
+ * @param props - Native div properties and optional consumer overrides.
5
+ * @returns The placeholder element with its loading animation.
6
+ */
1
7
  declare function Skeleton({ className, ...props }: React.ComponentProps<"div">): import("react").JSX.Element;
2
8
  export { Skeleton };
@@ -1,12 +1,18 @@
1
1
  import { MotionSlot } from "../motion/motion-slot.js";
2
2
  import { cn } from "../lib/utils.js";
3
3
  import { jsx as _jsx } from "react/jsx-runtime";
4
+ /**
5
+ * Placeholder with a soft shine that sweeps across it while content loads.
6
+ * The shine rests outside the box, so reduced motion shows a plain muted block.
7
+ * @param props - Native div properties and optional consumer overrides.
8
+ * @returns The placeholder element with its loading animation.
9
+ */
4
10
  function Skeleton({ className, ...props }) {
5
11
  return /* @__PURE__ */ _jsx(MotionSlot, {
6
12
  kind: "skeleton",
7
13
  children: /* @__PURE__ */ _jsx("div", {
8
14
  "data-slot": "skeleton",
9
- className: cn("rounded-md bg-muted", className),
15
+ className: cn("relative overflow-hidden rounded-md bg-muted after:pointer-events-none after:absolute after:inset-0 after:-translate-x-full after:bg-linear-to-r after:from-transparent after:via-foreground/6 after:to-transparent", className),
10
16
  ...props
11
17
  })
12
18
  });
@@ -36,7 +36,7 @@ function Switch(t0) {
36
36
  kind: "thumb",
37
37
  children: /* @__PURE__ */ _jsx(SwitchPrimitive.Thumb, {
38
38
  "data-slot": "switch-thumb",
39
- className: "pointer-events-none block rounded-full bg-background ring-0 group-data-[size=default]/switch:size-4 group-data-[size=sm]/switch:size-3 group-data-[size=default]/switch:data-checked:translate-x-[calc(100%-2px)] group-data-[size=sm]/switch:data-checked:translate-x-[calc(100%-2px)] dark:data-checked:bg-primary-foreground group-data-[size=default]/switch:data-unchecked:translate-x-0 group-data-[size=sm]/switch:data-unchecked:translate-x-0 dark:data-unchecked:bg-foreground"
39
+ className: "pointer-events-none block rounded-full bg-background shadow-sm ring-0 group-data-[size=default]/switch:size-4 group-data-[size=sm]/switch:size-3 group-data-[size=default]/switch:data-checked:translate-x-[calc(100%-2px)] group-data-[size=sm]/switch:data-checked:translate-x-[calc(100%-2px)] dark:data-checked:bg-primary-foreground group-data-[size=default]/switch:data-unchecked:translate-x-0 group-data-[size=sm]/switch:data-unchecked:translate-x-0 dark:data-unchecked:bg-foreground"
40
40
  })
41
41
  });
42
42
  $[6] = t3;
@@ -12,7 +12,7 @@ function Textarea({ className, ...props }) {
12
12
  kind: "field",
13
13
  children: /* @__PURE__ */ _jsx("textarea", {
14
14
  "data-slot": "textarea",
15
- className: cn("flex field-sizing-content min-h-16 w-full rounded-lg border border-input bg-transparent px-2.5 py-2 text-base transition-colors outline-none placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:bg-input/50 disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 md:text-sm dark:bg-input/30 dark:disabled:bg-input/80 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40", className),
15
+ className: cn("flex field-sizing-content min-h-16 w-full rounded-lg border border-input bg-transparent px-2.5 py-2 text-base transition-[color,background-color,border-color,box-shadow] outline-none placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:bg-input/50 disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 md:text-sm dark:bg-input/30 dark:disabled:bg-input/80 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40", className),
16
16
  ...props
17
17
  })
18
18
  });