nuxt-ui-tools 1.5.0 → 1.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. package/dist/module.json +1 -1
  2. package/dist/module.mjs +1 -0
  3. package/dist/runtime/i18n/locales/en.js +23 -2
  4. package/dist/runtime/i18n/locales/fr.js +23 -2
  5. package/dist/runtime/i18n/types.d.ts +21 -0
  6. package/dist/runtime/table/components/data-list/data-list-content.vue +7 -1
  7. package/dist/runtime/table/components/data-list/data-list-error-state.d.vue.ts +18 -1
  8. package/dist/runtime/table/components/data-list/data-list-error-state.vue +65 -41
  9. package/dist/runtime/table/components/data-list/data-list-error-state.vue.d.ts +18 -1
  10. package/dist/runtime/table/components/data-list/sort-menu-panel.vue +33 -25
  11. package/dist/runtime/table/components/drawers/column-panel.vue +19 -6
  12. package/dist/runtime/table/components/filters/shared/dynamic-filter-picker.vue +1 -1
  13. package/dist/runtime/table/components/filters/shared/filter-editor-header.d.vue.ts +16 -0
  14. package/dist/runtime/table/components/filters/shared/filter-editor-header.vue +46 -0
  15. package/dist/runtime/table/components/filters/shared/filter-editor-header.vue.d.ts +16 -0
  16. package/dist/runtime/table/components/filters/shared/filter-option-multiple-list.d.vue.ts +3 -1
  17. package/dist/runtime/table/components/filters/shared/filter-option-multiple-list.vue +5 -4
  18. package/dist/runtime/table/components/filters/shared/filter-option-multiple-list.vue.d.ts +3 -1
  19. package/dist/runtime/table/components/filters/shared/filter-option-picker-content.vue +4 -1
  20. package/dist/runtime/table/components/filters/shared/filter-option-single-list.vue +3 -3
  21. package/dist/runtime/table/components/filters/shared/filter-option-tree-content.vue +7 -3
  22. package/dist/runtime/table/components/filters/shared/filter-popover-shell.vue +10 -1
  23. package/dist/runtime/table/components/filters/shared/filter-searchable-panel.vue +14 -6
  24. package/dist/runtime/table/components/filters/shared/filter-trigger-tag.vue +5 -1
  25. package/dist/runtime/table/components/filters/tags/boolean-filter-tag.d.vue.ts +6 -1
  26. package/dist/runtime/table/components/filters/tags/boolean-filter-tag.vue +19 -5
  27. package/dist/runtime/table/components/filters/tags/boolean-filter-tag.vue.d.ts +6 -1
  28. package/dist/runtime/table/components/filters/tags/date-filter-tag.d.vue.ts +6 -1
  29. package/dist/runtime/table/components/filters/tags/date-filter-tag.vue +65 -29
  30. package/dist/runtime/table/components/filters/tags/date-filter-tag.vue.d.ts +6 -1
  31. package/dist/runtime/table/components/filters/tags/number-filter-tag.d.vue.ts +6 -1
  32. package/dist/runtime/table/components/filters/tags/number-filter-tag.vue +66 -18
  33. package/dist/runtime/table/components/filters/tags/number-filter-tag.vue.d.ts +6 -1
  34. package/dist/runtime/table/components/filters/tags/option-filter-tag.d.vue.ts +2 -2
  35. package/dist/runtime/table/components/filters/tags/option-filter-tag.vue +10 -34
  36. package/dist/runtime/table/components/filters/tags/option-filter-tag.vue.d.ts +2 -2
  37. package/dist/runtime/table/components/filters/tags/text-filter-tag.d.vue.ts +6 -1
  38. package/dist/runtime/table/components/filters/tags/text-filter-tag.vue +39 -14
  39. package/dist/runtime/table/components/filters/tags/text-filter-tag.vue.d.ts +6 -1
  40. package/dist/runtime/table/components/grid/grid-renderer.d.vue.ts +8 -2
  41. package/dist/runtime/table/components/grid/grid-renderer.vue +47 -115
  42. package/dist/runtime/table/components/grid/grid-renderer.vue.d.ts +8 -2
  43. package/dist/runtime/table/components/layout/progress-line.d.vue.ts +9 -0
  44. package/dist/runtime/table/components/layout/progress-line.vue +43 -0
  45. package/dist/runtime/table/components/layout/progress-line.vue.d.ts +9 -0
  46. package/dist/runtime/table/components/table/table-empty-state.d.vue.ts +1 -1
  47. package/dist/runtime/table/components/table/table-empty-state.vue +1 -1
  48. package/dist/runtime/table/components/table/table-empty-state.vue.d.ts +1 -1
  49. package/dist/runtime/table/components/table/table-layout.d.ts +57 -0
  50. package/dist/runtime/table/components/table/table-layout.js +23 -0
  51. package/dist/runtime/table/components/table/table-renderer.d.vue.ts +8 -16
  52. package/dist/runtime/table/components/table/table-renderer.vue +180 -274
  53. package/dist/runtime/table/components/table/table-renderer.vue.d.ts +8 -16
  54. package/dist/runtime/table/components/table/table-row.d.vue.ts +19 -0
  55. package/dist/runtime/table/components/table/table-row.vue +51 -0
  56. package/dist/runtime/table/components/table/table-row.vue.d.ts +19 -0
  57. package/dist/runtime/table/components/table/table-skeleton-cell.d.ts +9 -0
  58. package/dist/runtime/table/components/table/table-skeleton-cell.js +104 -0
  59. package/dist/runtime/table/components/utils/search-query-input.vue +27 -1
  60. package/dist/runtime/table/composables/use-deferred-commit.d.ts +20 -0
  61. package/dist/runtime/table/composables/use-deferred-commit.js +31 -0
  62. package/dist/runtime/table/composables/use-table-data.d.ts +5 -1
  63. package/dist/runtime/table/composables/use-table-data.js +20 -2
  64. package/dist/runtime/table/composables/use-table-summaries.js +10 -1
  65. package/dist/runtime/table/types/columns.d.ts +18 -3
  66. package/dist/runtime/table/types/data-list.d.ts +1 -0
  67. package/dist/runtime/table/types/layout.d.ts +1 -1
  68. package/dist/runtime/table/utils/columns/defs.js +1 -1
  69. package/dist/runtime/table/utils/filters/date.d.ts +6 -0
  70. package/dist/runtime/table/utils/filters/date.js +26 -2
  71. package/dist/runtime/table/utils/filters/index.d.ts +1 -0
  72. package/dist/runtime/table/utils/filters/index.js +1 -0
  73. package/dist/runtime/table/utils/filters/number.d.ts +5 -0
  74. package/dist/runtime/table/utils/filters/number.js +11 -0
  75. package/dist/runtime/table/utils/filters/ui.js +5 -5
  76. package/package.json +1 -1
@@ -4,6 +4,7 @@ type __VLS_Props = {
4
4
  dynamic?: boolean;
5
5
  session?: boolean;
6
6
  embedded?: boolean;
7
+ header?: boolean;
7
8
  initialOperator?: TableFilterOperator;
8
9
  };
9
10
  declare var __VLS_10: {
@@ -28,11 +29,15 @@ type __VLS_Slots = {} & {
28
29
  };
29
30
  declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
30
31
  dismiss: () => any;
32
+ back: () => any;
31
33
  sessionClosed: () => any;
32
34
  }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
33
35
  onDismiss?: (() => any) | undefined;
36
+ onBack?: (() => any) | undefined;
34
37
  onSessionClosed?: (() => any) | undefined;
35
- }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
38
+ }>, {
39
+ header: boolean;
40
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
36
41
  declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
37
42
  declare const _default: typeof __VLS_export;
38
43
  export default _default;
@@ -3,17 +3,21 @@ import UButton from "@nuxt/ui/components/Button.vue";
3
3
  import UInputNumber from "@nuxt/ui/components/InputNumber.vue";
4
4
  import USlider from "@nuxt/ui/components/Slider.vue";
5
5
  import { computed, ref, watch } from "vue";
6
+ import { useUiToolsLocale } from "#ui-tools/i18n";
6
7
  import { isArray, isDate, isNumber, isObject, isNullish } from "../../../../shared/utils/predicate";
7
8
  import { useDataListUi } from "../../../composables/use-data-list-ui";
9
+ import { useDeferredCommit } from "../../../composables/use-deferred-commit";
8
10
  import { useFilterTagSession } from "../../../composables/use-filter-tag-session";
9
11
  import { useTableInternals } from "../../../composables/use-table-internals";
10
12
  import {
11
13
  mergeDataListUiClass,
14
+ parseTypedNumber,
12
15
  resolveDataListControlGeometry,
13
16
  resolveFilterEditorSizeClasses,
14
17
  resolveFilterTriggerIcon,
15
18
  resolveNumberFilterUi
16
19
  } from "../../../utils";
20
+ import FilterEditorHeader from "../shared/filter-editor-header.vue";
17
21
  import FilterMatchModePanel from "../shared/filter-match-mode-panel.vue";
18
22
  import FilterPopoverShell from "../shared/filter-popover-shell.vue";
19
23
  import FilterStageTransition from "../shared/filter-stage-transition.vue";
@@ -23,15 +27,20 @@ const props = defineProps({
23
27
  dynamic: { type: Boolean, required: false },
24
28
  session: { type: Boolean, required: false },
25
29
  embedded: { type: Boolean, required: false },
30
+ header: { type: Boolean, required: false, default: true },
26
31
  initialOperator: { type: String, required: false }
27
32
  });
28
- const emit = defineEmits(["dismiss", "sessionClosed"]);
33
+ const emit = defineEmits(["back", "dismiss", "sessionClosed"]);
29
34
  const internals = useTableInternals();
30
35
  const dataListUi = useDataListUi();
36
+ const { locale } = useUiToolsLocale();
31
37
  const dataListFilterUi = computed(() => dataListUi.ui.value.filterTags?.ui);
32
38
  const size = computed(() => dataListUi.ui.value.filterTags?.size ?? dataListUi.controlSize.value);
33
39
  const sizeClasses = computed(() => resolveFilterEditorSizeClasses(size.value));
34
40
  const geometry = computed(() => resolveDataListControlGeometry(size.value));
41
+ const showHeader = computed(
42
+ () => props.header && dataListUi.ui.value.filterTags?.props?.editorHeader !== false
43
+ );
35
44
  const pendingOperator = ref(props.initialOperator);
36
45
  const localValue = ref("");
37
46
  const rangeValue = ref({ from: "", to: "" });
@@ -60,6 +69,8 @@ const operatorItems = computed(
60
69
  })
61
70
  );
62
71
  const filterUi = computed(() => resolveNumberFilterUi(props.definition, operator.value));
72
+ const autoCommit = computed(() => filterUi.value.commitMode === "auto");
73
+ const deferred = useDeferredCommit({ commit: commitValue, flushOnDispose: props.embedded });
63
74
  const scalarValue = computed({
64
75
  get() {
65
76
  return localValue.value === "" ? void 0 : Number(localValue.value);
@@ -81,6 +92,11 @@ const session = useFilterTagSession({
81
92
  embedded: props.embedded,
82
93
  hasCommittedState: () => !isNullish(internals.filters.getActiveFilterState({ key: props.definition.key })),
83
94
  onClose: () => {
95
+ if (autoCommit.value) {
96
+ deferred.flush();
97
+ } else {
98
+ deferred.cancel();
99
+ }
84
100
  pendingOperator.value = void 0;
85
101
  },
86
102
  onDismiss: () => emit("dismiss"),
@@ -128,6 +144,7 @@ function handleRequestMatchMode() {
128
144
  session.open();
129
145
  }
130
146
  function handleOperatorChange(op) {
147
+ deferred.cancel();
131
148
  localValue.value = "";
132
149
  rangeValue.value = { from: "", to: "" };
133
150
  pendingOperator.value = op;
@@ -135,18 +152,16 @@ function handleOperatorChange(op) {
135
152
  stageTransitioning.value = true;
136
153
  stage.value = "editor";
137
154
  }
138
- function commitIfAuto() {
139
- if (filterUi.value.commitMode === "auto") {
140
- applyFilter();
155
+ function scheduleCommit() {
156
+ if (autoCommit.value) {
157
+ deferred.schedule();
141
158
  }
142
159
  }
143
- function applyFilter() {
144
- const nextOperator = pendingOperator.value;
145
- pendingOperator.value = void 0;
160
+ function commitValue() {
146
161
  if (operator.value === "between") {
147
162
  internals.filters.setScalarFilterValue({
148
163
  key: props.definition.key,
149
- operator: nextOperator,
164
+ operator: pendingOperator.value,
150
165
  value: rangeValue.value.from === "" && rangeValue.value.to === "" ? void 0 : Object.fromEntries(
151
166
  [
152
167
  rangeValue.value.from === "" ? void 0 : ["from", Number(rangeValue.value.from)],
@@ -154,44 +169,65 @@ function applyFilter() {
154
169
  ].filter((entry) => entry !== void 0)
155
170
  )
156
171
  });
157
- session.close();
158
172
  return;
159
173
  }
160
174
  internals.filters.setScalarFilterValue({
161
175
  key: props.definition.key,
162
- operator: nextOperator,
176
+ operator: pendingOperator.value,
163
177
  value: scalarValue.value
164
178
  });
179
+ }
180
+ function applyFilter() {
181
+ deferred.cancel();
182
+ commitValue();
183
+ pendingOperator.value = void 0;
165
184
  session.close();
166
185
  }
167
186
  function clearFilter() {
187
+ deferred.cancel();
168
188
  internals.filters.clearFilter({ key: props.definition.key });
189
+ localValue.value = "";
190
+ rangeValue.value = { from: "", to: "" };
169
191
  session.close();
170
192
  }
171
193
  function updateScalarValue(value) {
172
194
  scalarValue.value = value;
173
- commitIfAuto();
195
+ scheduleCommit();
196
+ }
197
+ function typedNumber(event) {
198
+ const value = event.target instanceof HTMLInputElement ? parseTypedNumber({ locale: locale.value.code, text: event.target.value }) : void 0;
199
+ const digits = filterUi.value.formatOptions?.maximumFractionDigits;
200
+ return isNullish(value) || isNullish(digits) ? value : Number(value.toFixed(digits));
201
+ }
202
+ function typeScalarValue(event) {
203
+ updateScalarValue(typedNumber(event));
204
+ }
205
+ function typeRangeFrom(event) {
206
+ updateRangeFrom(typedNumber(event));
207
+ }
208
+ function typeRangeTo(event) {
209
+ updateRangeTo(typedNumber(event));
174
210
  }
175
211
  function updateRangeFrom(value) {
176
212
  rangeValue.value = {
177
213
  ...rangeValue.value,
178
214
  from: isNullish(value) ? "" : String(value)
179
215
  };
180
- commitIfAuto();
216
+ scheduleCommit();
181
217
  }
182
218
  function updateRangeTo(value) {
183
219
  rangeValue.value = {
184
220
  ...rangeValue.value,
185
221
  to: isNullish(value) ? "" : String(value)
186
222
  };
187
- commitIfAuto();
223
+ scheduleCommit();
188
224
  }
189
225
  function updateSliderScalarValue(value) {
190
226
  if (!isNumber(value)) {
191
227
  return;
192
228
  }
193
229
  scalarValue.value = value;
194
- commitIfAuto();
230
+ scheduleCommit();
195
231
  }
196
232
  function updateSliderRangeValue(value) {
197
233
  if (!isArray(value) || value.length < 2) {
@@ -205,7 +241,7 @@ function updateSliderRangeValue(value) {
205
241
  from: String(from),
206
242
  to: String(to)
207
243
  };
208
- commitIfAuto();
244
+ scheduleCommit();
209
245
  }
210
246
  function resolveIncrementConfig(hideStepper) {
211
247
  return hideStepper ? false : { variant: "ghost" };
@@ -276,11 +312,20 @@ function resolveIncrementConfig(hideStepper) {
276
312
  )
277
313
  "
278
314
  >
315
+ <FilterEditorHeader
316
+ v-if="showHeader"
317
+ :label="internals.filters.getFilterLabelText({ label: definition.label })"
318
+ :active="preview.active"
319
+ :embedded="embedded"
320
+ :ui="dataListFilterUi"
321
+ @back="emit('back')"
322
+ @clear="clearFilter"
323
+ />
279
324
  <div
280
325
  v-if="operator === 'between'"
281
326
  :class="
282
327
  mergeDataListUiClass(
283
- `grid border-b border-default ${geometry.toolbarGap} ${sizeClasses.searchHeader}`,
328
+ `nut-dl-editor__input grid ${geometry.toolbarGap} ${sizeClasses.searchHeader} ${autoCommit ? '' : 'border-b border-default'}`,
284
329
  void 0,
285
330
  dataListFilterUi?.inputs
286
331
  )
@@ -304,6 +349,7 @@ function resolveIncrementConfig(hideStepper) {
304
349
  :decrement="resolveIncrementConfig(filterUi.range.inputs.hideStepper)"
305
350
  :size="size"
306
351
  @update:model-value="updateRangeFrom"
352
+ @input="typeRangeFrom"
307
353
  @keydown.enter.prevent="applyFilter"
308
354
  />
309
355
 
@@ -319,6 +365,7 @@ function resolveIncrementConfig(hideStepper) {
319
365
  :decrement="resolveIncrementConfig(filterUi.range.inputs.hideStepper)"
320
366
  :size="size"
321
367
  @update:model-value="updateRangeTo"
368
+ @input="typeRangeTo"
322
369
  @keydown.enter.prevent="applyFilter"
323
370
  />
324
371
  </div>
@@ -342,7 +389,7 @@ function resolveIncrementConfig(hideStepper) {
342
389
  v-else
343
390
  :class="
344
391
  mergeDataListUiClass(
345
- `grid border-b border-default ${geometry.toolbarGap} ${sizeClasses.searchHeader}`,
392
+ `nut-dl-editor__input grid ${geometry.toolbarGap} ${sizeClasses.searchHeader} ${autoCommit ? '' : 'border-b border-default'}`,
346
393
  void 0,
347
394
  dataListFilterUi?.inputs
348
395
  )
@@ -363,6 +410,7 @@ function resolveIncrementConfig(hideStepper) {
363
410
  :decrement="resolveIncrementConfig(filterUi.scalar.input.hideStepper)"
364
411
  :size="size"
365
412
  @update:model-value="updateScalarValue"
413
+ @input="typeScalarValue"
366
414
  @keydown.enter.prevent="applyFilter"
367
415
  />
368
416
 
@@ -381,7 +429,7 @@ function resolveIncrementConfig(hideStepper) {
381
429
  </div>
382
430
 
383
431
  <div
384
- v-if="filterUi.commitMode === 'manual'"
432
+ v-if="!autoCommit"
385
433
  :class="
386
434
  mergeDataListUiClass(
387
435
  `flex items-center justify-between border-t border-default ${sizeClasses.footer}`,
@@ -4,6 +4,7 @@ type __VLS_Props = {
4
4
  dynamic?: boolean;
5
5
  session?: boolean;
6
6
  embedded?: boolean;
7
+ header?: boolean;
7
8
  initialOperator?: TableFilterOperator;
8
9
  };
9
10
  declare var __VLS_10: {
@@ -28,11 +29,15 @@ type __VLS_Slots = {} & {
28
29
  };
29
30
  declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
30
31
  dismiss: () => any;
32
+ back: () => any;
31
33
  sessionClosed: () => any;
32
34
  }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
33
35
  onDismiss?: (() => any) | undefined;
36
+ onBack?: (() => any) | undefined;
34
37
  onSessionClosed?: (() => any) | undefined;
35
- }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
38
+ }>, {
39
+ header: boolean;
40
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
36
41
  declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
37
42
  declare const _default: typeof __VLS_export;
38
43
  export default _default;
@@ -29,12 +29,12 @@ type __VLS_Slots = {} & {
29
29
  };
30
30
  declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
31
31
  dismiss: () => any;
32
- sessionClosed: () => any;
33
32
  back: () => any;
33
+ sessionClosed: () => any;
34
34
  }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
35
35
  onDismiss?: (() => any) | undefined;
36
- onSessionClosed?: (() => any) | undefined;
37
36
  onBack?: (() => any) | undefined;
37
+ onSessionClosed?: (() => any) | undefined;
38
38
  }>, {
39
39
  header: boolean;
40
40
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
@@ -1,8 +1,6 @@
1
1
  <script setup>
2
2
  import UButton from "@nuxt/ui/components/Button.vue";
3
- import UIcon from "@nuxt/ui/components/Icon.vue";
4
3
  import { computed, ref } from "vue";
5
- import { useUiToolsLocale } from "#ui-tools/i18n";
6
4
  import { useRangeSelect } from "../../../../shared";
7
5
  import { isBoolean, isNumber, isString, isNullish } from "../../../../shared/utils/predicate";
8
6
  import { useDataListUi } from "../../../composables/use-data-list-ui";
@@ -14,6 +12,7 @@ import {
14
12
  resolveFilterEditorSizeClasses,
15
13
  resolveFilterTriggerIcon
16
14
  } from "../../../utils";
15
+ import FilterEditorHeader from "../shared/filter-editor-header.vue";
17
16
  import FilterMatchModePanel from "../shared/filter-match-mode-panel.vue";
18
17
  import FilterOptionPickerContent from "../shared/filter-option-picker-content.vue";
19
18
  import FilterPopoverShell from "../shared/filter-popover-shell.vue";
@@ -30,7 +29,6 @@ const props = defineProps({
30
29
  const emit = defineEmits(["back", "dismiss", "sessionClosed"]);
31
30
  const internals = useTableInternals();
32
31
  const dataListUi = useDataListUi();
33
- const { t } = useUiToolsLocale();
34
32
  const dataListFilterUi = computed(() => dataListUi.ui.value.filterTags?.ui);
35
33
  const size = computed(() => dataListUi.ui.value.filterTags?.size ?? dataListUi.controlSize.value);
36
34
  const sizeClasses = computed(() => resolveFilterEditorSizeClasses(size.value));
@@ -289,37 +287,15 @@ function handleContentMounted() {
289
287
  "
290
288
  @vue:mounted="handleContentMounted"
291
289
  >
292
- <div
290
+ <FilterEditorHeader
293
291
  v-if="header !== false && dataListUi.ui.value.filterTags?.props?.editorHeader !== false"
294
- :class="
295
- mergeDataListUiClass(
296
- 'nut-dl-editor__head flex items-center gap-2 border-b border-default py-2 pr-3',
297
- embedded ? 'pl-1.5' : 'pl-3',
298
- dataListFilterUi?.editorHeader
299
- )
300
- "
301
- >
302
- <button
303
- v-if="embedded"
304
- type="button"
305
- class="nut-dl-editor__back flex size-6 items-center justify-center rounded-md text-muted hover:bg-elevated hover:text-default"
306
- :aria-label="t('table.filters.sheet.back')"
307
- @click="emit('back')"
308
- >
309
- <UIcon name="i-lucide-arrow-left" class="size-4" />
310
- </button>
311
- <span class="min-w-0 flex-1 truncate text-[12.5px] font-semibold text-highlighted">
312
- {{ internals.filters.getFilterLabelText({ label: definition.label }) }}
313
- </span>
314
- <button
315
- type="button"
316
- class="rounded text-[12.5px] font-semibold text-primary outline-none focus-visible:ring-2 focus-visible:ring-primary/40 disabled:opacity-40"
317
- :disabled="!preview.active"
318
- @click="clearFilter"
319
- >
320
- {{ t("table.filters.editor.clear") }}
321
- </button>
322
- </div>
292
+ :label="internals.filters.getFilterLabelText({ label: definition.label })"
293
+ :active="preview.active"
294
+ :embedded="embedded"
295
+ :ui="dataListFilterUi"
296
+ @back="emit('back')"
297
+ @clear="clearFilter"
298
+ />
323
299
  <FilterOptionPickerContent
324
300
  v-model:search-query="searchQuery"
325
301
  :flat-radio-value="state.flatRadioValue.value"
@@ -336,7 +312,7 @@ function handleContentMounted() {
336
312
  />
337
313
 
338
314
  <div
339
- v-if="state.filterUi.value.commitMode === 'manual'"
315
+ v-if="state.filterUi.value.commitMode !== 'auto'"
340
316
  :class="
341
317
  mergeDataListUiClass(
342
318
  `flex items-center justify-between border-t border-default ${sizeClasses.footer}`,
@@ -29,12 +29,12 @@ type __VLS_Slots = {} & {
29
29
  };
30
30
  declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
31
31
  dismiss: () => any;
32
- sessionClosed: () => any;
33
32
  back: () => any;
33
+ sessionClosed: () => any;
34
34
  }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
35
35
  onDismiss?: (() => any) | undefined;
36
- onSessionClosed?: (() => any) | undefined;
37
36
  onBack?: (() => any) | undefined;
37
+ onSessionClosed?: (() => any) | undefined;
38
38
  }>, {
39
39
  header: boolean;
40
40
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
@@ -4,6 +4,7 @@ type __VLS_Props = {
4
4
  dynamic?: boolean;
5
5
  session?: boolean;
6
6
  embedded?: boolean;
7
+ header?: boolean;
7
8
  initialOperator?: TableFilterOperator;
8
9
  };
9
10
  declare var __VLS_10: {
@@ -28,11 +29,15 @@ type __VLS_Slots = {} & {
28
29
  };
29
30
  declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
30
31
  dismiss: () => any;
32
+ back: () => any;
31
33
  sessionClosed: () => any;
32
34
  }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
33
35
  onDismiss?: (() => any) | undefined;
36
+ onBack?: (() => any) | undefined;
34
37
  onSessionClosed?: (() => any) | undefined;
35
- }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
38
+ }>, {
39
+ header: boolean;
40
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
36
41
  declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
37
42
  declare const _default: typeof __VLS_export;
38
43
  export default _default;
@@ -4,6 +4,7 @@ import UInput from "@nuxt/ui/components/Input.vue";
4
4
  import { computed, ref } from "vue";
5
5
  import { isNullish } from "../../../../shared/utils/predicate";
6
6
  import { useDataListUi } from "../../../composables/use-data-list-ui";
7
+ import { useDeferredCommit } from "../../../composables/use-deferred-commit";
7
8
  import { useFilterTagSession } from "../../../composables/use-filter-tag-session";
8
9
  import { useTableInternals } from "../../../composables/use-table-internals";
9
10
  import {
@@ -12,6 +13,7 @@ import {
12
13
  resolveFilterTriggerIcon,
13
14
  resolveTextFilterUi
14
15
  } from "../../../utils";
16
+ import FilterEditorHeader from "../shared/filter-editor-header.vue";
15
17
  import FilterMatchModePanel from "../shared/filter-match-mode-panel.vue";
16
18
  import FilterPopoverShell from "../shared/filter-popover-shell.vue";
17
19
  import FilterStageTransition from "../shared/filter-stage-transition.vue";
@@ -21,14 +23,18 @@ const props = defineProps({
21
23
  dynamic: { type: Boolean, required: false },
22
24
  session: { type: Boolean, required: false },
23
25
  embedded: { type: Boolean, required: false },
26
+ header: { type: Boolean, required: false, default: true },
24
27
  initialOperator: { type: String, required: false }
25
28
  });
26
- const emit = defineEmits(["dismiss", "sessionClosed"]);
29
+ const emit = defineEmits(["back", "dismiss", "sessionClosed"]);
27
30
  const internals = useTableInternals();
28
31
  const dataListUi = useDataListUi();
29
32
  const dataListFilterUi = computed(() => dataListUi.ui.value.filterTags?.ui);
30
33
  const size = computed(() => dataListUi.ui.value.filterTags?.size ?? dataListUi.controlSize.value);
31
34
  const sizeClasses = computed(() => resolveFilterEditorSizeClasses(size.value));
35
+ const showHeader = computed(
36
+ () => props.header && dataListUi.ui.value.filterTags?.props?.editorHeader !== false
37
+ );
32
38
  const pendingOperator = ref(props.initialOperator);
33
39
  const localValue = ref("");
34
40
  const stage = ref("editor");
@@ -56,6 +62,8 @@ const operatorItems = computed(
56
62
  })
57
63
  );
58
64
  const filterUi = computed(() => resolveTextFilterUi(props.definition, operator.value));
65
+ const autoCommit = computed(() => filterUi.value.commitMode === "auto");
66
+ const deferred = useDeferredCommit({ commit: commitValue, flushOnDispose: props.embedded });
59
67
  function initLocalState() {
60
68
  const value = internals.filters.getFilterState({
61
69
  key: props.definition.key
@@ -67,6 +75,11 @@ const session = useFilterTagSession({
67
75
  embedded: props.embedded,
68
76
  hasCommittedState: () => !isNullish(internals.filters.getActiveFilterState({ key: props.definition.key })),
69
77
  onClose: () => {
78
+ if (autoCommit.value) {
79
+ deferred.flush();
80
+ } else {
81
+ deferred.cancel();
82
+ }
70
83
  pendingOperator.value = void 0;
71
84
  },
72
85
  onDismiss: () => emit("dismiss"),
@@ -86,21 +99,27 @@ function handleRequestMatchMode() {
86
99
  stage.value = "match-mode";
87
100
  session.open();
88
101
  }
89
- function applyFilter() {
90
- const op = pendingOperator.value;
91
- pendingOperator.value = void 0;
102
+ function commitValue() {
92
103
  internals.filters.setScalarFilterValue({
93
104
  key: props.definition.key,
94
- operator: op,
105
+ operator: pendingOperator.value,
95
106
  value: localValue.value.trim() || void 0
96
107
  });
108
+ }
109
+ function applyFilter() {
110
+ deferred.cancel();
111
+ commitValue();
112
+ pendingOperator.value = void 0;
97
113
  session.close();
98
114
  }
99
115
  function clearFilter() {
116
+ deferred.cancel();
100
117
  internals.filters.clearFilter({ key: props.definition.key });
118
+ localValue.value = "";
101
119
  session.close();
102
120
  }
103
121
  function handleOperatorChange(op) {
122
+ deferred.cancel();
104
123
  localValue.value = "";
105
124
  pendingOperator.value = op;
106
125
  stageDirection.value = "forward";
@@ -109,12 +128,8 @@ function handleOperatorChange(op) {
109
128
  }
110
129
  function handleValueUpdate(value) {
111
130
  localValue.value = isNullish(value) ? "" : String(value);
112
- if (filterUi.value.commitMode === "auto") {
113
- internals.filters.setScalarFilterValue({
114
- key: props.definition.key,
115
- operator: pendingOperator.value,
116
- value: localValue.value.trim() || void 0
117
- });
131
+ if (autoCommit.value) {
132
+ deferred.schedule();
118
133
  }
119
134
  }
120
135
  </script>
@@ -183,10 +198,19 @@ function handleValueUpdate(value) {
183
198
  )
184
199
  "
185
200
  >
201
+ <FilterEditorHeader
202
+ v-if="showHeader"
203
+ :label="internals.filters.getFilterLabelText({ label: definition.label })"
204
+ :active="preview.active"
205
+ :embedded="embedded"
206
+ :ui="dataListFilterUi"
207
+ @back="emit('back')"
208
+ @clear="clearFilter"
209
+ />
186
210
  <div
187
211
  :class="
188
212
  mergeDataListUiClass(
189
- `border-b border-default ${sizeClasses.searchHeader}`,
213
+ `nut-dl-editor__input ${sizeClasses.searchHeader} ${autoCommit ? '' : 'border-b border-default'}`,
190
214
  void 0,
191
215
  dataListFilterUi?.inputs
192
216
  )
@@ -202,10 +226,11 @@ function handleValueUpdate(value) {
202
226
  :highlight="filterUi.input.highlight"
203
227
  :fixed="filterUi.input.fixed"
204
228
  :size="size"
229
+ variant="none"
205
230
  class="w-full min-w-0 max-w-full"
206
231
  :ui="{
207
232
  root: dataListFilterUi?.search,
208
- base: dataListFilterUi?.searchInput
233
+ base: mergeDataListUiClass('h-8', void 0, dataListFilterUi?.searchInput)
209
234
  }"
210
235
  @update:model-value="handleValueUpdate"
211
236
  @keydown.enter.prevent="applyFilter"
@@ -213,7 +238,7 @@ function handleValueUpdate(value) {
213
238
  </div>
214
239
 
215
240
  <div
216
- v-if="filterUi.commitMode === 'manual'"
241
+ v-if="!autoCommit"
217
242
  :class="
218
243
  mergeDataListUiClass(
219
244
  `flex items-center justify-between border-t border-default ${sizeClasses.footer}`,
@@ -4,6 +4,7 @@ type __VLS_Props = {
4
4
  dynamic?: boolean;
5
5
  session?: boolean;
6
6
  embedded?: boolean;
7
+ header?: boolean;
7
8
  initialOperator?: TableFilterOperator;
8
9
  };
9
10
  declare var __VLS_10: {
@@ -28,11 +29,15 @@ type __VLS_Slots = {} & {
28
29
  };
29
30
  declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
30
31
  dismiss: () => any;
32
+ back: () => any;
31
33
  sessionClosed: () => any;
32
34
  }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
33
35
  onDismiss?: (() => any) | undefined;
36
+ onBack?: (() => any) | undefined;
34
37
  onSessionClosed?: (() => any) | undefined;
35
- }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
38
+ }>, {
39
+ header: boolean;
40
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
36
41
  declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
37
42
  declare const _default: typeof __VLS_export;
38
43
  export default _default;
@@ -5,9 +5,15 @@ type __VLS_Props = {
5
5
  fill?: boolean;
6
6
  ui?: DataListGridUi;
7
7
  };
8
- declare var __VLS_19: {};
8
+ declare function refreshData(): void;
9
+ declare var __VLS_6: {
10
+ error: unknown;
11
+ retry: typeof refreshData;
12
+ }, __VLS_15: {};
9
13
  type __VLS_Slots = {} & {
10
- empty?: (props: typeof __VLS_19) => any;
14
+ error?: (props: typeof __VLS_6) => any;
15
+ } & {
16
+ empty?: (props: typeof __VLS_15) => any;
11
17
  };
12
18
  declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
13
19
  declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;