nuxt-ui-tools 0.1.1 → 0.1.3

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/module.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "compatibility": {
6
6
  "nuxt": ">=4.4.0"
7
7
  },
8
- "version": "0.1.1",
8
+ "version": "0.1.3",
9
9
  "builder": {
10
10
  "@nuxt/module-builder": "1.0.2",
11
11
  "unbuild": "unknown"
@@ -82,7 +82,7 @@ const session = useFilterTagSession({
82
82
  session: props.session,
83
83
  dynamic: props.dynamic,
84
84
  embedded: props.embedded,
85
- hasCommittedState: () => internals.filters.getFilterState({ key: props.definition.key }) != null,
85
+ hasCommittedState: () => internals.filters.getActiveFilterState({ key: props.definition.key }) != null,
86
86
  onOpen: initLocalState,
87
87
  onClose: () => {
88
88
  isContentReady.value = false;
@@ -102,7 +102,7 @@ const session = useFilterTagSession({
102
102
  session: props.session,
103
103
  dynamic: props.dynamic,
104
104
  embedded: props.embedded,
105
- hasCommittedState: () => internals.filters.getFilterState({ key: props.definition.key }) != null,
105
+ hasCommittedState: () => internals.filters.getActiveFilterState({ key: props.definition.key }) != null,
106
106
  onOpen: initLocalState,
107
107
  onClose: () => {
108
108
  pendingOperator.value = void 0;
@@ -75,7 +75,7 @@ const session = useFilterTagSession({
75
75
  session: props.session,
76
76
  dynamic: props.dynamic,
77
77
  embedded: props.embedded,
78
- hasCommittedState: () => internals.filters.getFilterState({ key: props.definition.key }) != null,
78
+ hasCommittedState: () => internals.filters.getActiveFilterState({ key: props.definition.key }) != null,
79
79
  onOpen: initLocalState,
80
80
  onClose: () => {
81
81
  pendingOperator.value = void 0;
@@ -61,7 +61,7 @@ const session = useFilterTagSession({
61
61
  session: props.session,
62
62
  dynamic: props.dynamic,
63
63
  embedded: props.embedded,
64
- hasCommittedState: () => internals.filters.getFilterState({ key: props.definition.key }) != null,
64
+ hasCommittedState: () => internals.filters.getActiveFilterState({ key: props.definition.key }) != null,
65
65
  onOpen: () => {
66
66
  isContentReady.value = false;
67
67
  initLocalState();
@@ -59,7 +59,7 @@ const session = useFilterTagSession({
59
59
  session: props.session,
60
60
  dynamic: props.dynamic,
61
61
  embedded: props.embedded,
62
- hasCommittedState: () => internals.filters.getFilterState({ key: props.definition.key }) != null,
62
+ hasCommittedState: () => internals.filters.getActiveFilterState({ key: props.definition.key }) != null,
63
63
  onOpen: initLocalState,
64
64
  onClose: () => {
65
65
  pendingOperator.value = void 0;
@@ -120,9 +120,12 @@ watch(tableEmpty, (isEmpty) => {
120
120
  "
121
121
  >
122
122
  <template #empty>
123
- <slot name="empty">
124
- <div />
125
- </slot>
123
+ <template v-if="tableEmpty">
124
+ <slot name="empty">
125
+ <div />
126
+ </slot>
127
+ </template>
128
+ <div v-else />
126
129
  </template>
127
130
  </UTable>
128
131
 
@@ -13,7 +13,7 @@ export function useTableFilterPresentation(options) {
13
13
  );
14
14
  const resolved = computed(
15
15
  () => definitions.value.map((definition) => {
16
- const active = options.filters.getFilterState({ key: definition.key }) != null;
16
+ const active = options.filters.getActiveFilterState({ key: definition.key }) != null;
17
17
  const location = resolveFilterDisplayLocation(definition.display?.location);
18
18
  const visible = location !== "tag-dynamic" || active;
19
19
  return {
@@ -57,7 +57,7 @@ export function useTableFilterPresentation(options) {
57
57
  const hasPanelFilters = computed(() => panelDefinitions.value.length > 0);
58
58
  const activePanelCount = computed(
59
59
  () => panelDefinitions.value.filter(
60
- (definition) => options.filters.getFilterState({ key: definition.key }) != null
60
+ (definition) => options.filters.getActiveFilterState({ key: definition.key }) != null
61
61
  ).length
62
62
  );
63
63
  const panelSections = computed(() => {
@@ -81,27 +81,30 @@ export function useTableFilterPresentation(options) {
81
81
  dynamicSessionKey.value = null;
82
82
  }
83
83
  function openPanel() {
84
- panelDraftFilters.value = options.filters.activeUiFilters.value.filter((rule) => isPanelKey(rule.key)).map((rule) => ({ ...rule }));
84
+ panelDraftFilters.value = options.filters.effectiveUiFilters.value.filter((rule) => isPanelKey(rule.key)).map((rule) => ({ ...rule }));
85
85
  panelOpen.value = true;
86
86
  }
87
87
  function closePanel() {
88
88
  panelOpen.value = false;
89
89
  }
90
90
  function resetPanelDraft() {
91
- panelDraftFilters.value = options.filters.activeUiFilters.value.filter((rule) => isPanelKey(rule.key)).map((rule) => ({ ...rule }));
91
+ panelDraftFilters.value = options.filters.effectiveUiFilters.value.filter((rule) => isPanelKey(rule.key)).map((rule) => ({ ...rule }));
92
92
  }
93
93
  function clearPanelDraft() {
94
- panelDraftFilters.value = [];
95
- const preservedRules = options.filters.activeUiFilters.value.filter(
94
+ panelDraftFilters.value = panelDefinitions.value.flatMap((definition) => {
95
+ const defaultRule = options.filters.getDefaultFilterState({ key: definition.key });
96
+ return defaultRule ? [{ ...defaultRule }] : [];
97
+ });
98
+ const preservedRules = options.filters.effectiveUiFilters.value.filter(
96
99
  (rule) => !isPanelKey(rule.key)
97
100
  );
98
101
  options.filters.replaceFilters({
99
- rules: preservedRules
102
+ rules: [...preservedRules, ...panelDraftFilters.value]
100
103
  });
101
104
  }
102
105
  function applyPanelDraft() {
103
106
  const nextPanelRules = panelDraftFilters.value.map((rule) => ({ ...rule }));
104
- const preservedRules = options.filters.activeUiFilters.value.filter(
107
+ const preservedRules = options.filters.effectiveUiFilters.value.filter(
105
108
  (rule) => !isPanelKey(rule.key)
106
109
  );
107
110
  options.filters.replaceFilters({
@@ -160,7 +163,11 @@ export function useTableFilterPresentation(options) {
160
163
  });
161
164
  }
162
165
  function clearPanelFilter(input) {
163
- panelDraftFilters.value = panelDraftFilters.value.filter((rule) => rule.key !== input.key);
166
+ const defaultRule = options.filters.getDefaultFilterState(input);
167
+ panelDraftFilters.value = [
168
+ ...panelDraftFilters.value.filter((rule) => rule.key !== input.key),
169
+ ...defaultRule ? [{ ...defaultRule }] : []
170
+ ];
164
171
  }
165
172
  function isPanelKey(key) {
166
173
  return panelDefinitions.value.some((definition) => definition.key === key);
@@ -13,6 +13,7 @@ export declare function useTableFilters(params: UseTableFiltersParams): {
13
13
  searchPlaceholder: ComputedRef<string>;
14
14
  hasActiveSearch: ComputedRef<boolean>;
15
15
  definitions: ComputedRef<TableUiFilterDefinition[]>;
16
+ effectiveUiFilters: ComputedRef<TableQueryStateFilterRule<string, TableFilterOperator, TableQueryStateFilterValue>[]>;
16
17
  activeUiFilters: ComputedRef<TableQueryStateFilterRule<string, TableFilterOperator, TableQueryStateFilterValue>[]>;
17
18
  hasActiveUiFilters: ComputedRef<boolean>;
18
19
  getDefinition: (input: {
@@ -21,6 +22,12 @@ export declare function useTableFilters(params: UseTableFiltersParams): {
21
22
  getFilterState: (input: {
22
23
  key: string;
23
24
  }) => TableQueryStateFilterRule<string, TableFilterOperator, TableQueryStateFilterValue> | undefined;
25
+ getActiveFilterState: (input: {
26
+ key: string;
27
+ }) => TableQueryStateFilterRule<string, TableFilterOperator, TableQueryStateFilterValue> | undefined;
28
+ getDefaultFilterState: (input: {
29
+ key: string;
30
+ }) => TableQueryStateFilterRule<string, TableFilterOperator, TableQueryStateFilterValue> | undefined;
24
31
  getFilterOptionEntries: (input: {
25
32
  key: string;
26
33
  entries?: TableFilterOptionEntry[];
@@ -6,6 +6,7 @@ import {
6
6
  flattenFilterOptionEntries,
7
7
  getFilterLabelText,
8
8
  mergeTableFilterDefaultRules,
9
+ resolveTableActiveFilterRules,
9
10
  resolveTableFilterDefaultRules,
10
11
  resolveFilterOptionEntries
11
12
  } from "../utils/index.js";
@@ -19,12 +20,18 @@ export function useTableFilters(params) {
19
20
  const definitions = computed(
20
21
  () => params.schema.value.filters?.ui ?? []
21
22
  );
22
- const activeUiFilters = computed(
23
+ const effectiveUiFilters = computed(
23
24
  () => params.state.queryState.filters.value.ui ?? []
24
25
  );
25
26
  const defaultUiFilters = computed(
26
27
  () => resolveTableFilterDefaultRules(definitions.value)
27
28
  );
29
+ const activeUiFilters = computed(
30
+ () => resolveTableActiveFilterRules({
31
+ rules: effectiveUiFilters.value,
32
+ definitions: definitions.value
33
+ })
34
+ );
28
35
  const hasActiveUiFilters = computed(() => activeUiFilters.value.length > 0);
29
36
  function getDefinition(input) {
30
37
  return definitions.value.find(
@@ -32,8 +39,16 @@ export function useTableFilters(params) {
32
39
  );
33
40
  }
34
41
  function getFilterState(input) {
42
+ return effectiveUiFilters.value.find(
43
+ (rule) => rule.key === input.key
44
+ );
45
+ }
46
+ function getActiveFilterState(input) {
35
47
  return activeUiFilters.value.find((rule) => rule.key === input.key);
36
48
  }
49
+ function getDefaultFilterState(input) {
50
+ return defaultUiFilters.value.find((rule) => rule.key === input.key);
51
+ }
37
52
  function getFilterOptionEntries(input) {
38
53
  const definition = getDefinition({ key: input.key });
39
54
  if (!definition) {
@@ -65,11 +80,15 @@ export function useTableFilters(params) {
65
80
  }
66
81
  });
67
82
  }
68
- return buildFilterPreview({
83
+ const preview = buildFilterPreview({
69
84
  definition,
70
85
  rule: getFilterState({ key: input.key }),
71
86
  optionEntries: input.entries
72
87
  });
88
+ return {
89
+ ...preview,
90
+ active: getActiveFilterState({ key: input.key }) != null
91
+ };
73
92
  }
74
93
  function getFilterOperator(input) {
75
94
  const definition = getDefinition({ key: input.key });
@@ -211,10 +230,13 @@ export function useTableFilters(params) {
211
230
  searchPlaceholder: search.searchPlaceholder,
212
231
  hasActiveSearch: search.hasActiveSearch,
213
232
  definitions,
233
+ effectiveUiFilters,
214
234
  activeUiFilters,
215
235
  hasActiveUiFilters,
216
236
  getDefinition,
217
237
  getFilterState,
238
+ getActiveFilterState,
239
+ getDefaultFilterState,
218
240
  getFilterOptionEntries,
219
241
  getFilterPreview,
220
242
  getFilterOperator,
@@ -104,6 +104,7 @@ declare function createTableInternals<TSchema>(options: {
104
104
  searchPlaceholder: import("vue").ComputedRef<string>;
105
105
  hasActiveSearch: import("vue").ComputedRef<boolean>;
106
106
  definitions: import("vue").ComputedRef<import("../types/index.js").TableUiFilterDefinition[]>;
107
+ effectiveUiFilters: import("vue").ComputedRef<import("../types/index.js").TableQueryStateFilterRule<string, import("../types/index.js").TableFilterOperator, import("../types/index.js").TableQueryStateFilterValue>[]>;
107
108
  activeUiFilters: import("vue").ComputedRef<import("../types/index.js").TableQueryStateFilterRule<string, import("../types/index.js").TableFilterOperator, import("../types/index.js").TableQueryStateFilterValue>[]>;
108
109
  hasActiveUiFilters: import("vue").ComputedRef<boolean>;
109
110
  getDefinition: (input: {
@@ -112,6 +113,12 @@ declare function createTableInternals<TSchema>(options: {
112
113
  getFilterState: (input: {
113
114
  key: string;
114
115
  }) => import("../types/index.js").TableQueryStateFilterRule<string, import("../types/index.js").TableFilterOperator, import("../types/index.js").TableQueryStateFilterValue> | undefined;
116
+ getActiveFilterState: (input: {
117
+ key: string;
118
+ }) => import("../types/index.js").TableQueryStateFilterRule<string, import("../types/index.js").TableFilterOperator, import("../types/index.js").TableQueryStateFilterValue> | undefined;
119
+ getDefaultFilterState: (input: {
120
+ key: string;
121
+ }) => import("../types/index.js").TableQueryStateFilterRule<string, import("../types/index.js").TableFilterOperator, import("../types/index.js").TableQueryStateFilterValue> | undefined;
115
122
  getFilterOptionEntries: (input: {
116
123
  key: string;
117
124
  entries?: import("../types/index.js").TableFilterOptionEntry[];
@@ -583,6 +590,7 @@ declare function useProvideTableInternals<TSchema>(options: {
583
590
  searchPlaceholder: import("vue").ComputedRef<string>;
584
591
  hasActiveSearch: import("vue").ComputedRef<boolean>;
585
592
  definitions: import("vue").ComputedRef<import("../types/index.js").TableUiFilterDefinition[]>;
593
+ effectiveUiFilters: import("vue").ComputedRef<import("../types/index.js").TableQueryStateFilterRule<string, import("../types/index.js").TableFilterOperator, import("../types/index.js").TableQueryStateFilterValue>[]>;
586
594
  activeUiFilters: import("vue").ComputedRef<import("../types/index.js").TableQueryStateFilterRule<string, import("../types/index.js").TableFilterOperator, import("../types/index.js").TableQueryStateFilterValue>[]>;
587
595
  hasActiveUiFilters: import("vue").ComputedRef<boolean>;
588
596
  getDefinition: (input: {
@@ -591,6 +599,12 @@ declare function useProvideTableInternals<TSchema>(options: {
591
599
  getFilterState: (input: {
592
600
  key: string;
593
601
  }) => import("../types/index.js").TableQueryStateFilterRule<string, import("../types/index.js").TableFilterOperator, import("../types/index.js").TableQueryStateFilterValue> | undefined;
602
+ getActiveFilterState: (input: {
603
+ key: string;
604
+ }) => import("../types/index.js").TableQueryStateFilterRule<string, import("../types/index.js").TableFilterOperator, import("../types/index.js").TableQueryStateFilterValue> | undefined;
605
+ getDefaultFilterState: (input: {
606
+ key: string;
607
+ }) => import("../types/index.js").TableQueryStateFilterRule<string, import("../types/index.js").TableFilterOperator, import("../types/index.js").TableQueryStateFilterValue> | undefined;
594
608
  getFilterOptionEntries: (input: {
595
609
  key: string;
596
610
  entries?: import("../types/index.js").TableFilterOptionEntry[];
@@ -1059,6 +1073,7 @@ declare function useTableInternals(): {
1059
1073
  searchPlaceholder: import("vue").ComputedRef<string>;
1060
1074
  hasActiveSearch: import("vue").ComputedRef<boolean>;
1061
1075
  definitions: import("vue").ComputedRef<import("../types/index.js").TableUiFilterDefinition[]>;
1076
+ effectiveUiFilters: import("vue").ComputedRef<import("../types/index.js").TableQueryStateFilterRule<string, import("../types/index.js").TableFilterOperator, import("../types/index.js").TableQueryStateFilterValue>[]>;
1062
1077
  activeUiFilters: import("vue").ComputedRef<import("../types/index.js").TableQueryStateFilterRule<string, import("../types/index.js").TableFilterOperator, import("../types/index.js").TableQueryStateFilterValue>[]>;
1063
1078
  hasActiveUiFilters: import("vue").ComputedRef<boolean>;
1064
1079
  getDefinition: (input: {
@@ -1067,6 +1082,12 @@ declare function useTableInternals(): {
1067
1082
  getFilterState: (input: {
1068
1083
  key: string;
1069
1084
  }) => import("../types/index.js").TableQueryStateFilterRule<string, import("../types/index.js").TableFilterOperator, import("../types/index.js").TableQueryStateFilterValue> | undefined;
1085
+ getActiveFilterState: (input: {
1086
+ key: string;
1087
+ }) => import("../types/index.js").TableQueryStateFilterRule<string, import("../types/index.js").TableFilterOperator, import("../types/index.js").TableQueryStateFilterValue> | undefined;
1088
+ getDefaultFilterState: (input: {
1089
+ key: string;
1090
+ }) => import("../types/index.js").TableQueryStateFilterRule<string, import("../types/index.js").TableFilterOperator, import("../types/index.js").TableQueryStateFilterValue> | undefined;
1070
1091
  getFilterOptionEntries: (input: {
1071
1092
  key: string;
1072
1093
  entries?: import("../types/index.js").TableFilterOptionEntry[];
@@ -19,7 +19,8 @@ export type TableFilterDisplayLocationValue = TableFilterDisplayLocation | strin
19
19
  export interface TableFilterBehaviorCommon<TOperator extends TableFilterOperator = TableFilterOperator> {
20
20
  /**
21
21
  * Effective filter value when the URL has no override for this definition.
22
- * The default stays active but is omitted from the URL; clearing the filter restores it.
22
+ * The default drives queries but is omitted from the URL and does not count as active UI state.
23
+ * Clearing an override restores this value.
23
24
  */
24
25
  defaultValue?: TableQueryStateFilterValue;
25
26
  operators?: TOperator[];
@@ -95,6 +95,7 @@ export interface TableApi<TSchema = TableSchemaView> {
95
95
  filters: {
96
96
  state: ComputedRef<TableFilterState>;
97
97
  search: WritableComputedRef<string>;
98
+ /** Number of UI filter rules that differ from their configured defaults. */
98
99
  activeCount: ComputedRef<number>;
99
100
  clear: () => void;
100
101
  remove: (key: string) => void;
@@ -117,32 +117,41 @@ export function createDataColumns(options) {
117
117
  content: { align: "start", side: "bottom", sideOffset: 10 },
118
118
  modal: false,
119
119
  ui: { content: "w-fit p-1 shadow-none" },
120
- children: /* @__PURE__ */ jsxs(
121
- "button",
122
- {
123
- type: "button",
124
- class: "inline-flex h-8 min-w-0 max-w-full items-center gap-2 rounded-md px-2.5 text-left text-sm text-default transition-colors hover:bg-elevated",
125
- children: [
126
- /* @__PURE__ */ jsxs("div", { class: "flex min-w-0 items-center gap-2.5", children: [
127
- runtimeColumn.icon ? /* @__PURE__ */ jsx(UIcon, { name: runtimeColumn.icon, class: "size-4 shrink-0 text-muted" }) : null,
128
- /* @__PURE__ */ jsx(TableCellEllipsis, { title: runtimeColumn.label, wrapperClass: "min-w-0 max-w-full", children: runtimeColumn.label })
129
- ] }),
130
- /* @__PURE__ */ jsx(
131
- UIcon,
132
- {
133
- name: getColumnHeaderIcon({
134
- columnId: runtimeColumn.id,
135
- canHide: tableColumn.getCanHide?.(),
136
- getSortState: options.getSortState,
137
- getPinnedState: options.getPinnedState
138
- }),
139
- class: "size-4 shrink-0 text-muted"
140
- }
141
- ),
142
- options.getPinnedState({ columnId: runtimeColumn.id }) ? /* @__PURE__ */ jsx(UIcon, { name: "i-lucide-pin", class: "size-3.5 shrink-0 text-muted" }) : null
143
- ]
144
- }
145
- )
120
+ "v-slots": {
121
+ default: () => /* @__PURE__ */ jsxs(
122
+ "button",
123
+ {
124
+ type: "button",
125
+ class: "inline-flex h-8 min-w-0 max-w-full items-center gap-2 rounded-md px-2.5 text-left text-sm text-default transition-colors hover:bg-elevated",
126
+ children: [
127
+ /* @__PURE__ */ jsxs("div", { class: "flex min-w-0 items-center gap-2.5", children: [
128
+ runtimeColumn.icon ? /* @__PURE__ */ jsx(UIcon, { name: runtimeColumn.icon, class: "size-4 shrink-0 text-muted" }) : null,
129
+ /* @__PURE__ */ jsx(
130
+ TableCellEllipsis,
131
+ {
132
+ title: runtimeColumn.label,
133
+ wrapperClass: "min-w-0 max-w-full",
134
+ children: runtimeColumn.label
135
+ }
136
+ )
137
+ ] }),
138
+ /* @__PURE__ */ jsx(
139
+ UIcon,
140
+ {
141
+ name: getColumnHeaderIcon({
142
+ columnId: runtimeColumn.id,
143
+ canHide: tableColumn.getCanHide?.(),
144
+ getSortState: options.getSortState,
145
+ getPinnedState: options.getPinnedState
146
+ }),
147
+ class: "size-4 shrink-0 text-muted"
148
+ }
149
+ ),
150
+ options.getPinnedState({ columnId: runtimeColumn.id }) ? /* @__PURE__ */ jsx(UIcon, { name: "i-lucide-pin", class: "size-3.5 shrink-0 text-muted" }) : null
151
+ ]
152
+ }
153
+ )
154
+ }
146
155
  }
147
156
  ),
148
157
  column.resizable !== false ? /* @__PURE__ */ jsx(
@@ -36,6 +36,18 @@ export declare function isTableFilterRuleDefault(options: {
36
36
  rule: TableQueryStateFilterRule;
37
37
  definition: TableUiFilterDefinition;
38
38
  }): boolean;
39
+ /**
40
+ * Returns only filter rules that deviate from their schema defaults.
41
+ *
42
+ * The full rule set remains effective for data queries, while this subset drives active-filter UI,
43
+ * counts, and reset affordances. Rules without a matching UI definition are treated as active.
44
+ */
45
+ export declare function resolveTableActiveFilterRules(options: {
46
+ /** Effective filter rules, including materialized schema defaults. */
47
+ rules: TableQueryStateFilterRule[];
48
+ /** UI filter definitions that own the default baseline. */
49
+ definitions: TableUiFilterDefinition[];
50
+ }): TableQueryStateFilterRule[];
39
51
  export declare function parseTableFilterQueryState(options: {
40
52
  entries: ReadonlyMap<string, unknown>;
41
53
  definitions: TableUiFilterDefinition[];
@@ -193,6 +193,12 @@ export function isTableFilterRuleDefault(options) {
193
193
  const defaultValue = normalizedDefinition.defaultValue;
194
194
  return defaultValue !== void 0 && (options.rule.operator ?? resolveFilterDefaultOperator(normalizedDefinition)) === resolveFilterDefaultOperator(normalizedDefinition) && areFilterValuesEqual(options.rule.value, defaultValue);
195
195
  }
196
+ export function resolveTableActiveFilterRules(options) {
197
+ return options.rules.filter((rule) => {
198
+ const definition = options.definitions.find((candidate) => candidate.key === rule.key);
199
+ return !definition || !isTableFilterRuleDefault({ rule, definition });
200
+ });
201
+ }
196
202
  export function parseTableFilterQueryState(options) {
197
203
  const rules = [];
198
204
  for (const filter of options.definitions) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nuxt-ui-tools",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "Nuxt module and runtime toolkit for UI-heavy Nuxt applications",
5
5
  "homepage": "https://github.com/ChronicStone/nuxt-ui-tools#readme",
6
6
  "bugs": "https://github.com/ChronicStone/nuxt-ui-tools/issues",