@botiverse/raft-ui 0.0.0-stage → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/CHANGELOG.md +576 -0
  2. package/LICENSE +21 -0
  3. package/README.md +103 -2
  4. package/codemods/package-name.mjs +168 -0
  5. package/codemods/token-names.mjs +150 -0
  6. package/dist/cn.d.mts +5 -0
  7. package/dist/cn.mjs +48 -0
  8. package/dist/components/combobox-select/combobox-select.css +286 -0
  9. package/dist/components/float-button/float-button.css +316 -0
  10. package/dist/components/steps/otter-indicator.css +141 -0
  11. package/dist/components/steps/steps.css +370 -0
  12. package/dist/components/timeline/timeline.css +255 -0
  13. package/dist/dialog-CY6S-Xqf.mjs +505 -0
  14. package/dist/fonts.css +13 -0
  15. package/dist/foundation.css +623 -0
  16. package/dist/index-B3_j9XYd.d.mts +329 -0
  17. package/dist/index.d.mts +5114 -0
  18. package/dist/index.mjs +16442 -0
  19. package/dist/style.css +1315 -0
  20. package/dist/styles.css +444 -0
  21. package/dist/tokens.json +3811 -0
  22. package/dist/wip.d.mts +92 -0
  23. package/dist/wip.mjs +517 -0
  24. package/package.json +92 -3
  25. package/skills/raft-ui-critique/SKILL.md +167 -0
  26. package/skills/raft-ui-critique/agents/openai.yaml +4 -0
  27. package/skills/raft-ui-critique/references/theme-lenses.md +69 -0
  28. package/skills/raft-ui-guide/SKILL.md +96 -0
  29. package/skills/raft-ui-guide/agents/openai.yaml +4 -0
  30. package/skills/raft-ui-guide/rules/adoption.md +55 -0
  31. package/skills/raft-ui-guide/rules/composition.md +14 -0
  32. package/skills/raft-ui-guide/rules/conversation.md +15 -0
  33. package/skills/raft-ui-guide/rules/display.md +14 -0
  34. package/skills/raft-ui-guide/rules/feedback.md +13 -0
  35. package/skills/raft-ui-guide/rules/forms.md +13 -0
  36. package/skills/raft-ui-guide/rules/layout.md +15 -0
  37. package/skills/raft-ui-guide/rules/lookup.md +78 -0
  38. package/skills/raft-ui-guide/rules/overlays.md +13 -0
  39. package/skills/raft-ui-guide/rules/overview.md +30 -0
  40. package/skills/raft-ui-guide/rules/styling.md +17 -0
  41. package/skills/raft-ui-guide/rules/technical-overview.md +80 -0
package/dist/wip.d.mts ADDED
@@ -0,0 +1,92 @@
1
+ import { O as ButtonProps, T as DialogTrigger, i as DialogClose, s as DialogContentProps, t as Dialog, w as DialogTitleProps } from "./index-B3_j9XYd.mjs";
2
+ import { CSSProperties, ComponentPropsWithRef, ReactNode } from "react";
3
+ import { Combobox } from "@base-ui/react/combobox";
4
+ //#region src/components/combobox-select/combobox-select.types.d.ts
5
+ type ComboboxSelectValue = string | number;
6
+ interface ComboboxSelectOption {
7
+ value: ComboboxSelectValue;
8
+ label: string;
9
+ disabled?: boolean;
10
+ }
11
+ interface ComboboxSelectGroup<Option = ComboboxSelectOption> {
12
+ type: "group";
13
+ key: string | number;
14
+ label: ReactNode;
15
+ children: readonly Option[];
16
+ }
17
+ type ComboboxSelectSelection<Multiple extends boolean | undefined> = Multiple extends true ? ComboboxSelectValue[] : ComboboxSelectValue | null;
18
+ interface ComboboxSelectMessages {
19
+ clear: string;
20
+ toggle: string;
21
+ selected: string;
22
+ chipDescription: string;
23
+ inputDescription: string;
24
+ remove: (label: string) => string;
25
+ }
26
+ type RootProps = Combobox.Root.Props<unknown, boolean>;
27
+ type ComboboxSelectProps<Option = ComboboxSelectOption, Multiple extends boolean | undefined = false> = Pick<RootProps, "name" | "form" | "required" | "disabled" | "readOnly" | "open" | "defaultOpen" | "onOpenChange" | "onOpenChangeComplete" | "autoHighlight" | "autoComplete" | "inputValue" | "defaultInputValue" | "onInputValueChange"> & Pick<ComponentPropsWithRef<"input">, "id" | "ref" | "aria-label" | "aria-labelledby" | "aria-describedby" | "aria-invalid"> & {
28
+ options: readonly (Option | ComboboxSelectGroup<Option>)[];
29
+ multiple?: Multiple;
30
+ value?: ComboboxSelectSelection<Multiple>;
31
+ defaultValue?: ComboboxSelectSelection<Multiple>;
32
+ onValueChange?: (value: ComboboxSelectSelection<Multiple>, options: Multiple extends true ? (Option | undefined)[] : Option | undefined | null, details: Combobox.Root.ChangeEventDetails) => void;
33
+ labelField?: keyof Option;
34
+ valueField?: keyof Option;
35
+ disabledField?: keyof Option;
36
+ /** Supplies labels for values that have not been loaded yet. */
37
+ fallbackOption?: (value: ComboboxSelectValue) => Option;
38
+ filterable?: boolean;
39
+ filter?: false | ((query: string, option: Option) => boolean);
40
+ /** Display the provided results without local filtering. Requests belong to the caller. */
41
+ remote?: boolean;
42
+ onSearch?: (query: string) => void;
43
+ loading?: boolean;
44
+ create?: boolean;
45
+ /** Alias for create, useful when matching Select libraries that call this mode creatable. */
46
+ creatable?: boolean;
47
+ /** Called only when the creation row is selected. Return null to reject creation. */
48
+ onCreate?: (query: string) => Option | null;
49
+ clearable?: boolean;
50
+ showArrow?: boolean;
51
+ clearFilterAfterSelect?: boolean;
52
+ onClear?: () => void;
53
+ /** Collapse chips when the control is unfocused; all remain reachable when focused. */
54
+ maxTagCount?: number;
55
+ size?: "sm" | "md" | "lg";
56
+ status?: "error" | "warning";
57
+ placeholder?: string;
58
+ renderLabel?: (option: Option) => ReactNode;
59
+ /** Customizes option content while preserving the Base UI option element. */
60
+ renderOption?: (option: Option, info: {
61
+ selected: boolean;
62
+ }) => ReactNode;
63
+ /** Customizes chip content while preserving keyboard navigation and removal. */
64
+ renderTag?: (option: Option) => ReactNode;
65
+ renderCreateLabel?: (query: string) => ReactNode;
66
+ emptyContent?: ReactNode;
67
+ loadingContent?: ReactNode;
68
+ messages?: Partial<ComboboxSelectMessages>;
69
+ inputProps?: Omit<Combobox.Input.Props, "value" | "defaultValue" | "size" | "children">;
70
+ portalProps?: Combobox.Portal.Props;
71
+ positionerProps?: Omit<Combobox.Positioner.Props, "children">;
72
+ popupProps?: Omit<Combobox.Popup.Props, "children">;
73
+ className?: string;
74
+ style?: CSSProperties;
75
+ };
76
+ //#endregion
77
+ //#region src/components/combobox-select/combobox-select.d.ts
78
+ export declare function ComboboxSelect<Option = ComboboxSelectOption, Multiple extends boolean | undefined = false>({ options, multiple, value, defaultValue, onValueChange, labelField, valueField, disabledField, fallbackOption, filterable, filter, remote, onSearch, loading, create, creatable, onCreate, clearable, showArrow, clearFilterAfterSelect, onClear, maxTagCount, size, status, placeholder, renderLabel, renderOption, renderTag, renderCreateLabel, emptyContent, loadingContent, messages, inputProps, portalProps, positionerProps, popupProps, className, style, id: idProp, ref, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, "aria-describedby": ariaDescribedBy, "aria-invalid": ariaInvalid, inputValue, defaultInputValue, onInputValueChange, disabled, readOnly, autoHighlight, ...rootProps }: ComboboxSelectProps<Option, Multiple>): import("react").JSX.Element;
79
+ //#endregion
80
+ //#region src/components/announcement-dialog/announcement-dialog.d.ts
81
+ export declare function AnnouncementDialogContent({ className, initialFocus, ref, ...props }: DialogContentProps): import("react").JSX.Element;
82
+ export declare function AnnouncementDialogBody({ className, ...props }: ComponentPropsWithRef<"div">): import("react").JSX.Element;
83
+ export declare function AnnouncementDialogHeader({ className, ...props }: ComponentPropsWithRef<"div">): import("react").JSX.Element;
84
+ export declare function AnnouncementDialogLabel({ className, children, ...props }: ComponentPropsWithRef<"div">): import("react").JSX.Element;
85
+ export declare function AnnouncementDialogTitle({ className, ...props }: DialogTitleProps): import("react").JSX.Element;
86
+ export declare function AnnouncementDialogPicture({ className, ...props }: ComponentPropsWithRef<"div">): import("react").JSX.Element;
87
+ export declare function AnnouncementDialogText({ className, ...props }: ComponentPropsWithRef<"div">): import("react").JSX.Element;
88
+ export declare function AnnouncementDialogFooter({ className, ...props }: ComponentPropsWithRef<"div">): import("react").JSX.Element;
89
+ export declare function AnnouncementDialogAction({ className, ...props }: Omit<ButtonProps, "variant">): import("react").JSX.Element;
90
+ export declare function AnnouncementDialogSecondaryAction({ className, ...props }: Omit<ButtonProps, "variant">): import("react").JSX.Element;
91
+ //#endregion
92
+ export { Dialog as AnnouncementDialog, DialogClose as AnnouncementDialogClose, DialogTrigger as AnnouncementDialogTrigger, type ComboboxSelectGroup, type ComboboxSelectMessages, type ComboboxSelectOption, type ComboboxSelectProps, type ComboboxSelectSelection, type ComboboxSelectValue };
package/dist/wip.mjs ADDED
@@ -0,0 +1,517 @@
1
+ import { S as tv, b as useTheme, f as DialogTitle, i as DialogContent, m as Button, p as DialogTrigger, r as DialogClose, t as Dialog, y as useThemeScopeProps } from "./dialog-CY6S-Xqf.mjs";
2
+ import { Check, ChevronDown, LoaderCircle, Plus, X } from "lucide-react";
3
+ import { useCallback, useId, useMemo, useRef, useState } from "react";
4
+ import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
5
+ import { Combobox } from "@base-ui/react/combobox";
6
+ //#region src/components/combobox-select/combobox-select.options.ts
7
+ function isOptionGroup(option) {
8
+ return typeof option === "object" && option !== null && "type" in option && option.type === "group" && "children" in option && Array.isArray(option.children);
9
+ }
10
+ function normalizeOption(option, labelField, valueField, disabledField) {
11
+ const fields = option;
12
+ const value = fields[valueField];
13
+ const label = fields[labelField];
14
+ if (typeof value !== "string" && typeof value !== "number") throw new Error("ComboboxSelect options must have a string or number value.");
15
+ return {
16
+ value,
17
+ label: typeof label === "string" || typeof label === "number" ? String(label) : String(value),
18
+ disabled: Boolean(fields[disabledField]),
19
+ option
20
+ };
21
+ }
22
+ function optionKey(value) {
23
+ return `${typeof value}:${value}`;
24
+ }
25
+ //#endregion
26
+ //#region src/components/combobox-select/combobox-select.tsx
27
+ const defaultMessages = {
28
+ clear: "Clear selection",
29
+ toggle: "Toggle options",
30
+ selected: "Selected options",
31
+ chipDescription: "Press Backspace or Delete to remove",
32
+ inputDescription: "From the start of the input, press Left Arrow to focus selected options",
33
+ remove: (label) => `Remove ${label}`
34
+ };
35
+ const defaultRenderCreateLabel = (query) => `Create “${query}”`;
36
+ function recordLabel(record, renderLabel) {
37
+ return record.option === void 0 ? record.label : renderLabel?.(record.option) ?? record.label;
38
+ }
39
+ function renderOptionContent({ record, selected, renderLabel, renderOption, renderCreateLabel }) {
40
+ if (record.createQuery !== void 0) return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(Plus, { "aria-hidden": true }), /* @__PURE__ */ jsx("span", {
41
+ className: "r-combobox-select__text",
42
+ children: renderCreateLabel(record.label)
43
+ })] });
44
+ const content = record.option === void 0 ? record.label : renderOption?.(record.option, { selected }) ?? recordLabel(record, renderLabel);
45
+ return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("span", {
46
+ className: "r-combobox-select__text",
47
+ children: content
48
+ }), /* @__PURE__ */ jsx(Combobox.ItemIndicator, {
49
+ className: "r-combobox-select__indicator",
50
+ children: /* @__PURE__ */ jsx(Check, { "aria-hidden": true })
51
+ })] });
52
+ }
53
+ function renderSelectedChip({ record, index, tagLimit, strings, renderLabel, renderTag }) {
54
+ const label = recordLabel(record, renderLabel);
55
+ const content = record.option === void 0 ? record.label : renderTag?.(record.option) ?? label;
56
+ const overflow = index >= tagLimit;
57
+ return /* @__PURE__ */ jsxs(Combobox.Chip, {
58
+ className: "r-combobox-select__chip",
59
+ "data-overflow": overflow || void 0,
60
+ "aria-label": record.label,
61
+ "aria-description": strings.chipDescription,
62
+ children: [/* @__PURE__ */ jsx("span", {
63
+ className: "r-combobox-select__text",
64
+ children: content
65
+ }), /* @__PURE__ */ jsx(Combobox.ChipRemove, {
66
+ className: "r-combobox-select__remove",
67
+ "aria-label": strings.remove(record.label),
68
+ children: /* @__PURE__ */ jsx(X, { "aria-hidden": true })
69
+ })]
70
+ }, optionKey(record.value));
71
+ }
72
+ /** Options-driven composition. The stable compound Combobox API stays unchanged. */
73
+ function isItemEqualToValue(a, b) {
74
+ return a.createQuery === b.createQuery && a.value === b.value;
75
+ }
76
+ function itemToStringLabel(record) {
77
+ return record.label;
78
+ }
79
+ function itemToStringValue(record) {
80
+ return String(record.value);
81
+ }
82
+ function ComboboxSelect({ options, multiple, value, defaultValue, onValueChange, labelField = "label", valueField = "value", disabledField = "disabled", fallbackOption, filterable = true, filter, remote = false, onSearch, loading = false, create = false, creatable, onCreate, clearable = false, showArrow = true, clearFilterAfterSelect = true, onClear, maxTagCount, size = "md", status, placeholder = "Select an option", renderLabel, renderOption, renderTag, renderCreateLabel = defaultRenderCreateLabel, emptyContent = "No options found", loadingContent = "Loading…", messages, inputProps, portalProps, positionerProps, popupProps, className, style, id: idProp, ref, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, "aria-describedby": ariaDescribedBy, "aria-invalid": ariaInvalid, inputValue, defaultInputValue, onInputValueChange, disabled, readOnly, autoHighlight = true, ...rootProps }) {
83
+ const generatedId = useId();
84
+ const id = idProp ?? generatedId;
85
+ const { resolvedMode } = useTheme();
86
+ const scopedPortalProps = useThemeScopeProps(portalProps ?? {});
87
+ const strings = {
88
+ ...defaultMessages,
89
+ ...messages
90
+ };
91
+ const [uncontrolledValue, setUncontrolledValue] = useState(defaultValue ?? (multiple ? [] : null));
92
+ const selectedValue = value === void 0 ? uncontrolledValue : value;
93
+ const selectedKeys = useMemo(() => Array.isArray(selectedValue) ? selectedValue : selectedValue == null ? [] : [selectedValue], [selectedValue]);
94
+ const [query, setQuery] = useState(String(defaultInputValue ?? ""));
95
+ const [createdOptions, setCreatedOptions] = useState([]);
96
+ const collator = useMemo(() => new Intl.Collator(void 0, {
97
+ sensitivity: "base",
98
+ usage: "search"
99
+ }), []);
100
+ const normalized = useMemo(() => {
101
+ const normalize = (option) => normalizeOption(option, labelField, valueField, disabledField);
102
+ const groups = [];
103
+ options.forEach((option, index) => {
104
+ if (isOptionGroup(option)) groups.push({
105
+ key: `group:${optionKey(option.key)}`,
106
+ label: option.label,
107
+ items: option.children.map(normalize)
108
+ });
109
+ else groups.push({
110
+ key: `option:${index}`,
111
+ items: [normalize(option)]
112
+ });
113
+ });
114
+ const records = new Map(groups.flatMap((group) => group.items.map((record) => [record.value, record])));
115
+ const created = createdOptions.map(normalize).filter((record) => !records.has(record.value));
116
+ created.forEach((record) => records.set(record.value, record));
117
+ if (created.length) groups.push({
118
+ key: "created",
119
+ items: created
120
+ });
121
+ return {
122
+ groups,
123
+ records
124
+ };
125
+ }, [
126
+ options,
127
+ createdOptions,
128
+ labelField,
129
+ valueField,
130
+ disabledField
131
+ ]);
132
+ const [retained, setRetained] = useState(() => /* @__PURE__ */ new Map());
133
+ const selected = useMemo(() => {
134
+ return selectedKeys.map((key) => normalized.records.get(key) ?? retained.get(key) ?? (fallbackOption ? normalizeOption(fallbackOption(key), labelField, valueField, disabledField) : {
135
+ value: key,
136
+ label: String(key),
137
+ disabled: false
138
+ }));
139
+ }, [
140
+ selectedKeys,
141
+ normalized,
142
+ retained,
143
+ fallbackOption,
144
+ labelField,
145
+ valueField,
146
+ disabledField
147
+ ]);
148
+ if (retained.size !== selected.length || !selected.every((record) => retained.get(record.value) === record)) setRetained(new Map(selected.map((record) => [record.value, record])));
149
+ const search = String(inputValue ?? query).trim();
150
+ const canCreate = (create || creatable) && filterable && !loading && search !== "" && ![...normalized.records.values(), ...selected].some((record) => record.label.trim().toLocaleLowerCase() === search.toLocaleLowerCase());
151
+ const items = useMemo(() => {
152
+ if (!canCreate) return normalized.groups;
153
+ const candidate = {
154
+ value: search,
155
+ label: search,
156
+ disabled: false,
157
+ createQuery: search
158
+ };
159
+ return [...normalized.groups, {
160
+ key: "create",
161
+ items: [candidate]
162
+ }];
163
+ }, [
164
+ canCreate,
165
+ normalized.groups,
166
+ search
167
+ ]);
168
+ const css = `r-combobox-select r-combobox-select--${size}${resolvedMode === "dark" ? " r-combobox-select--dark" : ""}`;
169
+ const tagLimit = maxTagCount === void 0 ? Infinity : Math.max(0, Math.floor(maxTagCount));
170
+ const inputClassName = ["r-combobox-select__input", typeof inputProps?.className === "string" ? inputProps.className : null].filter(Boolean).join(" ");
171
+ const controlClassName = [
172
+ css,
173
+ "r-combobox-select__control",
174
+ className
175
+ ].filter(Boolean).join(" ");
176
+ const positionerClassName = ["r-combobox-select__positioner", typeof positionerProps?.className === "string" ? positionerProps.className : null].filter(Boolean).join(" ");
177
+ const popupClassName = [
178
+ css,
179
+ "r-combobox-select__popup",
180
+ typeof popupProps?.className === "string" ? popupProps.className : null
181
+ ].filter(Boolean).join(" ");
182
+ const inputRef = ref ?? inputProps?.ref;
183
+ const inputLabel = ariaLabel ?? inputProps?.["aria-label"];
184
+ const inputLabelledBy = ariaLabelledBy ?? inputProps?.["aria-labelledby"];
185
+ const inputDescribedBy = ariaDescribedBy ?? inputProps?.["aria-describedby"];
186
+ const inputInvalid = ariaInvalid ?? (status === "error" ? true : inputProps?.["aria-invalid"]);
187
+ const inputDescription = multiple && selected.length ? strings.inputDescription : inputProps?.["aria-description"];
188
+ const inputPlaceholder = multiple && selected.length ? "" : placeholder;
189
+ const inputReadOnly = readOnly || !filterable;
190
+ const controlValue = multiple ? selected : selected[0] ?? null;
191
+ const handleValueChange = useCallback((next, details) => {
192
+ const nextRecords = next === null ? [] : Array.isArray(next) ? next : [next];
193
+ const createRecord = nextRecords.find((record) => record.createQuery !== void 0);
194
+ let newOption;
195
+ let resolved = nextRecords;
196
+ if (createRecord) {
197
+ const created = onCreate ? onCreate(createRecord.label) : {
198
+ [labelField]: createRecord.label,
199
+ [valueField]: createRecord.label
200
+ };
201
+ if (created === null) {
202
+ details.cancel();
203
+ return;
204
+ }
205
+ const record = normalizeOption(created, labelField, valueField, disabledField);
206
+ if (record.disabled) {
207
+ details.cancel();
208
+ return;
209
+ }
210
+ newOption = created;
211
+ const existing = normalized.records.get(record.value) ?? retained.get(record.value);
212
+ resolved = nextRecords.map((item) => item === createRecord ? existing ?? record : item);
213
+ resolved = [...new Map(resolved.map((item) => [item.value, item])).values()];
214
+ }
215
+ const nextValue = multiple ? resolved.map((record) => record.value) : resolved[0]?.value ?? null;
216
+ const nextOptions = multiple ? resolved.map((record) => record.option) : resolved[0]?.option ?? null;
217
+ onValueChange?.(nextValue, nextOptions, details);
218
+ if (details.isCanceled) return;
219
+ if (newOption !== void 0) setCreatedOptions((previous) => [...previous, newOption]);
220
+ setRetained(new Map(resolved.map((record) => [record.value, record])));
221
+ if (value === void 0) setUncontrolledValue(nextValue);
222
+ if (details.reason === "clear-press") onClear?.();
223
+ }, [
224
+ multiple,
225
+ onCreate,
226
+ labelField,
227
+ valueField,
228
+ disabledField,
229
+ normalized.records,
230
+ retained,
231
+ onValueChange,
232
+ value,
233
+ onClear
234
+ ]);
235
+ const handleInputValueChange = useCallback((next, details) => {
236
+ onInputValueChange?.(next, details);
237
+ if (details.isCanceled) return;
238
+ const shouldKeepQuery = details.reason === "input-change" || details.reason === "item-press" && !clearFilterAfterSelect;
239
+ setQuery(shouldKeepQuery ? next : "");
240
+ if (details.reason === "input-change" || details.reason === "clear-press") onSearch?.(next);
241
+ }, [
242
+ onInputValueChange,
243
+ clearFilterAfterSelect,
244
+ onSearch
245
+ ]);
246
+ const filterOptions = useCallback((record, pattern) => {
247
+ if (record.createQuery !== void 0) return true;
248
+ if (remote || !filterable || filter === false) return true;
249
+ return record.option !== void 0 && typeof filter === "function" ? filter(pattern, record.option) : collator.compare(record.label.slice(0, pattern.length), pattern) === 0 || record.label.toLocaleLowerCase().includes(pattern.toLocaleLowerCase());
250
+ }, [
251
+ remote,
252
+ filterable,
253
+ filter,
254
+ collator
255
+ ]);
256
+ const selectedChips = selected.map((record, index) => renderSelectedChip({
257
+ record,
258
+ index,
259
+ tagLimit,
260
+ strings,
261
+ renderLabel,
262
+ renderTag
263
+ }));
264
+ const overflowCount = selected.length > tagLimit ? selected.length - tagLimit : 0;
265
+ const overflowTitle = selected.slice(tagLimit).map((record) => record.label).join(", ");
266
+ const overflow = overflowCount ? /* @__PURE__ */ jsxs("span", {
267
+ className: "r-combobox-select__overflow",
268
+ title: overflowTitle,
269
+ children: ["+", overflowCount]
270
+ }) : null;
271
+ function renderRecord(record) {
272
+ const itemKey = record.createQuery !== void 0 ? "create" : optionKey(record.value);
273
+ const content = renderOptionContent({
274
+ record,
275
+ selected: selected.some((item) => item.value === record.value),
276
+ renderLabel,
277
+ renderOption,
278
+ renderCreateLabel
279
+ });
280
+ return /* @__PURE__ */ jsx(Combobox.Item, {
281
+ value: record,
282
+ disabled: record.disabled || loading,
283
+ className: "r-combobox-select__option",
284
+ children: content
285
+ }, itemKey);
286
+ }
287
+ function renderGroup(group) {
288
+ const groupLabel = group.label == null ? null : /* @__PURE__ */ jsx(Combobox.GroupLabel, {
289
+ className: "r-combobox-select__group-label",
290
+ children: group.label
291
+ });
292
+ return /* @__PURE__ */ jsxs(Combobox.Group, {
293
+ items: group.items,
294
+ children: [groupLabel, /* @__PURE__ */ jsx(Combobox.Collection, { children: renderRecord })]
295
+ }, group.key);
296
+ }
297
+ const input = /* @__PURE__ */ jsx(Combobox.Input, {
298
+ ...inputProps,
299
+ ref: inputRef,
300
+ id,
301
+ "data-slot": "combobox-select-input",
302
+ className: inputClassName,
303
+ "aria-label": inputLabel,
304
+ "aria-labelledby": inputLabelledBy,
305
+ "aria-describedby": inputDescribedBy,
306
+ "aria-invalid": inputInvalid,
307
+ "aria-description": inputDescription,
308
+ placeholder: inputPlaceholder,
309
+ readOnly: inputReadOnly
310
+ });
311
+ const controlContent = multiple ? /* @__PURE__ */ jsxs(Combobox.Chips, {
312
+ className: "r-combobox-select__chips",
313
+ "aria-label": strings.selected,
314
+ children: [
315
+ selectedChips,
316
+ overflow,
317
+ input
318
+ ]
319
+ }) : input;
320
+ const loadingMessage = loading ? /* @__PURE__ */ jsx("div", {
321
+ className: "r-combobox-select__message",
322
+ children: loadingContent
323
+ }) : null;
324
+ const emptyMessage = !loading ? /* @__PURE__ */ jsx("div", {
325
+ className: "r-combobox-select__message",
326
+ children: emptyContent
327
+ }) : null;
328
+ const loadingIndicator = loading ? /* @__PURE__ */ jsx(LoaderCircle, {
329
+ className: "r-combobox-select__spinner",
330
+ "aria-hidden": true
331
+ }) : null;
332
+ const clearAction = clearable ? /* @__PURE__ */ jsx(Combobox.Clear, {
333
+ className: "r-combobox-select__action",
334
+ "aria-label": strings.clear,
335
+ children: /* @__PURE__ */ jsx(X, { "aria-hidden": true })
336
+ }) : null;
337
+ const triggerAction = showArrow ? /* @__PURE__ */ jsx(Combobox.Trigger, {
338
+ className: "r-combobox-select__action",
339
+ "aria-label": strings.toggle,
340
+ children: /* @__PURE__ */ jsx(ChevronDown, { "aria-hidden": true })
341
+ }) : null;
342
+ const actions = /* @__PURE__ */ jsxs("span", {
343
+ className: "r-combobox-select__actions",
344
+ children: [
345
+ loadingIndicator,
346
+ clearAction,
347
+ triggerAction
348
+ ]
349
+ });
350
+ const valueChange = handleValueChange;
351
+ return /* @__PURE__ */ jsxs(Combobox.Root, {
352
+ ...rootProps,
353
+ id,
354
+ multiple,
355
+ disabled,
356
+ readOnly,
357
+ items,
358
+ value: controlValue,
359
+ onValueChange: valueChange,
360
+ inputValue,
361
+ defaultInputValue,
362
+ onInputValueChange: handleInputValueChange,
363
+ filter: filterOptions,
364
+ itemToStringLabel,
365
+ itemToStringValue,
366
+ isItemEqualToValue,
367
+ autoHighlight,
368
+ children: [/* @__PURE__ */ jsxs(Combobox.InputGroup, {
369
+ "data-slot": "combobox-select",
370
+ "data-status": status,
371
+ className: controlClassName,
372
+ style,
373
+ children: [controlContent, actions]
374
+ }), /* @__PURE__ */ jsx(Combobox.Portal, {
375
+ ...scopedPortalProps,
376
+ children: /* @__PURE__ */ jsx(Combobox.Positioner, {
377
+ sideOffset: 4,
378
+ align: "start",
379
+ ...positionerProps,
380
+ className: positionerClassName,
381
+ children: /* @__PURE__ */ jsxs(Combobox.Popup, {
382
+ initialFocus: false,
383
+ finalFocus: false,
384
+ ...popupProps,
385
+ "data-slot": "combobox-select-popup",
386
+ className: popupClassName,
387
+ children: [
388
+ /* @__PURE__ */ jsx(Combobox.Status, { children: loadingMessage }),
389
+ /* @__PURE__ */ jsx(Combobox.List, {
390
+ className: "r-combobox-select__list",
391
+ "aria-busy": loading,
392
+ children: renderGroup
393
+ }),
394
+ /* @__PURE__ */ jsx(Combobox.Empty, { children: emptyMessage })
395
+ ]
396
+ })
397
+ })
398
+ })]
399
+ });
400
+ }
401
+ //#endregion
402
+ //#region src/components/announcement-dialog/announcement-dialog.tsx
403
+ const announcement = tv({ slots: {
404
+ content: ["@container/announcement max-w-xl gap-0 overflow-clip p-0"],
405
+ body: [
406
+ "min-h-0 max-h-[70dvh] overflow-y-auto pb-5",
407
+ "[&_[data-slot=announcement-picture]+[data-slot=announcement-text]]:mt-5",
408
+ "px-5 pt-5"
409
+ ],
410
+ header: ["flex min-w-0 items-center justify-between gap-3"],
411
+ label: ["flex min-w-0 items-center gap-2 wrap-break-word", "text-caption text-foreground-muted"],
412
+ dot: ["shrink-0", "size-[9px] rounded-[2px] border-[1.5px] border-sticker-ink bg-attention-400"],
413
+ title: ["mt-3 wrap-break-word normal-case", "text-headline font-bold tracking-normal"],
414
+ picture: ["mt-5 h-44 w-full overflow-hidden border border-line-hairline [&_img]:size-full [&_img]:object-contain", "rounded-container bg-fill-muted"],
415
+ text: [
416
+ "mt-3 min-w-0 wrap-break-word [&_p+p]:mt-3",
417
+ "[&_ul]:list-disc [&_ol]:list-decimal [&_ul]:pl-5 [&_ol]:pl-5 [&_h1]:text-xl [&_h2]:text-lg [&_h3]:text-base [&_h1]:font-bold [&_h2]:font-bold [&_h3]:font-bold [&_pre]:max-w-full [&_pre]:overflow-x-auto",
418
+ "text-subhead text-foreground-muted"
419
+ ],
420
+ footer: ["flex shrink-0 flex-wrap items-center justify-between gap-3 border-line-hairline py-4 @max-[28rem]/announcement:flex-col", "border-t-0 px-5 pt-0 pb-5"],
421
+ action: ["ml-auto h-auto min-h-8 min-w-0 max-w-full py-1 whitespace-normal text-center font-bold @max-[28rem]/announcement:ml-0 @max-[28rem]/announcement:w-full"],
422
+ secondary: ["min-w-0 max-w-full px-0 whitespace-normal underline @max-[28rem]/announcement:w-full"]
423
+ } });
424
+ function AnnouncementDialogContent({ className, initialFocus, ref, ...props }) {
425
+ const localRef = useRef(null);
426
+ const setRef = useCallback((node) => {
427
+ localRef.current = node;
428
+ if (typeof ref === "function") return ref(node);
429
+ if (ref) ref.current = node;
430
+ }, [ref]);
431
+ const focusAction = useCallback(() => localRef.current?.querySelector("[data-announcement-action]:not(:disabled)") ?? true, []);
432
+ const { content } = announcement();
433
+ return /* @__PURE__ */ jsx(DialogContent, {
434
+ ref: setRef,
435
+ initialFocus: initialFocus ?? focusAction,
436
+ className: content({ className }),
437
+ ...props
438
+ });
439
+ }
440
+ function AnnouncementDialogBody({ className, ...props }) {
441
+ const { body } = announcement();
442
+ return /* @__PURE__ */ jsx("div", {
443
+ "data-slot": "announcement-body",
444
+ className: body({ className }),
445
+ ...props
446
+ });
447
+ }
448
+ function AnnouncementDialogHeader({ className, ...props }) {
449
+ const { header } = announcement();
450
+ return /* @__PURE__ */ jsx("div", {
451
+ "data-slot": "announcement-header",
452
+ className: header({ className }),
453
+ ...props
454
+ });
455
+ }
456
+ function AnnouncementDialogLabel({ className, children, ...props }) {
457
+ const { label, dot } = announcement();
458
+ return /* @__PURE__ */ jsxs("div", {
459
+ "data-slot": "announcement-label",
460
+ className: label({ className }),
461
+ ...props,
462
+ children: [/* @__PURE__ */ jsx("span", {
463
+ "aria-hidden": "true",
464
+ className: dot()
465
+ }), children]
466
+ });
467
+ }
468
+ function AnnouncementDialogTitle({ className, ...props }) {
469
+ const { title } = announcement();
470
+ return /* @__PURE__ */ jsx(DialogTitle, {
471
+ className: title({ className }),
472
+ ...props
473
+ });
474
+ }
475
+ function AnnouncementDialogPicture({ className, ...props }) {
476
+ const { picture } = announcement();
477
+ return /* @__PURE__ */ jsx("div", {
478
+ "data-slot": "announcement-picture",
479
+ className: picture({ className }),
480
+ ...props
481
+ });
482
+ }
483
+ function AnnouncementDialogText({ className, ...props }) {
484
+ const { text } = announcement();
485
+ return /* @__PURE__ */ jsx("div", {
486
+ "data-slot": "announcement-text",
487
+ className: text({ className }),
488
+ ...props
489
+ });
490
+ }
491
+ function AnnouncementDialogFooter({ className, ...props }) {
492
+ const { footer } = announcement();
493
+ return /* @__PURE__ */ jsx("div", {
494
+ "data-slot": "announcement-footer",
495
+ className: footer({ className }),
496
+ ...props
497
+ });
498
+ }
499
+ function AnnouncementDialogAction({ className, ...props }) {
500
+ const { action } = announcement();
501
+ return /* @__PURE__ */ jsx(Button, {
502
+ variant: "accent",
503
+ "data-announcement-action": true,
504
+ className: action({ className }),
505
+ ...props
506
+ });
507
+ }
508
+ function AnnouncementDialogSecondaryAction({ className, ...props }) {
509
+ const { secondary } = announcement();
510
+ return /* @__PURE__ */ jsx(Button, {
511
+ variant: "link",
512
+ className: secondary({ className }),
513
+ ...props
514
+ });
515
+ }
516
+ //#endregion
517
+ export { Dialog as AnnouncementDialog, AnnouncementDialogAction, AnnouncementDialogBody, DialogClose as AnnouncementDialogClose, AnnouncementDialogContent, AnnouncementDialogFooter, AnnouncementDialogHeader, AnnouncementDialogLabel, AnnouncementDialogPicture, AnnouncementDialogSecondaryAction, AnnouncementDialogText, AnnouncementDialogTitle, DialogTrigger as AnnouncementDialogTrigger, ComboboxSelect };