nuxt-ui-tools 1.17.1 → 1.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (178) hide show
  1. package/dist/module.json +1 -1
  2. package/dist/module.mjs +1 -0
  3. package/dist/runtime/form/components/page/form-page-header.d.vue.ts +3 -1
  4. package/dist/runtime/form/components/page/form-page-header.vue +44 -34
  5. package/dist/runtime/form/components/page/form-page-header.vue.d.ts +3 -1
  6. package/dist/runtime/form/components/page/form-page-navigation.d.vue.ts +5 -3
  7. package/dist/runtime/form/components/page/form-page-navigation.vue +6 -3
  8. package/dist/runtime/form/components/page/form-page-navigation.vue.d.ts +5 -3
  9. package/dist/runtime/form/components/page/form-page-section.vue +6 -5
  10. package/dist/runtime/form/components/page/form-page-sections.d.vue.ts +4 -3
  11. package/dist/runtime/form/components/page/form-page-sections.vue +7 -2
  12. package/dist/runtime/form/components/page/form-page-sections.vue.d.ts +4 -3
  13. package/dist/runtime/form/components/page/form-page.d.vue.ts +2 -0
  14. package/dist/runtime/form/components/page/form-page.vue +11 -2
  15. package/dist/runtime/form/components/page/form-page.vue.d.ts +2 -0
  16. package/dist/runtime/form/components/renderer/form-field-renderer.vue +6 -4
  17. package/dist/runtime/form/components/renderer/form-field-shell.d.vue.ts +4 -4
  18. package/dist/runtime/form/components/renderer/form-field-shell.vue +28 -4
  19. package/dist/runtime/form/components/renderer/form-field-shell.vue.d.ts +4 -4
  20. package/dist/runtime/form/components/root/form.vue +2 -2
  21. package/dist/runtime/form/components/utils/form-option-choice-label.d.vue.ts +16 -0
  22. package/dist/runtime/form/components/utils/form-option-choice-label.vue +37 -0
  23. package/dist/runtime/form/components/utils/form-option-choice-label.vue.d.ts +16 -0
  24. package/dist/runtime/form/components/utils/form-option-display-value.d.vue.ts +14 -0
  25. package/dist/runtime/form/components/utils/form-option-display-value.vue +20 -0
  26. package/dist/runtime/form/components/utils/form-option-display-value.vue.d.ts +14 -0
  27. package/dist/runtime/form/components/utils/form-option-item-label.d.vue.ts +9 -2
  28. package/dist/runtime/form/components/utils/form-option-item-label.vue +20 -13
  29. package/dist/runtime/form/components/utils/form-option-item-label.vue.d.ts +9 -2
  30. package/dist/runtime/form/components/utils/form-option-leading.d.vue.ts +23 -0
  31. package/dist/runtime/form/components/utils/form-option-leading.vue +41 -0
  32. package/dist/runtime/form/components/utils/form-option-leading.vue.d.ts +23 -0
  33. package/dist/runtime/form/components/utils/form-option-render.d.ts +11 -0
  34. package/dist/runtime/form/components/utils/form-option-render.js +5 -0
  35. package/dist/runtime/form/components/utils/form-option-suffix.d.vue.ts +8 -0
  36. package/dist/runtime/form/components/utils/form-option-suffix.vue +15 -0
  37. package/dist/runtime/form/components/utils/form-option-suffix.vue.d.ts +8 -0
  38. package/dist/runtime/form/components/utils/form-option-value-overlay.d.vue.ts +30 -0
  39. package/dist/runtime/form/components/utils/form-option-value-overlay.vue +44 -0
  40. package/dist/runtime/form/components/utils/form-option-value-overlay.vue.d.ts +30 -0
  41. package/dist/runtime/form/composables/use-choice-group-items.d.ts +27 -0
  42. package/dist/runtime/form/composables/use-choice-group-items.js +24 -0
  43. package/dist/runtime/form/composables/use-field-control.d.ts +6 -6
  44. package/dist/runtime/form/composables/use-field-control.js +9 -21
  45. package/dist/runtime/form/composables/use-field-options.js +8 -4
  46. package/dist/runtime/form/composables/use-form-layout.js +4 -3
  47. package/dist/runtime/form/composables/use-form-page.d.ts +11 -1
  48. package/dist/runtime/form/composables/use-form-page.js +12 -6
  49. package/dist/runtime/form/composables/use-form-runtime.js +1 -1
  50. package/dist/runtime/form/composables/use-option-menu.d.ts +20 -0
  51. package/dist/runtime/form/composables/use-option-menu.js +41 -0
  52. package/dist/runtime/form/fields/array-primitive/types.d.ts +1 -1
  53. package/dist/runtime/form/fields/auto-complete/component.vue +92 -51
  54. package/dist/runtime/form/fields/auto-complete/config.d.ts +1 -0
  55. package/dist/runtime/form/fields/auto-complete/config.js +1 -1
  56. package/dist/runtime/form/fields/auto-complete/types.d.ts +2 -2
  57. package/dist/runtime/form/fields/checkbox-card/component.vue +55 -29
  58. package/dist/runtime/form/fields/checkbox-card/config.d.ts +1 -0
  59. package/dist/runtime/form/fields/checkbox-card/config.js +1 -1
  60. package/dist/runtime/form/fields/checkbox-card/types.d.ts +3 -3
  61. package/dist/runtime/form/fields/checkbox-group/component.vue +18 -4
  62. package/dist/runtime/form/fields/checkbox-group/types.d.ts +2 -2
  63. package/dist/runtime/form/fields/choice-card/choice-card-label.d.vue.ts +7 -0
  64. package/dist/runtime/form/fields/choice-card/choice-card-label.vue +27 -1
  65. package/dist/runtime/form/fields/choice-card/choice-card-label.vue.d.ts +7 -0
  66. package/dist/runtime/form/fields/choice-card/types.d.ts +35 -1
  67. package/dist/runtime/form/fields/choice-card/use-choice-card.d.ts +7 -3
  68. package/dist/runtime/form/fields/choice-card/use-choice-card.js +37 -15
  69. package/dist/runtime/form/fields/choice-card/utils.d.ts +10 -0
  70. package/dist/runtime/form/fields/choice-card/utils.js +6 -0
  71. package/dist/runtime/form/fields/hierarchy/component.vue +3 -2
  72. package/dist/runtime/form/fields/index.d.ts +4 -0
  73. package/dist/runtime/form/fields/radio/component.vue +19 -2
  74. package/dist/runtime/form/fields/radio/types.d.ts +2 -2
  75. package/dist/runtime/form/fields/radio-card/component.vue +58 -28
  76. package/dist/runtime/form/fields/radio-card/config.d.ts +1 -0
  77. package/dist/runtime/form/fields/radio-card/config.js +1 -1
  78. package/dist/runtime/form/fields/radio-card/types.d.ts +3 -3
  79. package/dist/runtime/form/fields/select/component.vue +56 -58
  80. package/dist/runtime/form/fields/select/config.d.ts +1 -0
  81. package/dist/runtime/form/fields/select/config.js +1 -1
  82. package/dist/runtime/form/fields/select/types.d.ts +2 -2
  83. package/dist/runtime/form/types/field-base.d.ts +6 -0
  84. package/dist/runtime/form/types/field-kind.d.ts +3 -1
  85. package/dist/runtime/form/types/field.d.ts +1 -0
  86. package/dist/runtime/form/types/layout.d.ts +6 -0
  87. package/dist/runtime/form/types/options.d.ts +137 -0
  88. package/dist/runtime/form/types/page.d.ts +20 -8
  89. package/dist/runtime/form/types/ui.d.ts +29 -4
  90. package/dist/runtime/form/utils/disabled.d.ts +11 -0
  91. package/dist/runtime/form/utils/disabled.js +11 -0
  92. package/dist/runtime/form/utils/field-instance.js +3 -0
  93. package/dist/runtime/form/utils/options.d.ts +56 -11
  94. package/dist/runtime/form/utils/options.js +86 -0
  95. package/dist/runtime/form/utils/page-surface.d.ts +26 -0
  96. package/dist/runtime/form/utils/page-surface.js +28 -0
  97. package/dist/runtime/form/utils/page.d.ts +21 -1
  98. package/dist/runtime/form/utils/page.js +24 -2
  99. package/dist/runtime/i18n/locales/en.js +28 -8
  100. package/dist/runtime/i18n/locales/fr.js +28 -8
  101. package/dist/runtime/i18n/types.d.ts +46 -7
  102. package/dist/runtime/spreadsheet/components/internal/spreadsheet-import-column-row.d.vue.ts +2 -2
  103. package/dist/runtime/spreadsheet/components/internal/spreadsheet-import-column-row.vue.d.ts +2 -2
  104. package/dist/runtime/table/components/actions/row-actions.d.vue.ts +2 -0
  105. package/dist/runtime/table/components/actions/row-actions.vue +8 -3
  106. package/dist/runtime/table/components/actions/row-actions.vue.d.ts +2 -0
  107. package/dist/runtime/table/components/data-list/data-list-content.vue +7 -1
  108. package/dist/runtime/table/components/data-list/data-list-default.d.vue.ts +16 -16
  109. package/dist/runtime/table/components/data-list/data-list-default.vue +3 -0
  110. package/dist/runtime/table/components/data-list/data-list-default.vue.d.ts +16 -16
  111. package/dist/runtime/table/components/data-list/data-list-layout-switch.vue +7 -9
  112. package/dist/runtime/table/components/data-list/data-list-root.vue +5 -6
  113. package/dist/runtime/table/components/data-list/data-list-sort-menu.vue +3 -1
  114. package/dist/runtime/table/components/data-list/data-list-table.d.vue.ts +8 -1
  115. package/dist/runtime/table/components/data-list/data-list-table.vue +18 -1
  116. package/dist/runtime/table/components/data-list/data-list-table.vue.d.ts +8 -1
  117. package/dist/runtime/table/components/data-list/data-list-view-toggle.d.vue.ts +25 -0
  118. package/dist/runtime/table/components/data-list/data-list-view-toggle.vue +57 -0
  119. package/dist/runtime/table/components/data-list/data-list-view-toggle.vue.d.ts +25 -0
  120. package/dist/runtime/table/components/data-list/sort-menu-panel.vue +1 -1
  121. package/dist/runtime/table/components/filters/tags/boolean-filter-tag.d.vue.ts +2 -2
  122. package/dist/runtime/table/components/filters/tags/boolean-filter-tag.vue.d.ts +2 -2
  123. package/dist/runtime/table/components/filters/tags/date-filter-tag.d.vue.ts +2 -2
  124. package/dist/runtime/table/components/filters/tags/date-filter-tag.vue.d.ts +2 -2
  125. package/dist/runtime/table/components/filters/tags/number-filter-tag.d.vue.ts +2 -2
  126. package/dist/runtime/table/components/filters/tags/number-filter-tag.vue.d.ts +2 -2
  127. package/dist/runtime/table/components/filters/tags/option-filter-tag.d.vue.ts +2 -2
  128. package/dist/runtime/table/components/filters/tags/option-filter-tag.vue.d.ts +2 -2
  129. package/dist/runtime/table/components/filters/tags/text-filter-tag.d.vue.ts +2 -2
  130. package/dist/runtime/table/components/filters/tags/text-filter-tag.vue.d.ts +2 -2
  131. package/dist/runtime/table/components/layout/table-footer.d.vue.ts +6 -4
  132. package/dist/runtime/table/components/layout/table-footer.vue +80 -3
  133. package/dist/runtime/table/components/layout/table-footer.vue.d.ts +6 -4
  134. package/dist/runtime/table/components/summary/summary-content.d.ts +13 -0
  135. package/dist/runtime/table/components/summary/summary-content.js +5 -0
  136. package/dist/runtime/table/components/summary/summary-renderer.d.vue.ts +31 -0
  137. package/dist/runtime/table/components/summary/summary-renderer.vue +282 -0
  138. package/dist/runtime/table/components/summary/summary-renderer.vue.d.ts +31 -0
  139. package/dist/runtime/table/components/summary/summary-row.d.vue.ts +19 -0
  140. package/dist/runtime/table/components/summary/summary-row.vue +102 -0
  141. package/dist/runtime/table/components/summary/summary-row.vue.d.ts +19 -0
  142. package/dist/runtime/table/components/table/table-empty-state.vue +39 -9
  143. package/dist/runtime/table/components/table/table-renderer.vue +1 -1
  144. package/dist/runtime/table/components/table/table-row-actions-control.vue +10 -6
  145. package/dist/runtime/table/components/table/table-selection-control.d.vue.ts +5 -1
  146. package/dist/runtime/table/components/table/table-selection-control.vue +17 -4
  147. package/dist/runtime/table/components/table/table-selection-control.vue.d.ts +5 -1
  148. package/dist/runtime/table/components/table/table-tree-control.vue +2 -1
  149. package/dist/runtime/table/components/table/table-tree-header.vue +0 -1
  150. package/dist/runtime/table/composables/use-table-api.d.ts +2 -0
  151. package/dist/runtime/table/composables/use-table-api.js +8 -0
  152. package/dist/runtime/table/composables/use-table-columns.d.ts +2 -0
  153. package/dist/runtime/table/composables/use-table-controls.d.ts +6 -0
  154. package/dist/runtime/table/composables/use-table-controls.js +6 -3
  155. package/dist/runtime/table/composables/use-table-internals.d.ts +33 -0
  156. package/dist/runtime/table/composables/use-table-internals.js +9 -0
  157. package/dist/runtime/table/composables/use-table-row-labels.d.ts +16 -0
  158. package/dist/runtime/table/composables/use-table-row-labels.js +22 -0
  159. package/dist/runtime/table/composables/use-table-row-summary.d.ts +18 -0
  160. package/dist/runtime/table/composables/use-table-row-summary.js +41 -0
  161. package/dist/runtime/table/constants/mobile.d.ts +79 -0
  162. package/dist/runtime/table/constants/mobile.js +17 -0
  163. package/dist/runtime/table/constants/summary.d.ts +67 -0
  164. package/dist/runtime/table/constants/summary.js +31 -0
  165. package/dist/runtime/table/types/data-list.d.ts +58 -8
  166. package/dist/runtime/table/types/layout.d.ts +73 -0
  167. package/dist/runtime/table/types/remote-options.d.ts +4 -1
  168. package/dist/runtime/table/types/schema.d.ts +9 -1
  169. package/dist/runtime/table/types/table-api.d.ts +12 -0
  170. package/dist/runtime/table/utils/columns/defs.js +3 -1
  171. package/dist/runtime/table/utils/columns/render.d.ts +2 -0
  172. package/dist/runtime/table/utils/columns/render.js +2 -2
  173. package/dist/runtime/table/utils/data-list-ui.d.ts +1 -1
  174. package/dist/runtime/table/utils/data-list-ui.js +3 -1
  175. package/dist/runtime/table/utils/mobile-defaults.d.ts +7 -0
  176. package/dist/runtime/table/utils/mobile-defaults.js +25 -0
  177. package/dist/runtime/table/utils/remote-table-options.js +1 -1
  178. package/package.json +1 -1
@@ -28,12 +28,12 @@ type __VLS_Slots = {} & {
28
28
  trigger?: (props: typeof __VLS_10) => any;
29
29
  };
30
30
  declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
31
- back: () => any;
32
31
  dismiss: () => any;
32
+ back: () => any;
33
33
  sessionClosed: () => any;
34
34
  }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
35
- onBack?: (() => any) | undefined;
36
35
  onDismiss?: (() => any) | undefined;
36
+ onBack?: (() => any) | undefined;
37
37
  onSessionClosed?: (() => any) | undefined;
38
38
  }>, {
39
39
  header: boolean;
@@ -28,12 +28,12 @@ type __VLS_Slots = {} & {
28
28
  trigger?: (props: typeof __VLS_10) => any;
29
29
  };
30
30
  declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
31
- back: () => any;
32
31
  dismiss: () => any;
32
+ back: () => any;
33
33
  sessionClosed: () => any;
34
34
  }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
35
- onBack?: (() => any) | undefined;
36
35
  onDismiss?: (() => any) | undefined;
36
+ onBack?: (() => any) | undefined;
37
37
  onSessionClosed?: (() => any) | undefined;
38
38
  }>, {
39
39
  header: boolean;
@@ -28,12 +28,12 @@ type __VLS_Slots = {} & {
28
28
  trigger?: (props: typeof __VLS_10) => any;
29
29
  };
30
30
  declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
31
- back: () => any;
32
31
  dismiss: () => any;
32
+ back: () => any;
33
33
  sessionClosed: () => any;
34
34
  }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
35
- onBack?: (() => any) | undefined;
36
35
  onDismiss?: (() => any) | undefined;
36
+ onBack?: (() => any) | undefined;
37
37
  onSessionClosed?: (() => any) | undefined;
38
38
  }>, {
39
39
  header: boolean;
@@ -28,12 +28,12 @@ type __VLS_Slots = {} & {
28
28
  trigger?: (props: typeof __VLS_10) => any;
29
29
  };
30
30
  declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
31
- back: () => any;
32
31
  dismiss: () => any;
32
+ back: () => any;
33
33
  sessionClosed: () => any;
34
34
  }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
35
- onBack?: (() => any) | undefined;
36
35
  onDismiss?: (() => any) | undefined;
36
+ onBack?: (() => any) | undefined;
37
37
  onSessionClosed?: (() => any) | undefined;
38
38
  }>, {
39
39
  header: boolean;
@@ -14,10 +14,10 @@ declare var __VLS_1: {
14
14
  pageSize: number;
15
15
  options: number[];
16
16
  setPageSize: (nextPageSize: number) => void;
17
- }, __VLS_12: {
17
+ }, __VLS_12: {}, __VLS_19: {
18
18
  current: number;
19
19
  total: number;
20
- }, __VLS_14: {
20
+ }, __VLS_21: {
21
21
  state: {
22
22
  hasNextPage: boolean;
23
23
  hasPreviousPage: boolean;
@@ -39,9 +39,11 @@ type __VLS_Slots = {} & {
39
39
  } & {
40
40
  'page-size'?: (props: typeof __VLS_3) => any;
41
41
  } & {
42
- 'page-count'?: (props: typeof __VLS_12) => any;
42
+ 'view-toggle'?: (props: typeof __VLS_12) => any;
43
43
  } & {
44
- navigation?: (props: typeof __VLS_14) => any;
44
+ 'page-count'?: (props: typeof __VLS_19) => any;
45
+ } & {
46
+ navigation?: (props: typeof __VLS_21) => any;
45
47
  };
46
48
  declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
47
49
  compact: boolean;
@@ -12,6 +12,41 @@ import {
12
12
  mergeDataListUiClass,
13
13
  resolveDataListControlGeometry
14
14
  } from "../../utils";
15
+ import DataListViewToggle from "../data-list/data-list-view-toggle.vue";
16
+ const PAGER_CONTROLS = [
17
+ {
18
+ icon: "i-lucide-chevrons-left",
19
+ iconProp: "firstIcon",
20
+ label: "table.footer.firstPage",
21
+ mirrored: "i-lucide-chevrons-right",
22
+ slot: "first",
23
+ target: () => 1
24
+ },
25
+ {
26
+ icon: "i-lucide-chevron-left",
27
+ iconProp: "prevIcon",
28
+ label: "table.footer.previousPage",
29
+ mirrored: "i-lucide-chevron-right",
30
+ slot: "prev",
31
+ target: (page2) => page2 > 1 ? page2 - 1 : void 0
32
+ },
33
+ {
34
+ icon: "i-lucide-chevron-right",
35
+ iconProp: "nextIcon",
36
+ label: "table.footer.nextPage",
37
+ mirrored: "i-lucide-chevron-left",
38
+ slot: "next",
39
+ target: (page2, pages) => page2 < pages ? page2 + 1 : void 0
40
+ },
41
+ {
42
+ icon: "i-lucide-chevrons-right",
43
+ iconProp: "lastIcon",
44
+ label: "table.footer.lastPage",
45
+ mirrored: "i-lucide-chevrons-left",
46
+ slot: "last",
47
+ target: (_page, pages) => pages
48
+ }
49
+ ];
15
50
  const props = defineProps({
16
51
  size: { type: String, required: false },
17
52
  compact: { type: Boolean, required: false, default: void 0 },
@@ -22,7 +57,7 @@ const internals = useTableInternals();
22
57
  const { isMobile } = useDataListBreakpoint();
23
58
  const compact = computed(() => props.compact ?? isMobile.value);
24
59
  const dataListUi = useDataListUi();
25
- const { locale, t } = useUiToolsLocale();
60
+ const { dir, locale, t } = useUiToolsLocale();
26
61
  const controlSize = computed(
27
62
  () => props.size ?? dataListUi.ui.value.pagination?.size ?? dataListUi.controlSize.value
28
63
  );
@@ -49,6 +84,24 @@ const paginationProps = computed(
49
84
  controlProps.value.pagination
50
85
  )
51
86
  );
87
+ const pagerControls = computed(() => {
88
+ const resolved = paginationProps.value;
89
+ if (resolved.showControls === false) return [];
90
+ return PAGER_CONTROLS.map((control) => {
91
+ const target = control.target(page.value, internals.pagination.totalPages.value);
92
+ return {
93
+ label: t(control.label),
94
+ props: {
95
+ color: resolved.color,
96
+ icon: resolved[control.iconProp] || (dir.value === "rtl" ? control.mirrored : control.icon),
97
+ size: resolved.size,
98
+ to: target === void 0 ? void 0 : resolved.to?.(target),
99
+ variant: resolved.variant
100
+ },
101
+ slot: control.slot
102
+ };
103
+ });
104
+ });
52
105
  const pageSizeProps = computed(
53
106
  () => mergeDataListProps({ color: "neutral", size: controlSize.value, variant: "none" }, controlProps.value.pageSize)
54
107
  );
@@ -93,8 +146,9 @@ const paginationControls = computed(() => {
93
146
  showPagesList: pagination.showPagesList ?? true
94
147
  };
95
148
  });
149
+ const showViewToggle = computed(() => internals.controls.headerControls.value.summary);
96
150
  const showFooter = computed(
97
- () => internals.pagination.mode.value === "offset" && (paginationControls.value.showPageSizePicker || paginationControls.value.showPagesCount || paginationControls.value.showPagesList)
151
+ () => internals.pagination.mode.value === "offset" && (paginationControls.value.showPageSizePicker || paginationControls.value.showPagesCount || paginationControls.value.showPagesList || showViewToggle.value)
98
152
  );
99
153
  function formatCount(value) {
100
154
  return new Intl.NumberFormat(locale.value.code).format(value);
@@ -184,6 +238,10 @@ function formatCount(value) {
184
238
  </slot>
185
239
  </div>
186
240
 
241
+ <div v-if="showViewToggle" class="nut-dl-footer__view mx-auto">
242
+ <slot name="view-toggle"><DataListViewToggle /></slot>
243
+ </div>
244
+
187
245
  <div
188
246
  v-if="paginationControls.showPagesList"
189
247
  :class="
@@ -273,7 +331,26 @@ function formatCount(value) {
273
331
  ui.button
274
332
  )
275
333
  }"
276
- />
334
+ >
335
+ <template v-for="control in pagerControls" #[control.slot]>
336
+ <UButton v-bind="control.props" :aria-label="control.label" />
337
+ </template>
338
+ <template #item="{ item, page: current, pageCount }">
339
+ <UButton
340
+ v-if="item.type === 'page'"
341
+ :color="current === item.value ? paginationProps.activeColor : paginationProps.color"
342
+ :variant="
343
+ current === item.value ? paginationProps.activeVariant : paginationProps.variant
344
+ "
345
+ :size="paginationProps.size"
346
+ :label="String(item.value)"
347
+ :aria-label="t('table.footer.page', { current: item.value, total: pageCount })"
348
+ :to="paginationProps.to?.(item.value)"
349
+ :ui="{ label: 'min-w-5 text-center' }"
350
+ square
351
+ />
352
+ </template>
353
+ </UPagination>
277
354
  </slot>
278
355
  </div>
279
356
  </footer>
@@ -14,10 +14,10 @@ declare var __VLS_1: {
14
14
  pageSize: number;
15
15
  options: number[];
16
16
  setPageSize: (nextPageSize: number) => void;
17
- }, __VLS_12: {
17
+ }, __VLS_12: {}, __VLS_19: {
18
18
  current: number;
19
19
  total: number;
20
- }, __VLS_14: {
20
+ }, __VLS_21: {
21
21
  state: {
22
22
  hasNextPage: boolean;
23
23
  hasPreviousPage: boolean;
@@ -39,9 +39,11 @@ type __VLS_Slots = {} & {
39
39
  } & {
40
40
  'page-size'?: (props: typeof __VLS_3) => any;
41
41
  } & {
42
- 'page-count'?: (props: typeof __VLS_12) => any;
42
+ 'view-toggle'?: (props: typeof __VLS_12) => any;
43
43
  } & {
44
- navigation?: (props: typeof __VLS_14) => any;
44
+ 'page-count'?: (props: typeof __VLS_19) => any;
45
+ } & {
46
+ navigation?: (props: typeof __VLS_21) => any;
45
47
  };
46
48
  declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
47
49
  compact: boolean;
@@ -0,0 +1,13 @@
1
+ import type { FunctionalComponent } from 'vue';
2
+ import type { RenderableType } from '../../../shared/index.js';
3
+ import type { TableInjectedRowActionScope } from '../../composables/use-table-row-actions.js';
4
+ interface SummaryContentProps {
5
+ params: TableInjectedRowActionScope;
6
+ render: (params: TableInjectedRowActionScope) => RenderableType;
7
+ }
8
+ /**
9
+ * Renders one of a summary row's schema callbacks. The callback runs while this component renders,
10
+ * so each render gets fresh vnodes and the reactive reads inside it belong to this component only.
11
+ */
12
+ declare const SummaryContent: FunctionalComponent<SummaryContentProps>;
13
+ export default SummaryContent;
@@ -0,0 +1,5 @@
1
+ import { renderVNode } from "../../../shared/utils/render.js";
2
+ const SummaryContent = (props) => renderVNode(props.render(props.params));
3
+ SummaryContent.props = ["params", "render"];
4
+ SummaryContent.displayName = "DataListSummaryContent";
5
+ export default SummaryContent;
@@ -0,0 +1,31 @@
1
+ import type { DataListControlSize, DataListSummaryUi } from '../../types/index.js';
2
+ /**
3
+ * The table layout read as one compact row per record, the way a phone screen needs it. It takes
4
+ * the table renderer's place while `table.summary` is active and keeps its states: first-load
5
+ * placeholders, error, empty, refreshing, cursor pages and a virtualized window for long lists.
6
+ */
7
+ type __VLS_Props = {
8
+ height?: string;
9
+ size?: DataListControlSize;
10
+ fill?: boolean;
11
+ ui?: DataListSummaryUi;
12
+ };
13
+ declare function refresh(): void;
14
+ declare var __VLS_8: {
15
+ error: {};
16
+ retry: typeof refresh;
17
+ }, __VLS_17: {};
18
+ type __VLS_Slots = {} & {
19
+ error?: (props: typeof __VLS_8) => any;
20
+ } & {
21
+ empty?: (props: typeof __VLS_17) => any;
22
+ };
23
+ 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>;
24
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
25
+ declare const _default: typeof __VLS_export;
26
+ export default _default;
27
+ type __VLS_WithSlots<T, S> = T & {
28
+ new (): {
29
+ $slots: S;
30
+ };
31
+ };
@@ -0,0 +1,282 @@
1
+ <script setup>
2
+ import { useVirtualizer } from "@tanstack/vue-virtual";
3
+ import { useElementSize } from "@vueuse/core";
4
+ import { computed, nextTick, useTemplateRef, watch } from "vue";
5
+ import { useUiToolsLocale } from "#ui-tools/i18n";
6
+ import { useDataListUi } from "../../composables/use-data-list-ui";
7
+ import { useTableInternals } from "../../composables/use-table-internals";
8
+ import { useTableRowLabels } from "../../composables/use-table-row-labels";
9
+ import {
10
+ TABLE_SUMMARY_LOAD_MORE_THRESHOLD,
11
+ TABLE_SUMMARY_SIZE_TOKENS,
12
+ TABLE_SUMMARY_SKELETON_MIN_ROWS,
13
+ TABLE_SUMMARY_SLOT_CLASSES,
14
+ TABLE_SUMMARY_VIRTUALIZE_THRESHOLD
15
+ } from "../../constants/summary";
16
+ import { mergeDataListUiClass } from "../../utils";
17
+ import { ROW_ACTIONS_COLUMN_ID } from "../../utils/columns/types";
18
+ import DataListErrorState from "../data-list/data-list-error-state.vue";
19
+ import ProgressLine from "../layout/progress-line.vue";
20
+ import TableEmptyState from "../table/table-empty-state.vue";
21
+ import TableSelectionControl from "../table/table-selection-control.vue";
22
+ import SummaryRow from "./summary-row.vue";
23
+ const props = defineProps({
24
+ height: { type: String, required: false },
25
+ size: { type: String, required: false },
26
+ fill: { type: Boolean, required: false },
27
+ ui: { type: Object, required: false }
28
+ });
29
+ const internals = useTableInternals();
30
+ const { selection } = internals;
31
+ const { status } = internals.queryContent;
32
+ const dataListUi = useDataListUi();
33
+ const labels = useTableRowLabels();
34
+ const { t } = useUiToolsLocale();
35
+ const rows = computed(
36
+ () => internals.queryContent.error.value ? [] : internals.queryContent.data.value.rows
37
+ );
38
+ const isFirstLoad = computed(
39
+ () => status.value.isBooting || (status.value.isPending || status.value.isFetching) && rows.value.length === 0
40
+ );
41
+ const refreshing = computed(
42
+ () => rows.value.length > 0 && (status.value.isFetching || status.value.isRefreshing || status.value.isRevalidating)
43
+ );
44
+ const replacing = computed(() => rows.value.length > 0 && status.value.isReplacing);
45
+ const error = computed(() => rows.value.length === 0 ? internals.queryContent.error.value : null);
46
+ const empty = computed(() => !isFirstLoad.value && !error.value && rows.value.length === 0);
47
+ const scrolls = computed(() => Boolean(props.fill || props.height));
48
+ const resolvedSize = computed(
49
+ () => props.size ?? dataListUi.ui.value.table?.size ?? dataListUi.controlSize.value
50
+ );
51
+ const tokens = computed(() => TABLE_SUMMARY_SIZE_TOKENS[resolvedSize.value]);
52
+ const tokenStyle = computed(() => ({
53
+ "--nut-dl-summary-font": `${tokens.value.font}px`,
54
+ "--nut-dl-summary-meta": `${tokens.value.font - 1}px`,
55
+ "--nut-dl-summary-row-h": `${tokens.value.row}px`,
56
+ "--nut-dl-summary-tile": `${tokens.value.tile}px`,
57
+ "--nut-dl-summary-x": `${dataListUi.ui.value.table?.gutter ?? tokens.value.gutter}px`
58
+ }));
59
+ const hasActions = computed(
60
+ () => internals.tableColumns.runtimeColumns.value.some((column) => column.id === ROW_ACTIONS_COLUMN_ID)
61
+ );
62
+ const selectAllState = computed(
63
+ () => selection.allSelected.value || selection.partiallySelected.value && "indeterminate"
64
+ );
65
+ function css(slot, extra = "") {
66
+ return mergeDataListUiClass(
67
+ `${TABLE_SUMMARY_SLOT_CLASSES[slot]} ${extra}`,
68
+ void 0,
69
+ props.ui?.[slot]
70
+ );
71
+ }
72
+ function rowIdAt(index) {
73
+ const row = rows.value[index];
74
+ return row ? selection.getRowId({ index, row }) : String(index);
75
+ }
76
+ function refresh() {
77
+ void internals.queryContent.refreshData()();
78
+ }
79
+ function toggleAll() {
80
+ selection.toggleAllRows({ selected: !selection.allSelected.value });
81
+ }
82
+ function onSelectRow(rowId, event) {
83
+ selection.toggleRowSelection({
84
+ rowId,
85
+ selected: !selection.isRowSelected({ rowId }),
86
+ shiftKey: event.shiftKey
87
+ });
88
+ }
89
+ function skeletonTitleWidth(seed) {
90
+ return 45 + seed * 37 % 40;
91
+ }
92
+ const scrollRef = useTemplateRef("scrollRef");
93
+ const { height: viewportHeight } = useElementSize(scrollRef);
94
+ const skeletonCount = computed(
95
+ () => Math.max(TABLE_SUMMARY_SKELETON_MIN_ROWS, Math.ceil(viewportHeight.value / tokens.value.row))
96
+ );
97
+ const virtualized = computed(() => rows.value.length >= TABLE_SUMMARY_VIRTUALIZE_THRESHOLD);
98
+ const rowVirtualizer = useVirtualizer(
99
+ computed(() => ({
100
+ count: virtualized.value ? rows.value.length : 0,
101
+ estimateSize: () => tokens.value.row,
102
+ getItemKey: (index) => rowIdAt(index),
103
+ getScrollElement: () => scrollRef.value ?? null,
104
+ measureElement: (element) => element.getBoundingClientRect().height,
105
+ overscan: 12
106
+ }))
107
+ );
108
+ const virtualRows = computed(
109
+ () => virtualized.value ? rowVirtualizer.value.getVirtualItems() : []
110
+ );
111
+ const paddingTop = computed(() => virtualRows.value[0]?.start ?? 0);
112
+ const paddingBottom = computed(
113
+ () => virtualRows.value.length ? rowVirtualizer.value.getTotalSize() - (virtualRows.value.at(-1)?.end ?? 0) : 0
114
+ );
115
+ const renderedRows = computed(
116
+ () => virtualized.value ? virtualRows.value.flatMap((item) => {
117
+ const row = rows.value[item.index];
118
+ return row ? [{ index: item.index, row, rowId: rowIdAt(item.index) }] : [];
119
+ }) : rows.value.map((row, index) => ({ index, row, rowId: rowIdAt(index) }))
120
+ );
121
+ function measureRow(target) {
122
+ const element = target instanceof Element ? target : target?.$el;
123
+ if (!(element instanceof HTMLElement)) return;
124
+ if (element.isConnected) rowVirtualizer.value.measureElement(element);
125
+ else nextTick().then(() => element.isConnected && rowVirtualizer.value.measureElement(element));
126
+ }
127
+ const cursorMode = computed(() => internals.pagination.mode.value === "cursor");
128
+ const loadingMore = computed(
129
+ () => cursorMode.value && internals.pagination.state.value.isLoadingMore
130
+ );
131
+ const hasNextPage = computed(() => cursorMode.value && internals.pagination.state.value.hasNextPage);
132
+ watch(
133
+ () => [
134
+ virtualRows.value.at(-1)?.index ?? rows.value.length - 1,
135
+ rows.value.length,
136
+ hasNextPage.value,
137
+ loadingMore.value
138
+ ],
139
+ ([lastIndex, count, more, loading]) => {
140
+ if (!more || loading || !count) return;
141
+ const threshold = Math.max(TABLE_SUMMARY_LOAD_MORE_THRESHOLD, virtualRows.value.length);
142
+ if (lastIndex >= count - 1 - threshold) void internals.pagination.loadMore();
143
+ }
144
+ );
145
+ let scrollResetPending = false;
146
+ watch(
147
+ () => [
148
+ internals.pagination.currentPage.value,
149
+ internals.pagination.pageSize.value,
150
+ JSON.stringify(internals.tableColumns.sortingState.value),
151
+ JSON.stringify(internals.queryState.filters.value),
152
+ internals.filters.searchQuery.value
153
+ ],
154
+ () => {
155
+ if (!cursorMode.value) scrollResetPending = true;
156
+ }
157
+ );
158
+ function resetScroll() {
159
+ if (!scrollResetPending) return;
160
+ scrollResetPending = false;
161
+ scrollRef.value?.scrollTo({ top: 0 });
162
+ }
163
+ watch(rows, resetScroll);
164
+ watch(
165
+ () => status.value.isFetching,
166
+ (fetching) => !fetching && resetScroll()
167
+ );
168
+ </script>
169
+
170
+ <template>
171
+ <div
172
+ :class="
173
+ mergeDataListUiClass(
174
+ `${TABLE_SUMMARY_SLOT_CLASSES.root} ${fill ? 'h-full' : ''}`,
175
+ void 0,
176
+ ui?.root
177
+ )
178
+ "
179
+ :style="{ ...tokenStyle, height: !fill && height ? height : void 0 }"
180
+ :data-size="resolvedSize"
181
+ :data-virtualized="virtualized"
182
+ :data-loading="isFirstLoad"
183
+ :data-replacing="replacing"
184
+ >
185
+ <div v-if="selection.selectionEnabled.value && rows.length > 0" :class="css('header')">
186
+ <TableSelectionControl
187
+ class="min-h-11 min-w-11 justify-center"
188
+ :model-value="selectAllState"
189
+ @toggle="toggleAll"
190
+ />
191
+ <span>{{ labels.selectAll() }}</span>
192
+ </div>
193
+
194
+ <div ref="scrollRef" :class="css('viewport', scrolls ? 'flex flex-1 flex-col' : '')">
195
+ <div
196
+ v-if="error"
197
+ class="nut-dl-summary__state flex w-full flex-col"
198
+ :class="scrolls ? 'min-h-0 flex-1' : ''"
199
+ >
200
+ <slot name="error" :error="error" :retry="refresh">
201
+ <DataListErrorState
202
+ :min-height="scrolls ? void 0 : '16rem'"
203
+ :size="resolvedSize"
204
+ class="flex-1"
205
+ @retry="refresh"
206
+ />
207
+ </slot>
208
+ </div>
209
+ <div
210
+ v-else-if="empty"
211
+ class="nut-dl-summary__state flex w-full flex-col"
212
+ :class="scrolls ? 'min-h-0 flex-1' : ''"
213
+ >
214
+ <slot name="empty">
215
+ <TableEmptyState
216
+ :min-height="scrolls ? void 0 : '16rem'"
217
+ :size="resolvedSize"
218
+ class="flex-1"
219
+ />
220
+ </slot>
221
+ </div>
222
+ <ul v-else role="list" :class="css('list')">
223
+ <li
224
+ v-for="placeholder in isFirstLoad ? skeletonCount : 0"
225
+ :key="`skeleton-${placeholder}`"
226
+ :class="css('skeleton')"
227
+ aria-hidden="true"
228
+ >
229
+ <span
230
+ class="nut-dl-skeleton size-[var(--nut-dl-summary-tile)] shrink-0 rounded-lg"
231
+ :style="{ '--nut-dl-i': placeholder }"
232
+ />
233
+ <span class="min-w-0 flex-1">
234
+ <span
235
+ class="nut-dl-skeleton block h-3 rounded-full"
236
+ :style="{ '--nut-dl-i': placeholder, width: `${skeletonTitleWidth(placeholder)}%` }"
237
+ />
238
+ <span
239
+ class="nut-dl-skeleton mt-2 block h-2.5 w-1/3 rounded-full"
240
+ :style="{ '--nut-dl-i': placeholder }"
241
+ />
242
+ </span>
243
+ </li>
244
+
245
+ <li v-if="paddingTop" :style="{ height: `${paddingTop}px` }" aria-hidden="true" />
246
+ <SummaryRow
247
+ v-for="entry in renderedRows"
248
+ :key="entry.rowId"
249
+ :ref="measureRow"
250
+ :row-id="entry.rowId"
251
+ :original="entry.row"
252
+ :index="entry.index"
253
+ :selected="selection.isRowSelected({ rowId: entry.rowId })"
254
+ :selectable="selection.selectionEnabled.value"
255
+ :actions="hasActions"
256
+ :ui="ui"
257
+ @select="onSelectRow(entry.rowId, $event)"
258
+ />
259
+ <li v-if="paddingBottom" :style="{ height: `${paddingBottom}px` }" aria-hidden="true" />
260
+
261
+ <li v-if="loadingMore" :class="css('loadingMore')" aria-hidden="true">
262
+ <span
263
+ class="nut-dl-spinner size-3.5 rounded-full border-2 border-accented border-t-primary"
264
+ />
265
+ <span>{{ t("table.controls.loadingMore") }}</span>
266
+ </li>
267
+ </ul>
268
+ </div>
269
+
270
+ <ProgressLine
271
+ :active="refreshing"
272
+ :restart-key="internals.queryContent.refreshes.value"
273
+ class="absolute inset-x-0 top-0 z-[6]"
274
+ />
275
+ </div>
276
+ </template>
277
+
278
+ <style>
279
+ .nut-dl-summary__list{transition:opacity .16s ease-out}.nut-dl-summary[data-replacing=true] .nut-dl-summary__list{opacity:.55;transition:opacity .2s ease-in .18s}.nut-dl-summary__row{transition:background-color .1s}.nut-dl-summary__row[data-interactive=true]:active{background:var(--nut-dl-summary-row-pressed,var(--ui-bg-muted))}@media (hover:hover){.nut-dl-summary__row[data-interactive=true]:hover{background:var(--nut-dl-summary-row-hover,var(--ui-bg-elevated))}}.nut-dl-summary__row[data-selected=true],.nut-dl-summary__row[data-selected=true]:hover{background:var(
280
+ --nut-dl-summary-row-selected,color-mix(in srgb,var(--ui-primary) 10%,var(--ui-bg))
281
+ )}.nut-dl-summary__skeleton{animation:nut-dl-summary-in .18s ease .12s both}@keyframes nut-dl-summary-in{0%{opacity:0}to{opacity:1}}@media (prefers-reduced-motion:reduce){.nut-dl-summary__list,.nut-dl-summary__row{transition:none}.nut-dl-summary__skeleton{animation:none}}
282
+ </style>
@@ -0,0 +1,31 @@
1
+ import type { DataListControlSize, DataListSummaryUi } from '../../types/index.js';
2
+ /**
3
+ * The table layout read as one compact row per record, the way a phone screen needs it. It takes
4
+ * the table renderer's place while `table.summary` is active and keeps its states: first-load
5
+ * placeholders, error, empty, refreshing, cursor pages and a virtualized window for long lists.
6
+ */
7
+ type __VLS_Props = {
8
+ height?: string;
9
+ size?: DataListControlSize;
10
+ fill?: boolean;
11
+ ui?: DataListSummaryUi;
12
+ };
13
+ declare function refresh(): void;
14
+ declare var __VLS_8: {
15
+ error: {};
16
+ retry: typeof refresh;
17
+ }, __VLS_17: {};
18
+ type __VLS_Slots = {} & {
19
+ error?: (props: typeof __VLS_8) => any;
20
+ } & {
21
+ empty?: (props: typeof __VLS_17) => any;
22
+ };
23
+ 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>;
24
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
25
+ declare const _default: typeof __VLS_export;
26
+ export default _default;
27
+ type __VLS_WithSlots<T, S> = T & {
28
+ new (): {
29
+ $slots: S;
30
+ };
31
+ };
@@ -0,0 +1,19 @@
1
+ import type { DataListSummaryUi, GenericObject } from '../../types/index.js';
2
+ type __VLS_Props = {
3
+ rowId: string;
4
+ original: GenericObject;
5
+ index: number;
6
+ selected: boolean;
7
+ /** The row carries a checkbox. */
8
+ selectable: boolean;
9
+ /** The row carries the row-actions button. */
10
+ actions: boolean;
11
+ ui?: DataListSummaryUi;
12
+ };
13
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
14
+ select: (event: MouseEvent) => any;
15
+ }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
16
+ onSelect?: ((event: MouseEvent) => any) | undefined;
17
+ }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
18
+ declare const _default: typeof __VLS_export;
19
+ export default _default;