@lapismd/design-core 0.1.0 → 0.1.2

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 (67) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/README.md +1 -1
  3. package/package.json +12 -8
  4. package/spec/src/styling-and-themes.md +9 -9
  5. package/src/shared/ai/chat.css +2 -1
  6. package/src/shared/ai/composer-input/ComposerInput.svelte +3 -2
  7. package/src/shared/ai/experimental/reaction-bar/ReactionBar.svelte +1 -1
  8. package/src/shared/ai/tool-calls/ToolCalls.svelte +1 -1
  9. package/src/shared/ai/trigger-menu.ts +2 -3
  10. package/src/shared/diff/file-diff/FileDiff.svelte +5 -8
  11. package/src/shared/diff/file-listing/FileListingViewModeToggle.css +42 -5
  12. package/src/shared/diff/merge-editor/MergeEditor.svelte +2 -7
  13. package/src/shared/filter/filter-query/filters.ts +2 -2
  14. package/src/shared/filter/filter-query/parser.ts +9 -8
  15. package/src/shared/filter/power-search/PowerSearch.svelte +1 -1
  16. package/src/shared/filter/search-filter-bar/SearchFilterBar.svelte +2 -2
  17. package/src/shared/filter/search-filter-bar/SearchFilterInput.svelte +1 -1
  18. package/src/shared/filter/search-filter-bar/SearchFilterPredicateEditor.svelte +1 -1
  19. package/src/shared/filter/search-filter-bar/search-filter-syntax.ts +1 -1
  20. package/src/shared/forms/autocomplete-input/AutocompleteInput.svelte +19 -7
  21. package/src/shared/shadcn/command/command-dialog.svelte +1 -1
  22. package/src/shared/shadcn/command/command-group.svelte +3 -1
  23. package/src/shared/shadcn/command-view/command-view.svelte +1 -6
  24. package/src/shared/shadcn/dropdown-menu/dropdown-menu-checkbox-item.svelte +0 -691
  25. package/src/shared/shadcn/dropdown-menu/dropdown-menu-content.svelte +691 -0
  26. package/src/shared/shadcn/dropdown-menu/dropdown-menu-radio-group.svelte +1 -1
  27. package/src/shared/shadcn/scroll-area/scroll-area.svelte +2 -0
  28. package/src/shared/shadcn/spinner/spinner.svelte +3 -3
  29. package/src/shared/shell/app-shell/AppShell.demo.css +37 -0
  30. package/src/shared/shell/app-shell/AppShellBodyContent.svelte +5 -1
  31. package/src/shared/shell/app-shell/AppShellBodySidebar.svelte +5 -1
  32. package/src/shared/shell/app-shell/AppShellMobilePanelSelector.svelte +1 -1
  33. package/src/shared/shell/app-shell/app-shell-controller.svelte.ts +23 -9
  34. package/src/shared/shell/app-shell/examples/AppShellBodyDemo.svelte +4 -0
  35. package/src/shared/shell/app-shell/examples/AppShellCompleteDemo.svelte +1 -0
  36. package/src/shared/shell/app-shell/examples/AppShellConversationDemo.svelte +1 -0
  37. package/src/shared/shell/app-shell/examples/AppShellExamples.css +521 -0
  38. package/src/shared/shell/app-shell/examples/AppShellFilesSidebarDemo.svelte +1 -0
  39. package/src/shared/shell/app-shell/examples/AppShellMarkdownDocumentDemo.svelte +6 -1
  40. package/src/shared/shell/app-shell/examples/AppShellMarkdownFilesDemo.svelte +1 -0
  41. package/src/shared/shell/app-shell/examples/AppShellModeSwitchDemo.svelte +1 -0
  42. package/src/shared/shell/app-shell/examples/AppShellProjectSidebarDemo.svelte +1 -0
  43. package/src/shared/shell/app-shell/examples/AppShellSidebarDemo.svelte +1 -0
  44. package/src/shared/shell/app-shell/examples/AppShellToolbarDemo.svelte +1 -0
  45. package/src/shared/workspace/menu/WorkspaceContextMenuItems.svelte +2 -1
  46. package/src/shared/workspace/menu/WorkspaceMenuItems.svelte +2 -1
  47. package/src/shared/workspace/problems/ProblemsQuickFix.svelte +1 -4
  48. package/src/shared/workspace/settings/AppSettingsContent.svelte +6 -0
  49. package/src/shared/workspace/settings/AppSettingsNavigation.svelte +7 -0
  50. package/src/shared/workspace/settings/CopyableValue.svelte +81 -0
  51. package/src/shared/workspace/settings/DeclarativeSettingsSection.svelte +20 -0
  52. package/src/shared/workspace/settings/WorkspaceSettingField.svelte +110 -41
  53. package/src/shared/workspace/settings/WorkspaceSettingMultiSelect.svelte +7 -6
  54. package/src/shared/workspace/settings/WorkspaceSettingObjectTable.svelte +187 -23
  55. package/src/shared/workspace/settings/WorkspaceSettingSelect.svelte +29 -29
  56. package/src/shared/workspace/settings/WorkspaceSettings.css +190 -4
  57. package/src/shared/workspace/settings/WorkspaceSettingsStoryCustomField.svelte +2 -2
  58. package/src/shared/workspace/settings/WorkspaceSettingsStoryCustomPage.svelte +13 -0
  59. package/src/shared/workspace/settings/WorkspaceSettingsSurface.svelte +50 -0
  60. package/src/shared/workspace/settings/configuration.ts +5 -0
  61. package/src/shared/workspace/settings/copyable-value.ts +10 -0
  62. package/src/shared/workspace/settings/index.ts +5 -0
  63. package/src/shared/workspace/settings/settings-controller.svelte.ts +349 -15
  64. package/src/shared/workspace/settings/types.ts +90 -8
  65. package/src/storybook/app-shell-reference/AppShellTwoExpandedSidebarsReference.css +25 -0
  66. package/src/storybook/app-shell-reference/AppShellTwoExpandedSidebarsReference.svelte +48 -0
  67. package/src/storybook/app-shell-reference/index.ts +1 -0
package/CHANGELOG.md CHANGED
@@ -1,5 +1,27 @@
1
1
  # @lapismd/design-core
2
2
 
3
+ ## 0.1.2
4
+
5
+ ### Patch Changes
6
+
7
+ - [#2](https://github.com/lapismd/design-core/pull/2) [`af3a0b3`](https://github.com/lapismd/design-core/commit/af3a0b3aaabd24be368acea795b150af8f4e5b89) Thanks [@stevejuma](https://github.com/stevejuma)! - Keep workspace menu close handling lifecycle-safe when an action callback destroys its owning view.
8
+
9
+ - [#4](https://github.com/lapismd/design-core/pull/4) [`d153167`](https://github.com/lapismd/design-core/commit/d15316795ce7601a483796bce23f78bfc37188ae) Thanks [@stevejuma](https://github.com/stevejuma)! - Allow App Shell body content and body sidebar regions to configure scroll, hover, or always-on scrollbar visibility independently.
10
+
11
+ - [#4](https://github.com/lapismd/design-core/pull/4) [`31c7a2c`](https://github.com/lapismd/design-core/commit/31c7a2cb438213d75a5ef3193e957cd7c35dc34f) Thanks [@stevejuma](https://github.com/stevejuma)! - Inset vertical and horizontal Scroll Area thumbs by one pixel from their outer edge.
12
+
13
+ - [#4](https://github.com/lapismd/design-core/pull/4) [`24a6e98`](https://github.com/lapismd/design-core/commit/24a6e989354b9d00d2d93786e4255da088812ee9) Thanks [@stevejuma](https://github.com/stevejuma)! - Expose the canonical two-expanded-sidebars App Shell fixture, including bounded content extension points and an optional right-sidebar toggle, for downstream Storybook catalogs. Keep the focused Search Filter Bar source export compatible with strict consumers.
14
+
15
+ - [#4](https://github.com/lapismd/design-core/pull/4) [`413139d`](https://github.com/lapismd/design-core/commit/413139d1269d5f939d20c1f00de45f151372eae0) Thanks [@stevejuma](https://github.com/stevejuma)! - Keep composed Shadcn, AI, and Filter source exports compatible with strict consumers that enable exact optional properties and unchecked indexed access.
16
+
17
+ - [#4](https://github.com/lapismd/design-core/pull/4) [`61fa863`](https://github.com/lapismd/design-core/commit/61fa86315a840717c39f0a0701d8cb208a187cb2) Thanks [@stevejuma](https://github.com/stevejuma)! - Keep the public App Shell source compatible with consumers that enable exact optional-property semantics.
18
+
19
+ ## 0.1.1
20
+
21
+ ### Patch Changes
22
+
23
+ - [`d1dc4a8`](https://github.com/lapismd/design-core/commit/d1dc4a8fb13eec9b59075712f964a89cee18a1a8) Thanks [@stevejuma](https://github.com/stevejuma)! - Allow custom settings pages to contribute dynamic search entries and reveal the selected row before Design Core scrolls to and highlights it.
24
+
3
25
  ## 0.1.0
4
26
 
5
27
  ### Initial public release
package/README.md CHANGED
@@ -246,7 +246,7 @@ pnpm release:plan --registry https://registry.npmjs.org
246
246
  pnpm packages:pack
247
247
  ```
248
248
 
249
- The first public npm publication is a manual bootstrap from reviewed tarballs.
249
+ `@lapismd/design-core@0.1.0` was manually bootstrapped from a reviewed tarball.
250
250
  Future releases use Changesets and the repository release workflow.
251
251
 
252
252
  ## Further reading
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lapismd/design-core",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Shared Lapis design system, forms, shell, and workspace primitives",
5
5
  "license": "AGPL-3.0-or-later",
6
6
  "repository": {
@@ -36,7 +36,6 @@
36
36
  "svelte": "^5.0.0"
37
37
  },
38
38
  "dependencies": {
39
- "@lapismd/mira": "^0.0.1",
40
39
  "@codemirror/autocomplete": "^6.18.0",
41
40
  "@codemirror/commands": "^6.8.0",
42
41
  "@codemirror/lang-java": "^6.0.2",
@@ -54,16 +53,18 @@
54
53
  "@iconify-json/lucide": "^1.2.63",
55
54
  "@iconify/utils": "^2.3.0",
56
55
  "@internationalized/date": "^3.12.2",
56
+ "@lapismd/mira": "^0.0.1",
57
57
  "@lezer/common": "^1.2.3",
58
58
  "@lezer/highlight": "^1.2.3",
59
59
  "@lezer/lr": "^1.4.2",
60
60
  "@lucide/svelte": "^1.21.0",
61
+ "@types/luxon": "^3.4.2",
61
62
  "bits-ui": "^2.18.1",
62
63
  "chrono-node": "^2.10.1",
63
64
  "clsx": "^2.1.1",
64
65
  "codemirror-lang-mermaid": "^0.5.0",
65
66
  "luxon": "^3.5.0",
66
- "minimatch": "^10.2.5",
67
+ "minimatch": "^10.2.6",
67
68
  "paneforge": "^1.0.2",
68
69
  "shadcn-svelte": "^1.3.0",
69
70
  "tailwind-merge": "^3.6.0",
@@ -90,11 +91,10 @@
90
91
  "@sveltejs/vite-plugin-svelte": "^5.0.3",
91
92
  "@tailwindcss/cli": "^4.3.3",
92
93
  "@tailwindcss/vite": "^4.3.0",
93
- "@tobilu/qmd": "2.5.3",
94
94
  "@testing-library/jest-dom": "^7.0.0",
95
95
  "@testing-library/react": "^16.3.2",
96
96
  "@testing-library/user-event": "^14.6.1",
97
- "@types/luxon": "^3.4.2",
97
+ "@tobilu/qmd": "2.5.3",
98
98
  "@types/node": "^22.15.0",
99
99
  "@types/pixelmatch": "^5.2.6",
100
100
  "@types/pngjs": "^6.0.5",
@@ -107,11 +107,11 @@
107
107
  "highlight.js": "^11.11.1",
108
108
  "jsdom": "^29.1.1",
109
109
  "magic-string": "^1.0.0",
110
- "markdownlint-cli2": "^0.22.1",
110
+ "markdownlint-cli2": "^0.23.2",
111
111
  "pixelmatch": "^7.2.0",
112
112
  "playwright": "^1.52.0",
113
113
  "pngjs": "^7.0.0",
114
- "postcss": "^8.5.20",
114
+ "postcss": "^8.5.28",
115
115
  "postcss-selector-parser": "^7.1.4",
116
116
  "prettier": "3.3.3",
117
117
  "prettier-plugin-svelte": "^3.3.2",
@@ -174,6 +174,7 @@
174
174
  "./styles.css": "./src/styles.css",
175
175
  "./storybook.css": "./src/storybook.css",
176
176
  "./storybook/catalog-layout": "./src/storybook/catalog-layout.ts",
177
+ "./storybook/app-shell-reference": "./src/storybook/app-shell-reference/index.ts",
177
178
  "./themes/lapis.css": "./src/themes/lapis.css",
178
179
  "./ai": "./src/shared/ai/index.ts",
179
180
  "./ai/chat": "./src/shared/ai/chat.ts",
@@ -277,7 +278,10 @@
277
278
  "ui:visual:tag": "tsx scripts/ui-generator/cli.ts visual:tag",
278
279
  "test-unit": "pnpm test:unit",
279
280
  "test-storybook": "pnpm test:storybook",
280
- "check": "pnpm spec:validate && svelte-check --tsconfig ./tsconfig.json --fail-on-warnings",
281
+ "check": "pnpm spec:validate && svelte-check --tsconfig ./tsconfig.json --fail-on-warnings && pnpm check:shell-consumer && pnpm check:filter-consumer && pnpm check:source-consumer",
282
+ "check:filter-consumer": "svelte-check --tsconfig ./tsconfig.filter-consumer.json --fail-on-warnings",
283
+ "check:shell-consumer": "svelte-check --tsconfig ./tsconfig.shell-consumer.json --fail-on-warnings",
284
+ "check:source-consumer": "svelte-check --tsconfig ./tsconfig.source-consumer.json --fail-on-warnings",
281
285
  "fmt": "prettier . --write",
282
286
  "fmt:check": "prettier . --check",
283
287
  "check:no-tailwind": "tsx scripts/check-no-tailwind-utilities.ts",
@@ -107,15 +107,15 @@ pages.
107
107
 
108
108
  ### Token layers
109
109
 
110
- | Layer | Prefix | Defaults |
111
- | ------------------- | ------------------------------ | ------------------------------------------- |
112
- | Theme | `--background`, `--primary`, … | `src/theme.css` |
113
- | Shadcn family | `--ui-<family>-*` | `<family>.tokens.css` |
114
- | Forms | `--ui-form-*` | `src/shared/forms/form.tokens.css` |
115
- | Filter and AI | `--ui-*` / `--ui-ai-*` | colocated CSS and token maps |
116
- | Diff | `--ui-diff-*` | `src/shared/diff/diff.tokens.css` |
117
- | Structural shell | `--ui-shell-*` | `src/shared/shell/shell.tokens.css` |
118
- | Workspace framework | `--ui-workspace-*` | `src/shared/workspace/workspace.tokens.css` |
110
+ | Layer | Prefix | Defaults |
111
+ | ------------------- | ------------------------------ | ------------------------------------------------- |
112
+ | Theme | `--background`, `--primary`, … | `src/theme.css` |
113
+ | Shadcn family | `--ui-<family>-*` | `<family>.tokens.css` |
114
+ | Forms | `--ui-form-*` | `src/shared/forms/form.tokens.css` |
115
+ | Filter and AI | `--ui-*` / `--ui-ai-*` | colocated CSS and token maps |
116
+ | Diff | `--ui-diff-*` | `src/shared/diff/diff.tokens.css` |
117
+ | Structural shell | `--ui-shell-*` | `src/shared/shell/shell.tokens.css` |
118
+ | Workspace framework | `--ui-workspace-*` | `src/shared/workspace/workspace.tokens.css` |
119
119
  | Desktop drag | `data-desktop-drag-region` | `src/shared/workspace/workspace-desktop-drag.css` |
120
120
 
121
121
  Set public tokens on `:root` or an appropriate shared ancestor such as
@@ -1031,7 +1031,8 @@
1031
1031
 
1032
1032
  [data-ui-component="ai-chat-composer-drawer"]
1033
1033
  [data-ai-chat-part="drawer-content"]
1034
- [data-ui-part="attachment-remove"] svg {
1034
+ [data-ui-part="attachment-remove"]
1035
+ svg {
1035
1036
  width: 0.75rem;
1036
1037
  height: 0.75rem;
1037
1038
  }
@@ -331,9 +331,10 @@
331
331
  Math.max(1, searchState.items.length);
332
332
  return;
333
333
  }
334
- if (event.key === "Enter" && searchState.items[highlightedIndex]) {
334
+ const highlightedItem = searchState.items[highlightedIndex];
335
+ if (event.key === "Enter" && highlightedItem) {
335
336
  event.preventDefault();
336
- insertTriggerSelection(searchState.items[highlightedIndex]);
337
+ insertTriggerSelection(highlightedItem);
337
338
  return;
338
339
  }
339
340
  if (event.key === "Escape") {
@@ -74,7 +74,7 @@
74
74
  {/each}
75
75
  {#if onAdd}
76
76
  <EmojiPicker
77
- {emojis}
77
+ {...emojis === undefined ? {} : { emojis }}
78
78
  label={addLabel}
79
79
  triggerLabel={addLabel}
80
80
  onSelect={onAdd}
@@ -141,7 +141,7 @@
141
141
  >
142
142
  {#if !hasMultipleCalls}
143
143
  <ul data-ui-part="call-list" data-single-call>
144
- {@render callRow(calls[0], 0)}
144
+ {@render callRow(calls[0]!, 0)}
145
145
  </ul>
146
146
  {:else}
147
147
  <Collapsible.Root open={expanded} onOpenChange={setExpanded}>
@@ -40,9 +40,8 @@ export function nearestClipBottom(
40
40
  let bottom = viewportHeight;
41
41
  let current = element?.parentElement ?? null;
42
42
  while (current) {
43
- const overflowY = current.ownerDocument.defaultView
44
- ?.getComputedStyle(current)
45
- .overflowY;
43
+ const overflowY =
44
+ current.ownerDocument.defaultView?.getComputedStyle(current).overflowY;
46
45
  if (overflowY && CLIPPING_OVERFLOW.has(overflowY)) {
47
46
  bottom = Math.min(bottom, current.getBoundingClientRect().bottom);
48
47
  }
@@ -107,10 +107,7 @@
107
107
  if (candidate.scrollTop !== target.scrollTop) {
108
108
  candidate.scrollTop = target.scrollTop;
109
109
  }
110
- if (
111
- syncHorizontal &&
112
- candidate.scrollLeft !== target.scrollLeft
113
- ) {
110
+ if (syncHorizontal && candidate.scrollLeft !== target.scrollLeft) {
114
111
  candidate.scrollLeft = target.scrollLeft;
115
112
  }
116
113
  }
@@ -214,10 +211,10 @@
214
211
  {/snippet}
215
212
 
216
213
  {#snippet splitCell(
217
- row: UnifiedDiffRow | null,
218
- side: "left" | "right",
219
- pairKey: string,
220
- )}
214
+ row: UnifiedDiffRow | null,
215
+ side: "left" | "right",
216
+ pairKey: string,
217
+ )}
221
218
  {#if row}
222
219
  <div
223
220
  class="ui-diff-file-diff__row"
@@ -1,14 +1,51 @@
1
1
  @import "../diff.tokens.css";
2
2
 
3
- [data-ui-component="file-listing-view-mode-toggle"] svg {
4
- width: 0.875rem;
5
- height: 0.875rem;
3
+ [data-ui-component="file-listing-view-mode-toggle"][data-ui-part="toggle-group"] {
4
+ display: inline-flex;
5
+ align-items: stretch;
6
+ width: fit-content;
7
+ height: 1.375rem;
8
+ gap: 0;
9
+ overflow: hidden;
10
+ border: 1px solid var(--ui-diff-border, var(--border, #d4d4d4));
11
+ border-radius: calc(var(--radius, 0.5rem) * 0.6);
12
+ background: var(--ui-diff-surface, var(--background, #fff));
13
+ box-shadow: none;
6
14
  }
7
15
 
8
16
  [data-ui-component="file-listing-view-mode-toggle"]
9
- [data-ui-part="toggle-group-item"][data-state="on"],
17
+ [data-ui-component="toggle-group"][data-ui-part="toggle-group-item"][data-size="sm"],
10
18
  [data-ui-component="file-listing-view-mode-toggle"]
11
- [data-ui-part="toggle-group-item"][data-state="on"]:hover {
19
+ [data-ui-component="toggle-group"][data-ui-part="toggle-group-item"][data-variant="outline"] {
20
+ box-sizing: border-box;
21
+ height: 100%;
22
+ min-height: 0;
23
+ width: 1.375rem;
24
+ min-width: 1.375rem;
25
+ padding: 0;
26
+ border: none;
27
+ border-radius: 0;
28
+ box-shadow: none;
29
+ background-color: transparent;
30
+ }
31
+
32
+ [data-ui-component="file-listing-view-mode-toggle"]
33
+ [data-ui-component="toggle-group"][data-ui-part="toggle-group-item"]
34
+ + [data-ui-component="toggle-group"][data-ui-part="toggle-group-item"] {
35
+ border-left: 1px solid var(--ui-diff-border, var(--border, #d4d4d4));
36
+ }
37
+
38
+ [data-ui-component="file-listing-view-mode-toggle"]
39
+ [data-ui-component="toggle-group"][data-ui-part="toggle-group-item"]
40
+ svg {
41
+ width: 0.75rem;
42
+ height: 0.75rem;
43
+ }
44
+
45
+ [data-ui-component="file-listing-view-mode-toggle"]
46
+ [data-ui-component="toggle-group"][data-ui-part="toggle-group-item"][data-state="on"],
47
+ [data-ui-component="file-listing-view-mode-toggle"]
48
+ [data-ui-component="toggle-group"][data-ui-part="toggle-group-item"][data-state="on"]:hover {
12
49
  background-color: var(--ui-diff-selected);
13
50
  color: inherit;
14
51
  }
@@ -187,9 +187,7 @@
187
187
  const viewport = view.querySelector<HTMLElement>(
188
188
  "[data-ui-part='scroll-area-viewport']",
189
189
  );
190
- return viewport
191
- ? [{ side: view.dataset.mergeSide, viewport }]
192
- : [];
190
+ return viewport ? [{ side: view.dataset.mergeSide, viewport }] : [];
193
191
  });
194
192
  if (targets.length === 0) return;
195
193
  let syncing = false;
@@ -202,10 +200,7 @@
202
200
  if (candidate.viewport.scrollTop !== target.viewport.scrollTop) {
203
201
  candidate.viewport.scrollTop = target.viewport.scrollTop;
204
202
  }
205
- if (
206
- !syncAcross &&
207
- candidate.side !== target.side
208
- ) {
203
+ if (!syncAcross && candidate.side !== target.side) {
209
204
  continue;
210
205
  }
211
206
  if (candidate.viewport.scrollLeft !== target.viewport.scrollLeft) {
@@ -350,14 +350,14 @@ export class BooleanFilter extends Filter {
350
350
  const size = this.args.length;
351
351
  if (this.op == FilterType.NOT) {
352
352
  if (size == 1) {
353
- return `-${this.args[0]}`;
353
+ return `-${this.args[0]!}`;
354
354
  }
355
355
  return `-(${this.args.map((it) => it.toString()).join("")})`;
356
356
  }
357
357
 
358
358
  const separator = this.op === FilterType.AND ? " " : ",";
359
359
  return size == 1
360
- ? this.args[0].toString()
360
+ ? this.args[0]!.toString()
361
361
  : `(${this.args.map((it) => it.toString()).join(separator)})`;
362
362
  }
363
363
 
@@ -310,13 +310,14 @@ export class DateExpression {
310
310
 
311
311
  resolve(): DateExpressionInput | DateRange {
312
312
  if (this.#operands.length == 1) {
313
- if (this.#operands[0] instanceof DateExpression) {
314
- return this.#operands[0].resolve();
313
+ const operand = this.#operands[0]!;
314
+ if (operand instanceof DateExpression) {
315
+ return operand.resolve();
315
316
  } else {
316
- return this.#operands[0];
317
+ return operand;
317
318
  }
318
319
  }
319
- return this.eval(this.#operands[0], this.#operands[1]);
320
+ return this.eval(this.#operands[0]!, this.#operands[1]!);
320
321
  }
321
322
 
322
323
  private eval(left: DateExpressionInput, right: DateExpressionInput) {
@@ -510,9 +511,9 @@ export class Parser {
510
511
  }, this.leave.bind(this));
511
512
 
512
513
  if (this.stack.length == 1) {
513
- const filter = this.stack[0];
514
+ const filter = this.stack[0]!;
514
515
  if (filter instanceof BooleanFilter) {
515
- this.predicate = filter.args.length == 1 ? filter.args[0] : filter;
516
+ this.predicate = filter.args.length == 1 ? filter.args[0]! : filter;
516
517
  } else {
517
518
  this.errors.push(
518
519
  `Expected {${filter}} to be instance of BooleanFilter`,
@@ -658,7 +659,7 @@ export class Parser {
658
659
  return new NumberFilter(this.content(node));
659
660
  } else if (node.name === "Regex") {
660
661
  const value = this.content(node).match(/\/(.+)\/([a-z]+)?/) || [];
661
- return new PatternFilter(new RegExp(value[1], value[2] ?? ""));
662
+ return new PatternFilter(new RegExp(value[1] ?? "", value[2] ?? ""));
662
663
  } else if (node.name === "AccountName") {
663
664
  return new AccountFilter(this.content(node));
664
665
  }
@@ -704,7 +705,7 @@ export class Parser {
704
705
  private dateExpression(node: SyntaxNode | null | undefined) {
705
706
  return dateExpression(node, {
706
707
  content: this.content.bind(this),
707
- now: this.options.now,
708
+ ...(this.options.now === undefined ? {} : { now: this.options.now }),
708
709
  });
709
710
  }
710
711
  }
@@ -207,7 +207,7 @@
207
207
  {disabled}
208
208
  ariaLabel="Add filter field"
209
209
  onSelectField={openAddForField}
210
- onCommitText={contentSearchFieldKey ? handleCommitText : undefined}
210
+ {...contentSearchFieldKey ? { onCommitText: handleCommitText } : {}}
211
211
  />
212
212
  </div>
213
213
 
@@ -112,12 +112,12 @@
112
112
  {ariaLabel}
113
113
  shortcut={!showFilterToggle || filtersExpanded ? shortcut : ""}
114
114
  {disabled}
115
- {inputId}
115
+ {...inputId === undefined ? {} : { inputId }}
116
116
  {inputMode}
117
117
  {clearSearchLabel}
118
118
  {error}
119
119
  {editorExtensions}
120
- {filterSyntax}
120
+ {...filterSyntax === undefined ? {} : { filterSyntax }}
121
121
  {onValueChange}
122
122
  {onClearSearch}
123
123
  >
@@ -403,7 +403,7 @@
403
403
  {#key `${chipEditSession.from}:${chipEditSession.to}:${chipEditSession.field}`}
404
404
  <SearchFilterPredicateEditor
405
405
  session={chipEditSession}
406
- {filterSyntax}
406
+ {...filterSyntax === undefined ? {} : { filterSyntax }}
407
407
  {disabled}
408
408
  onCancel={closePredicateChipEditor}
409
409
  onApply={applyPredicateChipEdit}
@@ -158,7 +158,7 @@
158
158
  <div class="cv-search-filter-bar__predicate-editor-row">
159
159
  <SearchFilterFieldAutocomplete
160
160
  value={field}
161
- {filterSyntax}
161
+ {...filterSyntax === undefined ? {} : { filterSyntax }}
162
162
  {disabled}
163
163
  onValueChange={handleFieldChange}
164
164
  />
@@ -261,7 +261,7 @@ function operatorDescription(operator: string) {
261
261
  function valueCompletions(field: SearchFilterField): Completion[] {
262
262
  return uniqueValues(field).map((value) => ({
263
263
  label: value.label ?? value.value,
264
- detail: value.description,
264
+ ...(value.description === undefined ? {} : { detail: value.description }),
265
265
  type: "constant",
266
266
  apply: value.apply ?? value.value,
267
267
  }));
@@ -52,6 +52,7 @@
52
52
  let editing = $state(false);
53
53
  let filterValue = $state("");
54
54
  let activeIndex = $state(0);
55
+ let blurFocusTarget: HTMLElement | null = null;
55
56
  const listId = `autocomplete-list-${Math.random().toString(36).slice(2)}`;
56
57
 
57
58
  const normalizedSuggestions = $derived.by(() => {
@@ -115,10 +116,10 @@
115
116
  void onCommit(suggestion);
116
117
  }
117
118
 
118
- function commitValue() {
119
+ function commitValue(close = true) {
119
120
  const committed = value.trim();
120
121
  if (!committed) return;
121
- if (!forceOpen) open = false;
122
+ if (close && !forceOpen) open = false;
122
123
  editing = false;
123
124
  filterValue = "";
124
125
  void onCommit(committed);
@@ -132,6 +133,13 @@
132
133
  activeIndex = 0;
133
134
  }
134
135
 
136
+ function handleCloseAutoFocus(event: Event) {
137
+ event.preventDefault();
138
+ const target = blurFocusTarget;
139
+ blurFocusTarget = null;
140
+ target?.focus({ preventScroll: true });
141
+ }
142
+
135
143
  function handleKeydown(event: KeyboardEvent) {
136
144
  if (event.key === "ArrowDown") {
137
145
  event.preventDefault();
@@ -166,9 +174,8 @@
166
174
  }
167
175
  if (event.key === "Tab") {
168
176
  if (commitOnTab && value.trim()) {
169
- commitValue();
177
+ commitValue(false);
170
178
  }
171
- closeList();
172
179
  return;
173
180
  }
174
181
  if (event.key === "Backspace" && !value) {
@@ -213,11 +220,16 @@
213
220
  activeIndex = 0;
214
221
  }}
215
222
  onkeydown={handleKeydown}
216
- onblur={() => {
223
+ onblur={(event) => {
224
+ blurFocusTarget =
225
+ event.relatedTarget instanceof HTMLElement
226
+ ? event.relatedTarget
227
+ : null;
217
228
  if (commitOnBlur) {
218
229
  commitValue();
230
+ } else {
231
+ closeList();
219
232
  }
220
- closeList();
221
233
  }}
222
234
  />
223
235
  <Popover.Content
@@ -227,7 +239,7 @@
227
239
  customAnchor={input}
228
240
  {portalProps}
229
241
  onOpenAutoFocus={(event) => event.preventDefault()}
230
- onCloseAutoFocus={(event) => event.preventDefault()}
242
+ onCloseAutoFocus={handleCloseAutoFocus}
231
243
  >
232
244
  <div id={listId} class="ui-autocomplete-input__list" role="listbox">
233
245
  {#each normalizedSuggestions as suggestion, index (suggestion)}
@@ -41,7 +41,7 @@
41
41
  data-slot="command-content"
42
42
  class={className}
43
43
  {showCloseButton}
44
- {portalProps}
44
+ {...portalProps === undefined ? {} : { portalProps }}
45
45
  >
46
46
  <Command {...restProps} bind:value bind:ref {children} />
47
47
  </Dialog.Content>
@@ -31,5 +31,7 @@
31
31
  {heading}
32
32
  </CommandPrimitive.GroupHeading>
33
33
  {/if}
34
- <CommandPrimitive.GroupItems {children} />
34
+ <CommandPrimitive.GroupItems>
35
+ {#if children}{@render children()}{/if}
36
+ </CommandPrimitive.GroupItems>
35
37
  </CommandPrimitive.Group>
@@ -19,12 +19,7 @@
19
19
  data-slot="command-view"
20
20
  class={className}
21
21
  >
22
- <Command.Root
23
- bind:value
24
- bind:ref
25
- {shouldFilter}
26
- {...restProps}
27
- >
22
+ <Command.Root bind:value bind:ref {shouldFilter} {...restProps}>
28
23
  {@render children?.()}
29
24
  </Command.Root>
30
25
  </div>