@shipfox/react-ui 0.32.2 → 0.33.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.
- package/dist/components/alert/index.d.ts +1 -1
- package/dist/components/avatar/avatar-group.d.ts +1 -1
- package/dist/components/avatar/avatar.d.ts +1 -1
- package/dist/components/avatar/index.d.ts +2 -2
- package/dist/components/badge/badge.d.ts +1 -1
- package/dist/components/badge/icon-badge.d.ts +1 -1
- package/dist/components/badge/index.d.ts +4 -4
- package/dist/components/button/button-link.d.ts +1 -1
- package/dist/components/button/button.d.ts +1 -1
- package/dist/components/button/icon-button.d.ts +1 -1
- package/dist/components/button/index.d.ts +3 -3
- package/dist/components/button-group/index.d.ts +1 -1
- package/dist/components/calendar/index.d.ts +1 -1
- package/dist/components/card/card.d.ts +1 -1
- package/dist/components/card/index.d.ts +1 -1
- package/dist/components/checkbox/checkbox-label.d.ts +1 -1
- package/dist/components/checkbox/checkbox-links.d.ts +1 -1
- package/dist/components/checkbox/index.d.ts +3 -3
- package/dist/components/code-block/code-block-footer.js +7 -2
- package/dist/components/code-block/index.d.ts +3 -3
- package/dist/components/combobox/combobox.d.ts +1 -1
- package/dist/components/combobox/index.d.ts +1 -1
- package/dist/components/command/command.d.ts +1 -1
- package/dist/components/command/index.d.ts +1 -1
- package/dist/components/confetti/index.d.ts +1 -1
- package/dist/components/count-up/index.d.ts +1 -1
- package/dist/components/dashboard/components/charts/bar-chart.d.ts +1 -1
- package/dist/components/dashboard/components/charts/index.d.ts +5 -5
- package/dist/components/dashboard/components/charts/line-chart.d.ts +1 -1
- package/dist/components/dashboard/components/charts/utils.d.ts +2 -2
- package/dist/components/dashboard/components/dashboard-alert.d.ts +1 -1
- package/dist/components/dashboard/components/mobile-sidebar.d.ts +1 -1
- package/dist/components/dashboard/components/sidebar.d.ts +1 -1
- package/dist/components/dashboard/components/topbar-button.d.ts +1 -1
- package/dist/components/dashboard/context/dashboard-context.d.ts +2 -2
- package/dist/components/dashboard/context/index.d.ts +4 -4
- package/dist/components/dashboard/context/types.d.ts +1 -1
- package/dist/components/dashboard/context/utils.d.ts +1 -1
- package/dist/components/dashboard/index.d.ts +18 -18
- package/dist/components/dashboard/pages/index.d.ts +2 -2
- package/dist/components/dashboard/table/index.d.ts +2 -2
- package/dist/components/dashboard/toolbar/filter-button.d.ts +1 -1
- package/dist/components/dashboard/toolbar/index.d.ts +9 -9
- package/dist/components/date-picker/index.d.ts +1 -1
- package/dist/components/date-time-range-picker/index.d.ts +1 -1
- package/dist/components/dot-grid/index.d.ts +1 -1
- package/dist/components/dropdown-menu/dropdown-menu.d.ts +1 -1
- package/dist/components/dropdown-menu/index.d.ts +1 -1
- package/dist/components/dynamic-item/dynamic-item.d.ts +1 -1
- package/dist/components/dynamic-item/index.d.ts +1 -1
- package/dist/components/empty-state/empty-state.d.ts +1 -1
- package/dist/components/empty-state/index.d.ts +1 -1
- package/dist/components/form/index.d.ts +1 -1
- package/dist/components/icon/custom/index.d.ts +14 -14
- package/dist/components/icon/icon.d.ts +1 -1
- package/dist/components/icon/index.d.ts +1 -1
- package/dist/components/index.d.ts +47 -47
- package/dist/components/inline-tips/index.d.ts +1 -1
- package/dist/components/input/index.d.ts +1 -1
- package/dist/components/interval-selector/hooks/index.d.ts +3 -3
- package/dist/components/interval-selector/hooks/use-interval-selector-input.d.ts +1 -1
- package/dist/components/interval-selector/hooks/use-interval-selector-navigation.d.ts +1 -1
- package/dist/components/interval-selector/hooks/use-interval-selector.d.ts +2 -2
- package/dist/components/interval-selector/index.d.ts +2 -2
- package/dist/components/interval-selector/interval-selector-calendar.d.ts +1 -1
- package/dist/components/interval-selector/interval-selector-input.d.ts +1 -1
- package/dist/components/interval-selector/interval-selector-suggestions.d.ts +1 -1
- package/dist/components/interval-selector/interval-selector.d.ts +1 -1
- package/dist/components/interval-selector/utils/format.d.ts +1 -1
- package/dist/components/interval-selector/utils/index.d.ts +2 -2
- package/dist/components/item/index.d.ts +1 -1
- package/dist/components/kbd/index.d.ts +1 -1
- package/dist/components/label/index.d.ts +1 -1
- package/dist/components/modal/index.d.ts +1 -1
- package/dist/components/moving-border/index.d.ts +1 -1
- package/dist/components/popover/index.d.ts +1 -1
- package/dist/components/scroll-area/index.d.ts +1 -1
- package/dist/components/search/index.d.ts +6 -6
- package/dist/components/search/search-inline.d.ts +1 -1
- package/dist/components/search/search-modal.d.ts +1 -1
- package/dist/components/search/search-trigger.d.ts +1 -1
- package/dist/components/select/index.d.ts +1 -1
- package/dist/components/select/select.d.ts +1 -1
- package/dist/components/sheet/index.d.ts +1 -1
- package/dist/components/shiny-text/index.d.ts +1 -1
- package/dist/components/shipql-editor/index.d.ts +2 -2
- package/dist/components/shipql-editor/lexical/on-blur-plugin.d.ts +2 -1
- package/dist/components/shipql-editor/lexical/on-blur-plugin.js +8 -4
- package/dist/components/shipql-editor/lexical/shipql-leaf-node.d.ts +5 -2
- package/dist/components/shipql-editor/lexical/shipql-leaf-node.js +18 -8
- package/dist/components/shipql-editor/lexical/shipql-plugin.d.ts +3 -2
- package/dist/components/shipql-editor/lexical/shipql-plugin.js +188 -34
- package/dist/components/shipql-editor/shipql-editor-inner.d.ts +2 -2
- package/dist/components/shipql-editor/shipql-editor-inner.js +52 -7
- package/dist/components/shipql-editor/shipql-editor.d.ts +4 -3
- package/dist/components/shipql-editor/suggestions/generate-suggestions.d.ts +9 -3
- package/dist/components/shipql-editor/suggestions/generate-suggestions.js +94 -20
- package/dist/components/shipql-editor/suggestions/shipql-range-facet-panel.d.ts +1 -1
- package/dist/components/shipql-editor/suggestions/shipql-range-facet-panel.js +2 -2
- package/dist/components/shipql-editor/suggestions/shipql-suggestion-item.d.ts +2 -2
- package/dist/components/shipql-editor/suggestions/shipql-suggestion-item.js +74 -10
- package/dist/components/shipql-editor/suggestions/shipql-suggestions-dropdown.d.ts +4 -3
- package/dist/components/shipql-editor/suggestions/shipql-suggestions-dropdown.js +56 -11
- package/dist/components/shipql-editor/suggestions/shipql-suggestions-plugin.d.ts +2 -2
- package/dist/components/shipql-editor/suggestions/shipql-suggestions-plugin.js +7 -5
- package/dist/components/shipql-editor/suggestions/types.d.ts +25 -3
- package/dist/components/skeleton/index.d.ts +1 -1
- package/dist/components/slider/index.d.ts +1 -1
- package/dist/components/switch/index.d.ts +1 -1
- package/dist/components/table/index.d.ts +4 -4
- package/dist/components/table/table.stories.columns.d.ts +1 -1
- package/dist/components/tabs/index.d.ts +1 -1
- package/dist/components/textarea/index.d.ts +1 -1
- package/dist/components/theme/index.d.ts +1 -1
- package/dist/components/theme/theme-provider.d.ts +1 -1
- package/dist/components/toast/index.d.ts +2 -2
- package/dist/components/tooltip/index.d.ts +1 -1
- package/dist/components/typography/index.d.ts +3 -3
- package/dist/hooks/index.d.ts +6 -6
- package/dist/hooks/useTheme.d.ts +1 -1
- package/dist/index.d.ts +4 -4
- package/dist/styles.css +2 -1
- package/dist/utils/format/index.d.ts +5 -5
- package/dist/utils/index.d.ts +6 -6
- package/package.json +10 -10
|
@@ -11,14 +11,37 @@ export function tryParse(text) {
|
|
|
11
11
|
}
|
|
12
12
|
// ─── Facet normalization ───────────────────────────────────────────────────────
|
|
13
13
|
export function normalizeFacets(facets) {
|
|
14
|
-
return facets.map((f)=>typeof f === 'string' ? f : f.
|
|
14
|
+
return facets.map((f)=>typeof f === 'string' ? f : f.id);
|
|
15
15
|
}
|
|
16
|
-
export function getFacetConfig(facets,
|
|
16
|
+
export function getFacetConfig(facets, id) {
|
|
17
17
|
for (const f of facets){
|
|
18
|
-
if (typeof f !== 'string' && f.
|
|
18
|
+
if (typeof f !== 'string' && f.id.toLowerCase() === id.toLowerCase()) return f.config;
|
|
19
19
|
}
|
|
20
20
|
return undefined;
|
|
21
21
|
}
|
|
22
|
+
// Private: finds the object-form FacetDef by exact id match.
|
|
23
|
+
function findFacet(facets, id) {
|
|
24
|
+
for (const f of facets){
|
|
25
|
+
if (typeof f !== 'string' && f.id === id) return f;
|
|
26
|
+
}
|
|
27
|
+
return undefined;
|
|
28
|
+
}
|
|
29
|
+
/** Returns the human-readable display label, falling back to the raw id. */ export function getFacetLabel(facets, id) {
|
|
30
|
+
return findFacet(facets, id)?.metadata?.label ?? id;
|
|
31
|
+
}
|
|
32
|
+
/** Returns the description for a facet, if any. */ export function getFacetDescription(facets, id) {
|
|
33
|
+
return findFacet(facets, id)?.metadata?.description;
|
|
34
|
+
}
|
|
35
|
+
/** Returns grouping information for a facet, with defaults applied. */ export function getFacetGroupInfo(facets, id) {
|
|
36
|
+
const metadata = findFacet(facets, id)?.metadata;
|
|
37
|
+
const key = metadata?.group ?? '';
|
|
38
|
+
return {
|
|
39
|
+
key,
|
|
40
|
+
label: metadata?.groupLabel ?? (key ? key.charAt(0).toUpperCase() + key.slice(1) : undefined),
|
|
41
|
+
order: metadata?.groupOrder ?? Infinity,
|
|
42
|
+
icon: metadata?.groupIcon
|
|
43
|
+
};
|
|
44
|
+
}
|
|
22
45
|
// ─── Leaf helpers ─────────────────────────────────────────────────────────────
|
|
23
46
|
export function extractFacetFromLeaf(leaf) {
|
|
24
47
|
if (leaf.type === 'match') return leaf.facet;
|
|
@@ -70,13 +93,32 @@ export function detectFacetContext(activeText, facets) {
|
|
|
70
93
|
// ─── Suggestion builder ───────────────────────────────────────────────────────
|
|
71
94
|
export function buildSuggestionItems(facets, valueSuggestions, activeText, focusedLeaf) {
|
|
72
95
|
const facetNames = normalizeFacets(facets);
|
|
73
|
-
const header = (label)=>({
|
|
96
|
+
const header = (label, iconName)=>({
|
|
74
97
|
value: `__header__${label}`,
|
|
75
98
|
label,
|
|
76
|
-
icon:
|
|
99
|
+
icon: iconName ? /*#__PURE__*/ _jsx(Icon, {
|
|
100
|
+
name: iconName,
|
|
101
|
+
className: "size-12 text-foreground-neutral-muted"
|
|
102
|
+
}) : null,
|
|
77
103
|
selected: false,
|
|
78
104
|
type: 'section-header'
|
|
79
105
|
});
|
|
106
|
+
const facetContext = (id)=>{
|
|
107
|
+
const groupInfo = getFacetGroupInfo(facets, id);
|
|
108
|
+
return {
|
|
109
|
+
value: `__facet-context__${id}`,
|
|
110
|
+
label: getFacetLabel(facets, id),
|
|
111
|
+
icon: groupInfo.icon ? /*#__PURE__*/ _jsx(Icon, {
|
|
112
|
+
name: groupInfo.icon,
|
|
113
|
+
className: "size-12 text-foreground-neutral-muted"
|
|
114
|
+
}) : null,
|
|
115
|
+
selected: false,
|
|
116
|
+
type: 'facet-context',
|
|
117
|
+
facetName: id,
|
|
118
|
+
description: getFacetDescription(facets, id),
|
|
119
|
+
sectionLabel: groupInfo.label
|
|
120
|
+
};
|
|
121
|
+
};
|
|
80
122
|
// Focused leaf — show values with current value marked selected.
|
|
81
123
|
// Text-type leaves (bare words) are not facet:value matches, so fall through
|
|
82
124
|
// to facet filtering using the leaf's text as the partial query.
|
|
@@ -99,7 +141,7 @@ export function buildSuggestionItems(facets, valueSuggestions, activeText, focus
|
|
|
99
141
|
const currentValue = extractValueFromLeaf(focusedLeaf);
|
|
100
142
|
if (valueSuggestions.length === 0) return [];
|
|
101
143
|
return [
|
|
102
|
-
|
|
144
|
+
facetContext(facetName),
|
|
103
145
|
...valueSuggestions.map((v)=>{
|
|
104
146
|
const selected = v === currentValue;
|
|
105
147
|
return {
|
|
@@ -134,7 +176,7 @@ export function buildSuggestionItems(facets, valueSuggestions, activeText, focus
|
|
|
134
176
|
// Regular facet — show value suggestions (parent is responsible for filtering)
|
|
135
177
|
if (valueSuggestions.length === 0) return [];
|
|
136
178
|
return [
|
|
137
|
-
|
|
179
|
+
facetContext(facetCtx.facet),
|
|
138
180
|
...valueSuggestions.map((v)=>({
|
|
139
181
|
value: v,
|
|
140
182
|
label: v,
|
|
@@ -151,20 +193,52 @@ export function buildSuggestionItems(facets, valueSuggestions, activeText, focus
|
|
|
151
193
|
// before matching so "NOT sta" still suggests "status", "-sta" suggests "status", etc.
|
|
152
194
|
const rawPartial = focusedLeaf?.type === 'text' ? focusedLeaf.value : activeText;
|
|
153
195
|
const partial = stripNegationPrefix(rawPartial.trim()).stripped.toLowerCase();
|
|
154
|
-
|
|
196
|
+
// Filter against raw id AND metadata label
|
|
197
|
+
const filtered = partial ? facets.filter((f)=>{
|
|
198
|
+
const id = typeof f === 'string' ? f : f.id;
|
|
199
|
+
const label = typeof f !== 'string' ? f.metadata?.label : undefined;
|
|
200
|
+
return id.toLowerCase().includes(partial) || (label?.toLowerCase().includes(partial) ?? false);
|
|
201
|
+
}) : facets;
|
|
155
202
|
if (filtered.length === 0) return [];
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
203
|
+
const groups = new Map();
|
|
204
|
+
for (const f of filtered){
|
|
205
|
+
const id = typeof f === 'string' ? f : f.id;
|
|
206
|
+
const { key: group, label: groupLabel, order: groupOrder, icon: groupIcon } = getFacetGroupInfo(facets, id);
|
|
207
|
+
if (!groups.has(group)) groups.set(group, []);
|
|
208
|
+
const groupList = groups.get(group);
|
|
209
|
+
if (groupList) groupList.push({
|
|
210
|
+
id,
|
|
211
|
+
label: getFacetLabel(facets, id),
|
|
212
|
+
description: getFacetDescription(facets, id),
|
|
213
|
+
groupOrder,
|
|
214
|
+
groupLabel,
|
|
215
|
+
groupIcon
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
const sortedGroups = [
|
|
219
|
+
...groups.entries()
|
|
220
|
+
].sort(([, aItems], [, bItems])=>{
|
|
221
|
+
const aOrder = aItems[0]?.groupOrder ?? Infinity;
|
|
222
|
+
const bOrder = bItems[0]?.groupOrder ?? Infinity;
|
|
223
|
+
return aOrder - bOrder;
|
|
224
|
+
});
|
|
225
|
+
const items = [];
|
|
226
|
+
for (const [, groupItems] of sortedGroups){
|
|
227
|
+
groupItems.sort((a, b)=>a.label.localeCompare(b.label));
|
|
228
|
+
const firstItem = groupItems[0];
|
|
229
|
+
if (!firstItem) continue;
|
|
230
|
+
if (firstItem.groupLabel) items.push(header(firstItem.groupLabel, firstItem.groupIcon));
|
|
231
|
+
for (const entry of groupItems){
|
|
232
|
+
items.push({
|
|
233
|
+
value: entry.id,
|
|
234
|
+
label: entry.label,
|
|
235
|
+
icon: null,
|
|
236
|
+
selected: false,
|
|
237
|
+
description: entry.description
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
return items;
|
|
168
242
|
}
|
|
169
243
|
|
|
170
244
|
//# sourceMappingURL=generate-suggestions.js.map
|
|
@@ -151,10 +151,10 @@ export function ShipQLRangeFacetPanel({ facetName, config, onApply, isSelectingR
|
|
|
151
151
|
isSelectingRef.current = true;
|
|
152
152
|
};
|
|
153
153
|
const onUp = ()=>{
|
|
154
|
-
//
|
|
154
|
+
// Defer reset so the blur handler still sees isSelectingRef=true.
|
|
155
155
|
setTimeout(()=>{
|
|
156
156
|
isSelectingRef.current = false;
|
|
157
|
-
},
|
|
157
|
+
}, 0);
|
|
158
158
|
};
|
|
159
159
|
el.addEventListener('pointerdown', onDown);
|
|
160
160
|
window.addEventListener('pointerup', onUp);
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import type { SuggestionItem } from './types';
|
|
1
|
+
import type { SuggestionItem } from './types.js';
|
|
2
2
|
interface ShipQLSuggestionItemProps {
|
|
3
3
|
item: SuggestionItem;
|
|
4
4
|
isHighlighted: boolean;
|
|
5
5
|
isNegated?: boolean;
|
|
6
6
|
onMouseDown: (value: string) => void;
|
|
7
|
-
itemRef?: (el:
|
|
7
|
+
itemRef?: (el: HTMLElement | null) => void;
|
|
8
8
|
}
|
|
9
9
|
export declare function ShipQLSuggestionItem({ item, isHighlighted, isNegated, onMouseDown, itemRef, }: ShipQLSuggestionItemProps): import("react/jsx-runtime").JSX.Element;
|
|
10
10
|
export {};
|
|
@@ -2,14 +2,56 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import { cn } from '../../../utils/cn.js';
|
|
3
3
|
export function ShipQLSuggestionItem({ item, isHighlighted, isNegated, onMouseDown, itemRef }) {
|
|
4
4
|
if (item.type === 'section-header') {
|
|
5
|
-
return /*#__PURE__*/
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
5
|
+
return /*#__PURE__*/ _jsxs("div", {
|
|
6
|
+
ref: itemRef,
|
|
7
|
+
className: "flex w-full items-center gap-6 px-8 h-30 shrink-0",
|
|
8
|
+
children: [
|
|
9
|
+
item.icon,
|
|
10
|
+
/*#__PURE__*/ _jsx("span", {
|
|
11
|
+
className: "text-xs font-normal uppercase text-foreground-neutral-muted",
|
|
12
|
+
children: item.label
|
|
13
|
+
})
|
|
14
|
+
]
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
if (item.type === 'facet-context') {
|
|
18
|
+
const showRawFacetName = typeof item.label === 'string' && item.facetName && item.label !== item.facetName;
|
|
19
|
+
return /*#__PURE__*/ _jsxs("div", {
|
|
20
|
+
ref: itemRef,
|
|
21
|
+
className: "flex w-full flex-col gap-2 px-8 py-8 border-b border-border-neutral-subtle shrink-0",
|
|
22
|
+
children: [
|
|
23
|
+
item.sectionLabel && /*#__PURE__*/ _jsxs("div", {
|
|
24
|
+
className: "flex items-center gap-4",
|
|
25
|
+
children: [
|
|
26
|
+
item.icon,
|
|
27
|
+
/*#__PURE__*/ _jsx("span", {
|
|
28
|
+
className: "text-xs text-foreground-neutral-muted",
|
|
29
|
+
children: item.sectionLabel
|
|
30
|
+
})
|
|
31
|
+
]
|
|
32
|
+
}),
|
|
33
|
+
/*#__PURE__*/ _jsxs("div", {
|
|
34
|
+
className: "flex items-baseline gap-8",
|
|
35
|
+
children: [
|
|
36
|
+
/*#__PURE__*/ _jsx("span", {
|
|
37
|
+
className: "text-sm font-medium text-foreground-neutral-base",
|
|
38
|
+
children: item.label
|
|
39
|
+
}),
|
|
40
|
+
showRawFacetName && /*#__PURE__*/ _jsx("span", {
|
|
41
|
+
className: "font-mono text-xs text-foreground-neutral-muted",
|
|
42
|
+
children: item.facetName
|
|
43
|
+
})
|
|
44
|
+
]
|
|
45
|
+
}),
|
|
46
|
+
item.description && /*#__PURE__*/ _jsx("span", {
|
|
47
|
+
className: "text-xs text-foreground-neutral-muted",
|
|
48
|
+
children: item.description
|
|
49
|
+
})
|
|
50
|
+
]
|
|
11
51
|
});
|
|
12
52
|
}
|
|
53
|
+
const labelText = isNegated ? `-${item.label}` : item.label;
|
|
54
|
+
const showRawId = typeof item.label === 'string' && item.label !== item.value;
|
|
13
55
|
return /*#__PURE__*/ _jsxs("button", {
|
|
14
56
|
ref: itemRef,
|
|
15
57
|
type: "button",
|
|
@@ -17,15 +59,37 @@ export function ShipQLSuggestionItem({ item, isHighlighted, isNegated, onMouseDo
|
|
|
17
59
|
e.preventDefault();
|
|
18
60
|
onMouseDown(item.value);
|
|
19
61
|
},
|
|
20
|
-
className: cn('flex w-full
|
|
62
|
+
className: cn('flex w-full gap-12 rounded-none px-8 py-6 text-left transition-colors duration-75 cursor-pointer', item.description ? 'items-start' : 'items-center h-24', isHighlighted ? 'bg-background-button-transparent-hover' : 'hover:bg-background-button-transparent-hover'),
|
|
21
63
|
children: [
|
|
22
64
|
/*#__PURE__*/ _jsxs("div", {
|
|
23
|
-
className:
|
|
65
|
+
className: cn('flex min-w-0 flex-1 gap-12', item.description ? 'items-start' : 'items-center'),
|
|
24
66
|
children: [
|
|
25
67
|
item.icon,
|
|
26
|
-
/*#__PURE__*/
|
|
68
|
+
item.description ? /*#__PURE__*/ _jsxs("div", {
|
|
69
|
+
className: "flex min-w-0 flex-1 flex-col",
|
|
70
|
+
children: [
|
|
71
|
+
/*#__PURE__*/ _jsxs("div", {
|
|
72
|
+
className: "flex items-center gap-8",
|
|
73
|
+
children: [
|
|
74
|
+
/*#__PURE__*/ _jsx("span", {
|
|
75
|
+
className: cn('flex-1 truncate text-sm', isNegated ? 'text-foreground-highlights-interactive' : item.selected ? 'text-foreground-neutral-base' : 'text-foreground-neutral-subtle'),
|
|
76
|
+
children: labelText
|
|
77
|
+
}),
|
|
78
|
+
showRawId && /*#__PURE__*/ _jsx("span", {
|
|
79
|
+
className: "shrink-0 max-w-[40%] truncate font-mono text-xs text-foreground-neutral-muted",
|
|
80
|
+
children: item.value
|
|
81
|
+
})
|
|
82
|
+
]
|
|
83
|
+
}),
|
|
84
|
+
/*#__PURE__*/ _jsx("span", {
|
|
85
|
+
title: item.description,
|
|
86
|
+
className: "truncate text-xs text-foreground-neutral-muted",
|
|
87
|
+
children: item.description
|
|
88
|
+
})
|
|
89
|
+
]
|
|
90
|
+
}) : /*#__PURE__*/ _jsx("span", {
|
|
27
91
|
className: cn('flex-1 truncate text-sm', isNegated ? 'text-foreground-highlights-interactive' : item.selected ? 'text-foreground-neutral-base' : 'text-foreground-neutral-subtle'),
|
|
28
|
-
children:
|
|
92
|
+
children: labelText
|
|
29
93
|
})
|
|
30
94
|
]
|
|
31
95
|
}),
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import { type SyntaxHintMode } from './shipql-suggestions-footer';
|
|
2
|
-
import type { SuggestionItem } from './types';
|
|
1
|
+
import { type SyntaxHintMode } from './shipql-suggestions-footer.js';
|
|
2
|
+
import type { SuggestionItem } from './types.js';
|
|
3
3
|
interface ShipQLSuggestionsDropdownProps {
|
|
4
4
|
items: SuggestionItem[];
|
|
5
5
|
selectedIndex: number;
|
|
6
6
|
isSelectingRef: React.RefObject<boolean>;
|
|
7
7
|
onSelect: (value: string) => void;
|
|
8
|
+
onClose: () => void;
|
|
8
9
|
isLoading?: boolean;
|
|
9
10
|
isNegated: boolean;
|
|
10
11
|
onToggleNegate: (negated: boolean) => void;
|
|
@@ -14,6 +15,6 @@ interface ShipQLSuggestionsDropdownProps {
|
|
|
14
15
|
isError?: boolean;
|
|
15
16
|
syntaxHintMode: SyntaxHintMode;
|
|
16
17
|
}
|
|
17
|
-
export declare function ShipQLSuggestionsDropdown({ items, selectedIndex, isSelectingRef, onSelect, isLoading, isNegated, onToggleNegate, showValueActions, showSyntaxHelp, onToggleSyntaxHelp, isError, syntaxHintMode, }: ShipQLSuggestionsDropdownProps): import("react/jsx-runtime").JSX.Element;
|
|
18
|
+
export declare function ShipQLSuggestionsDropdown({ items, selectedIndex, isSelectingRef, onSelect, onClose, isLoading, isNegated, onToggleNegate, showValueActions, showSyntaxHelp, onToggleSyntaxHelp, isError, syntaxHintMode, }: ShipQLSuggestionsDropdownProps): import("react/jsx-runtime").JSX.Element;
|
|
18
19
|
export {};
|
|
19
20
|
//# sourceMappingURL=shipql-suggestions-dropdown.d.ts.map
|
|
@@ -6,16 +6,40 @@ import { useCallback, useEffect, useRef } from 'react';
|
|
|
6
6
|
import { ShipQLRangeFacetPanel } from './shipql-range-facet-panel.js';
|
|
7
7
|
import { ShipQLSuggestionItem } from './shipql-suggestion-item.js';
|
|
8
8
|
import { ShipQLSuggestionsFooter } from './shipql-suggestions-footer.js';
|
|
9
|
-
export function ShipQLSuggestionsDropdown({ items, selectedIndex, isSelectingRef, onSelect, isLoading, isNegated, onToggleNegate, showValueActions, showSyntaxHelp, onToggleSyntaxHelp, isError, syntaxHintMode }) {
|
|
9
|
+
export function ShipQLSuggestionsDropdown({ items, selectedIndex, isSelectingRef, onSelect, onClose, isLoading, isNegated, onToggleNegate, showValueActions, showSyntaxHelp, onToggleSyntaxHelp, isError, syntaxHintMode }) {
|
|
10
10
|
const itemRefs = useRef([]);
|
|
11
|
+
const prevSelectedIndexRef = useRef(-1);
|
|
11
12
|
useEffect(()=>{
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
const prevIndex = prevSelectedIndexRef.current;
|
|
14
|
+
prevSelectedIndexRef.current = selectedIndex;
|
|
15
|
+
const prevItem = items[selectedIndex - 1];
|
|
16
|
+
const isPrecededByHeader = prevItem?.type === 'section-header' || prevItem?.type === 'facet-context';
|
|
17
|
+
const isWrapping = prevIndex >= 0 && Math.abs(selectedIndex - prevIndex) > items.length / 2;
|
|
18
|
+
// When wrapping bottom→top the header is safe to include (it's just above the
|
|
19
|
+
// first item). When wrapping top→bottom we skip the header because it sits far
|
|
20
|
+
// above the last item and pinning to it would push the actual item off-screen.
|
|
21
|
+
const isWrappingToBottom = isWrapping && selectedIndex > prevIndex;
|
|
22
|
+
const isGoingForward = selectedIndex > prevIndex && !isWrapping || isWrapping && !isWrappingToBottom;
|
|
23
|
+
if (!isWrappingToBottom && isPrecededByHeader) {
|
|
24
|
+
const headerEl = itemRefs.current[selectedIndex - 1] ?? itemRefs.current[selectedIndex];
|
|
25
|
+
// Going forward / wrapping to top: pin the header to the top so the selected
|
|
26
|
+
// item below it is visible. Going backward: nearest is enough because the
|
|
27
|
+
// header is above and scrolling up will bring it into view at the top edge.
|
|
28
|
+
const block = isGoingForward ? 'start' : 'nearest';
|
|
29
|
+
if (headerEl) headerEl.scrollIntoView({
|
|
30
|
+
behavior: 'smooth',
|
|
31
|
+
block
|
|
32
|
+
});
|
|
33
|
+
} else {
|
|
34
|
+
const el = itemRefs.current[selectedIndex];
|
|
35
|
+
if (el) el.scrollIntoView({
|
|
36
|
+
behavior: 'smooth',
|
|
37
|
+
block: 'nearest'
|
|
38
|
+
});
|
|
39
|
+
}
|
|
17
40
|
}, [
|
|
18
|
-
selectedIndex
|
|
41
|
+
selectedIndex,
|
|
42
|
+
items
|
|
19
43
|
]);
|
|
20
44
|
// Shift key toggles negation while dropdown is visible
|
|
21
45
|
useEffect(()=>{
|
|
@@ -48,7 +72,7 @@ export function ShipQLSuggestionsDropdown({ items, selectedIndex, isSelectingRef
|
|
|
48
72
|
onSelect(value);
|
|
49
73
|
setTimeout(()=>{
|
|
50
74
|
isSelectingRef.current = false;
|
|
51
|
-
},
|
|
75
|
+
}, 0);
|
|
52
76
|
}, [
|
|
53
77
|
isSelectingRef,
|
|
54
78
|
onSelect
|
|
@@ -76,7 +100,7 @@ export function ShipQLSuggestionsDropdown({ items, selectedIndex, isSelectingRef
|
|
|
76
100
|
})
|
|
77
101
|
]
|
|
78
102
|
}) : /*#__PURE__*/ _jsxs("div", {
|
|
79
|
-
className: "flex flex-col overflow-hidden rounded-8 bg-background-neutral-base shadow-tooltip max-h-[min(70vh,
|
|
103
|
+
className: "flex flex-col overflow-hidden rounded-8 bg-background-neutral-base shadow-tooltip max-h-[min(70vh,400px)] min-h-0",
|
|
80
104
|
children: [
|
|
81
105
|
/*#__PURE__*/ _jsx(ScrollArea, {
|
|
82
106
|
className: "flex-1 min-h-0 overflow-y-auto scrollbar",
|
|
@@ -111,15 +135,36 @@ export function ShipQLSuggestionsDropdown({ items, selectedIndex, isSelectingRef
|
|
|
111
135
|
]
|
|
112
136
|
});
|
|
113
137
|
return /*#__PURE__*/ _jsx(PopoverContent, {
|
|
138
|
+
"data-shipql-suggestions": true,
|
|
114
139
|
align: "start",
|
|
115
140
|
sideOffset: 4,
|
|
116
141
|
className: "p-0 w-(--radix-popover-trigger-width) rounded-8",
|
|
117
142
|
onOpenAutoFocus: (e)=>e.preventDefault(),
|
|
118
143
|
onInteractOutside: (e)=>{
|
|
119
|
-
if (isSelectingRef.current)
|
|
144
|
+
if (isSelectingRef.current) {
|
|
145
|
+
e.preventDefault();
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
const target = e.detail?.originalEvent?.target;
|
|
149
|
+
if (target instanceof Element && target.closest('[data-shipql-editor]')) {
|
|
150
|
+
e.preventDefault();
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
onClose();
|
|
120
154
|
},
|
|
121
155
|
onPointerDownOutside: (e)=>{
|
|
122
|
-
if (isSelectingRef.current)
|
|
156
|
+
if (isSelectingRef.current) {
|
|
157
|
+
e.preventDefault();
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
// Clicks inside the editor are handled by Lexical's focus/blur
|
|
161
|
+
// commands — only dismiss for clicks truly outside the editor.
|
|
162
|
+
const target = e.detail?.originalEvent?.target;
|
|
163
|
+
if (target instanceof Element && target.closest('[data-shipql-editor]')) {
|
|
164
|
+
e.preventDefault();
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
onClose();
|
|
123
168
|
},
|
|
124
169
|
children: popoverContent
|
|
125
170
|
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { AstNode } from '@shipfox/shipql-parser';
|
|
2
|
-
import type { LeafAstNode } from '../lexical/shipql-leaf-node';
|
|
3
|
-
import type { FacetDef, SuggestionItem } from './types';
|
|
2
|
+
import type { LeafAstNode } from '../lexical/shipql-leaf-node.js';
|
|
3
|
+
import type { FacetDef, SuggestionItem } from './types.js';
|
|
4
4
|
interface ShipQLSuggestionsPluginProps {
|
|
5
5
|
facets: FacetDef[];
|
|
6
6
|
currentFacet: string | null;
|
|
@@ -280,11 +280,12 @@ export function ShipQLSuggestionsPlugin({ facets, currentFacet, setCurrentFacet,
|
|
|
280
280
|
if (!openRef.current || itemsRef.current.length === 0) return false;
|
|
281
281
|
e?.preventDefault();
|
|
282
282
|
const its = itemsRef.current;
|
|
283
|
+
const isNonSelectable = (i)=>its[i]?.type === 'section-header' || its[i]?.type === 'facet-context';
|
|
283
284
|
let next = selectedIndexRef.current + 1;
|
|
284
|
-
while(next < its.length &&
|
|
285
|
+
while(next < its.length && isNonSelectable(next))next++;
|
|
285
286
|
if (next >= its.length) {
|
|
286
287
|
next = 0;
|
|
287
|
-
while(next < its.length &&
|
|
288
|
+
while(next < its.length && isNonSelectable(next))next++;
|
|
288
289
|
}
|
|
289
290
|
if (next < its.length) {
|
|
290
291
|
hasNavigatedRef.current = true;
|
|
@@ -296,11 +297,12 @@ export function ShipQLSuggestionsPlugin({ facets, currentFacet, setCurrentFacet,
|
|
|
296
297
|
if (!openRef.current || itemsRef.current.length === 0) return false;
|
|
297
298
|
e?.preventDefault();
|
|
298
299
|
const its = itemsRef.current;
|
|
300
|
+
const isNonSelectable = (i)=>its[i]?.type === 'section-header' || its[i]?.type === 'facet-context';
|
|
299
301
|
let prev = selectedIndexRef.current - 1;
|
|
300
|
-
while(prev >= 0 &&
|
|
302
|
+
while(prev >= 0 && isNonSelectable(prev))prev--;
|
|
301
303
|
if (prev < 0) {
|
|
302
304
|
prev = its.length - 1;
|
|
303
|
-
while(prev >= 0 &&
|
|
305
|
+
while(prev >= 0 && isNonSelectable(prev))prev--;
|
|
304
306
|
}
|
|
305
307
|
if (prev >= 0) {
|
|
306
308
|
hasNavigatedRef.current = true;
|
|
@@ -312,7 +314,7 @@ export function ShipQLSuggestionsPlugin({ facets, currentFacet, setCurrentFacet,
|
|
|
312
314
|
if (!openRef.current || itemsRef.current.length === 0) return false;
|
|
313
315
|
if (!hasNavigatedRef.current || selectedIndexRef.current < 0) return false;
|
|
314
316
|
const item = itemsRef.current[selectedIndexRef.current];
|
|
315
|
-
if (!item || item.type === 'section-header') return false;
|
|
317
|
+
if (!item || item.type === 'section-header' || item.type === 'facet-context') return false;
|
|
316
318
|
e?.preventDefault();
|
|
317
319
|
applyRef.current?.(item.value);
|
|
318
320
|
return true;
|
|
@@ -7,9 +7,28 @@ export interface RangeFacetConfig {
|
|
|
7
7
|
presets?: string[];
|
|
8
8
|
format?: (value: string) => string;
|
|
9
9
|
}
|
|
10
|
+
export interface FacetGroupInfo {
|
|
11
|
+
/** Group key (empty string = ungrouped). */
|
|
12
|
+
key: string;
|
|
13
|
+
/** Display label for the section header. Derived from key when not explicitly set. */
|
|
14
|
+
label: string | undefined;
|
|
15
|
+
/** Sort order for the group. Defaults to Infinity (last). */
|
|
16
|
+
order: number;
|
|
17
|
+
/** Icon name for the section header, if any. */
|
|
18
|
+
icon: string | undefined;
|
|
19
|
+
}
|
|
20
|
+
export interface FacetMetadata {
|
|
21
|
+
label?: string;
|
|
22
|
+
description?: string;
|
|
23
|
+
group?: string;
|
|
24
|
+
groupLabel?: string;
|
|
25
|
+
groupOrder?: number;
|
|
26
|
+
groupIcon?: string;
|
|
27
|
+
}
|
|
10
28
|
export type FacetDef = string | {
|
|
11
|
-
|
|
12
|
-
config
|
|
29
|
+
id: string;
|
|
30
|
+
config?: RangeFacetConfig;
|
|
31
|
+
metadata?: FacetMetadata;
|
|
13
32
|
};
|
|
14
33
|
export type FormatLeafDisplay = (source: string, node: AstNode) => string;
|
|
15
34
|
export interface SuggestionItem {
|
|
@@ -17,8 +36,11 @@ export interface SuggestionItem {
|
|
|
17
36
|
label: React.ReactNode;
|
|
18
37
|
icon: React.ReactNode | null;
|
|
19
38
|
selected: boolean;
|
|
20
|
-
type?: 'section-header' | 'range-slider';
|
|
39
|
+
type?: 'section-header' | 'range-slider' | 'facet-context';
|
|
21
40
|
rangeFacetConfig?: RangeFacetConfig;
|
|
22
41
|
facetName?: string;
|
|
42
|
+
description?: string;
|
|
43
|
+
/** For facet-context items: the group label shown above the facet name */
|
|
44
|
+
sectionLabel?: string;
|
|
23
45
|
}
|
|
24
46
|
//# sourceMappingURL=types.d.ts.map
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export * from './skeleton';
|
|
1
|
+
export * from './skeleton.js';
|
|
2
2
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export * from './slider';
|
|
1
|
+
export * from './slider.js';
|
|
2
2
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export * from './switch';
|
|
1
|
+
export * from './switch.js';
|
|
2
2
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export type { ColumnDef } from '@tanstack/react-table';
|
|
2
|
-
export * from './data-table';
|
|
3
|
-
export * from './table';
|
|
4
|
-
export * from './table-column-header';
|
|
5
|
-
export * from './table-pagination';
|
|
2
|
+
export * from './data-table.js';
|
|
3
|
+
export * from './table.js';
|
|
4
|
+
export * from './table-column-header.js';
|
|
5
|
+
export * from './table-pagination.js';
|
|
6
6
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Column definitions for Table stories
|
|
3
3
|
*/
|
|
4
4
|
import type { ColumnDef } from '@tanstack/react-table';
|
|
5
|
-
import type { JobData, SearchJobData, User } from './table.stories.data';
|
|
5
|
+
import type { JobData, SearchJobData, User } from './table.stories.data.js';
|
|
6
6
|
/**
|
|
7
7
|
* Create column definitions for JobData
|
|
8
8
|
*/
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export * from './tabs';
|
|
1
|
+
export * from './tabs.js';
|
|
2
2
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export * from './textarea';
|
|
1
|
+
export * from './textarea.js';
|
|
2
2
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export * from './theme-provider';
|
|
1
|
+
export * from './theme-provider.js';
|
|
2
2
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export * from './toast';
|
|
2
|
-
export * from './toast-custom';
|
|
1
|
+
export * from './toast.js';
|
|
2
|
+
export * from './toast-custom.js';
|
|
3
3
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export * from './tooltip';
|
|
1
|
+
export * from './tooltip.js';
|
|
2
2
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export * from './code';
|
|
2
|
-
export * from './header';
|
|
3
|
-
export * from './text';
|
|
1
|
+
export * from './code.js';
|
|
2
|
+
export * from './header.js';
|
|
3
|
+
export * from './text.js';
|
|
4
4
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/hooks/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
export * from './useCopyToClipboard';
|
|
2
|
-
export * from './useMediaQuery';
|
|
3
|
-
export * from './useResolvedTheme';
|
|
4
|
-
export * from './useShikiHighlight';
|
|
5
|
-
export * from './useShikiStyleInjection';
|
|
6
|
-
export * from './useTheme';
|
|
1
|
+
export * from './useCopyToClipboard.js';
|
|
2
|
+
export * from './useMediaQuery.js';
|
|
3
|
+
export * from './useResolvedTheme.js';
|
|
4
|
+
export * from './useShikiHighlight.js';
|
|
5
|
+
export * from './useShikiStyleInjection.js';
|
|
6
|
+
export * from './useTheme.js';
|
|
7
7
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/hooks/useTheme.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const useTheme: () => import("../state/theme").ThemeProviderState;
|
|
1
|
+
export declare const useTheme: () => import("../state/theme.js").ThemeProviderState;
|
|
2
2
|
//# sourceMappingURL=useTheme.d.ts.map
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { ShipfoxLoader } from 'shipfox-loader-react';
|
|
2
|
-
export * from './components';
|
|
3
|
-
export * from './hooks';
|
|
4
|
-
export type { Theme, ThemeProviderState } from './state/theme';
|
|
5
|
-
export * from './utils';
|
|
2
|
+
export * from './components/index.js';
|
|
3
|
+
export * from './hooks/index.js';
|
|
4
|
+
export type { Theme, ThemeProviderState } from './state/theme.js';
|
|
5
|
+
export * from './utils/index.js';
|
|
6
6
|
//# sourceMappingURL=index.d.ts.map
|