@ucdjs-internal/shared-ui 0.1.2 → 0.1.5

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.
@@ -5,7 +5,7 @@ import * as class_variance_authority_types0 from "class-variance-authority/types
5
5
 
6
6
  //#region src/ui/badge.d.ts
7
7
  declare const badgeVariants: (props?: ({
8
- variant?: "default" | "secondary" | "destructive" | "outline" | "ghost" | "link" | null | undefined;
8
+ variant?: "link" | "default" | "outline" | "secondary" | "ghost" | "destructive" | null | undefined;
9
9
  } & class_variance_authority_types0.ClassProp) | undefined) => string;
10
10
  declare function Badge({
11
11
  className,
@@ -5,8 +5,8 @@ import * as class_variance_authority_types0 from "class-variance-authority/types
5
5
 
6
6
  //#region src/ui/button.d.ts
7
7
  declare const buttonVariants: (props?: ({
8
- variant?: "default" | "secondary" | "destructive" | "outline" | "ghost" | "link" | null | undefined;
9
- size?: "default" | "xs" | "sm" | "lg" | "icon" | "icon-xs" | "icon-sm" | "icon-lg" | null | undefined;
8
+ variant?: "link" | "default" | "outline" | "secondary" | "ghost" | "destructive" | null | undefined;
9
+ size?: "xs" | "sm" | "icon-xs" | "icon-sm" | "default" | "lg" | "icon" | "icon-lg" | null | undefined;
10
10
  } & class_variance_authority_types0.ClassProp) | undefined) => string;
11
11
  declare function Button({
12
12
  className,
@@ -1,13 +1,13 @@
1
1
  import { Dialog } from "./dialog.mjs";
2
+ import { pkg } from "../vendor/cmdk/index.mjs";
2
3
  import * as React from "react";
3
4
  import * as react_jsx_runtime0 from "react/jsx-runtime";
4
- import { Command as Command$1 } from "cmdk";
5
5
 
6
6
  //#region src/ui/command.d.ts
7
7
  declare function Command({
8
8
  className,
9
9
  ...props
10
- }: React.ComponentProps<typeof Command$1>): react_jsx_runtime0.JSX.Element;
10
+ }: React.ComponentProps<typeof pkg>): react_jsx_runtime0.JSX.Element;
11
11
  declare function CommandDialog({
12
12
  title,
13
13
  description,
@@ -25,28 +25,28 @@ declare function CommandDialog({
25
25
  declare function CommandInput({
26
26
  className,
27
27
  ...props
28
- }: React.ComponentProps<typeof Command$1.Input>): react_jsx_runtime0.JSX.Element;
28
+ }: React.ComponentProps<typeof pkg.Input>): react_jsx_runtime0.JSX.Element;
29
29
  declare function CommandList({
30
30
  className,
31
31
  ...props
32
- }: React.ComponentProps<typeof Command$1.List>): react_jsx_runtime0.JSX.Element;
32
+ }: React.ComponentProps<typeof pkg.List>): react_jsx_runtime0.JSX.Element;
33
33
  declare function CommandEmpty({
34
34
  className,
35
35
  ...props
36
- }: React.ComponentProps<typeof Command$1.Empty>): react_jsx_runtime0.JSX.Element;
36
+ }: React.ComponentProps<typeof pkg.Empty>): react_jsx_runtime0.JSX.Element;
37
37
  declare function CommandGroup({
38
38
  className,
39
39
  ...props
40
- }: React.ComponentProps<typeof Command$1.Group>): react_jsx_runtime0.JSX.Element;
40
+ }: React.ComponentProps<typeof pkg.Group>): react_jsx_runtime0.JSX.Element;
41
41
  declare function CommandSeparator({
42
42
  className,
43
43
  ...props
44
- }: React.ComponentProps<typeof Command$1.Separator>): react_jsx_runtime0.JSX.Element;
44
+ }: React.ComponentProps<typeof pkg.Separator>): react_jsx_runtime0.JSX.Element;
45
45
  declare function CommandItem({
46
46
  className,
47
47
  children,
48
48
  ...props
49
- }: React.ComponentProps<typeof Command$1.Item>): react_jsx_runtime0.JSX.Element;
49
+ }: React.ComponentProps<typeof pkg.Item>): react_jsx_runtime0.JSX.Element;
50
50
  declare function CommandShortcut({
51
51
  className,
52
52
  ...props
@@ -1,11 +1,11 @@
1
1
  import { cn } from "../lib/utils.mjs";
2
2
  import { InputGroup, InputGroupAddon } from "./input-group.mjs";
3
3
  import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from "./dialog.mjs";
4
+ import { pkg } from "../vendor/cmdk/index.mjs";
4
5
  import "react";
5
6
  import { jsx, jsxs } from "react/jsx-runtime";
6
7
  import { c } from "react/compiler-runtime";
7
8
  import { CheckIcon, SearchIcon } from "lucide-react";
8
- import { Command as Command$1 } from "cmdk";
9
9
 
10
10
  //#region src/ui/command.tsx
11
11
  function Command(t0) {
@@ -29,7 +29,7 @@ function Command(t0) {
29
29
  } else t1 = $[4];
30
30
  let t2;
31
31
  if ($[5] !== props || $[6] !== t1) {
32
- t2 = /* @__PURE__ */ jsx(Command$1, {
32
+ t2 = /* @__PURE__ */ jsx(pkg, {
33
33
  "data-slot": "command",
34
34
  className: t1,
35
35
  ...props
@@ -142,7 +142,7 @@ function CommandInput(t0) {
142
142
  } else t1 = $[4];
143
143
  let t2;
144
144
  if ($[5] !== props || $[6] !== t1) {
145
- t2 = /* @__PURE__ */ jsx(Command$1.Input, {
145
+ t2 = /* @__PURE__ */ jsx(pkg.Input, {
146
146
  "data-slot": "command-input",
147
147
  className: t1,
148
148
  ...props
@@ -192,7 +192,7 @@ function CommandList(t0) {
192
192
  } else t1 = $[4];
193
193
  let t2;
194
194
  if ($[5] !== props || $[6] !== t1) {
195
- t2 = /* @__PURE__ */ jsx(Command$1.List, {
195
+ t2 = /* @__PURE__ */ jsx(pkg.List, {
196
196
  "data-slot": "command-list",
197
197
  className: t1,
198
198
  ...props
@@ -224,7 +224,7 @@ function CommandEmpty(t0) {
224
224
  } else t1 = $[4];
225
225
  let t2;
226
226
  if ($[5] !== props || $[6] !== t1) {
227
- t2 = /* @__PURE__ */ jsx(Command$1.Empty, {
227
+ t2 = /* @__PURE__ */ jsx(pkg.Empty, {
228
228
  "data-slot": "command-empty",
229
229
  className: t1,
230
230
  ...props
@@ -256,7 +256,7 @@ function CommandGroup(t0) {
256
256
  } else t1 = $[4];
257
257
  let t2;
258
258
  if ($[5] !== props || $[6] !== t1) {
259
- t2 = /* @__PURE__ */ jsx(Command$1.Group, {
259
+ t2 = /* @__PURE__ */ jsx(pkg.Group, {
260
260
  "data-slot": "command-group",
261
261
  className: t1,
262
262
  ...props
@@ -288,7 +288,7 @@ function CommandSeparator(t0) {
288
288
  } else t1 = $[4];
289
289
  let t2;
290
290
  if ($[5] !== props || $[6] !== t1) {
291
- t2 = /* @__PURE__ */ jsx(Command$1.Separator, {
291
+ t2 = /* @__PURE__ */ jsx(pkg.Separator, {
292
292
  "data-slot": "command-separator",
293
293
  className: t1,
294
294
  ...props
@@ -328,7 +328,7 @@ function CommandItem(t0) {
328
328
  } else t2 = $[6];
329
329
  let t3;
330
330
  if ($[7] !== children || $[8] !== props || $[9] !== t1) {
331
- t3 = /* @__PURE__ */ jsxs(Command$1.Item, {
331
+ t3 = /* @__PURE__ */ jsxs(pkg.Item, {
332
332
  "data-slot": "command-item",
333
333
  className: t1,
334
334
  ...props,
@@ -20,7 +20,7 @@ declare function FieldGroup({
20
20
  ...props
21
21
  }: React.ComponentProps<"div">): react_jsx_runtime0.JSX.Element;
22
22
  declare const fieldVariants: (props?: ({
23
- orientation?: "horizontal" | "vertical" | "responsive" | null | undefined;
23
+ orientation?: "vertical" | "horizontal" | "responsive" | null | undefined;
24
24
  } & class_variance_authority_types0.ClassProp) | undefined) => string;
25
25
  declare function Field({
26
26
  className,
@@ -105,7 +105,7 @@ declare function SidebarMenuItem({
105
105
  }: React.ComponentProps<"li">): react_jsx_runtime0.JSX.Element;
106
106
  declare const sidebarMenuButtonVariants: (props?: ({
107
107
  variant?: "default" | "outline" | null | undefined;
108
- size?: "default" | "sm" | "lg" | null | undefined;
108
+ size?: "sm" | "default" | "lg" | null | undefined;
109
109
  } & class_variance_authority_types0.ClassProp) | undefined) => string;
110
110
  declare function SidebarMenuButton({
111
111
  render,
@@ -0,0 +1,62 @@
1
+ //#region src/vendor/cmdk/command-score.ts
2
+ const SCORE_CONTINUE_MATCH = 1;
3
+ const SCORE_SPACE_WORD_JUMP = .9;
4
+ const SCORE_NON_SPACE_WORD_JUMP = .8;
5
+ const SCORE_CHARACTER_JUMP = .17;
6
+ const SCORE_TRANSPOSITION = .1;
7
+ const PENALTY_SKIPPED = .999;
8
+ const PENALTY_CASE_MISMATCH = .9999;
9
+ const PENALTY_NOT_COMPLETE = .99;
10
+ const IS_GAP_REGEXP = /[\\/_+.#"@[({&]/;
11
+ const COUNT_GAPS_REGEXP = /[\\/_+.#"@[({&]/g;
12
+ const IS_SPACE_REGEXP = /[\s-]/;
13
+ const COUNT_SPACE_REGEXP = /[\s-]/g;
14
+ function commandScoreInner(value, abbreviation, lowerString, lowerAbbreviation, stringIndex, abbreviationIndex, memoizedResults) {
15
+ if (abbreviationIndex === abbreviation.length) {
16
+ if (stringIndex === value.length) return SCORE_CONTINUE_MATCH;
17
+ return PENALTY_NOT_COMPLETE;
18
+ }
19
+ const memoizeKey = `${stringIndex},${abbreviationIndex}`;
20
+ if (memoizedResults[memoizeKey] !== void 0) return memoizedResults[memoizeKey];
21
+ const abbreviationChar = lowerAbbreviation.charAt(abbreviationIndex);
22
+ let index = lowerString.indexOf(abbreviationChar, stringIndex);
23
+ let highScore = 0;
24
+ let score, transposedScore, wordBreaks, spaceBreaks;
25
+ while (index >= 0) {
26
+ score = commandScoreInner(value, abbreviation, lowerString, lowerAbbreviation, index + 1, abbreviationIndex + 1, memoizedResults);
27
+ if (score > highScore) {
28
+ if (index === stringIndex) score *= SCORE_CONTINUE_MATCH;
29
+ else if (IS_GAP_REGEXP.test(value.charAt(index - 1))) {
30
+ score *= SCORE_NON_SPACE_WORD_JUMP;
31
+ wordBreaks = value.slice(stringIndex, index - 1).match(COUNT_GAPS_REGEXP);
32
+ if (wordBreaks && stringIndex > 0) score *= PENALTY_SKIPPED ** wordBreaks.length;
33
+ } else if (IS_SPACE_REGEXP.test(value.charAt(index - 1))) {
34
+ score *= SCORE_SPACE_WORD_JUMP;
35
+ spaceBreaks = value.slice(stringIndex, index - 1).match(COUNT_SPACE_REGEXP);
36
+ if (spaceBreaks && stringIndex > 0) score *= PENALTY_SKIPPED ** spaceBreaks.length;
37
+ } else {
38
+ score *= SCORE_CHARACTER_JUMP;
39
+ if (stringIndex > 0) score *= PENALTY_SKIPPED ** (index - stringIndex);
40
+ }
41
+ if (value.charAt(index) !== abbreviation.charAt(abbreviationIndex)) score *= PENALTY_CASE_MISMATCH;
42
+ }
43
+ if (score < SCORE_TRANSPOSITION && lowerString.charAt(index - 1) === lowerAbbreviation.charAt(abbreviationIndex + 1) || lowerAbbreviation.charAt(abbreviationIndex + 1) === lowerAbbreviation.charAt(abbreviationIndex) && lowerString.charAt(index - 1) !== lowerAbbreviation.charAt(abbreviationIndex)) {
44
+ transposedScore = commandScoreInner(value, abbreviation, lowerString, lowerAbbreviation, index + 1, abbreviationIndex + 2, memoizedResults);
45
+ if (transposedScore * SCORE_TRANSPOSITION > score) score = transposedScore * SCORE_TRANSPOSITION;
46
+ }
47
+ if (score > highScore) highScore = score;
48
+ index = lowerString.indexOf(abbreviationChar, index + 1);
49
+ }
50
+ memoizedResults[memoizeKey] = highScore;
51
+ return highScore;
52
+ }
53
+ function formatInput(value) {
54
+ return value.toLowerCase().replace(COUNT_SPACE_REGEXP, " ");
55
+ }
56
+ function commandScore(string, abbreviation, aliases) {
57
+ string = aliases && aliases.length > 0 ? `${`${string} ${aliases.join(" ")}`}` : string;
58
+ return commandScoreInner(string, abbreviation, formatInput(string), formatInput(abbreviation), 0, 0, {});
59
+ }
60
+
61
+ //#endregion
62
+ export { commandScore };
@@ -0,0 +1,181 @@
1
+ import * as React from "react";
2
+ import * as react_jsx_runtime0 from "react/jsx-runtime";
3
+ import { Dialog } from "@base-ui/react";
4
+
5
+ //#region src/vendor/cmdk/index.d.ts
6
+ interface Children {
7
+ children?: React.ReactNode;
8
+ }
9
+ type DivProps = React.ComponentPropsWithoutRef<"div">;
10
+ interface RefProp<T> {
11
+ ref?: React.Ref<T>;
12
+ }
13
+ type LoadingProps = Children & DivProps & {
14
+ /** Estimated progress of loading asynchronous options. */progress?: number;
15
+ /**
16
+ * Accessible label for this loading progressbar. Not shown visibly.
17
+ */
18
+ label?: string;
19
+ };
20
+ type EmptyProps = Children & DivProps & {};
21
+ type SeparatorProps = DivProps & {
22
+ /** Whether this separator should always be rendered. Useful if you disable automatic filtering. */alwaysRender?: boolean;
23
+ };
24
+ type DialogProps = Dialog.Root.Props & CommandProps & {
25
+ /** Provide a className to the Dialog overlay. */overlayClassName?: string; /** Provide a className to the Dialog content. */
26
+ contentClassName?: string; /** Provide a custom element the Dialog should portal into. */
27
+ container?: HTMLElement;
28
+ };
29
+ type ListProps = Children & DivProps & {
30
+ /**
31
+ * Accessible label for this List of suggestions. Not shown visibly.
32
+ */
33
+ label?: string;
34
+ };
35
+ type ItemProps = Children & Omit<DivProps, "disabled" | "onSelect" | "value"> & {
36
+ /** Whether this item is currently disabled. */disabled?: boolean; /** Event handler for when this item is selected, either via click or keyboard selection. */
37
+ onSelect?: (value: string) => void;
38
+ /**
39
+ * A unique value for this item.
40
+ * If no value is provided, it will be inferred from `children` or the rendered `textContent`. If your `textContent` changes between renders, you _must_ provide a stable, unique `value`.
41
+ */
42
+ value?: string; /** Optional keywords to match against when filtering. */
43
+ keywords?: string[]; /** Whether this item is forcibly rendered regardless of filtering. */
44
+ forceMount?: boolean;
45
+ };
46
+ type GroupProps = Children & Omit<DivProps, "heading" | "value"> & {
47
+ /** Optional heading to render for this group. */heading?: React.ReactNode; /** If no heading is provided, you must provide a value that is unique for this group. */
48
+ value?: string; /** Whether this group is forcibly rendered regardless of filtering. */
49
+ forceMount?: boolean;
50
+ };
51
+ type InputProps = Omit<React.ComponentPropsWithoutRef<"input">, "value" | "onChange" | "type"> & {
52
+ /**
53
+ * Optional controlled state for the value of the search input.
54
+ */
55
+ value?: string;
56
+ /**
57
+ * Event handler called when the search value changes.
58
+ */
59
+ onValueChange?: (search: string) => void;
60
+ };
61
+ type CommandFilter = (value: string, search: string, keywords?: string[]) => number;
62
+ type CommandProps = Children & DivProps & {
63
+ /**
64
+ * Accessible label for this command menu. Not shown visibly.
65
+ */
66
+ label?: string;
67
+ /**
68
+ * Optionally set to `false` to turn off the automatic filtering and sorting.
69
+ * If `false`, you must conditionally render valid items based on the search query yourself.
70
+ */
71
+ shouldFilter?: boolean;
72
+ /**
73
+ * Custom filter function for whether each command menu item should matches the given search query.
74
+ * It should return a number between 0 and 1, with 1 being the best match and 0 being hidden entirely.
75
+ * By default, uses the `command-score` library.
76
+ */
77
+ filter?: CommandFilter;
78
+ /**
79
+ * Optional default item value when it is initially rendered.
80
+ */
81
+ defaultValue?: string;
82
+ /**
83
+ * Optional controlled state of the selected command menu item.
84
+ */
85
+ value?: string;
86
+ /**
87
+ * Event handler called when the selected item of the menu changes.
88
+ */
89
+ onValueChange?: (value: string) => void;
90
+ /**
91
+ * Optionally set to `true` to turn on looping around when using the arrow keys.
92
+ */
93
+ loop?: boolean;
94
+ /**
95
+ * Optionally set to `true` to disable selection via pointer events.
96
+ */
97
+ disablePointerSelection?: boolean;
98
+ /**
99
+ * Set to `false` to disable ctrl+n/j/p/k shortcuts. Defaults to `true`.
100
+ */
101
+ vimBindings?: boolean;
102
+ };
103
+ declare function Command({
104
+ ref: forwardedRef,
105
+ ...props
106
+ }: CommandProps & RefProp<HTMLDivElement>): react_jsx_runtime0.JSX.Element;
107
+ /**
108
+ * Command menu item. Becomes active on pointer enter or through keyboard navigation.
109
+ * Preferably pass a `value`, otherwise the value will be inferred from `children` or
110
+ * the rendered item's `textContent`.
111
+ */
112
+ declare function Item({
113
+ ref: forwardedRef,
114
+ ...props
115
+ }: ItemProps & RefProp<HTMLDivElement>): react_jsx_runtime0.JSX.Element | null;
116
+ /**
117
+ * Group command menu items together with a heading.
118
+ * Grouped items are always shown together.
119
+ */
120
+ declare function Group({
121
+ ref: forwardedRef,
122
+ ...props
123
+ }: GroupProps & RefProp<HTMLDivElement>): react_jsx_runtime0.JSX.Element;
124
+ /**
125
+ * A visual and semantic separator between items or groups.
126
+ * Visible when the search query is empty or `alwaysRender` is true, hidden otherwise.
127
+ */
128
+ declare function Separator({
129
+ ref: forwardedRef,
130
+ ...props
131
+ }: SeparatorProps & RefProp<HTMLDivElement>): react_jsx_runtime0.JSX.Element | null;
132
+ /**
133
+ * Command menu input.
134
+ * All props are forwarded to the underyling `input` element.
135
+ */
136
+ declare function Input({
137
+ ref: forwardedRef,
138
+ ...props
139
+ }: InputProps & RefProp<HTMLInputElement>): react_jsx_runtime0.JSX.Element;
140
+ /**
141
+ * Contains `Item`, `Group`, and `Separator`.
142
+ * Use the `--cmdk-list-height` CSS variable to animate height based on the number of results.
143
+ */
144
+ declare function List({
145
+ ref: forwardedRef,
146
+ ...props
147
+ }: ListProps & RefProp<HTMLDivElement>): react_jsx_runtime0.JSX.Element;
148
+ /**
149
+ * Renders the command menu in a Base UI Dialog.
150
+ */
151
+ declare function Dialog$1({
152
+ ref: forwardedRef,
153
+ ...props
154
+ }: DialogProps & RefProp<HTMLDivElement>): react_jsx_runtime0.JSX.Element;
155
+ /**
156
+ * Automatically renders when there are no results for the search query.
157
+ */
158
+ declare function Empty({
159
+ ref: forwardedRef,
160
+ ...props
161
+ }: EmptyProps & RefProp<HTMLDivElement>): react_jsx_runtime0.JSX.Element | null;
162
+ /**
163
+ * You should conditionally render this with `progress` while loading asynchronous items.
164
+ */
165
+ declare function Loading({
166
+ ref: forwardedRef,
167
+ ...props
168
+ }: LoadingProps & RefProp<HTMLDivElement>): react_jsx_runtime0.JSX.Element;
169
+ declare const pkg: typeof Command & {
170
+ List: typeof List;
171
+ Item: typeof Item;
172
+ Input: typeof Input;
173
+ Group: typeof Group;
174
+ Separator: typeof Separator;
175
+ Dialog: typeof Dialog$1;
176
+ Empty: typeof Empty;
177
+ Loading: typeof Loading;
178
+ };
179
+ /** Run a selector against the store state. */
180
+ //#endregion
181
+ export { pkg };
@@ -0,0 +1,713 @@
1
+ import { commandScore } from "./command-score.mjs";
2
+ import * as React from "react";
3
+ import { jsx, jsxs } from "react/jsx-runtime";
4
+ import { Dialog } from "@base-ui/react";
5
+ import { useId } from "@base-ui/utils/useId";
6
+
7
+ //#region src/vendor/cmdk/index.tsx
8
+ const GROUP_SELECTOR = `[cmdk-group=""]`;
9
+ const GROUP_ITEMS_SELECTOR = `[cmdk-group-items=""]`;
10
+ const GROUP_HEADING_SELECTOR = `[cmdk-group-heading=""]`;
11
+ const ITEM_SELECTOR = `[cmdk-item=""]`;
12
+ const VALID_ITEM_SELECTOR = `${ITEM_SELECTOR}:not([aria-disabled="true"])`;
13
+ const SELECT_EVENT = `cmdk-item-select`;
14
+ const VALUE_ATTR = `data-value`;
15
+ const defaultFilter = (value, search, keywords = []) => commandScore(value, search, keywords);
16
+ const useLayoutEffect = typeof window === "undefined" ? React.useEffect : React.useLayoutEffect;
17
+ const srOnlyStyles = {
18
+ position: "absolute",
19
+ width: "1px",
20
+ height: "1px",
21
+ padding: "0",
22
+ margin: "-1px",
23
+ overflow: "hidden",
24
+ clip: "rect(0, 0, 0, 0)",
25
+ whiteSpace: "nowrap",
26
+ borderWidth: "0"
27
+ };
28
+ const CommandContext = React.createContext(void 0);
29
+ const useCommand = () => React.use(CommandContext);
30
+ const StoreContext = React.createContext(void 0);
31
+ const useStore = () => React.use(StoreContext);
32
+ const GroupContext = React.createContext(void 0);
33
+ function Command({ ref: forwardedRef, ...props }) {
34
+ const state = useLazyRef(() => ({
35
+ search: "",
36
+ value: props.value ?? props.defaultValue ?? "",
37
+ selectedItemId: void 0,
38
+ filtered: {
39
+ count: 0,
40
+ items: /* @__PURE__ */ new Map(),
41
+ groups: /* @__PURE__ */ new Set()
42
+ }
43
+ }));
44
+ const allItems = useLazyRef(() => /* @__PURE__ */ new Set());
45
+ const allGroups = useLazyRef(() => /* @__PURE__ */ new Map());
46
+ const ids = useLazyRef(() => /* @__PURE__ */ new Map());
47
+ const listeners = useLazyRef(() => /* @__PURE__ */ new Set());
48
+ const propsRef = useAsRef(props);
49
+ const { label, children: _children, value, onValueChange: _onValueChange, filter: _filter, shouldFilter: _shouldFilter, loop: _loop, disablePointerSelection: _disablePointerSelection = false, vimBindings = true, ...etc } = props;
50
+ const listId = useId();
51
+ const labelId = useId();
52
+ const inputId = useId();
53
+ const listInnerRef = React.useRef(null);
54
+ const schedule = useScheduleLayoutEffect();
55
+ const store = React.useMemo(() => {
56
+ return {
57
+ subscribe: (cb) => {
58
+ listeners.current.add(cb);
59
+ return () => listeners.current.delete(cb);
60
+ },
61
+ snapshot: () => {
62
+ return state.current;
63
+ },
64
+ setState: (key, value, opts) => {
65
+ if (Object.is(state.current[key], value)) return;
66
+ state.current[key] = value;
67
+ if (key === "search") {
68
+ filterItems();
69
+ sort();
70
+ schedule(1, selectFirstItem);
71
+ } else if (key === "value") {
72
+ const activeElement = document.activeElement;
73
+ if (activeElement && (activeElement.hasAttribute("cmdk-input") || activeElement.hasAttribute("cmdk-root"))) {
74
+ const input = inputId ? document.getElementById(inputId) : null;
75
+ if (input) input.focus();
76
+ else if (listId) document.getElementById(listId)?.focus();
77
+ }
78
+ schedule(7, () => {
79
+ state.current.selectedItemId = getSelectedItem()?.id;
80
+ store.emit();
81
+ });
82
+ if (!opts) schedule(5, scrollSelectedIntoView);
83
+ if (propsRef.current?.value !== void 0) {
84
+ const newValue = value ?? "";
85
+ propsRef.current.onValueChange?.(newValue);
86
+ return;
87
+ }
88
+ }
89
+ store.emit();
90
+ },
91
+ emit: () => {
92
+ listeners.current.forEach((l) => l());
93
+ }
94
+ };
95
+ }, []);
96
+ const context = React.useMemo(() => ({
97
+ value: (id, value, keywords) => {
98
+ if (value !== ids.current.get(id)?.value) {
99
+ ids.current.set(id, {
100
+ value,
101
+ keywords
102
+ });
103
+ state.current.filtered.items.set(id, score(value, keywords));
104
+ schedule(2, () => {
105
+ sort();
106
+ store.emit();
107
+ });
108
+ }
109
+ },
110
+ item: (id, groupId) => {
111
+ allItems.current.add(id);
112
+ if (groupId) if (!allGroups.current.has(groupId)) allGroups.current.set(groupId, new Set([id]));
113
+ else {
114
+ const group = allGroups.current.get(groupId);
115
+ if (group) group.add(id);
116
+ }
117
+ schedule(3, () => {
118
+ filterItems();
119
+ sort();
120
+ if (!state.current.value) selectFirstItem();
121
+ store.emit();
122
+ });
123
+ return () => {
124
+ ids.current.delete(id);
125
+ allItems.current.delete(id);
126
+ state.current.filtered.items.delete(id);
127
+ const selectedItem = getSelectedItem();
128
+ schedule(4, () => {
129
+ filterItems();
130
+ if (selectedItem?.getAttribute("id") === id) selectFirstItem();
131
+ store.emit();
132
+ });
133
+ };
134
+ },
135
+ group: (id) => {
136
+ if (!allGroups.current.has(id)) allGroups.current.set(id, /* @__PURE__ */ new Set());
137
+ return () => {
138
+ ids.current.delete(id);
139
+ allGroups.current.delete(id);
140
+ };
141
+ },
142
+ filter: () => {
143
+ return propsRef.current.shouldFilter ?? true;
144
+ },
145
+ label: label || props["aria-label"] || "",
146
+ getDisablePointerSelection: () => {
147
+ return propsRef.current.disablePointerSelection ?? false;
148
+ },
149
+ listId,
150
+ inputId,
151
+ labelId,
152
+ listInnerRef
153
+ }), []);
154
+ /** Controlled mode `value` handling. */
155
+ useLayoutEffect(() => {
156
+ if (value !== void 0) {
157
+ const v = value.trim();
158
+ state.current.value = v;
159
+ store.emit();
160
+ }
161
+ }, [store, value]);
162
+ useLayoutEffect(() => {
163
+ schedule(6, scrollSelectedIntoView);
164
+ }, [schedule]);
165
+ function score(value, keywords) {
166
+ const filter = propsRef.current?.filter ?? defaultFilter;
167
+ return value ? filter(value, state.current.search, keywords) : 0;
168
+ }
169
+ /** Sorts items by score, and groups by highest item score. */
170
+ function sort() {
171
+ if (!state.current.search || propsRef.current.shouldFilter === false) return;
172
+ const scores = state.current.filtered.items;
173
+ const groups = [];
174
+ state.current.filtered.groups.forEach((value) => {
175
+ const items = allGroups.current.get(value);
176
+ let max = 0;
177
+ if (items) items.forEach((item) => {
178
+ const score = scores.get(item) ?? 0;
179
+ max = Math.max(score, max);
180
+ });
181
+ groups.push([value, max]);
182
+ });
183
+ const listInsertionElement = listInnerRef.current;
184
+ getValidItems().sort((a, b) => {
185
+ const valueA = a.getAttribute("id") ?? "";
186
+ const valueB = b.getAttribute("id") ?? "";
187
+ return (scores.get(valueB) ?? 0) - (scores.get(valueA) ?? 0);
188
+ }).forEach((item) => {
189
+ const group = item.closest(GROUP_ITEMS_SELECTOR);
190
+ if (group) {
191
+ const target = item.parentElement === group ? item : item.closest(`${GROUP_ITEMS_SELECTOR} > *`);
192
+ if (target) group.appendChild(target);
193
+ } else if (listInsertionElement) {
194
+ const target = item.parentElement === listInsertionElement ? item : item.closest(`${GROUP_ITEMS_SELECTOR} > *`);
195
+ if (target) listInsertionElement.appendChild(target);
196
+ }
197
+ });
198
+ groups.sort((a, b) => b[1] - a[1]).forEach((group) => {
199
+ const element = listInnerRef.current?.querySelector(`${GROUP_SELECTOR}[${VALUE_ATTR}="${encodeURIComponent(group[0])}"]`);
200
+ if (element && element.parentElement) element.parentElement.appendChild(element);
201
+ });
202
+ }
203
+ function selectFirstItem() {
204
+ const value = getValidItems().find((item) => item.getAttribute("aria-disabled") !== "true")?.getAttribute(VALUE_ATTR);
205
+ store.setState("value", value ?? "");
206
+ }
207
+ /** Filters the current items. */
208
+ function filterItems() {
209
+ if (!state.current.search || propsRef.current.shouldFilter === false) {
210
+ state.current.filtered.count = allItems.current.size;
211
+ return;
212
+ }
213
+ state.current.filtered.groups = /* @__PURE__ */ new Set();
214
+ let itemCount = 0;
215
+ for (const id of allItems.current) {
216
+ const rank = score(ids.current.get(id)?.value ?? "", ids.current.get(id)?.keywords ?? []);
217
+ state.current.filtered.items.set(id, rank);
218
+ if (rank > 0) itemCount++;
219
+ }
220
+ for (const [groupId, group] of allGroups.current) for (const itemId of group) if ((state.current.filtered.items.get(itemId) ?? 0) > 0) {
221
+ state.current.filtered.groups.add(groupId);
222
+ break;
223
+ }
224
+ state.current.filtered.count = itemCount;
225
+ }
226
+ function scrollSelectedIntoView() {
227
+ requestAnimationFrame(() => {
228
+ const item = getSelectedItem();
229
+ if (item) {
230
+ if (item.parentElement?.firstChild === item) item.closest(GROUP_SELECTOR)?.querySelector(GROUP_HEADING_SELECTOR)?.scrollIntoView({ block: "nearest" });
231
+ item.scrollIntoView({ block: "nearest" });
232
+ }
233
+ });
234
+ }
235
+ /** Getters */
236
+ function getSelectedItem() {
237
+ return listInnerRef.current?.querySelector(`${ITEM_SELECTOR}[aria-selected="true"]`);
238
+ }
239
+ function getValidItems() {
240
+ return Array.from(listInnerRef.current?.querySelectorAll(VALID_ITEM_SELECTOR) || []);
241
+ }
242
+ /** Setters */
243
+ function updateSelectedToIndex(index) {
244
+ const item = getValidItems()[index];
245
+ if (item) store.setState("value", item.getAttribute(VALUE_ATTR) ?? "");
246
+ }
247
+ function updateSelectedByItem(change) {
248
+ const selected = getSelectedItem();
249
+ const items = getValidItems();
250
+ const index = items.findIndex((item) => item === selected);
251
+ let newSelected = items[index + change];
252
+ if (propsRef.current?.loop) newSelected = index + change < 0 ? items[items.length - 1] : index + change === items.length ? items[0] : items[index + change];
253
+ if (newSelected) store.setState("value", newSelected.getAttribute(VALUE_ATTR) ?? "");
254
+ }
255
+ function updateSelectedByGroup(change) {
256
+ let group = getSelectedItem()?.closest(GROUP_SELECTOR);
257
+ let item;
258
+ while (group && !item) {
259
+ group = change > 0 ? findNextSibling(group, GROUP_SELECTOR) : findPreviousSibling(group, GROUP_SELECTOR);
260
+ item = group?.querySelector(VALID_ITEM_SELECTOR) ?? void 0;
261
+ }
262
+ if (item) store.setState("value", item.getAttribute(VALUE_ATTR) ?? "");
263
+ else updateSelectedByItem(change);
264
+ }
265
+ const last = () => updateSelectedToIndex(getValidItems().length - 1);
266
+ const next = (e) => {
267
+ e.preventDefault();
268
+ if (e.metaKey) last();
269
+ else if (e.altKey) updateSelectedByGroup(1);
270
+ else updateSelectedByItem(1);
271
+ };
272
+ const prev = (e) => {
273
+ e.preventDefault();
274
+ if (e.metaKey) updateSelectedToIndex(0);
275
+ else if (e.altKey) updateSelectedByGroup(-1);
276
+ else updateSelectedByItem(-1);
277
+ };
278
+ return /* @__PURE__ */ jsxs("div", {
279
+ ref: forwardedRef,
280
+ tabIndex: -1,
281
+ ...etc,
282
+ "cmdk-root": "",
283
+ onKeyDown: (e) => {
284
+ etc.onKeyDown?.(e);
285
+ const isComposing = e.nativeEvent.isComposing || e.keyCode === 229;
286
+ if (e.defaultPrevented || isComposing) return;
287
+ switch (e.key) {
288
+ case "n":
289
+ case "j":
290
+ if (vimBindings && e.ctrlKey) next(e);
291
+ break;
292
+ case "ArrowDown":
293
+ next(e);
294
+ break;
295
+ case "p":
296
+ case "k":
297
+ if (vimBindings && e.ctrlKey) prev(e);
298
+ break;
299
+ case "ArrowUp":
300
+ prev(e);
301
+ break;
302
+ case "Home":
303
+ e.preventDefault();
304
+ updateSelectedToIndex(0);
305
+ break;
306
+ case "End":
307
+ e.preventDefault();
308
+ last();
309
+ break;
310
+ case "Enter": {
311
+ e.preventDefault();
312
+ const item = getSelectedItem();
313
+ if (item) {
314
+ const event = new Event(SELECT_EVENT);
315
+ item.dispatchEvent(event);
316
+ }
317
+ }
318
+ }
319
+ },
320
+ children: [/* @__PURE__ */ jsx("label", {
321
+ "cmdk-label": "",
322
+ htmlFor: context.inputId,
323
+ id: context.labelId,
324
+ style: srOnlyStyles,
325
+ children: label
326
+ }), SlottableWithNestedChildren(props, (child) => /* @__PURE__ */ jsx(StoreContext, {
327
+ value: store,
328
+ children: /* @__PURE__ */ jsx(CommandContext, {
329
+ value: context,
330
+ children: child
331
+ })
332
+ }))]
333
+ });
334
+ }
335
+ /**
336
+ * Command menu item. Becomes active on pointer enter or through keyboard navigation.
337
+ * Preferably pass a `value`, otherwise the value will be inferred from `children` or
338
+ * the rendered item's `textContent`.
339
+ */
340
+ function Item({ ref: forwardedRef, ...props }) {
341
+ const id = useId();
342
+ const ref = React.useRef(null);
343
+ const groupContext = React.use(GroupContext);
344
+ const context = useCommand();
345
+ const propsRef = useAsRef(props);
346
+ const forceMount = propsRef.current?.forceMount ?? groupContext?.forceMount;
347
+ useLayoutEffect(() => {
348
+ if (!forceMount) return context.item(id, groupContext?.id ?? "");
349
+ }, [
350
+ context,
351
+ forceMount,
352
+ groupContext?.id,
353
+ id
354
+ ]);
355
+ const value = useValue(id, ref, [
356
+ props.value,
357
+ props.children,
358
+ ref
359
+ ], props.keywords);
360
+ const store = useStore();
361
+ const selected = useCmdk((state) => state.value && state.value === value.current);
362
+ const render = useCmdk((state) => forceMount ? true : context.filter() === false ? true : !state.search ? true : (state.filtered.items.get(id) ?? 0) > 0);
363
+ const select = React.useCallback(() => {
364
+ store.setState("value", value.current ?? "", true);
365
+ }, [store, value]);
366
+ const onSelect = React.useCallback(() => {
367
+ select();
368
+ propsRef.current.onSelect?.(value.current ?? "");
369
+ }, [
370
+ propsRef,
371
+ select,
372
+ value
373
+ ]);
374
+ React.useEffect(() => {
375
+ const element = ref.current;
376
+ if (!element || props.disabled) return;
377
+ element.addEventListener(SELECT_EVENT, onSelect);
378
+ return () => element.removeEventListener(SELECT_EVENT, onSelect);
379
+ }, [
380
+ onSelect,
381
+ props.disabled,
382
+ render
383
+ ]);
384
+ if (!render) return null;
385
+ const { disabled, value: _, onSelect: __, forceMount: ___, keywords: ____, ...etc } = props;
386
+ return /* @__PURE__ */ jsx("div", {
387
+ ref: mergeRefs([ref, forwardedRef]),
388
+ ...etc,
389
+ id,
390
+ "cmdk-item": "",
391
+ role: "option",
392
+ "aria-disabled": Boolean(disabled),
393
+ "aria-selected": Boolean(selected),
394
+ "data-disabled": Boolean(disabled),
395
+ "data-selected": Boolean(selected),
396
+ onPointerMove: disabled || context.getDisablePointerSelection() ? void 0 : select,
397
+ onClick: disabled ? void 0 : onSelect,
398
+ children: props.children
399
+ });
400
+ }
401
+ /**
402
+ * Group command menu items together with a heading.
403
+ * Grouped items are always shown together.
404
+ */
405
+ function Group({ ref: forwardedRef, ...props }) {
406
+ const { heading, children: _children, forceMount, ...etc } = props;
407
+ const id = useId();
408
+ const ref = React.useRef(null);
409
+ const headingRef = React.useRef(null);
410
+ const headingId = useId();
411
+ const context = useCommand();
412
+ const render = useCmdk((state) => forceMount ? true : context.filter() === false ? true : !state.search ? true : state.filtered.groups.has(id));
413
+ useLayoutEffect(() => {
414
+ return context.group(id);
415
+ }, [context, id]);
416
+ useValue(id, ref, [
417
+ props.value,
418
+ props.heading,
419
+ headingRef
420
+ ]);
421
+ const contextValue = React.useMemo(() => ({
422
+ id,
423
+ forceMount
424
+ }), [forceMount, id]);
425
+ return /* @__PURE__ */ jsxs("div", {
426
+ ref: mergeRefs([ref, forwardedRef]),
427
+ ...etc,
428
+ "cmdk-group": "",
429
+ role: "presentation",
430
+ hidden: render ? void 0 : true,
431
+ children: [heading && /* @__PURE__ */ jsx("div", {
432
+ ref: headingRef,
433
+ "cmdk-group-heading": "",
434
+ "aria-hidden": true,
435
+ id: headingId,
436
+ children: heading
437
+ }), SlottableWithNestedChildren(props, (child) => /* @__PURE__ */ jsx("div", {
438
+ "cmdk-group-items": "",
439
+ role: "group",
440
+ "aria-labelledby": heading ? headingId : void 0,
441
+ children: /* @__PURE__ */ jsx(GroupContext, {
442
+ value: contextValue,
443
+ children: child
444
+ })
445
+ }))]
446
+ });
447
+ }
448
+ /**
449
+ * A visual and semantic separator between items or groups.
450
+ * Visible when the search query is empty or `alwaysRender` is true, hidden otherwise.
451
+ */
452
+ function Separator({ ref: forwardedRef, ...props }) {
453
+ const { alwaysRender, ...etc } = props;
454
+ const ref = React.useRef(null);
455
+ const render = useCmdk((state) => !state.search);
456
+ if (!alwaysRender && !render) return null;
457
+ return /* @__PURE__ */ jsx("div", {
458
+ ref: mergeRefs([ref, forwardedRef]),
459
+ ...etc,
460
+ "cmdk-separator": "",
461
+ role: "separator"
462
+ });
463
+ }
464
+ /**
465
+ * Command menu input.
466
+ * All props are forwarded to the underyling `input` element.
467
+ */
468
+ function Input({ ref: forwardedRef, ...props }) {
469
+ const { onValueChange, ...etc } = props;
470
+ const isControlled = props.value != null;
471
+ const store = useStore();
472
+ const search = useCmdk((state) => state.search);
473
+ const selectedItemId = useCmdk((state) => state.selectedItemId);
474
+ const context = useCommand();
475
+ React.useEffect(() => {
476
+ if (props.value != null) store.setState("search", props.value);
477
+ }, [props.value, store]);
478
+ return /* @__PURE__ */ jsx("input", {
479
+ ref: forwardedRef,
480
+ ...etc,
481
+ "cmdk-input": "",
482
+ autoComplete: "off",
483
+ autoCorrect: "off",
484
+ spellCheck: false,
485
+ "aria-autocomplete": "list",
486
+ role: "combobox",
487
+ "aria-expanded": true,
488
+ "aria-controls": context.listId,
489
+ "aria-labelledby": context.labelId,
490
+ "aria-activedescendant": selectedItemId,
491
+ id: context.inputId,
492
+ type: "text",
493
+ value: isControlled ? props.value : search,
494
+ onChange: (e) => {
495
+ if (!isControlled) store.setState("search", e.target.value);
496
+ onValueChange?.(e.target.value);
497
+ }
498
+ });
499
+ }
500
+ /**
501
+ * Contains `Item`, `Group`, and `Separator`.
502
+ * Use the `--cmdk-list-height` CSS variable to animate height based on the number of results.
503
+ */
504
+ function List({ ref: forwardedRef, ...props }) {
505
+ const { children: _children, label = "Suggestions", ...etc } = props;
506
+ const ref = React.useRef(null);
507
+ const heightRef = React.useRef(null);
508
+ const selectedItemId = useCmdk((state) => state.selectedItemId);
509
+ const context = useCommand();
510
+ React.useEffect(() => {
511
+ if (heightRef.current && ref.current) {
512
+ const el = heightRef.current;
513
+ const wrapper = ref.current;
514
+ let animationFrame;
515
+ const observer = new ResizeObserver(() => {
516
+ animationFrame = requestAnimationFrame(() => {
517
+ const height = el.offsetHeight;
518
+ wrapper.style.setProperty(`--cmdk-list-height`, `${height.toFixed(1)}px`);
519
+ });
520
+ });
521
+ observer.observe(el);
522
+ return () => {
523
+ if (animationFrame !== void 0) cancelAnimationFrame(animationFrame);
524
+ observer.disconnect();
525
+ };
526
+ }
527
+ }, []);
528
+ return /* @__PURE__ */ jsx("div", {
529
+ ref: mergeRefs([ref, forwardedRef]),
530
+ ...etc,
531
+ "cmdk-list": "",
532
+ role: "listbox",
533
+ tabIndex: -1,
534
+ "aria-activedescendant": selectedItemId,
535
+ "aria-label": label,
536
+ id: context.listId,
537
+ children: SlottableWithNestedChildren(props, (child) => /* @__PURE__ */ jsx("div", {
538
+ ref: mergeRefs([heightRef, context.listInnerRef]),
539
+ "cmdk-list-sizer": "",
540
+ children: child
541
+ }))
542
+ });
543
+ }
544
+ /**
545
+ * Renders the command menu in a Base UI Dialog.
546
+ */
547
+ function Dialog$1({ ref: forwardedRef, ...props }) {
548
+ const { open, onOpenChange, overlayClassName, contentClassName, container, ...etc } = props;
549
+ return /* @__PURE__ */ jsx(Dialog.Root, {
550
+ open,
551
+ onOpenChange,
552
+ children: /* @__PURE__ */ jsxs(Dialog.Portal, {
553
+ container,
554
+ children: [/* @__PURE__ */ jsx(Dialog.Backdrop, {
555
+ "cmdk-overlay": "",
556
+ className: overlayClassName
557
+ }), /* @__PURE__ */ jsx(Dialog.Popup, {
558
+ "aria-label": props.label,
559
+ "cmdk-dialog": "",
560
+ className: contentClassName,
561
+ children: /* @__PURE__ */ jsx(Command, {
562
+ ref: forwardedRef,
563
+ ...etc
564
+ })
565
+ })]
566
+ })
567
+ });
568
+ }
569
+ /**
570
+ * Automatically renders when there are no results for the search query.
571
+ */
572
+ function Empty({ ref: forwardedRef, ...props }) {
573
+ if (!useCmdk((state) => state.filtered.count === 0)) return null;
574
+ return /* @__PURE__ */ jsx("div", {
575
+ ref: forwardedRef,
576
+ ...props,
577
+ "cmdk-empty": "",
578
+ role: "presentation"
579
+ });
580
+ }
581
+ /**
582
+ * You should conditionally render this with `progress` while loading asynchronous items.
583
+ */
584
+ function Loading({ ref: forwardedRef, ...props }) {
585
+ const { progress, children: _children, label = "Loading...", ...etc } = props;
586
+ return /* @__PURE__ */ jsx("div", {
587
+ ref: forwardedRef,
588
+ ...etc,
589
+ "cmdk-loading": "",
590
+ role: "progressbar",
591
+ "aria-valuenow": progress,
592
+ "aria-valuemin": 0,
593
+ "aria-valuemax": 100,
594
+ "aria-label": label,
595
+ children: SlottableWithNestedChildren(props, (child) => /* @__PURE__ */ jsx("div", {
596
+ "aria-hidden": true,
597
+ children: child
598
+ }))
599
+ });
600
+ }
601
+ const pkg = Object.assign(Command, {
602
+ List,
603
+ Item,
604
+ Input,
605
+ Group,
606
+ Separator,
607
+ Dialog: Dialog$1,
608
+ Empty,
609
+ Loading
610
+ });
611
+ /**
612
+ *
613
+ *
614
+ * Helpers
615
+ *
616
+ *
617
+ */
618
+ function findNextSibling(el, selector) {
619
+ let sibling = el.nextElementSibling;
620
+ while (sibling) {
621
+ if (sibling.matches(selector)) return sibling;
622
+ sibling = sibling.nextElementSibling;
623
+ }
624
+ }
625
+ function findPreviousSibling(el, selector) {
626
+ let sibling = el.previousElementSibling;
627
+ while (sibling) {
628
+ if (sibling.matches(selector)) return sibling;
629
+ sibling = sibling.previousElementSibling;
630
+ }
631
+ }
632
+ function useAsRef(data) {
633
+ const ref = React.useRef(data);
634
+ useLayoutEffect(() => {
635
+ ref.current = data;
636
+ });
637
+ return ref;
638
+ }
639
+ function useLazyRef(fn) {
640
+ const ref = React.useRef(void 0);
641
+ if (ref.current === void 0) ref.current = fn();
642
+ return ref;
643
+ }
644
+ /** Run a selector against the store state. */
645
+ function useCmdk(selector) {
646
+ const store = useStore();
647
+ const cb = () => selector(store.snapshot());
648
+ return React.useSyncExternalStore(store.subscribe, cb, cb);
649
+ }
650
+ function useValue(id, ref, deps, aliases = []) {
651
+ const valueRef = React.useRef(void 0);
652
+ const context = useCommand();
653
+ useLayoutEffect(() => {
654
+ const value = (() => {
655
+ for (const part of deps) {
656
+ if (typeof part === "string") return part.trim();
657
+ if (typeof part === "object" && part !== null && "current" in part) {
658
+ if (part.current) return part.current.textContent?.trim();
659
+ return valueRef.current;
660
+ }
661
+ }
662
+ })();
663
+ const keywords = aliases.map((alias) => alias.trim());
664
+ if (value) {
665
+ context.value(id, value, keywords);
666
+ ref.current?.setAttribute(VALUE_ATTR, value);
667
+ valueRef.current = value;
668
+ }
669
+ });
670
+ return valueRef;
671
+ }
672
+ /** Imperatively run a function on the next layout effect cycle. */
673
+ function useScheduleLayoutEffect() {
674
+ const [state, setState] = React.useState(null);
675
+ const fnsRef = useLazyRef(() => /* @__PURE__ */ new Map());
676
+ useLayoutEffect(() => {
677
+ fnsRef.current.forEach((f) => f());
678
+ fnsRef.current.clear();
679
+ }, [fnsRef, state]);
680
+ return (id, cb) => {
681
+ fnsRef.current.set(id, cb);
682
+ setState({});
683
+ };
684
+ }
685
+ function renderChildren(children) {
686
+ const childrenType = children.type;
687
+ if (typeof childrenType === "function") return childrenType(children.props);
688
+ else if ("render" in childrenType) return childrenType.render(children.props);
689
+ else return children;
690
+ }
691
+ function SlottableWithNestedChildren({ asChild, children }, render) {
692
+ if (asChild && React.isValidElement(children)) {
693
+ const child = children;
694
+ const renderedChild = renderChildren(child);
695
+ if (!React.isValidElement(renderedChild)) return render(child.props.children);
696
+ return React.createElement(renderedChild.type, {
697
+ ...renderedChild.props,
698
+ ref: child.ref
699
+ }, render(child.props.children));
700
+ }
701
+ return render(children);
702
+ }
703
+ function mergeRefs(refs) {
704
+ return (value) => {
705
+ refs.forEach((ref) => {
706
+ if (typeof ref === "function") ref(value);
707
+ else if (ref != null) ref.current = value;
708
+ });
709
+ };
710
+ }
711
+
712
+ //#endregion
713
+ export { pkg };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ucdjs-internal/shared-ui",
3
- "version": "0.1.2",
3
+ "version": "0.1.5",
4
4
  "type": "module",
5
5
  "author": {
6
6
  "name": "Lucas Nørgård",
@@ -21,7 +21,8 @@
21
21
  "#components/*": "./src/components/*.tsx",
22
22
  "#ui/*": "./src/ui/*.tsx",
23
23
  "#lib/*": "./src/lib/*.ts",
24
- "#hooks/*": "./src/hooks/*.ts"
24
+ "#hooks/*": "./src/hooks/*.ts",
25
+ "#vendor/cmdk": "./src/vendor/cmdk/index.tsx"
25
26
  },
26
27
  "exports": {
27
28
  ".": "./dist/index.mjs",
@@ -64,25 +65,25 @@
64
65
  "dist"
65
66
  ],
66
67
  "engines": {
67
- "node": ">=22.18"
68
+ "node": ">=24.13"
68
69
  },
69
70
  "dependencies": {
70
- "@base-ui/react": "1.1.0",
71
+ "@base-ui/react": "1.2.0",
72
+ "@base-ui/utils": "0.2.5",
71
73
  "@fontsource-variable/inter": "5.2.8",
72
74
  "class-variance-authority": "0.7.1",
73
75
  "clsx": "2.1.1",
74
- "cmdk": "1.1.1",
75
- "lucide-react": "0.563.0",
76
+ "lucide-react": "0.574.0",
76
77
  "react": "19.2.4",
77
78
  "react-dom": "19.2.4",
78
79
  "shiki": "3.22.0",
79
- "tailwind-merge": "3.4.0",
80
- "tailwindcss": "4.1.18",
80
+ "tailwind-merge": "3.4.1",
81
+ "tailwindcss": "4.2.0",
81
82
  "tw-animate-css": "1.4.0",
82
83
  "zod": "4.3.6"
83
84
  },
84
85
  "devDependencies": {
85
- "@eslint-react/eslint-plugin": "2.12.4",
86
+ "@eslint-react/eslint-plugin": "2.13.0",
86
87
  "@luxass/eslint-config": "7.2.0",
87
88
  "@rollup/plugin-babel": "6.1.0",
88
89
  "@types/react": "19.2.14",