@exsto/ds 0.0.1-rc.1 → 0.0.1-rc.10

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 (148) hide show
  1. package/README.md +108 -27
  2. package/dist/chunks/date-range-picker-CWVcHgy2.js +204 -0
  3. package/dist/chunks/date-range-picker-CWVcHgy2.js.map +1 -0
  4. package/dist/chunks/input-syWxjY2U.js +172 -0
  5. package/dist/chunks/input-syWxjY2U.js.map +1 -0
  6. package/dist/chunks/toggle-CVnIkJVC.js +484 -0
  7. package/dist/chunks/toggle-CVnIkJVC.js.map +1 -0
  8. package/dist/date-picker.js +345 -0
  9. package/dist/date-picker.js.map +1 -0
  10. package/dist/ds/src/date-picker.d.ts +9 -0
  11. package/dist/ds/src/index.d.ts +2 -3
  12. package/dist/ds/src/rich-text-editor.d.ts +8 -0
  13. package/dist/index.js +4512 -2
  14. package/dist/index.js.map +1 -0
  15. package/dist/rich-text-editor.js +905 -0
  16. package/dist/rich-text-editor.js.map +1 -0
  17. package/dist/styles.css +915 -234
  18. package/dist/theme.css +308 -0
  19. package/dist/theme.css.d.ts +2 -0
  20. package/dist/ui/src/components/edyn/animated-number/animated-number.d.ts +30 -0
  21. package/dist/ui/src/components/edyn/animated-number/animated-number.test.d.ts +9 -0
  22. package/dist/ui/src/components/edyn/animated-number/index.d.ts +1 -0
  23. package/dist/ui/src/components/edyn/audio-player/audio-player.d.ts +3 -2
  24. package/dist/ui/src/components/edyn/date-picker/date-picker.d.ts +76 -0
  25. package/dist/ui/src/components/edyn/date-picker/date-picker.state.test.d.ts +9 -0
  26. package/dist/ui/src/components/edyn/date-picker/date-text.d.ts +40 -0
  27. package/dist/ui/src/components/edyn/date-picker/index.d.ts +2 -0
  28. package/dist/ui/src/components/edyn/date-range-picker/date-range-picker.d.ts +28 -0
  29. package/dist/ui/src/components/edyn/date-range-picker/date-range-picker.test.d.ts +9 -0
  30. package/dist/ui/src/components/edyn/date-range-picker/index.d.ts +1 -0
  31. package/dist/ui/src/components/edyn/initials-avatar/index.d.ts +1 -0
  32. package/dist/ui/src/components/edyn/initials-avatar/initials-avatar.d.ts +54 -0
  33. package/dist/ui/src/components/edyn/initials-avatar/initials-avatar.test.d.ts +10 -0
  34. package/dist/ui/src/components/edyn/multi-select/index.d.ts +1 -0
  35. package/dist/ui/src/components/edyn/multi-select/multi-select.d.ts +106 -0
  36. package/dist/ui/src/components/edyn/multi-select/multi-select.test.d.ts +9 -0
  37. package/dist/ui/src/components/edyn/progress-line/index.d.ts +1 -0
  38. package/dist/ui/src/components/edyn/progress-line/progress-line.d.ts +23 -0
  39. package/dist/ui/src/components/edyn/progress-line/progress-line.test.d.ts +9 -0
  40. package/dist/ui/src/components/edyn/rich-text-content/allow-list.d.ts +11 -0
  41. package/dist/ui/src/components/edyn/rich-text-content/index.d.ts +2 -0
  42. package/dist/ui/src/components/edyn/rich-text-content/rich-text-content.d.ts +22 -0
  43. package/dist/ui/src/components/edyn/rich-text-content/rich-text-content.test.d.ts +8 -0
  44. package/dist/ui/src/components/edyn/rich-text-editor/extensions.d.ts +18 -0
  45. package/dist/ui/src/components/edyn/rich-text-editor/index.d.ts +3 -0
  46. package/dist/ui/src/components/edyn/rich-text-editor/mention-list.d.ts +17 -0
  47. package/dist/ui/src/components/edyn/rich-text-editor/rich-text-editor.d.ts +53 -0
  48. package/dist/ui/src/components/edyn/rich-text-editor/rich-text-editor.test.d.ts +6 -0
  49. package/dist/ui/src/components/edyn/rich-text-editor/serialize.d.ts +13 -0
  50. package/dist/ui/src/components/edyn/rich-text-editor/sync.d.ts +19 -0
  51. package/dist/ui/src/components/edyn/rich-text-editor/sync.test.d.ts +11 -0
  52. package/dist/ui/src/components/edyn/rich-text-editor/toolbar.d.ts +20 -0
  53. package/dist/ui/src/components/edyn/rich-text-editor/types.d.ts +68 -0
  54. package/dist/ui/src/components/edyn/video-player/video-player.d.ts +2 -2
  55. package/dist/ui/src/components/forwarded-props.test.d.ts +8 -0
  56. package/dist/ui/src/components/ui/accordion/accordion.d.ts +9 -8
  57. package/dist/ui/src/components/ui/attachment/attachment.d.ts +1 -1
  58. package/dist/ui/src/components/ui/badge/badge.d.ts +1 -1
  59. package/dist/ui/src/components/ui/button/button.behavior.test.d.ts +8 -0
  60. package/dist/ui/src/components/ui/button/button.d.ts +1 -1
  61. package/dist/ui/src/components/ui/command/command.d.ts +17 -1
  62. package/dist/ui/src/components/ui/dropdown-menu/dropdown-menu.d.ts +12 -1
  63. package/dist/ui/src/components/ui/input-group/input-group.d.ts +1 -1
  64. package/dist/ui/src/components/ui/item/item.d.ts +1 -1
  65. package/dist/ui/src/components/ui/pagination/pagination.d.ts +3 -2
  66. package/dist/ui/src/components/ui/popover/popover.d.ts +1 -1
  67. package/dist/ui/src/components/ui/progress/progress.behavior.test.d.ts +8 -0
  68. package/dist/ui/src/components/ui/progress/progress.d.ts +43 -1
  69. package/dist/ui/src/components/ui/scroll-area/scroll-area.behavior.test.d.ts +12 -0
  70. package/dist/ui/src/components/ui/scroll-area/scroll-area.d.ts +59 -6
  71. package/dist/ui/src/components/ui/separator/separator.behavior.test.d.ts +14 -0
  72. package/dist/ui/src/components/ui/separator/separator.d.ts +14 -0
  73. package/dist/ui/src/components/ui/table/table.behavior.test.d.ts +4 -5
  74. package/dist/ui/src/components/ui/tabs/tabs.d.ts +9 -8
  75. package/dist/ui/src/index.d.ts +6 -0
  76. package/dist/ui/src/lib/first-weekday.d.ts +6 -0
  77. package/dist/ui/src/lib/focus-ring.test.d.ts +8 -0
  78. package/dist/ui/src/lib/popup-list.d.ts +47 -0
  79. package/dist/ui/src/lib/popup-list.test.d.ts +10 -0
  80. package/package.json +31 -8
  81. package/dist/chunks/toggle-group-ByNq8g7H.js +0 -4263
  82. package/dist/chunks/toggle-group-ByNq8g7H.js.map +0 -1
  83. package/dist/dom/src/context.d.ts +0 -34
  84. package/dist/dom/src/define-element.d.ts +0 -11
  85. package/dist/dom/src/field-control.d.ts +0 -5
  86. package/dist/dom/src/index.d.ts +0 -6
  87. package/dist/dom/src/mode.d.ts +0 -8
  88. package/dist/dom/src/styles.d.ts +0 -6
  89. package/dist/dom/src/theme-state.d.ts +0 -1
  90. package/dist/dom/src/types.d.ts +0 -65
  91. package/dist/ds/src/elements.d.ts +0 -12
  92. package/dist/elements/src/edx-accordion.d.ts +0 -14
  93. package/dist/elements/src/edx-accordion.test.d.ts +0 -1
  94. package/dist/elements/src/edx-alert.d.ts +0 -14
  95. package/dist/elements/src/edx-audio-player.d.ts +0 -11
  96. package/dist/elements/src/edx-avatar.d.ts +0 -10
  97. package/dist/elements/src/edx-badge.d.ts +0 -12
  98. package/dist/elements/src/edx-breadcrumb.d.ts +0 -11
  99. package/dist/elements/src/edx-button-group.d.ts +0 -7
  100. package/dist/elements/src/edx-button.d.ts +0 -20
  101. package/dist/elements/src/edx-calendar.d.ts +0 -21
  102. package/dist/elements/src/edx-card.d.ts +0 -8
  103. package/dist/elements/src/edx-checkbox.d.ts +0 -18
  104. package/dist/elements/src/edx-combobox.d.ts +0 -28
  105. package/dist/elements/src/edx-content-components.d.ts +0 -2
  106. package/dist/elements/src/edx-dialog.d.ts +0 -20
  107. package/dist/elements/src/edx-drawer.d.ts +0 -21
  108. package/dist/elements/src/edx-dropdown-menu.d.ts +0 -29
  109. package/dist/elements/src/edx-field.d.ts +0 -9
  110. package/dist/elements/src/edx-field.test.d.ts +0 -1
  111. package/dist/elements/src/edx-indicator.d.ts +0 -14
  112. package/dist/elements/src/edx-input-group.d.ts +0 -32
  113. package/dist/elements/src/edx-input-otp.d.ts +0 -19
  114. package/dist/elements/src/edx-input.d.ts +0 -31
  115. package/dist/elements/src/edx-interactive-components.d.ts +0 -2
  116. package/dist/elements/src/edx-label.d.ts +0 -6
  117. package/dist/elements/src/edx-pagination.d.ts +0 -8
  118. package/dist/elements/src/edx-popover.d.ts +0 -24
  119. package/dist/elements/src/edx-progress.d.ts +0 -10
  120. package/dist/elements/src/edx-radio-group.d.ts +0 -22
  121. package/dist/elements/src/edx-radio-group.test.d.ts +0 -1
  122. package/dist/elements/src/edx-scroll-area.d.ts +0 -15
  123. package/dist/elements/src/edx-scroll-area.test.d.ts +0 -1
  124. package/dist/elements/src/edx-select.d.ts +0 -34
  125. package/dist/elements/src/edx-separator.d.ts +0 -10
  126. package/dist/elements/src/edx-skeleton.d.ts +0 -8
  127. package/dist/elements/src/edx-slider.d.ts +0 -17
  128. package/dist/elements/src/edx-slider.test.d.ts +0 -1
  129. package/dist/elements/src/edx-switch.d.ts +0 -18
  130. package/dist/elements/src/edx-table.d.ts +0 -13
  131. package/dist/elements/src/edx-table.test.d.ts +0 -1
  132. package/dist/elements/src/edx-tabs.d.ts +0 -15
  133. package/dist/elements/src/edx-tabs.test.d.ts +0 -1
  134. package/dist/elements/src/edx-textarea.d.ts +0 -25
  135. package/dist/elements/src/edx-toggle-group.d.ts +0 -27
  136. package/dist/elements/src/edx-toggle-group.test.d.ts +0 -1
  137. package/dist/elements/src/edx-toggle.d.ts +0 -18
  138. package/dist/elements/src/edx-tooltip.d.ts +0 -28
  139. package/dist/elements/src/edx-video-player.d.ts +0 -16
  140. package/dist/elements/src/field-control-bridge.d.ts +0 -7
  141. package/dist/elements/src/index.d.ts +0 -14
  142. package/dist/elements/src/projected-content.test.d.ts +0 -1
  143. package/dist/elements/src/registry.d.ts +0 -39
  144. package/dist/elements/src/registry.test.d.ts +0 -1
  145. package/dist/elements.js +0 -4020
  146. package/dist/elements.js.map +0 -1
  147. /package/dist/{dom/src/define-element.test.d.ts → ui/src/components/edyn/date-picker/date-text.test.d.ts} +0 -0
  148. /package/dist/{dom/src/native-slot.test.d.ts → ui/src/lib/first-weekday.test.d.ts} +0 -0
@@ -0,0 +1,484 @@
1
+ import { u as cn } from "./input-syWxjY2U.js";
2
+ import { createElement, useCallback, useEffect, useMemo, useRef } from "react";
3
+ import { jsx, jsxs } from "react/jsx-runtime";
4
+ import { cva } from "class-variance-authority";
5
+ import { IconCheck, IconChevronRight } from "@tabler/icons-react";
6
+ import { ScrollArea } from "@base-ui/react/scroll-area";
7
+ import { Menu } from "@base-ui/react/menu";
8
+ import { Toggle } from "@base-ui/react/toggle";
9
+ //#region ../ui/src/hooks/use-merged-refs.ts
10
+ var assignRef = (ref, value) => {
11
+ if (typeof ref === "function") ref(value);
12
+ else if (ref !== null) ref.current = value;
13
+ };
14
+ var mergeRefs = (...refs) => {
15
+ return (node) => {
16
+ for (const ref of refs) if (ref) assignRef(ref, node);
17
+ };
18
+ };
19
+ var useMergedRefs = (...refs) => {
20
+ return useCallback(mergeRefs(...refs), [...refs]);
21
+ };
22
+ //#endregion
23
+ //#region ../ui/src/components/ui/scroll-area/scroll-area.tsx
24
+ var ScrollBar = ({ className, orientation = "vertical", visibility = "hover", ...props }) => {
25
+ return /* @__PURE__ */ jsx(ScrollArea.Scrollbar, {
26
+ "data-slot": "scroll-area-scrollbar",
27
+ orientation,
28
+ className: cn("peer/scrollbar z-100 flex touch-none select-none motion-safe:transition-opacity motion-safe:duration-150", orientation === "vertical" && "h-(--scroll-bar-length) w-(--scroll-bar-size) me-(--scroll-bar-gap) mt-(--scroll-bar-offset-top) border-l border-l-transparent p-px", orientation === "horizontal" && "h-(--scroll-bar-size) ms-(--scroll-bar-gap) me-(--scroll-bar-gap) mb-(--scroll-bar-gap) flex-col border-t border-t-transparent p-px", visibility !== "always" && "opacity-0 data-scrolling:opacity-100", visibility === "hover" && "data-hovering:opacity-100 group-hover/scroll-area:opacity-100", className),
29
+ ...props,
30
+ children: /* @__PURE__ */ jsx(ScrollArea.Thumb, { className: "relative flex-1 rounded-full bg-muted-foreground/50 transition-colors hover:bg-muted-foreground/70 data-scrolling:bg-muted-foreground/70" })
31
+ });
32
+ };
33
+ /**
34
+ * Which axes fade, published for scroll-fade.css to key its mask off. The
35
+ * stylesheet reaches this element's own viewport through a child combinator, so a
36
+ * ScrollArea nested in another one cannot pick up its ancestor's edges.
37
+ */
38
+ /**
39
+ * Base UI gives the root, the viewport and the content `role="presentation"`. On
40
+ * a div that changes nothing for a screen reader, but it is an EXPLICIT role, and
41
+ * axe treats explicit presentation children as foreign to a parent that owns
42
+ * required children. A ScrollArea inside `role="menu"` or `role="listbox"` then
43
+ * fails as a critical aria-required-children violation, while the same div with
44
+ * no role passes straight through. Clearing it is what makes a ScrollArea legal
45
+ * in a popup list. A spread because the literal `role={undefined}` is flagged by
46
+ * the a11y lint rule, which cannot tell it from an invalid role.
47
+ */
48
+ var NO_ROLE = { role: void 0 };
49
+ /** Base UI makes the viewport a tab stop (0, or -1 with nothing to scroll); undefined takes that away. */
50
+ var NO_TAB_STOP = { tabIndex: void 0 };
51
+ var FADE_AXIS = {
52
+ vertical: "block",
53
+ horizontal: "inline",
54
+ both: "both"
55
+ };
56
+ /**
57
+ * Themed scroll container (Base UI): overflowing content scrolls INSIDE the component
58
+ * with a slim overlay scrollbar instead of exposing a native browser scrollbar. House
59
+ * rule: wide/tall content (tables, lists, code) always goes through this, never a bare
60
+ * overflow-* utility.
61
+ *
62
+ * Cap the height with a plain class on the component itself, e.g.
63
+ * `<ScrollArea className="max-h-88">`. The viewport picks the cap up through
64
+ * `max-h-inherit`, which matters because the viewport is the element that actually
65
+ * scrolls: a cap that lands only on the root leaves tall content spilling out
66
+ * underneath with no scrollbar, and that reads as a working height right up until the
67
+ * content outgrows it.
68
+ *
69
+ * `fade` fades out each edge that is currently hiding content, rather than always
70
+ * fading one: a permanent fade is a lie half the time, dimming the last row that fits
71
+ * and promising more below when the reader is already at the end. It is cut into the
72
+ * content by a mask (@edyn/theme/scroll-fade.css), so it needs no surface colour and
73
+ * reads correctly over a tint, a gradient or a glow. A host that keeps something
74
+ * unscrolled at the top, such as a sticky table header, exempts that band by setting
75
+ * --scroll-fade-offset on the ScrollArea. The static faded-* utilities in
76
+ * @edyn/theme/utilities.css are the other tool, for DECORATIVE edges that do not
77
+ * track scroll position.
78
+ *
79
+ * The viewport publishes its size as --scroll-area-width/--scroll-area-height CSS vars
80
+ * so children can size against the visible area.
81
+ */
82
+ var ScrollArea$1 = ({ className, children, orientation = "vertical", type = "hover", fade = false, fadeFrom = "card", scrollbarClassName, viewportId, viewportRef, viewportClassName, scrollRestorationId, focusable = true, viewPortId, viewPortRef, viewPortClassName, scrollVerticalClassName, scrollHorizontalClassName, ...props }) => {
83
+ const refInner = useRef(null);
84
+ const refsViewport = useMergedRefs(refInner, viewportRef ?? viewPortRef);
85
+ useEffect(() => {
86
+ const el = refInner.current;
87
+ if (!el) return;
88
+ const observer = new ResizeObserver(() => {
89
+ el.style.setProperty("--scroll-area-width", `${el.clientWidth}px`);
90
+ el.style.setProperty("--scroll-area-height", `${el.clientHeight}px`);
91
+ });
92
+ observer.observe(el);
93
+ return () => {
94
+ observer.disconnect();
95
+ };
96
+ }, []);
97
+ return /* @__PURE__ */ jsxs(ScrollArea.Root, {
98
+ "data-slot": "scroll-area",
99
+ "data-focus": "inset",
100
+ className: cn("group/scroll-area relative grid min-w-0 grid-rows-1 overflow-hidden", className),
101
+ "data-fade": fade ? FADE_AXIS[orientation] : void 0,
102
+ ...NO_ROLE,
103
+ ...props,
104
+ children: [
105
+ (orientation === "vertical" || orientation === "both") && /* @__PURE__ */ jsx(ScrollBar, {
106
+ orientation: "vertical",
107
+ visibility: type,
108
+ className: cn(scrollbarClassName, scrollVerticalClassName)
109
+ }),
110
+ (orientation === "horizontal" || orientation === "both") && /* @__PURE__ */ jsx(ScrollBar, {
111
+ orientation: "horizontal",
112
+ visibility: type,
113
+ className: cn(scrollbarClassName, scrollHorizontalClassName)
114
+ }),
115
+ /* @__PURE__ */ jsx(ScrollArea.Corner, {}),
116
+ /* @__PURE__ */ jsx(ScrollArea.Viewport, {
117
+ "data-slot": "scroll-area-viewport",
118
+ id: viewportId ?? viewPortId,
119
+ ref: refsViewport,
120
+ "data-scroll-restoration-id": scrollRestorationId,
121
+ ...NO_ROLE,
122
+ ...focusable ? null : NO_TAB_STOP,
123
+ className: cn("max-h-inherit w-full rounded-[inherit]", orientation === "vertical" && "overflow-x-hidden!", orientation === "horizontal" && "overflow-y-hidden!", viewportClassName ?? viewPortClassName),
124
+ children: /* @__PURE__ */ jsx(ScrollArea.Content, {
125
+ ...NO_ROLE,
126
+ style: orientation === "vertical" ? { minWidth: 0 } : void 0,
127
+ children
128
+ })
129
+ })
130
+ ]
131
+ });
132
+ };
133
+ //#endregion
134
+ //#region ../ui/src/lib/popup-list.ts
135
+ var ITEM_BASE = "relative flex min-h-8 cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm text-foreground outline-none select-none [&>svg]:pointer-events-none [&>svg]:shrink-0 [&>svg]:text-muted-foreground [&>svg:not([class*='size-'])]:size-4";
136
+ var ITEM_STATES = {
137
+ "base-ui": "data-highlighted:bg-foreground/6 data-highlighted:[&>svg]:text-foreground data-[selected]:font-medium data-disabled:pointer-events-none data-disabled:opacity-50",
138
+ cmdk: "data-[selected=true]:bg-foreground/6 data-[selected=true]:[&>svg]:text-foreground data-[checked=true]:font-medium data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50"
139
+ };
140
+ /** The shared item look. `checkable` leaves room at the end for the check. */
141
+ var popupItemClass = (flavor = "base-ui", checkable = false) => cn(ITEM_BASE, ITEM_STATES[flavor], checkable && "pr-8");
142
+ /**
143
+ * The check's slot, at the end of the item and the same size whether or not the
144
+ * check is in it, so a list does not shift as the choice moves.
145
+ */
146
+ var POPUP_ITEM_INDICATOR_CLASS = "pointer-events-none absolute right-2 flex size-4 items-center justify-center text-foreground";
147
+ /** A group's heading in any of these lists. */
148
+ var POPUP_GROUP_LABEL_CLASS = "px-2 py-1.5 text-xs font-medium text-muted-foreground";
149
+ //#endregion
150
+ //#region ../ui/src/components/edyn/rich-text-content/allow-list.ts
151
+ /**
152
+ * The HTML the rich-text editor emits, and the only HTML RichTextContent renders. An app that
153
+ * sanitises on a server takes its allow-list from here: nothing outside these elements and this
154
+ * attribute ever comes out of the editor, whatever was pasted into it.
155
+ */
156
+ var RICH_TEXT_ELEMENTS = [
157
+ "p",
158
+ "br",
159
+ "hr",
160
+ "strong",
161
+ "em",
162
+ "u",
163
+ "ul",
164
+ "ol",
165
+ "li",
166
+ "a"
167
+ ];
168
+ /** The attributes each element may carry. Every other element carries none (no class, no style). */
169
+ var RICH_TEXT_ATTRIBUTES = { a: ["href"] };
170
+ /** A link must be absolute and use one of these. `javascript:`, `data:` and relative links are refused. */
171
+ var RICH_TEXT_LINK_PROTOCOLS = [
172
+ "http",
173
+ "https",
174
+ "mailto"
175
+ ];
176
+ var isAllowedRichTextHref = (href) => {
177
+ const cleaned = Array.from(href).filter((char) => char.charCodeAt(0) > 32).join("");
178
+ const colon = cleaned.indexOf(":");
179
+ if (colon < 1) return false;
180
+ const protocol = cleaned.slice(0, colon).toLowerCase();
181
+ return RICH_TEXT_LINK_PROTOCOLS.includes(protocol);
182
+ };
183
+ //#endregion
184
+ //#region ../ui/src/components/edyn/rich-text-content/rich-text-content.tsx
185
+ /**
186
+ * How rich text looks, shared by the editor and by RichTextContent so a comment reads the same while it is typed and
187
+ * after it is saved. Descendant selectors rather than classes on the elements, because the HTML that is stored carries
188
+ * no classes.
189
+ */
190
+ var RICH_TEXT_BODY_CLASS = "text-sm leading-6 wrap-break-word [&_a]:text-primary [&_a]:underline [&_a]:underline-offset-2 [&_hr]:my-3 [&_hr]:border-0 [&_hr]:border-t [&_hr]:border-border [&_ol]:list-decimal [&_ol]:ps-5 [&_p+p]:mt-2 [&_ul]:list-disc [&_ul]:ps-5 [&_ul+p]:mt-2 [&_ol+p]:mt-2 [&_p+ul]:mt-2 [&_p+ol]:mt-2";
191
+ var MENTION_PATTERN = /(?<![\w.+-])@(?:assignees\b|[A-Za-z0-9._%+-]+@[A-Za-z0-9-]+(?:\.[A-Za-z0-9-]+)+)/g;
192
+ var RICH_TEXT_MENTION_CLASS = "rounded-sm bg-primary/10 px-1 py-0.5 font-medium text-primary";
193
+ var TAG_FOR = {
194
+ b: "strong",
195
+ i: "em"
196
+ };
197
+ var KEPT = /* @__PURE__ */ new Set([
198
+ "p",
199
+ "strong",
200
+ "em",
201
+ "u",
202
+ "ul",
203
+ "ol",
204
+ "li",
205
+ "a",
206
+ "br",
207
+ "hr"
208
+ ]);
209
+ var DROPPED_WITH_CONTENT = /* @__PURE__ */ new Set([
210
+ "script",
211
+ "style",
212
+ "template",
213
+ "iframe",
214
+ "object",
215
+ "embed",
216
+ "noscript",
217
+ "svg",
218
+ "math",
219
+ "head",
220
+ "title"
221
+ ]);
222
+ var withMentions = (text, key) => {
223
+ const parts = [];
224
+ let last = 0;
225
+ for (const match of text.matchAll(MENTION_PATTERN)) {
226
+ const start = match.index ?? 0;
227
+ if (start > last) parts.push(text.slice(last, start));
228
+ parts.push(/* @__PURE__ */ jsx("span", {
229
+ "data-slot": "rich-text-mention",
230
+ className: RICH_TEXT_MENTION_CLASS,
231
+ children: match[0]
232
+ }, `${key}-${start}`));
233
+ last = start + match[0].length;
234
+ }
235
+ if (last < text.length) parts.push(text.slice(last));
236
+ return parts;
237
+ };
238
+ var toNodes = (parent, key, insideLink) => {
239
+ const out = [];
240
+ parent.childNodes.forEach((child, index) => {
241
+ const childKey = `${key}.${index}`;
242
+ if (child.nodeType === 3) {
243
+ const text = child.textContent ?? "";
244
+ out.push(...insideLink ? [text] : withMentions(text, childKey));
245
+ return;
246
+ }
247
+ if (child.nodeType !== 1) return;
248
+ const element = child;
249
+ const name = element.tagName.toLowerCase();
250
+ if (DROPPED_WITH_CONTENT.has(name)) return;
251
+ const tag = TAG_FOR[name] ?? name;
252
+ if (!KEPT.has(tag)) {
253
+ out.push(...toNodes(element, childKey, insideLink));
254
+ return;
255
+ }
256
+ if (tag === "br") {
257
+ out.push(/* @__PURE__ */ jsx("br", {}, childKey));
258
+ return;
259
+ }
260
+ if (tag === "hr") {
261
+ out.push(/* @__PURE__ */ jsx("hr", {}, childKey));
262
+ return;
263
+ }
264
+ if (tag === "a") {
265
+ const href = element.getAttribute("href") ?? "";
266
+ const inner = toNodes(element, childKey, true);
267
+ out.push(...isAllowedRichTextHref(href) ? [/* @__PURE__ */ jsx("a", {
268
+ href: href.trim(),
269
+ rel: "noopener noreferrer",
270
+ target: "_blank",
271
+ children: inner
272
+ }, childKey)] : inner);
273
+ return;
274
+ }
275
+ out.push(createElement(tag, { key: childKey }, ...toNodes(element, childKey, insideLink)));
276
+ });
277
+ return out;
278
+ };
279
+ /** The HTML as React elements, keeping only what the editor can produce. Browser only (it needs a DOM parser). */
280
+ var richTextToNodes = (html) => {
281
+ if (typeof DOMParser === "undefined" || html === "") return [];
282
+ return toNodes(new DOMParser().parseFromString(`<body>${html}`, "text/html").body, "r", false);
283
+ };
284
+ /**
285
+ * Shows rich text the editor produced (or any HTML), as the same elements the editor emits and nothing else:
286
+ * `p`, `br`, `hr`, `strong`, `em`, `u`, `ul`, `ol`, `li` and `a` with an `href` (http, https or mailto; it opens in a new tab
287
+ * with `rel="noopener noreferrer"`). Everything else is dropped and its text kept. Built as React elements, not injected
288
+ * as markup, so it is safe on HTML that has not been cleaned. A run like `@name@example.test` or `@assignees` is shown
289
+ * as a chip.
290
+ */
291
+ var RichTextContent = ({ html, className, ...props }) => {
292
+ const nodes = useMemo(() => richTextToNodes(html), [html]);
293
+ return /* @__PURE__ */ jsx("div", {
294
+ "data-slot": "rich-text-content",
295
+ className: cn(RICH_TEXT_BODY_CLASS, className),
296
+ ...props,
297
+ children: nodes
298
+ });
299
+ };
300
+ //#endregion
301
+ //#region ../ui/src/components/ui/dropdown-menu/dropdown-menu.tsx
302
+ var DropdownMenu = ({ ...props }) => {
303
+ return /* @__PURE__ */ jsx(Menu.Root, {
304
+ "data-slot": "dropdown-menu",
305
+ ...props
306
+ });
307
+ };
308
+ var DropdownMenuPortal = ({ ...props }) => {
309
+ return /* @__PURE__ */ jsx(Menu.Portal, {
310
+ "data-slot": "dropdown-menu-portal",
311
+ ...props
312
+ });
313
+ };
314
+ var DropdownMenuTrigger = ({ ...props }) => {
315
+ return /* @__PURE__ */ jsx(Menu.Trigger, {
316
+ "data-slot": "dropdown-menu-trigger",
317
+ ...props
318
+ });
319
+ };
320
+ /**
321
+ * Scrolls inside a DS ScrollArea like the other popup lists, with the bar shown
322
+ * for as long as the menu overflows and a fade on whichever end is cut off.
323
+ *
324
+ * Base UI puts `role="menu"` on this popup itself and offers no inner list part
325
+ * to move it onto, so the ScrollArea sits INSIDE the role. That is only legal
326
+ * because ScrollArea drops the `role="presentation"` Base UI gives its root,
327
+ * viewport and content: a menu may not own presentation wrappers (axe reports
328
+ * a critical aria-required-children violation), but it may own plain divs.
329
+ * e2e/a11y.spec.ts scans the open menu in both themes to keep it that way.
330
+ */
331
+ var DropdownMenuContent = ({ align = "start", alignOffset = 0, side = "bottom", sideOffset = 4, className, children, ...props }) => {
332
+ return /* @__PURE__ */ jsx(Menu.Portal, { children: /* @__PURE__ */ jsx(Menu.Positioner, {
333
+ className: "isolate z-50 outline-none",
334
+ align,
335
+ alignOffset,
336
+ side,
337
+ sideOffset,
338
+ children: /* @__PURE__ */ jsx(Menu.Popup, {
339
+ "data-slot": "dropdown-menu-content",
340
+ className: cn("z-50 max-h-(--available-height) w-(--anchor-width) min-w-32 origin-(--transform-origin) overflow-hidden rounded-lg bg-popover text-popover-foreground shadow-md ring-1 ring-foreground/10 duration-100 outline-none data-[side=bottom]:slide-in-from-top-2 data-[side=inline-end]:slide-in-from-left-2 data-[side=inline-start]:slide-in-from-right-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:overflow-hidden data-closed:fade-out-0 data-closed:zoom-out-95", "motion-reduce:animate-none", className),
341
+ ...props,
342
+ children: /* @__PURE__ */ jsx(ScrollArea$1, {
343
+ type: "always",
344
+ fade: true,
345
+ focusable: false,
346
+ className: "max-h-inherit",
347
+ children: /* @__PURE__ */ jsx("div", {
348
+ className: "p-1",
349
+ children
350
+ })
351
+ })
352
+ })
353
+ }) });
354
+ };
355
+ var DropdownMenuGroup = ({ ...props }) => {
356
+ return /* @__PURE__ */ jsx(Menu.Group, {
357
+ "data-slot": "dropdown-menu-group",
358
+ ...props
359
+ });
360
+ };
361
+ var DropdownMenuLabel = ({ className, inset, ...props }) => {
362
+ return /* @__PURE__ */ jsx(Menu.GroupLabel, {
363
+ "data-slot": "dropdown-menu-label",
364
+ "data-inset": inset,
365
+ className: cn(POPUP_GROUP_LABEL_CLASS, "data-[inset=true]:pl-7", className),
366
+ ...props
367
+ });
368
+ };
369
+ var DropdownMenuItem = ({ className, inset, variant = "default", ...props }) => {
370
+ return /* @__PURE__ */ jsx(Menu.Item, {
371
+ "data-slot": "dropdown-menu-item",
372
+ "data-inset": inset,
373
+ "data-variant": variant,
374
+ className: cn("group/dropdown-menu-item", popupItemClass(), "data-[inset=true]:pl-7", "data-[variant=destructive]:text-destructive data-[variant=destructive]:[&>svg]:text-destructive", "data-[variant=destructive]:data-highlighted:bg-destructive/10 data-[variant=destructive]:data-highlighted:text-destructive", className),
375
+ ...props
376
+ });
377
+ };
378
+ var DropdownMenuSub = ({ ...props }) => {
379
+ return /* @__PURE__ */ jsx(Menu.SubmenuRoot, {
380
+ "data-slot": "dropdown-menu-sub",
381
+ ...props
382
+ });
383
+ };
384
+ var DropdownMenuSubTrigger = ({ className, inset, children, ...props }) => {
385
+ return /* @__PURE__ */ jsxs(Menu.SubmenuTrigger, {
386
+ "data-slot": "dropdown-menu-sub-trigger",
387
+ "data-inset": inset,
388
+ className: cn(popupItemClass(), "data-[inset=true]:pl-7 data-popup-open:bg-foreground/6 data-popup-open:[&>svg]:text-foreground", className),
389
+ ...props,
390
+ children: [children, /* @__PURE__ */ jsx(IconChevronRight, { className: "ml-auto" })]
391
+ });
392
+ };
393
+ var DropdownMenuSubContent = ({ align = "start", alignOffset = -3, side = "right", sideOffset = 0, className, ...props }) => {
394
+ return /* @__PURE__ */ jsx(DropdownMenuContent, {
395
+ "data-slot": "dropdown-menu-sub-content",
396
+ className: cn("w-auto min-w-[96px] rounded-lg bg-popover p-1 text-popover-foreground shadow-lg ring-1 ring-foreground/10 duration-100 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95", "motion-reduce:animate-none", className),
397
+ align,
398
+ alignOffset,
399
+ side,
400
+ sideOffset,
401
+ ...props
402
+ });
403
+ };
404
+ var DropdownMenuCheckboxItem = ({ className, children, checked, inset, ...props }) => {
405
+ return /* @__PURE__ */ jsxs(Menu.CheckboxItem, {
406
+ "data-slot": "dropdown-menu-checkbox-item",
407
+ "data-inset": inset,
408
+ className: cn(popupItemClass("base-ui", true), "data-checked:font-medium data-[inset=true]:pl-7", className),
409
+ checked,
410
+ ...props,
411
+ children: [/* @__PURE__ */ jsx("span", {
412
+ className: POPUP_ITEM_INDICATOR_CLASS,
413
+ "data-slot": "dropdown-menu-checkbox-item-indicator",
414
+ children: /* @__PURE__ */ jsx(Menu.CheckboxItemIndicator, { children: /* @__PURE__ */ jsx(IconCheck, {}) })
415
+ }), children]
416
+ });
417
+ };
418
+ var DropdownMenuRadioGroup = ({ ...props }) => {
419
+ return /* @__PURE__ */ jsx(Menu.RadioGroup, {
420
+ "data-slot": "dropdown-menu-radio-group",
421
+ ...props
422
+ });
423
+ };
424
+ var DropdownMenuRadioItem = ({ className, children, inset, ...props }) => {
425
+ return /* @__PURE__ */ jsxs(Menu.RadioItem, {
426
+ "data-slot": "dropdown-menu-radio-item",
427
+ "data-inset": inset,
428
+ className: cn(popupItemClass("base-ui", true), "data-checked:font-medium data-[inset=true]:pl-7", className),
429
+ ...props,
430
+ children: [/* @__PURE__ */ jsx("span", {
431
+ className: POPUP_ITEM_INDICATOR_CLASS,
432
+ "data-slot": "dropdown-menu-radio-item-indicator",
433
+ children: /* @__PURE__ */ jsx(Menu.RadioItemIndicator, { children: /* @__PURE__ */ jsx(IconCheck, {}) })
434
+ }), children]
435
+ });
436
+ };
437
+ var DropdownMenuSeparator = ({ className, ...props }) => {
438
+ return /* @__PURE__ */ jsx(Menu.Separator, {
439
+ "data-slot": "dropdown-menu-separator",
440
+ className: cn("-mx-1 my-1 h-px bg-border", className),
441
+ ...props
442
+ });
443
+ };
444
+ var DropdownMenuShortcut = ({ className, ...props }) => {
445
+ return /* @__PURE__ */ jsx("span", {
446
+ "data-slot": "dropdown-menu-shortcut",
447
+ className: cn("ml-auto text-xs tracking-widest text-muted-foreground group-focus/dropdown-menu-item:text-accent-foreground", className),
448
+ ...props
449
+ });
450
+ };
451
+ //#endregion
452
+ //#region ../ui/src/components/ui/toggle/toggle.tsx
453
+ var toggleVariants = cva("inline-flex shrink-0 cursor-pointer items-center justify-center gap-1.5 rounded-lg border border-transparent text-sm font-medium whitespace-nowrap transition-all outline-none select-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 data-pressed:text-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*=\"size-\"])]:size-4", {
454
+ variants: {
455
+ variant: {
456
+ default: "bg-transparent hover:bg-muted hover:text-foreground data-pressed:bg-muted",
457
+ outline: "border-border bg-background hover:bg-muted hover:text-foreground data-pressed:bg-muted dark:border-input dark:bg-input/30 dark:hover:bg-input/50"
458
+ },
459
+ size: {
460
+ sm: "h-7 px-2.5 text-[0.8rem]",
461
+ default: "h-8 px-2.5",
462
+ lg: "h-9 px-3"
463
+ }
464
+ },
465
+ defaultVariants: {
466
+ variant: "default",
467
+ size: "default"
468
+ }
469
+ });
470
+ var Toggle$1 = ({ className, variant = "default", size = "default", ...props }) => {
471
+ return /* @__PURE__ */ jsx(Toggle, {
472
+ "data-slot": "toggle",
473
+ className: cn(toggleVariants({
474
+ variant,
475
+ size,
476
+ className
477
+ })),
478
+ ...props
479
+ });
480
+ };
481
+ //#endregion
482
+ export { useMergedRefs as A, RICH_TEXT_ELEMENTS as C, popupItemClass as D, POPUP_ITEM_INDICATOR_CLASS as E, ScrollArea$1 as O, RICH_TEXT_ATTRIBUTES as S, isAllowedRichTextHref as T, DropdownMenuTrigger as _, DropdownMenuContent as a, RichTextContent as b, DropdownMenuLabel as c, DropdownMenuRadioItem as d, DropdownMenuSeparator as f, DropdownMenuSubTrigger as g, DropdownMenuSubContent as h, DropdownMenuCheckboxItem as i, ScrollBar as k, DropdownMenuPortal as l, DropdownMenuSub as m, toggleVariants as n, DropdownMenuGroup as o, DropdownMenuShortcut as p, DropdownMenu as r, DropdownMenuItem as s, Toggle$1 as t, DropdownMenuRadioGroup as u, RICH_TEXT_BODY_CLASS as v, RICH_TEXT_LINK_PROTOCOLS as w, richTextToNodes as x, RICH_TEXT_MENTION_CLASS as y };
483
+
484
+ //# sourceMappingURL=toggle-CVnIkJVC.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toggle-CVnIkJVC.js","names":[],"sources":["../../../ui/src/hooks/use-merged-refs.ts","../../../ui/src/components/ui/scroll-area/scroll-area.tsx","../../../ui/src/lib/popup-list.ts","../../../ui/src/components/edyn/rich-text-content/allow-list.ts","../../../ui/src/components/edyn/rich-text-content/rich-text-content.tsx","../../../ui/src/components/ui/dropdown-menu/dropdown-menu.tsx","../../../ui/src/components/ui/toggle/toggle.tsx"],"sourcesContent":["import { type Ref, type RefCallback, useCallback } from 'react';\n\ntype TPossibleRef<T> = Ref<T> | undefined;\n\nconst assignRef = <T>(ref: TPossibleRef<T>, value: T) => {\n if (typeof ref === 'function') {\n ref(value);\n } else if (ref !== null) {\n // Using type assertion to RefObject since we know it's not null\n (ref as { current: T }).current = value;\n }\n};\n\nconst mergeRefs = <T>(...refs: TPossibleRef<T>[]) => {\n return (node: T) => {\n for (const ref of refs) {\n if (ref) {\n assignRef(ref, node);\n }\n }\n };\n};\n\nexport const useMergedRefs = <T>(...refs: TPossibleRef<T>[]) => {\n return useCallback(mergeRefs(...refs), [...refs]) as RefCallback<T>;\n};\n","import { ScrollArea as BaseScrollArea } from '@base-ui/react/scroll-area';\nimport { useMergedRefs } from '@edyn/ui/hooks/use-merged-refs';\nimport { cn } from '@edyn/ui/lib/utils';\nimport { type ComponentProps, type RefObject, useEffect, useRef } from 'react';\n\n/**\n * When the bar shows: 'hover' on area hover or while scrolling (default),\n * 'scroll' only while scrolling, 'always' permanent. In every mode the bar is\n * mounted only while that axis actually overflows, so 'always' means \"always\n * when there is something to scroll\", never a bar on a list that fits.\n */\nexport type TScrollbarVisibility = 'hover' | 'scroll' | 'always';\n\n/**\n * Surface the edge fades blended into, back when they were painted.\n *\n * @deprecated The fades are cut into the content by a mask, so they match any\n * surface without being told which one. Still accepted, and ignored.\n */\nexport type TScrollAreaFadeFrom = 'card' | 'background' | 'sidebar' | 'popover';\n\nexport interface IScrollBarProps extends ComponentProps<typeof BaseScrollArea.Scrollbar> {\n visibility?: TScrollbarVisibility;\n}\n\nexport const ScrollBar = ({ className, orientation = 'vertical', visibility = 'hover', ...props }: IScrollBarProps) => {\n return (\n <BaseScrollArea.Scrollbar\n data-slot=\"scroll-area-scrollbar\"\n orientation={orientation}\n className={cn(\n 'peer/scrollbar z-100 flex touch-none select-none motion-safe:transition-opacity motion-safe:duration-150',\n // Size, gap and start read --scroll-bar-size, --scroll-bar-gap and --scroll-bar-start (see scroll-bar.css), whose\n // defaults are the 8px bar flush with the box that it has always been.\n orientation === 'vertical' &&\n 'h-(--scroll-bar-length) w-(--scroll-bar-size) me-(--scroll-bar-gap) mt-(--scroll-bar-offset-top) border-l border-l-transparent p-px',\n orientation === 'horizontal' &&\n 'h-(--scroll-bar-size) ms-(--scroll-bar-gap) me-(--scroll-bar-gap) mb-(--scroll-bar-gap) flex-col border-t border-t-transparent p-px',\n visibility !== 'always' && 'opacity-0 data-scrolling:opacity-100',\n visibility === 'hover' && 'data-hovering:opacity-100 group-hover/scroll-area:opacity-100',\n className,\n )}\n {...props}\n >\n <BaseScrollArea.Thumb className=\"relative flex-1 rounded-full bg-muted-foreground/50 transition-colors hover:bg-muted-foreground/70 data-scrolling:bg-muted-foreground/70\" />\n </BaseScrollArea.Scrollbar>\n );\n};\n\nexport interface IScrollAreaProps extends ComponentProps<typeof BaseScrollArea.Root> {\n /** Which axes get a styled scrollbar; content decides what actually overflows. */\n orientation?: 'horizontal' | 'vertical' | 'both';\n /** Scrollbar reveal behavior (mirrors the Radix ScrollArea `type` prop). */\n type?: TScrollbarVisibility;\n /** Edge fades hinting at clipped content; each one shows only while its own edge hides something. */\n fade?: boolean;\n /**\n * @deprecated No longer read. The fades mask the content, so they sit correctly\n * on any surface; passing this does nothing and is safe to delete.\n */\n fadeFrom?: TScrollAreaFadeFrom;\n /** Places both bars, for a host that gives them a gutter of their own (a sidebar menu). */\n scrollbarClassName?: string;\n viewportId?: string;\n /** Access to the scrollable viewport (e.g. to reset scroll position on route changes). */\n viewportRef?: RefObject<HTMLDivElement | null>;\n viewportClassName?: string;\n /** Published on the viewport as data-scroll-restoration-id, for a router that restores scroll position. */\n scrollRestorationId?: string;\n /**\n * Whether the viewport is a tab stop of its own (default). Turn it off inside a\n * widget that already owns focus, a menu above all: its items are the tab\n * stops, and a focusable wrapper between the role and its items is both\n * redundant and an aria-required-children violation.\n */\n focusable?: boolean;\n /** @deprecated Use `viewportId`. */\n viewPortId?: string;\n /** @deprecated Use `viewportRef`. */\n viewPortRef?: RefObject<HTMLDivElement | null>;\n /** @deprecated Use `viewportClassName`. */\n viewPortClassName?: string;\n /** Places the vertical bar only; `scrollbarClassName` covers both. */\n scrollVerticalClassName?: string;\n /** Places the horizontal bar only; `scrollbarClassName` covers both. */\n scrollHorizontalClassName?: string;\n}\n\n/**\n * Which axes fade, published for scroll-fade.css to key its mask off. The\n * stylesheet reaches this element's own viewport through a child combinator, so a\n * ScrollArea nested in another one cannot pick up its ancestor's edges.\n */\n/**\n * Base UI gives the root, the viewport and the content `role=\"presentation\"`. On\n * a div that changes nothing for a screen reader, but it is an EXPLICIT role, and\n * axe treats explicit presentation children as foreign to a parent that owns\n * required children. A ScrollArea inside `role=\"menu\"` or `role=\"listbox\"` then\n * fails as a critical aria-required-children violation, while the same div with\n * no role passes straight through. Clearing it is what makes a ScrollArea legal\n * in a popup list. A spread because the literal `role={undefined}` is flagged by\n * the a11y lint rule, which cannot tell it from an invalid role.\n */\nconst NO_ROLE = { role: undefined } as const;\n\n/** Base UI makes the viewport a tab stop (0, or -1 with nothing to scroll); undefined takes that away. */\nconst NO_TAB_STOP = { tabIndex: undefined } as const;\n\nconst FADE_AXIS = {\n vertical: 'block',\n horizontal: 'inline',\n both: 'both',\n} as const;\n\n/**\n * Themed scroll container (Base UI): overflowing content scrolls INSIDE the component\n * with a slim overlay scrollbar instead of exposing a native browser scrollbar. House\n * rule: wide/tall content (tables, lists, code) always goes through this, never a bare\n * overflow-* utility.\n *\n * Cap the height with a plain class on the component itself, e.g.\n * `<ScrollArea className=\"max-h-88\">`. The viewport picks the cap up through\n * `max-h-inherit`, which matters because the viewport is the element that actually\n * scrolls: a cap that lands only on the root leaves tall content spilling out\n * underneath with no scrollbar, and that reads as a working height right up until the\n * content outgrows it.\n *\n * `fade` fades out each edge that is currently hiding content, rather than always\n * fading one: a permanent fade is a lie half the time, dimming the last row that fits\n * and promising more below when the reader is already at the end. It is cut into the\n * content by a mask (@edyn/theme/scroll-fade.css), so it needs no surface colour and\n * reads correctly over a tint, a gradient or a glow. A host that keeps something\n * unscrolled at the top, such as a sticky table header, exempts that band by setting\n * --scroll-fade-offset on the ScrollArea. The static faded-* utilities in\n * @edyn/theme/utilities.css are the other tool, for DECORATIVE edges that do not\n * track scroll position.\n *\n * The viewport publishes its size as --scroll-area-width/--scroll-area-height CSS vars\n * so children can size against the visible area.\n */\nexport const ScrollArea = ({\n className,\n children,\n orientation = 'vertical',\n type = 'hover',\n fade = false,\n fadeFrom = 'card',\n scrollbarClassName,\n viewportId,\n viewportRef,\n viewportClassName,\n scrollRestorationId,\n focusable = true,\n viewPortId,\n viewPortRef,\n viewPortClassName,\n scrollVerticalClassName,\n scrollHorizontalClassName,\n ...props\n}: IScrollAreaProps) => {\n const refInner = useRef<HTMLDivElement | null>(null);\n // The viewPort* spellings are the pre-rc.4 names, kept so existing callers\n // keep working; the viewport* ones match the rest of the ecosystem.\n const refsViewport = useMergedRefs(refInner, viewportRef ?? viewPortRef);\n\n useEffect(() => {\n const el = refInner.current;\n if (!el) {\n return;\n }\n const observer = new ResizeObserver(() => {\n el.style.setProperty('--scroll-area-width', `${el.clientWidth}px`);\n el.style.setProperty('--scroll-area-height', `${el.clientHeight}px`);\n });\n observer.observe(el);\n return () => {\n observer.disconnect();\n };\n }, []);\n\n return (\n <BaseScrollArea.Root\n data-slot=\"scroll-area\"\n // Everything inside clips at this box, so a focus ring drawn outside an\n // element at the edge would be cut off; see @edyn/theme/focus.css.\n data-focus=\"inset\"\n // The single-row grid is load-bearing rather than tidying. `h-full` on the viewport\n // cannot be trusted to size it: a percentage height only resolves against a definite\n // containing block, and a host that sizes this by flex inside a max-height column\n // (`min-h-0 flex-1`) is not definite, so the viewport fell back to auto and grew to\n // its content instead of scrolling. A grid item stretches to its track, and the track\n // is sized from the root's used height, which flex has already settled. `grid-rows-1`\n // is `repeat(1, minmax(0, 1fr))`: one track that may shrink below its content.\n className={cn('group/scroll-area relative grid min-w-0 grid-rows-1 overflow-hidden', className)}\n data-fade={fade ? FADE_AXIS[orientation] : undefined}\n {...NO_ROLE}\n {...props}\n >\n {(orientation === 'vertical' || orientation === 'both') && (\n <ScrollBar orientation=\"vertical\" visibility={type} className={cn(scrollbarClassName, scrollVerticalClassName)} />\n )}\n {(orientation === 'horizontal' || orientation === 'both') && (\n <ScrollBar orientation=\"horizontal\" visibility={type} className={cn(scrollbarClassName, scrollHorizontalClassName)} />\n )}\n <BaseScrollArea.Corner />\n <BaseScrollArea.Viewport\n data-slot=\"scroll-area-viewport\"\n id={viewportId ?? viewPortId}\n ref={refsViewport}\n data-scroll-restoration-id={scrollRestorationId}\n {...NO_ROLE}\n {...(focusable ? null : NO_TAB_STOP)}\n // One axis means one axis. Base UI leaves both axes scrollable, so a\n // vertical list could still be dragged sideways, and anything that put a\n // row in view (focus moving, scrollIntoView with inline: nearest) slid\n // the whole list across. The clamp is marked important because Base UI\n // sets the viewport's overflow itself.\n className={cn(\n 'max-h-inherit w-full rounded-[inherit]',\n orientation === 'vertical' && 'overflow-x-hidden!',\n orientation === 'horizontal' && 'overflow-y-hidden!',\n viewportClassName ?? viewPortClassName,\n )}\n >\n {/* Content is NOT optional: it carries the ResizeObserver that recomputes the\n thumb when the CONTENT resizes without the viewport resizing (e.g. a route\n swap to a shorter page). Without it the thumb keeps the previous page's\n geometry and a fully-visible page still shows a scrollbar.\n\n A vertical scroller also pins its content to the viewport's width, so a\n long label truncates instead of widening the list and inventing a\n horizontal scroll. Base UI sets min-width: fit-content inline, which is\n what makes that happen and why this is an inline style too. */}\n <BaseScrollArea.Content {...NO_ROLE} style={orientation === 'vertical' ? { minWidth: 0 } : undefined}>\n {children}\n </BaseScrollArea.Content>\n </BaseScrollArea.Viewport>\n </BaseScrollArea.Root>\n );\n};\n","import { cn } from '@edyn/ui/lib/utils';\n\n/**\n * The one look for a list in a popup or a menu: the command palette, Select,\n * Combobox, MultiSelect and the dropdown menus.\n *\n * These lists used to disagree with each other in every detail that shows:\n * three different radii, two different paddings, a grey fill for the highlight\n * in one and the accent in another, and the chosen item marked by a check on\n * the left in Select and on the right in the menus. Picking something from one\n * list then felt like a different product from picking something in the next.\n *\n * It lives here as classes rather than as a stylesheet so a caller's own\n * className still wins: an unlayered rule would beat every utility, including\n * the one someone passes for a single list.\n *\n * ONE ITEM: transparent at rest, 32px tall, 6px radius (--radius-sm), 6px by\n * 8px of padding, text-sm, its own icons 16px and muted. Under the pointer or\n * the keyboard it takes one translucent fill of the text colour, and its icons\n * the text colour. Chosen is medium weight with a check at the END, never a\n * fill, so \"where I am\" and \"what I picked\" can be told apart at a glance.\n */\n\n/**\n * Which primitive renders the item, because the two disagree about the same\n * attribute names in a way that silently breaks the styling:\n *\n * - cmdk writes `data-selected=\"false\"` and `data-disabled=\"false\"` on items\n * that are neither, so a bare `data-selected:` variant matches EVERY item and\n * highlights the whole list. Its states have to be matched by value.\n * - Base UI omits the attribute instead, so presence is the test there. That\n * needs the BRACKET form for `selected`: shadcn redefines the bare\n * `data-selected:` variant to match only data-selected=\"true\" (for the\n * calendar), and Base UI writes it as an empty string, so the bare form\n * compiles and silently never applies. `highlighted` and `disabled` have no\n * such override, so those stay bare.\n * - And the same name means different things: cmdk's `data-selected` is the\n * keyboard cursor, Base UI's is the chosen value. In cmdk the chosen state is\n * `data-checked`, which the DS's own CommandItem sets.\n */\nexport type TPopupItemFlavor = 'base-ui' | 'cmdk';\n\nconst ITEM_BASE =\n \"relative flex min-h-8 cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm text-foreground outline-none select-none [&>svg]:pointer-events-none [&>svg]:shrink-0 [&>svg]:text-muted-foreground [&>svg:not([class*='size-'])]:size-4\";\n\nconst ITEM_STATES: Record<TPopupItemFlavor, string> = {\n 'base-ui':\n 'data-highlighted:bg-foreground/6 data-highlighted:[&>svg]:text-foreground data-[selected]:font-medium data-disabled:pointer-events-none data-disabled:opacity-50',\n cmdk: 'data-[selected=true]:bg-foreground/6 data-[selected=true]:[&>svg]:text-foreground data-[checked=true]:font-medium data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50',\n};\n\n/** The shared item look. `checkable` leaves room at the end for the check. */\nexport const popupItemClass = (flavor: TPopupItemFlavor = 'base-ui', checkable = false): string =>\n cn(ITEM_BASE, ITEM_STATES[flavor], checkable && 'pr-8');\n\n/**\n * The check's slot, at the end of the item and the same size whether or not the\n * check is in it, so a list does not shift as the choice moves.\n */\nexport const POPUP_ITEM_INDICATOR_CLASS = 'pointer-events-none absolute right-2 flex size-4 items-center justify-center text-foreground';\n\n/** A group's heading in any of these lists. */\nexport const POPUP_GROUP_LABEL_CLASS = 'px-2 py-1.5 text-xs font-medium text-muted-foreground';\n","/**\n * The HTML the rich-text editor emits, and the only HTML RichTextContent renders. An app that\n * sanitises on a server takes its allow-list from here: nothing outside these elements and this\n * attribute ever comes out of the editor, whatever was pasted into it.\n */\nexport const RICH_TEXT_ELEMENTS = ['p', 'br', 'hr', 'strong', 'em', 'u', 'ul', 'ol', 'li', 'a'] as const;\n\n/** The attributes each element may carry. Every other element carries none (no class, no style). */\nexport const RICH_TEXT_ATTRIBUTES: Readonly<Record<string, readonly string[]>> = { a: ['href'] };\n\n/** A link must be absolute and use one of these. `javascript:`, `data:` and relative links are refused. */\nexport const RICH_TEXT_LINK_PROTOCOLS = ['http', 'https', 'mailto'] as const;\n\nexport const isAllowedRichTextHref = (href: string): boolean => {\n const cleaned = Array.from(href)\n .filter((char) => char.charCodeAt(0) > 32)\n .join('');\n const colon = cleaned.indexOf(':');\n if (colon < 1) {\n return false;\n }\n const protocol = cleaned.slice(0, colon).toLowerCase();\n return (RICH_TEXT_LINK_PROTOCOLS as readonly string[]).includes(protocol);\n};\n","import { cn } from '@edyn/ui/lib/utils';\nimport { createElement, type HTMLAttributes, type ReactNode, useMemo } from 'react';\nimport { isAllowedRichTextHref } from './allow-list';\n\n/**\n * How rich text looks, shared by the editor and by RichTextContent so a comment reads the same while it is typed and\n * after it is saved. Descendant selectors rather than classes on the elements, because the HTML that is stored carries\n * no classes.\n */\nexport const RICH_TEXT_BODY_CLASS =\n 'text-sm leading-6 wrap-break-word [&_a]:text-primary [&_a]:underline [&_a]:underline-offset-2 [&_hr]:my-3 [&_hr]:border-0 [&_hr]:border-t [&_hr]:border-border [&_ol]:list-decimal [&_ol]:ps-5 [&_p+p]:mt-2 [&_ul]:list-disc [&_ul]:ps-5 [&_ul+p]:mt-2 [&_ol+p]:mt-2 [&_p+ul]:mt-2 [&_p+ol]:mt-2';\n\nconst MENTION_PATTERN = /(?<![\\w.+-])@(?:assignees\\b|[A-Za-z0-9._%+-]+@[A-Za-z0-9-]+(?:\\.[A-Za-z0-9-]+)+)/g;\n\nexport const RICH_TEXT_MENTION_CLASS = 'rounded-sm bg-primary/10 px-1 py-0.5 font-medium text-primary';\n\nconst TAG_FOR: Readonly<Record<string, string>> = { b: 'strong', i: 'em' };\nconst KEPT = new Set(['p', 'strong', 'em', 'u', 'ul', 'ol', 'li', 'a', 'br', 'hr']);\nconst DROPPED_WITH_CONTENT = new Set(['script', 'style', 'template', 'iframe', 'object', 'embed', 'noscript', 'svg', 'math', 'head', 'title']);\n\nconst withMentions = (text: string, key: string): ReactNode[] => {\n const parts: ReactNode[] = [];\n let last = 0;\n for (const match of text.matchAll(MENTION_PATTERN)) {\n const start = match.index ?? 0;\n if (start > last) {\n parts.push(text.slice(last, start));\n }\n parts.push(\n <span key={`${key}-${start}`} data-slot=\"rich-text-mention\" className={RICH_TEXT_MENTION_CLASS}>\n {match[0]}\n </span>,\n );\n last = start + match[0].length;\n }\n if (last < text.length) {\n parts.push(text.slice(last));\n }\n return parts;\n};\n\nconst toNodes = (parent: Node, key: string, insideLink: boolean): ReactNode[] => {\n const out: ReactNode[] = [];\n parent.childNodes.forEach((child, index) => {\n const childKey = `${key}.${index}`;\n if (child.nodeType === 3) {\n const text = child.textContent ?? '';\n out.push(...(insideLink ? [text] : withMentions(text, childKey)));\n return;\n }\n if (child.nodeType !== 1) {\n return;\n }\n const element = child as Element;\n const name = element.tagName.toLowerCase();\n if (DROPPED_WITH_CONTENT.has(name)) {\n return;\n }\n const tag = TAG_FOR[name] ?? name;\n if (!KEPT.has(tag)) {\n out.push(...toNodes(element, childKey, insideLink));\n return;\n }\n if (tag === 'br') {\n out.push(<br key={childKey} />);\n return;\n }\n if (tag === 'hr') {\n out.push(<hr key={childKey} />);\n return;\n }\n if (tag === 'a') {\n const href = element.getAttribute('href') ?? '';\n const inner = toNodes(element, childKey, true);\n out.push(\n ...(isAllowedRichTextHref(href)\n ? [\n <a key={childKey} href={href.trim()} rel=\"noopener noreferrer\" target=\"_blank\">\n {inner}\n </a>,\n ]\n : inner),\n );\n return;\n }\n out.push(createElement(tag, { key: childKey }, ...toNodes(element, childKey, insideLink)));\n });\n return out;\n};\n\n/** The HTML as React elements, keeping only what the editor can produce. Browser only (it needs a DOM parser). */\nexport const richTextToNodes = (html: string): ReactNode[] => {\n if (typeof DOMParser === 'undefined' || html === '') {\n return [];\n }\n const parsed = new DOMParser().parseFromString(`<body>${html}`, 'text/html');\n return toNodes(parsed.body, 'r', false);\n};\n\nexport interface IRichTextContentProps extends Omit<HTMLAttributes<HTMLDivElement>, 'children' | 'dangerouslySetInnerHTML'> {\n /** The HTML to show. Only the editor's elements are rendered, whatever else it holds. */\n html: string;\n}\n\n/**\n * Shows rich text the editor produced (or any HTML), as the same elements the editor emits and nothing else:\n * `p`, `br`, `hr`, `strong`, `em`, `u`, `ul`, `ol`, `li` and `a` with an `href` (http, https or mailto; it opens in a new tab\n * with `rel=\"noopener noreferrer\"`). Everything else is dropped and its text kept. Built as React elements, not injected\n * as markup, so it is safe on HTML that has not been cleaned. A run like `@name@example.test` or `@assignees` is shown\n * as a chip.\n */\nexport const RichTextContent = ({ html, className, ...props }: IRichTextContentProps) => {\n const nodes = useMemo(() => richTextToNodes(html), [html]);\n return (\n <div data-slot=\"rich-text-content\" className={cn(RICH_TEXT_BODY_CLASS, className)} {...props}>\n {nodes}\n </div>\n );\n};\n","import { Menu as MenuPrimitive } from '@base-ui/react/menu';\nimport { POPUP_GROUP_LABEL_CLASS, POPUP_ITEM_INDICATOR_CLASS, popupItemClass } from '@edyn/ui/lib/popup-list';\nimport { cn } from '@edyn/ui/lib/utils';\nimport { IconCheck, IconChevronRight } from '@tabler/icons-react';\nimport type * as React from 'react';\nimport { ScrollArea } from '../scroll-area';\n\nexport const DropdownMenu = ({ ...props }: MenuPrimitive.Root.Props) => {\n return <MenuPrimitive.Root data-slot=\"dropdown-menu\" {...props} />;\n};\n\nexport const DropdownMenuPortal = ({ ...props }: MenuPrimitive.Portal.Props) => {\n return <MenuPrimitive.Portal data-slot=\"dropdown-menu-portal\" {...props} />;\n};\n\nexport const DropdownMenuTrigger = ({ ...props }: MenuPrimitive.Trigger.Props) => {\n return <MenuPrimitive.Trigger data-slot=\"dropdown-menu-trigger\" {...props} />;\n};\n\n/**\n * Scrolls inside a DS ScrollArea like the other popup lists, with the bar shown\n * for as long as the menu overflows and a fade on whichever end is cut off.\n *\n * Base UI puts `role=\"menu\"` on this popup itself and offers no inner list part\n * to move it onto, so the ScrollArea sits INSIDE the role. That is only legal\n * because ScrollArea drops the `role=\"presentation\"` Base UI gives its root,\n * viewport and content: a menu may not own presentation wrappers (axe reports\n * a critical aria-required-children violation), but it may own plain divs.\n * e2e/a11y.spec.ts scans the open menu in both themes to keep it that way.\n */\nexport const DropdownMenuContent = ({\n align = 'start',\n alignOffset = 0,\n side = 'bottom',\n sideOffset = 4,\n className,\n children,\n ...props\n}: MenuPrimitive.Popup.Props & Pick<MenuPrimitive.Positioner.Props, 'align' | 'alignOffset' | 'side' | 'sideOffset'>) => {\n return (\n <MenuPrimitive.Portal>\n <MenuPrimitive.Positioner className=\"isolate z-50 outline-none\" align={align} alignOffset={alignOffset} side={side} sideOffset={sideOffset}>\n <MenuPrimitive.Popup\n data-slot=\"dropdown-menu-content\"\n className={cn(\n 'z-50 max-h-(--available-height) w-(--anchor-width) min-w-32 origin-(--transform-origin) overflow-hidden rounded-lg bg-popover text-popover-foreground shadow-md ring-1 ring-foreground/10 duration-100 outline-none data-[side=bottom]:slide-in-from-top-2 data-[side=inline-end]:slide-in-from-left-2 data-[side=inline-start]:slide-in-from-right-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:overflow-hidden data-closed:fade-out-0 data-closed:zoom-out-95',\n 'motion-reduce:animate-none',\n className,\n )}\n {...props}\n >\n {/* max-h-inherit hands the positioner's measured height to the element that\n scrolls; the padding sits on the content so the cap is the popup's exactly. */}\n <ScrollArea type=\"always\" fade focusable={false} className=\"max-h-inherit\">\n <div className=\"p-1\">{children}</div>\n </ScrollArea>\n </MenuPrimitive.Popup>\n </MenuPrimitive.Positioner>\n </MenuPrimitive.Portal>\n );\n};\n\nexport const DropdownMenuGroup = ({ ...props }: MenuPrimitive.Group.Props) => {\n return <MenuPrimitive.Group data-slot=\"dropdown-menu-group\" {...props} />;\n};\n\nexport const DropdownMenuLabel = ({\n className,\n inset,\n ...props\n}: MenuPrimitive.GroupLabel.Props & {\n inset?: boolean;\n}) => {\n return (\n <MenuPrimitive.GroupLabel\n data-slot=\"dropdown-menu-label\"\n data-inset={inset}\n className={cn(POPUP_GROUP_LABEL_CLASS, 'data-[inset=true]:pl-7', className)}\n {...props}\n />\n );\n};\n\nexport const DropdownMenuItem = ({\n className,\n inset,\n variant = 'default',\n ...props\n}: MenuPrimitive.Item.Props & {\n inset?: boolean;\n variant?: 'default' | 'destructive';\n}) => {\n return (\n <MenuPrimitive.Item\n data-slot=\"dropdown-menu-item\"\n data-inset={inset}\n data-variant={variant}\n className={cn(\n 'group/dropdown-menu-item',\n popupItemClass(),\n 'data-[inset=true]:pl-7',\n // A destructive item keeps its own colour, and its own highlight with it:\n // the shared translucent one would make it read like any other item.\n 'data-[variant=destructive]:text-destructive data-[variant=destructive]:[&>svg]:text-destructive',\n 'data-[variant=destructive]:data-highlighted:bg-destructive/10 data-[variant=destructive]:data-highlighted:text-destructive',\n className,\n )}\n {...props}\n />\n );\n};\n\nexport const DropdownMenuSub = ({ ...props }: MenuPrimitive.SubmenuRoot.Props) => {\n return <MenuPrimitive.SubmenuRoot data-slot=\"dropdown-menu-sub\" {...props} />;\n};\n\nexport const DropdownMenuSubTrigger = ({\n className,\n inset,\n children,\n ...props\n}: MenuPrimitive.SubmenuTrigger.Props & {\n inset?: boolean;\n}) => {\n return (\n <MenuPrimitive.SubmenuTrigger\n data-slot=\"dropdown-menu-sub-trigger\"\n data-inset={inset}\n className={cn(\n popupItemClass(),\n // An open submenu holds its trigger in the highlight while the pointer is\n // down in its panel.\n 'data-[inset=true]:pl-7 data-popup-open:bg-foreground/6 data-popup-open:[&>svg]:text-foreground',\n className,\n )}\n {...props}\n >\n {children}\n <IconChevronRight className=\"ml-auto\" />\n </MenuPrimitive.SubmenuTrigger>\n );\n};\n\nexport const DropdownMenuSubContent = ({\n align = 'start',\n alignOffset = -3,\n side = 'right',\n sideOffset = 0,\n className,\n ...props\n}: React.ComponentProps<typeof DropdownMenuContent>) => {\n return (\n <DropdownMenuContent\n data-slot=\"dropdown-menu-sub-content\"\n className={cn(\n 'w-auto min-w-[96px] rounded-lg bg-popover p-1 text-popover-foreground shadow-lg ring-1 ring-foreground/10 duration-100 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95',\n 'motion-reduce:animate-none',\n className,\n )}\n align={align}\n alignOffset={alignOffset}\n side={side}\n sideOffset={sideOffset}\n {...props}\n />\n );\n};\n\nexport const DropdownMenuCheckboxItem = ({\n className,\n children,\n checked,\n inset,\n ...props\n}: MenuPrimitive.CheckboxItem.Props & {\n inset?: boolean;\n}) => {\n return (\n <MenuPrimitive.CheckboxItem\n data-slot=\"dropdown-menu-checkbox-item\"\n data-inset={inset}\n className={cn(popupItemClass('base-ui', true), 'data-checked:font-medium data-[inset=true]:pl-7', className)}\n checked={checked}\n {...props}\n >\n <span className={POPUP_ITEM_INDICATOR_CLASS} data-slot=\"dropdown-menu-checkbox-item-indicator\">\n <MenuPrimitive.CheckboxItemIndicator>\n <IconCheck />\n </MenuPrimitive.CheckboxItemIndicator>\n </span>\n {children}\n </MenuPrimitive.CheckboxItem>\n );\n};\n\nexport const DropdownMenuRadioGroup = ({ ...props }: MenuPrimitive.RadioGroup.Props) => {\n return <MenuPrimitive.RadioGroup data-slot=\"dropdown-menu-radio-group\" {...props} />;\n};\n\nexport const DropdownMenuRadioItem = ({\n className,\n children,\n inset,\n ...props\n}: MenuPrimitive.RadioItem.Props & {\n inset?: boolean;\n}) => {\n return (\n <MenuPrimitive.RadioItem\n data-slot=\"dropdown-menu-radio-item\"\n data-inset={inset}\n className={cn(popupItemClass('base-ui', true), 'data-checked:font-medium data-[inset=true]:pl-7', className)}\n {...props}\n >\n <span className={POPUP_ITEM_INDICATOR_CLASS} data-slot=\"dropdown-menu-radio-item-indicator\">\n <MenuPrimitive.RadioItemIndicator>\n <IconCheck />\n </MenuPrimitive.RadioItemIndicator>\n </span>\n {children}\n </MenuPrimitive.RadioItem>\n );\n};\n\nexport const DropdownMenuSeparator = ({ className, ...props }: MenuPrimitive.Separator.Props) => {\n return <MenuPrimitive.Separator data-slot=\"dropdown-menu-separator\" className={cn('-mx-1 my-1 h-px bg-border', className)} {...props} />;\n};\n\nexport const DropdownMenuShortcut = ({ className, ...props }: React.ComponentProps<'span'>) => {\n return (\n <span\n data-slot=\"dropdown-menu-shortcut\"\n className={cn('ml-auto text-xs tracking-widest text-muted-foreground group-focus/dropdown-menu-item:text-accent-foreground', className)}\n {...props}\n />\n );\n};\n","import { Toggle as TogglePrimitive } from '@base-ui/react/toggle';\nimport { cn } from '@edyn/ui/lib/utils';\nimport { cva, type VariantProps } from 'class-variance-authority';\n\nexport const toggleVariants = cva(\n 'inline-flex shrink-0 cursor-pointer items-center justify-center gap-1.5 rounded-lg border border-transparent text-sm font-medium whitespace-nowrap transition-all outline-none select-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 data-pressed:text-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*=\"size-\"])]:size-4',\n {\n variants: {\n variant: {\n default: 'bg-transparent hover:bg-muted hover:text-foreground data-pressed:bg-muted',\n outline:\n 'border-border bg-background hover:bg-muted hover:text-foreground data-pressed:bg-muted dark:border-input dark:bg-input/30 dark:hover:bg-input/50',\n },\n size: {\n sm: 'h-7 px-2.5 text-[0.8rem]',\n default: 'h-8 px-2.5',\n lg: 'h-9 px-3',\n },\n },\n defaultVariants: {\n variant: 'default',\n size: 'default',\n },\n },\n);\n\nexport type TToggleVariants = VariantProps<typeof toggleVariants>;\n\nexport const Toggle = <Value extends string>({\n className,\n variant = 'default',\n size = 'default',\n ...props\n}: TogglePrimitive.Props<Value> & TToggleVariants) => {\n return <TogglePrimitive data-slot=\"toggle\" className={cn(toggleVariants({ variant, size, className }))} {...props} />;\n};\n"],"mappings":"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"}