@octanejs/cmdk 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/types.ts ADDED
@@ -0,0 +1,171 @@
1
+ // Public prop types and internal store/context types for @octanejs/cmdk.
2
+ // Mirrors cmdk@1.1.1's type surface (cmdk/src/index.tsx lines 10-152), adapted
3
+ // to octane: children are `OctaneNode`, refs are the octane `Ref` union, and
4
+ // host-element props come from octane's JSX intrinsics instead of React's
5
+ // `ComponentPropsWithoutRef<typeof Primitive.div>`. Each component's `ref` is
6
+ // declared explicitly (octane has no forwardRef), so the div/input bases have
7
+ // their intrinsic `ref` omitted.
8
+ import type { OctaneNode } from 'octane';
9
+ import type { Octane } from 'octane/jsx-runtime';
10
+
11
+ export type Ref<T> = ((value: T | null) => void) | { current: T | null } | null;
12
+
13
+ type Children = { children?: OctaneNode };
14
+ export type DivProps = Omit<Octane.JSX.IntrinsicElements['div'], 'ref'>;
15
+ type InputElementProps = Omit<Octane.JSX.IntrinsicElements['input'], 'ref'>;
16
+
17
+ export type LoadingProps = Children &
18
+ DivProps & {
19
+ ref?: Ref<HTMLDivElement>;
20
+ /** Estimated progress of loading asynchronous options. */
21
+ progress?: number;
22
+ /** Accessible label for this loading progressbar. Not shown visibly. */
23
+ label?: string;
24
+ };
25
+
26
+ export type EmptyProps = Children & DivProps & { ref?: Ref<HTMLDivElement> };
27
+
28
+ export type SeparatorProps = DivProps & {
29
+ ref?: Ref<HTMLDivElement>;
30
+ /** Whether this separator should always be rendered. Useful if you disable automatic filtering. */
31
+ alwaysRender?: boolean;
32
+ };
33
+
34
+ export type ListProps = Children &
35
+ DivProps & {
36
+ ref?: Ref<HTMLDivElement>;
37
+ /** Accessible label for this List of suggestions. Not shown visibly. */
38
+ label?: string;
39
+ };
40
+
41
+ export type ItemProps = Children &
42
+ Omit<DivProps, 'disabled' | 'onSelect' | 'value'> & {
43
+ ref?: Ref<HTMLDivElement>;
44
+ /** Whether this item is currently disabled. */
45
+ disabled?: boolean;
46
+ /** Event handler for when this item is selected, either via click or keyboard selection. */
47
+ onSelect?: (value: string) => void;
48
+ /**
49
+ * A unique value for this item. If no value is provided, it will be inferred
50
+ * from the rendered `textContent`. If your `textContent` changes between
51
+ * renders, you _must_ provide a stable, unique `value`.
52
+ */
53
+ value?: string;
54
+ /** Optional keywords to match against when filtering. */
55
+ keywords?: string[];
56
+ /** Whether this item is forcibly rendered regardless of filtering. */
57
+ forceMount?: boolean;
58
+ };
59
+
60
+ export type GroupProps = Children &
61
+ Omit<DivProps, 'heading' | 'value'> & {
62
+ ref?: Ref<HTMLDivElement>;
63
+ /** Optional heading to render for this group. */
64
+ heading?: OctaneNode;
65
+ /** If no heading is provided, you must provide a value that is unique for this group. */
66
+ value?: string;
67
+ /** Whether this group is forcibly rendered regardless of filtering. */
68
+ forceMount?: boolean;
69
+ };
70
+
71
+ export type InputProps = Omit<InputElementProps, 'value' | 'onChange' | 'onInput' | 'type'> & {
72
+ ref?: Ref<HTMLInputElement>;
73
+ /** Optional controlled state for the value of the search input. */
74
+ value?: string;
75
+ /** Event handler called when the search value changes. */
76
+ onValueChange?: (search: string) => void;
77
+ };
78
+
79
+ export type DialogProps = CommandProps & {
80
+ /** Controlled open state of the dialog. */
81
+ open?: boolean;
82
+ /** Uncontrolled initial open state. */
83
+ defaultOpen?: boolean;
84
+ /** Called when the dialog requests to open or close. */
85
+ onOpenChange?: (open: boolean) => void;
86
+ /** Whether the dialog traps focus and blocks the page (default true). */
87
+ modal?: boolean;
88
+ /** className applied to the Dialog overlay. */
89
+ overlayClassName?: string;
90
+ /** className applied to the Dialog content. */
91
+ contentClassName?: string;
92
+ /** Custom element the Dialog should portal into. */
93
+ container?: HTMLElement;
94
+ };
95
+
96
+ export type CommandFilter = (value: string, search: string, keywords?: string[]) => number;
97
+
98
+ export type CommandProps = Children &
99
+ DivProps & {
100
+ ref?: Ref<HTMLDivElement>;
101
+ /** Accessible label for this command menu. Not shown visibly. */
102
+ label?: string;
103
+ /**
104
+ * Optionally set to `false` to turn off the automatic filtering and sorting.
105
+ * If `false`, you must conditionally render valid items based on the search
106
+ * query yourself.
107
+ */
108
+ shouldFilter?: boolean;
109
+ /**
110
+ * Custom filter function for whether each command menu item matches the
111
+ * given search query. Should return a number between 0 and 1, with 1 the
112
+ * best match and 0 hidden entirely. Defaults to the `command-score` scorer.
113
+ */
114
+ filter?: CommandFilter;
115
+ /** Optional default item value when it is initially rendered. */
116
+ defaultValue?: string;
117
+ /** Optional controlled state of the selected command menu item. */
118
+ value?: string;
119
+ /** Event handler called when the selected item of the menu changes. */
120
+ onValueChange?: (value: string) => void;
121
+ /** Optionally set to `true` to turn on looping when using the arrow keys. */
122
+ loop?: boolean;
123
+ /** Optionally set to `true` to disable selection via pointer events. */
124
+ disablePointerSelection?: boolean;
125
+ /** Set to `false` to disable ctrl+n/j/p/k shortcuts. Defaults to `true`. */
126
+ vimBindings?: boolean;
127
+ };
128
+
129
+ // Internal store/context shapes (cmdk/src/index.tsx lines 123-152).
130
+
131
+ export type State = {
132
+ search: string;
133
+ value: string;
134
+ selectedItemId?: string;
135
+ filtered: { count: number; items: Map<string, number>; groups: Set<string> };
136
+ /**
137
+ * How many force-mounted items are live. They bypass registration and
138
+ * filtering entirely, so they never reach `filtered.count` — but they ARE on
139
+ * screen, and `Command.Empty` must not claim "no results" while one is
140
+ * visible. Kept separate from `filtered.count` so that count keeps its
141
+ * upstream meaning (items matching the current search) for `useCommandState`.
142
+ */
143
+ forceMountedCount: number;
144
+ };
145
+
146
+ export type Store = {
147
+ subscribe: (callback: () => void) => () => void;
148
+ snapshot: () => State;
149
+ setState: <K extends keyof State>(key: K, value: State[K], opts?: unknown) => void;
150
+ emit: () => void;
151
+ };
152
+
153
+ export type Context = {
154
+ value: (id: string, value: string | undefined, keywords?: string[]) => void;
155
+ item: (id: string, groupId: string | undefined) => () => void;
156
+ /** Registers a force-mounted item, which is exempt from filtering. */
157
+ forceItem: (id: string) => () => void;
158
+ group: (id: string) => () => void;
159
+ filter: () => boolean;
160
+ label: string;
161
+ getDisablePointerSelection: () => boolean;
162
+ listId: string;
163
+ labelId: string;
164
+ inputId: string;
165
+ listInnerRef: { current: HTMLDivElement | null };
166
+ };
167
+
168
+ export type Group = {
169
+ id: string;
170
+ forceMount?: boolean;
171
+ };