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
@@ -0,0 +1,102 @@
1
+ <script setup>
2
+ import ULink from "@nuxt/ui/components/Link.vue";
3
+ import { computed } from "vue";
4
+ import { isNullish } from "../../../shared/utils/predicate";
5
+ import { useTableInternals } from "../../composables/use-table-internals";
6
+ import {
7
+ TABLE_SUMMARY_DETAILS_SEPARATOR,
8
+ TABLE_SUMMARY_SLOT_CLASSES
9
+ } from "../../constants/summary";
10
+ import { mergeDataListUiClass } from "../../utils";
11
+ import TableRowScopeProvider from "../actions/table-row-scope-provider.vue";
12
+ import TableRowActionsControl from "../table/table-row-actions-control.vue";
13
+ import TableSelectionControl from "../table/table-selection-control.vue";
14
+ import SummaryContent from "./summary-content";
15
+ const props = defineProps({
16
+ rowId: { type: String, required: true },
17
+ original: { type: Object, required: true },
18
+ index: { type: Number, required: true },
19
+ selected: { type: Boolean, required: true },
20
+ selectable: { type: Boolean, required: true },
21
+ actions: { type: Boolean, required: true },
22
+ ui: { type: Object, required: false }
23
+ });
24
+ const emit = defineEmits(["select"]);
25
+ const internals = useTableInternals();
26
+ const summary = computed(() => internals.schema.value.table?.summary);
27
+ const params = computed(() => ({
28
+ context: internals.queryContent.contextData.value,
29
+ index: props.index,
30
+ layout: internals.controls.tableLayout.value,
31
+ pageContext: internals.queryContent.pageContextData.value,
32
+ row: props.original,
33
+ tableApi: internals.tableApi
34
+ }));
35
+ const title = computed(() => String(summary.value?.title(params.value) ?? ""));
36
+ const target = computed(() => summary.value?.to?.(params.value));
37
+ const interactive = computed(() => target.value !== void 0 || Boolean(summary.value?.onSelect));
38
+ const details = computed(() => joinDetails(summary.value?.details?.(params.value) ?? []));
39
+ function joinDetails(values) {
40
+ return values.filter((value) => value !== false && value !== "" && !isNullish(value)).join(TABLE_SUMMARY_DETAILS_SEPARATOR);
41
+ }
42
+ function css(slot, extra = "") {
43
+ return mergeDataListUiClass(
44
+ `${TABLE_SUMMARY_SLOT_CLASSES[slot]} ${extra}`,
45
+ void 0,
46
+ props.ui?.[slot]
47
+ );
48
+ }
49
+ function select() {
50
+ summary.value?.onSelect?.(params.value);
51
+ }
52
+ </script>
53
+
54
+ <template>
55
+ <li
56
+ :class="css('row')"
57
+ :data-row-id="rowId"
58
+ :data-index="index"
59
+ :data-selected="selected"
60
+ :data-interactive="interactive"
61
+ >
62
+ <div v-if="selectable" :class="css('select')">
63
+ <TableSelectionControl
64
+ class="min-h-11 min-w-11 justify-center"
65
+ :model-value="selected"
66
+ :row="original"
67
+ :index="index"
68
+ @toggle="emit('select', $event)"
69
+ />
70
+ </div>
71
+ <ULink
72
+ :as="interactive ? 'button' : 'div'"
73
+ :to="target"
74
+ raw
75
+ :class="
76
+ css(
77
+ 'main',
78
+ `${selectable ? 'ps-1' : 'ps-[var(--nut-dl-summary-x)]'} ${actions ? 'pe-1' : 'pe-[var(--nut-dl-summary-x)]'}`
79
+ )
80
+ "
81
+ @click="select"
82
+ >
83
+ <span v-if="summary?.leading" :class="css('leading')">
84
+ <SummaryContent :render="summary.leading" :params="params" />
85
+ </span>
86
+ <span :class="css('body')">
87
+ <span :class="css('title')" :title="title">{{ title }}</span>
88
+ <span v-if="summary?.status || details" :class="css('meta')">
89
+ <span v-if="summary?.status" :class="css('status')">
90
+ <SummaryContent :render="summary.status" :params="params" />
91
+ </span>
92
+ <span v-if="details" :class="css('details')">{{ details }}</span>
93
+ </span>
94
+ </span>
95
+ </ULink>
96
+ <div v-if="actions" :class="css('actions')">
97
+ <TableRowScopeProvider :scope="params">
98
+ <TableRowActionsControl />
99
+ </TableRowScopeProvider>
100
+ </div>
101
+ </li>
102
+ </template>
@@ -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;
@@ -3,9 +3,10 @@ import UButton from "@nuxt/ui/components/Button.vue";
3
3
  import UIcon from "@nuxt/ui/components/Icon.vue";
4
4
  import { computed } from "vue";
5
5
  import { useUiToolsLocale } from "#ui-tools/i18n";
6
+ import { resolveTextValue } from "../../../shared/utils/render";
6
7
  import { useDataListUi } from "../../composables/use-data-list-ui";
7
8
  import { useTableInternals } from "../../composables/use-table-internals";
8
- import { mergeDataListUiClass } from "../../utils";
9
+ import { mergeDataListProps, mergeDataListUiClass } from "../../utils";
9
10
  const props = defineProps({
10
11
  minHeight: { type: String, required: false },
11
12
  size: { type: String, required: false }
@@ -14,22 +15,42 @@ const { t } = useUiToolsLocale();
14
15
  const internals = useTableInternals();
15
16
  const dataListUi = useDataListUi();
16
17
  const ui = computed(() => dataListUi.ui.value.table?.ui);
17
- const emptyProps = computed(() => dataListUi.ui.value.table?.props?.empty);
18
18
  const filtered = computed(
19
19
  () => internals.filters.hasActiveUiFilters.value || Boolean(internals.filters.searchQuery.value)
20
20
  );
21
- const custom = computed(() => filtered.value ? void 0 : emptyProps.value);
21
+ const custom = computed(() => {
22
+ if (filtered.value) return void 0;
23
+ const own = internals.schema.value.empty;
24
+ const app = dataListUi.ui.value.table?.props?.empty;
25
+ return {
26
+ action: own?.action ?? app?.action,
27
+ description: own?.description ?? app?.description,
28
+ icon: own?.icon ?? app?.icon,
29
+ title: own?.title ?? app?.title
30
+ };
31
+ });
22
32
  const icon = computed(
23
33
  () => custom.value?.icon ?? (filtered.value ? "i-lucide-search-x" : "i-lucide-inbox")
24
34
  );
25
35
  const title = computed(
26
- () => custom.value?.title ?? (filtered.value ? t("table.states.empty.filteredTitle") : t("table.states.empty.title"))
36
+ () => resolveTextValue(
37
+ custom.value?.title,
38
+ filtered.value ? t("table.states.empty.filteredTitle") : t("table.states.empty.title")
39
+ )
27
40
  );
28
41
  const description = computed(() => {
29
- if (custom.value?.description === false) {
30
- return "";
31
- }
32
- return custom.value?.description || (filtered.value ? t("table.states.empty.filteredDescription") : t("table.states.empty.description"));
42
+ if (custom.value?.description === false) return "";
43
+ return resolveTextValue(custom.value?.description) || (filtered.value ? t("table.states.empty.filteredDescription") : t("table.states.empty.description"));
44
+ });
45
+ const action = computed(() => {
46
+ const configured = custom.value?.action;
47
+ if (!configured) return void 0;
48
+ const { label, onClick, ...button } = configured;
49
+ return {
50
+ button: mergeDataListProps({ color: "primary", size: "md" }, button),
51
+ label: resolveTextValue(label),
52
+ onClick
53
+ };
33
54
  });
34
55
  function reset() {
35
56
  internals.filters.clearAllFilters();
@@ -66,18 +87,27 @@ function reset() {
66
87
  {{ description }}
67
88
  </p>
68
89
  <div
69
- v-if="filtered || $slots.actions"
90
+ v-if="filtered || action || $slots.actions"
70
91
  class="nut-dl-empty__actions mt-4 flex items-center gap-2"
71
92
  >
72
93
  <slot name="actions">
73
94
  <UButton
95
+ v-if="filtered"
74
96
  color="neutral"
75
97
  variant="outline"
76
98
  size="sm"
77
99
  icon="i-lucide-rotate-ccw"
78
100
  :label="t('table.states.empty.reset')"
101
+ :ui="{ base: mergeDataListUiClass('nut-dl-empty__action', void 0, ui?.emptyAction) }"
79
102
  @click="reset"
80
103
  />
104
+ <UButton
105
+ v-else-if="action"
106
+ v-bind="action.button"
107
+ :label="action.label"
108
+ :ui="{ base: mergeDataListUiClass('nut-dl-empty__action', void 0, ui?.emptyAction) }"
109
+ @click="action.onClick"
110
+ />
81
111
  </slot>
82
112
  </div>
83
113
  </div>
@@ -934,5 +934,5 @@ defineExpose({ resetColumnSizing });
934
934
  <style>
935
935
  .nut-dl-table{--nut-dl-surface:var(--nut-dl-table-surface,var(--ui-bg-elevated));--nut-dl-line:var(--nut-dl-table-line,var(--ui-border));--nut-dl-line-soft:var(--nut-dl-table-line-soft,var(--ui-border-muted));--nut-dl-head-bg:var(--nut-dl-table-head-bg,var(--ui-bg-muted));--nut-dl-head-fg:var(--nut-dl-table-head-fg,var(--ui-text-muted));--nut-dl-head-font:var(--nut-dl-table-head-font,11px);--nut-dl-head-weight:var(--nut-dl-table-head-weight,600);--nut-dl-head-tracking:var(--nut-dl-table-head-tracking,0.04em);--nut-dl-head-transform:var(--nut-dl-table-head-transform,none);--nut-dl-row-hover:var(--nut-dl-table-row-hover,var(--ui-bg-muted));--nut-dl-row-selected:var(
936
936
  --nut-dl-table-row-selected,color-mix(in srgb,var(--ui-primary) 10%,var(--nut-dl-surface))
937
- );--nut-dl-accent:var(--ui-primary);--nut-dl-cell-fg:var(--nut-dl-table-cell-fg,var(--ui-text-toned));--nut-dl-pin-line:var(--nut-dl-table-pin-line,var(--nut-dl-line));--nut-dl-rail:var(--nut-dl-table-rail,var(--ui-border-accented));--nut-dl-rail-lit:var(--nut-dl-table-rail-lit,var(--ui-primary));--nut-dl-rail-radius:var(--nut-dl-table-rail-radius,calc(var(--ui-radius)*1.5));--nut-dl-toggle-hover:var(--nut-dl-table-toggle-hover,var(--ui-bg-accented));--nut-dl-tree-shift:var(--nut-dl-table-tree-shift,6px)}.nut-dl-table__scroll{overflow-anchor:none;scrollbar-width:none}.nut-dl-table__scroll::-webkit-scrollbar{display:none}.nut-dl-th{color:var(--nut-dl-head-fg);font-size:var(--nut-dl-head-font);font-weight:var(--nut-dl-head-weight);letter-spacing:var(--nut-dl-head-tracking);text-transform:var(--nut-dl-head-transform);-webkit-user-select:none;-moz-user-select:none;user-select:none;white-space:nowrap}.nut-dl-table__fill,.nut-dl-table__spacer,.nut-dl-th{background:var(--nut-dl-head-bg);border-bottom:1px solid var(--nut-dl-line)}.nut-dl-tf{background:var(--nut-dl-head-bg);border-top:1px solid var(--nut-dl-line);color:var(--ui-text-highlighted);font-weight:var(--nut-dl-table-foot-weight,500);white-space:nowrap}tfoot .nut-dl-table__fill,tfoot .nut-dl-table__spacer{border-bottom:0;border-top:1px solid var(--nut-dl-line)}.nut-dl-spinner{animation:nut-dl-spin .8s linear infinite}@keyframes nut-dl-spin{to{transform:rotate(1turn)}}tbody .nut-dl-table__spacer{background:var(--nut-dl-surface);border-bottom:1px solid var(--nut-dl-line-soft)}tbody .nut-dl-table__fill{background:inherit;border-bottom:1px solid var(--nut-dl-line-soft)}.nut-dl-th__btn--open{background:color-mix(in srgb,var(--nut-dl-head-fg) 8%,transparent)}.nut-dl-rz:after{background:var(--ui-border-accented);bottom:10px;content:"";opacity:0;position:absolute;right:0;top:10px;transition:opacity .12s;width:1px}.nut-dl-rz:hover:after,.nut-dl-th:hover .nut-dl-rz:after{opacity:1}.nut-dl-rz--active:after,.nut-dl-rz:hover:after{background:var(--nut-dl-accent);bottom:6px;left:2.5px;opacity:1;top:6px;width:2px}.nut-dl-row{background:var(--nut-dl-surface);transition:background-color .1s}.nut-dl-row:hover{background:var(--nut-dl-row-hover)}.nut-dl-row--selected,.nut-dl-row--selected:hover{background:var(--nut-dl-row-selected)}.nut-dl-td,.nut-dl-tf[data-col],.nut-dl-th__btn,.nut-dl-th__static{padding-left:var(--nut-dl-cell-l,var(--nut-dl-cell-x));padding-right:var(--nut-dl-cell-r,var(--nut-dl-cell-x))}.nut-dl-row>.nut-dl-td:first-child,.nut-dl-table__foot-row>.nut-dl-tf:first-child,.nut-dl-table__head-row>.nut-dl-th:first-child{--nut-dl-cell-l:var(--nut-dl-gutter)}.nut-dl-row>.nut-dl-td:last-child,.nut-dl-table__foot-row>.nut-dl-tf:last-child,.nut-dl-table__head-row>.nut-dl-th:last-child{--nut-dl-cell-r:var(--nut-dl-gutter)}.nut-dl-row>.nut-dl-td--actions:last-child,.nut-dl-table__foot-row>.nut-dl-tf--actions:last-child,.nut-dl-table__head-row>.nut-dl-th--actions:last-child,.nut-dl-td--actions,.nut-dl-tf--actions{--nut-dl-cell-l:var(--nut-dl-cell-x);--nut-dl-cell-r:var(--nut-dl-cell-x)}.nut-dl-td--actions .nut-dl-td__inner{justify-content:flex-end}.nut-dl-td{background:inherit;border-bottom:1px solid var(--nut-dl-line-soft);box-sizing:border-box;color:var(--nut-dl-cell-fg);overflow:hidden;overflow-wrap:anywhere;padding-block:var(--nut-dl-cell-y,6px);white-space:normal}.nut-dl-table__table tbody:has(+tfoot)>.nut-dl-row:last-child>.nut-dl-td{border-bottom:0}.nut-dl-td{contain:paint}.nut-dl-td__inner{display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:var(--nut-dl-lines,3);line-clamp:var(--nut-dl-lines,3);max-height:calc(var(--nut-dl-lines, 3)*1.5em);overflow:hidden}.nut-dl-td--ellipsis{--nut-dl-lines:1;white-space:nowrap}.nut-dl-td--ellipsis .nut-dl-td__inner{display:block;text-overflow:ellipsis}.nut-dl-td--actions .nut-dl-td__inner,.nut-dl-td--selection .nut-dl-td__inner{align-items:center;display:flex}.nut-dl-td--actions,.nut-dl-td--selection{white-space:nowrap}.nut-dl-td--actions .nut-dl-td__inner>*{opacity:.55;transition:opacity .12s}.nut-dl-row:hover .nut-dl-td--actions .nut-dl-td__inner>*{opacity:1}.nut-dl-pin{position:sticky}.nut-dl-pin--first-end:before,.nut-dl-pin--last-start:after{background:var(--nut-dl-line);bottom:0;content:"";pointer-events:none;position:absolute;top:0;width:1px}.nut-dl-pin--last-start:after{right:0}.nut-dl-pin--first-end:before{left:0}.nut-dl-pin--first-end:before,.nut-dl-pin--last-start:after{background:var(--nut-dl-pin-line)}.nut-dl-td--actions.nut-dl-pin--first-end:before,.nut-dl-th--actions.nut-dl-pin--first-end:before{display:none}.nut-dl-skeleton{animation:nut-dl-shimmer 1.6s ease-in-out infinite;animation-delay:calc(var(--nut-dl-i, 0)*-90ms);background:linear-gradient(90deg,var(--ui-bg-accented) 0,var(--ui-bg-muted) 45%,var(--ui-bg-accented) 100%);background-size:200% 100%}.nut-dl-row--skeleton{animation:nut-dl-fade-in .18s ease .12s both}.nut-dl-row--appended{animation:nut-dl-fade-in .2s ease both}.nut-dl-table__body{transition:opacity .16s ease-out}.nut-dl-table__body[data-replacing=true]{opacity:.55;transition:opacity .2s ease-in .18s}@keyframes nut-dl-fade-in{0%{opacity:0}to{opacity:1}}@keyframes nut-dl-shimmer{0%{background-position:100% 0}to{background-position:-100% 0}}@media (prefers-reduced-motion:reduce){.nut-dl-row,.nut-dl-table__body{transition:none}.nut-dl-row--appended,.nut-dl-row--skeleton,.nut-dl-skeleton{animation:none}}
937
+ );--nut-dl-accent:var(--ui-primary);--nut-dl-cell-fg:var(--nut-dl-table-cell-fg,var(--ui-text-toned));--nut-dl-pin-line:var(--nut-dl-table-pin-line,var(--nut-dl-line));--nut-dl-rail:var(--nut-dl-table-rail,var(--ui-border-accented));--nut-dl-rail-lit:var(--nut-dl-table-rail-lit,var(--ui-primary));--nut-dl-rail-radius:var(--nut-dl-table-rail-radius,calc(var(--ui-radius)*1.5));--nut-dl-toggle-hover:var(--nut-dl-table-toggle-hover,var(--ui-bg-accented));--nut-dl-tree-shift:var(--nut-dl-table-tree-shift,6px)}.nut-dl-table__scroll{overflow-anchor:none;scrollbar-width:none}.nut-dl-table__scroll::-webkit-scrollbar{display:none}.nut-dl-th{color:var(--nut-dl-head-fg);font-size:var(--nut-dl-head-font);font-weight:var(--nut-dl-head-weight);letter-spacing:var(--nut-dl-head-tracking);text-transform:var(--nut-dl-head-transform);-webkit-user-select:none;-moz-user-select:none;user-select:none;white-space:nowrap}.nut-dl-table__fill,.nut-dl-table__spacer,.nut-dl-th{background:var(--nut-dl-head-bg);border-bottom:1px solid var(--nut-dl-line)}.nut-dl-tf{background:var(--nut-dl-head-bg);border-top:1px solid var(--nut-dl-line);color:var(--ui-text-highlighted);font-weight:var(--nut-dl-table-foot-weight,500);white-space:nowrap}tfoot .nut-dl-table__fill,tfoot .nut-dl-table__spacer{border-bottom:0;border-top:1px solid var(--nut-dl-line)}.nut-dl-spinner{animation:nut-dl-spin .8s linear infinite}@keyframes nut-dl-spin{to{transform:rotate(1turn)}}tbody .nut-dl-table__spacer{background:var(--nut-dl-surface);border-bottom:1px solid var(--nut-dl-line-soft)}tbody .nut-dl-table__fill{background:inherit;border-bottom:1px solid var(--nut-dl-line-soft)}.nut-dl-th__btn--open{background:color-mix(in srgb,var(--nut-dl-head-fg) 8%,transparent)}.nut-dl-rz:after{background:var(--ui-border-accented);bottom:10px;content:"";opacity:0;position:absolute;right:0;top:10px;transition:opacity .12s;width:1px}.nut-dl-rz:hover:after,.nut-dl-th:hover .nut-dl-rz:after{opacity:1}.nut-dl-rz--active:after,.nut-dl-rz:hover:after{background:var(--nut-dl-accent);bottom:6px;left:2.5px;opacity:1;top:6px;width:2px}.nut-dl-row{background:var(--nut-dl-surface);transition:background-color .1s}.nut-dl-row:hover{background:var(--nut-dl-row-hover)}.nut-dl-row--selected,.nut-dl-row--selected:hover{background:var(--nut-dl-row-selected)}.nut-dl-td,.nut-dl-tf[data-col],.nut-dl-th__btn,.nut-dl-th__static{padding-left:var(--nut-dl-cell-l,var(--nut-dl-cell-x));padding-right:var(--nut-dl-cell-r,var(--nut-dl-cell-x))}.nut-dl-row>.nut-dl-td:first-child,.nut-dl-table__foot-row>.nut-dl-tf:first-child,.nut-dl-table__head-row>.nut-dl-th:first-child{--nut-dl-cell-l:var(--nut-dl-gutter)}.nut-dl-row>.nut-dl-td:last-child,.nut-dl-table__foot-row>.nut-dl-tf:last-child,.nut-dl-table__head-row>.nut-dl-th:last-child{--nut-dl-cell-r:var(--nut-dl-gutter)}.nut-dl-row>.nut-dl-td--actions:last-child,.nut-dl-table__foot-row>.nut-dl-tf--actions:last-child,.nut-dl-table__head-row>.nut-dl-th--actions:last-child,.nut-dl-td--actions,.nut-dl-tf--actions{--nut-dl-cell-l:var(--nut-dl-cell-x);--nut-dl-cell-r:var(--nut-dl-cell-x)}.nut-dl-td--actions .nut-dl-td__inner{justify-content:flex-end}.nut-dl-td{background:inherit;border-bottom:1px solid var(--nut-dl-line-soft);box-sizing:border-box;color:var(--nut-dl-cell-fg);overflow:hidden;overflow-wrap:anywhere;padding-block:var(--nut-dl-cell-y,6px);white-space:normal}.nut-dl-table__table tbody:has(+tfoot)>.nut-dl-row:last-child>.nut-dl-td{border-bottom:0}.nut-dl-td{contain:paint}.nut-dl-td__inner{display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:var(--nut-dl-lines,3);line-clamp:var(--nut-dl-lines,3);max-height:calc(var(--nut-dl-lines, 3)*1.5em);overflow:hidden}.nut-dl-td--ellipsis{--nut-dl-lines:1;white-space:nowrap}.nut-dl-td--ellipsis .nut-dl-td__inner{display:block;text-overflow:ellipsis}.nut-dl-td--actions .nut-dl-td__inner,.nut-dl-td--selection .nut-dl-td__inner{align-items:center;display:flex}.nut-dl-td--actions,.nut-dl-td--selection{white-space:nowrap;--nut-dl-cell-y:0px}.nut-dl-td--selection .nut-dl-td__inner{overflow:visible}.nut-dl-td--actions .nut-dl-td__inner>*{opacity:.55;transition:opacity .12s}.nut-dl-row:hover .nut-dl-td--actions .nut-dl-td__inner>*{opacity:1}.nut-dl-pin{position:sticky}.nut-dl-pin--first-end:before,.nut-dl-pin--last-start:after{background:var(--nut-dl-line);bottom:0;content:"";pointer-events:none;position:absolute;top:0;width:1px}.nut-dl-pin--last-start:after{right:0}.nut-dl-pin--first-end:before{left:0}.nut-dl-pin--first-end:before,.nut-dl-pin--last-start:after{background:var(--nut-dl-pin-line)}.nut-dl-td--actions.nut-dl-pin--first-end:before,.nut-dl-th--actions.nut-dl-pin--first-end:before{display:none}.nut-dl-skeleton{animation:nut-dl-shimmer 1.6s ease-in-out infinite;animation-delay:calc(var(--nut-dl-i, 0)*-90ms);background:linear-gradient(90deg,var(--ui-bg-accented) 0,var(--ui-bg-muted) 45%,var(--ui-bg-accented) 100%);background-size:200% 100%}.nut-dl-row--skeleton{animation:nut-dl-fade-in .18s ease .12s both}.nut-dl-row--appended{animation:nut-dl-fade-in .2s ease both}.nut-dl-table__body{transition:opacity .16s ease-out}.nut-dl-table__body[data-replacing=true]{opacity:.55;transition:opacity .2s ease-in .18s}@keyframes nut-dl-fade-in{0%{opacity:0}to{opacity:1}}@keyframes nut-dl-shimmer{0%{background-position:100% 0}to{background-position:-100% 0}}@media (prefers-reduced-motion:reduce){.nut-dl-row,.nut-dl-table__body{transition:none}.nut-dl-row--appended,.nut-dl-row--skeleton,.nut-dl-skeleton{animation:none}}
938
938
  </style>
@@ -5,6 +5,7 @@ import { useDataListUi } from "../../composables/use-data-list-ui";
5
5
  import { mergeDataListProps } from "../../utils";
6
6
  import RowActions from "../actions/row-actions.vue";
7
7
  const dataListUi = useDataListUi();
8
+ const ui = computed(() => dataListUi.ui.value.table?.ui);
8
9
  const buttonProps = computed(
9
10
  () => mergeDataListProps(
10
11
  {
@@ -31,12 +32,15 @@ const buttonProps = computed(
31
32
  itemLeadingIcon: 'size-3.5'
32
33
  }"
33
34
  >
34
- <UButton
35
- v-bind="buttonProps"
36
- square
37
- aria-label="Row actions"
38
- class="nut-dl-rowbtn text-muted hover:text-default focus-visible:text-default"
39
- />
35
+ <template #default="{ label }">
36
+ <UButton
37
+ v-bind="buttonProps"
38
+ square
39
+ :aria-label="label"
40
+ :ui="{ base: ui?.rowAction }"
41
+ class="nut-dl-rowbtn text-muted hover:text-default focus-visible:text-default"
42
+ />
43
+ </template>
40
44
  </RowActions>
41
45
  </div>
42
46
  </template>
@@ -1,6 +1,10 @@
1
+ import type { GenericObject } from '../../types/index.js';
1
2
  type __VLS_Props = {
2
3
  modelValue: boolean | 'indeterminate';
3
- ariaLabel: string;
4
+ /** The record this checkbox selects; without one it selects every row. */
5
+ row?: GenericObject;
6
+ /** Where the record sits in the rendered rows: it names the record when the schema has no `rowLabel`. */
7
+ index?: number;
4
8
  };
5
9
  declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
6
10
  toggle: (event: MouseEvent) => any;
@@ -2,13 +2,26 @@
2
2
  import UCheckbox from "@nuxt/ui/components/Checkbox.vue";
3
3
  import { computed } from "vue";
4
4
  import { useDataListUi } from "../../composables/use-data-list-ui";
5
- import { mergeDataListProps } from "../../utils";
5
+ import { useTableRowLabels } from "../../composables/use-table-row-labels";
6
+ import { mergeDataListProps, mergeDataListUiClass } from "../../utils";
6
7
  const props = defineProps({
7
8
  modelValue: { type: [Boolean, String], required: true },
8
- ariaLabel: { type: String, required: true }
9
+ row: { type: Object, required: false },
10
+ index: { type: Number, required: false }
9
11
  });
10
12
  const emit = defineEmits(["toggle"]);
11
13
  const dataListUi = useDataListUi();
14
+ const labels = useTableRowLabels();
15
+ const areaClass = computed(
16
+ () => mergeDataListUiClass(
17
+ "nut-dl-select inline-flex items-center",
18
+ void 0,
19
+ dataListUi.ui.value.table?.ui?.selectControl
20
+ )
21
+ );
22
+ const ariaLabel = computed(
23
+ () => props.row ? labels.selectRow({ index: props.index ?? 0, row: props.row }) : labels.selectAll()
24
+ );
12
25
  const checkboxProps = computed(
13
26
  () => mergeDataListProps(
14
27
  { color: "primary", size: dataListUi.controlSize.value },
@@ -23,11 +36,11 @@ function toggle(event) {
23
36
  </script>
24
37
 
25
38
  <template>
26
- <span class="inline-flex items-center" @click="toggle">
39
+ <span :class="areaClass" @click="toggle">
27
40
  <UCheckbox
28
41
  v-bind="checkboxProps"
29
42
  :model-value="props.modelValue"
30
- :aria-label="props.ariaLabel"
43
+ :aria-label="ariaLabel"
31
44
  class="nut-dl-check"
32
45
  />
33
46
  </span>
@@ -1,6 +1,10 @@
1
+ import type { GenericObject } from '../../types/index.js';
1
2
  type __VLS_Props = {
2
3
  modelValue: boolean | 'indeterminate';
3
- ariaLabel: string;
4
+ /** The record this checkbox selects; without one it selects every row. */
5
+ row?: GenericObject;
6
+ /** Where the record sits in the rendered rows: it names the record when the schema has no `rowLabel`. */
7
+ index?: number;
4
8
  };
5
9
  declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
6
10
  toggle: (event: MouseEvent) => any;
@@ -100,7 +100,8 @@ function onKeydown(event) {
100
100
  <TableSelectionControl
101
101
  v-if="checkbox"
102
102
  :model-value="selected"
103
- :ariaLabel="t('table.tree.selectRow')"
103
+ :row="node.row"
104
+ :index="index"
104
105
  @toggle="emit('select', $event)"
105
106
  />
106
107
  </span>
@@ -54,7 +54,6 @@ function toggle() {
54
54
  <TableSelectionControl
55
55
  v-if="selection.selectionEnabled.value"
56
56
  :model-value="checkState"
57
- :ariaLabel="t('table.tree.selectAll')"
58
57
  @toggle="selection.toggleAllRows({ selected: !selection.allSelected.value })"
59
58
  />
60
59
  </span>
@@ -6,6 +6,7 @@ import type { UseTableDataReturn } from './use-table-data.js';
6
6
  import type { useTableFilters } from './use-table-filters.js';
7
7
  import type { useTableLayout } from './use-table-layout.js';
8
8
  import type { useTablePagination } from './use-table-pagination.js';
9
+ import type { useTableRowSummary } from './use-table-row-summary.js';
9
10
  import type { useTableSelection } from './use-table-selection.js';
10
11
  import type { useTableState } from './use-table-state.js';
11
12
  import type { useTableTree } from './use-table-tree.js';
@@ -21,5 +22,6 @@ export interface UseTableApiParams<TSchema = TableSchemaView> {
21
22
  filters: ReturnType<typeof useTableFilters>;
22
23
  pagination: ReturnType<typeof useTablePagination>;
23
24
  queryContent: UseTableDataReturn;
25
+ rowSummary: ReturnType<typeof useTableRowSummary>;
24
26
  }
25
27
  export declare function useTableApi<TSchema = TableSchemaView>(params: UseTableApiParams<TSchema>): TableApi<TSchema>;
@@ -49,6 +49,13 @@ export function useTableApi(params) {
49
49
  },
50
50
  state: params.controls.layoutState
51
51
  };
52
+ const summary = {
53
+ set: params.rowSummary.setActive,
54
+ state: computed(() => ({
55
+ active: params.rowSummary.active.value,
56
+ available: params.rowSummary.available.value
57
+ }))
58
+ };
52
59
  const filters = {
53
60
  activeCount: computed(() => params.filters.activeUiFilters.value.length),
54
61
  clear: params.filters.clearAllFilters,
@@ -111,6 +118,7 @@ export function useTableApi(params) {
111
118
  selection,
112
119
  sorting,
113
120
  state,
121
+ summary,
114
122
  updateRow: data.updateRow,
115
123
  updateRows: data.updateRows
116
124
  };
@@ -41,6 +41,8 @@ export declare function useTableColumns(params: UseTableColumnsParams): {
41
41
  cell: ({ row }: {
42
42
  row: {
43
43
  id: string;
44
+ original: import("../types/index.js").GenericObject;
45
+ index: number;
44
46
  };
45
47
  }) => import("vue/jsx-runtime").JSX.Element;
46
48
  enableHiding: boolean;
@@ -1,9 +1,11 @@
1
1
  import type { ComputedRef } from 'vue';
2
2
  import type { TableControlsSchema, TableLayout, TableSchemaView } from '../types/index.js';
3
3
  import type { useTableLayout } from './use-table-layout.js';
4
+ import type { useTableRowSummary } from './use-table-row-summary.js';
4
5
  export interface UseTableControlsParams {
5
6
  schema: ComputedRef<TableSchemaView>;
6
7
  layout: ReturnType<typeof useTableLayout>;
8
+ rowSummary: ReturnType<typeof useTableRowSummary>;
7
9
  }
8
10
  export declare function useTableControls(options: UseTableControlsParams): {
9
11
  columnsPanelOpen: import("vue").Ref<boolean, boolean>;
@@ -39,6 +41,10 @@ export declare function useTableControls(options: UseTableControlsParams): {
39
41
  grid: ComputedRef<boolean | null>;
40
42
  table: ComputedRef<boolean | null>;
41
43
  };
44
+ summary: {
45
+ grid: ComputedRef<boolean | null>;
46
+ table: ComputedRef<boolean | null>;
47
+ };
42
48
  };
43
49
  setTableLayout: (layout: TableLayout) => void;
44
50
  tableEnabled: ComputedRef<boolean>;
@@ -13,15 +13,18 @@ export function useTableControls(options) {
13
13
  filters: responsiveControl("filters"),
14
14
  layout: responsiveControl("layout"),
15
15
  refresh: responsiveControl("refresh"),
16
- sort: responsiveControl("sort")
16
+ sort: responsiveControl("sort"),
17
+ summary: responsiveControl("summary")
17
18
  };
18
19
  const headerControls = computed(() => ({
19
20
  actions: Boolean(rawControls.actions[tableLayout.value].value) && Boolean(options.schema.value.toolbarActions?.length),
20
- columns: Boolean(rawControls.columns[tableLayout.value].value) && tableLayout.value === "table",
21
+ columns: Boolean(rawControls.columns[tableLayout.value].value) && tableLayout.value === "table" && !options.rowSummary.active.value,
21
22
  filters: Boolean(rawControls.filters[tableLayout.value].value) && Boolean(options.schema.value.filters?.ui?.length),
22
23
  layout: Boolean(rawControls.layout[tableLayout.value].value) && gridEnabled.value && tableEnabled.value,
23
24
  refresh: Boolean(rawControls.refresh[tableLayout.value].value),
24
- sort: Boolean(rawControls.sort[tableLayout.value].value) && tableLayout.value === "grid" && Boolean(options.schema.value.grid?.sortOptions?.length)
25
+ /* Summary rows have no column headers to sort by, so the menu stands in for them. */
26
+ sort: Boolean(rawControls.sort[tableLayout.value].value) && (tableLayout.value === "grid" && Boolean(options.schema.value.grid?.sortOptions?.length) || options.rowSummary.active.value),
27
+ summary: Boolean(rawControls.summary[tableLayout.value].value) && options.rowSummary.available.value
25
28
  }));
26
29
  const layoutState = computed(() => {
27
30
  const available = [];
@@ -60,6 +60,10 @@ declare function createTableInternals<TSchema>(options: {
60
60
  grid: import("vue").ComputedRef<boolean | null>;
61
61
  table: import("vue").ComputedRef<boolean | null>;
62
62
  };
63
+ summary: {
64
+ grid: import("vue").ComputedRef<boolean | null>;
65
+ table: import("vue").ComputedRef<boolean | null>;
66
+ };
63
67
  };
64
68
  setTableLayout: (layout: import("../types/index.js").TableLayout) => void;
65
69
  tableEnabled: import("vue").ComputedRef<boolean>;
@@ -327,6 +331,11 @@ declare function createTableInternals<TSchema>(options: {
327
331
  } | null>;
328
332
  };
329
333
  resolvedFilterState: import("vue").ComputedRef<import("../types/index.js").TableResolvedFilterGroup<string>>;
334
+ rowSummary: {
335
+ active: import("vue").ComputedRef<boolean>;
336
+ available: import("vue").ComputedRef<boolean>;
337
+ setActive: (next: boolean) => void;
338
+ };
330
339
  schema: import("vue").ComputedRef<TableSchemaView>;
331
340
  selection: {
332
341
  allSelected: import("vue").ComputedRef<boolean>;
@@ -433,6 +442,8 @@ declare function createTableInternals<TSchema>(options: {
433
442
  cell: ({ row }: {
434
443
  row: {
435
444
  id: string;
445
+ original: import("../types/index.js").GenericObject;
446
+ index: number;
436
447
  };
437
448
  }) => import("vue/jsx-runtime").JSX.Element;
438
449
  enableHiding: boolean;
@@ -672,6 +683,10 @@ declare function useProvideTableInternals<TSchema>(options: {
672
683
  grid: import("vue").ComputedRef<boolean | null>;
673
684
  table: import("vue").ComputedRef<boolean | null>;
674
685
  };
686
+ summary: {
687
+ grid: import("vue").ComputedRef<boolean | null>;
688
+ table: import("vue").ComputedRef<boolean | null>;
689
+ };
675
690
  };
676
691
  setTableLayout: (layout: import("../types/index.js").TableLayout) => void;
677
692
  tableEnabled: import("vue").ComputedRef<boolean>;
@@ -939,6 +954,11 @@ declare function useProvideTableInternals<TSchema>(options: {
939
954
  } | null>;
940
955
  };
941
956
  resolvedFilterState: import("vue").ComputedRef<import("../types/index.js").TableResolvedFilterGroup<string>>;
957
+ rowSummary: {
958
+ active: import("vue").ComputedRef<boolean>;
959
+ available: import("vue").ComputedRef<boolean>;
960
+ setActive: (next: boolean) => void;
961
+ };
942
962
  schema: import("vue").ComputedRef<TableSchemaView>;
943
963
  selection: {
944
964
  allSelected: import("vue").ComputedRef<boolean>;
@@ -1045,6 +1065,8 @@ declare function useProvideTableInternals<TSchema>(options: {
1045
1065
  cell: ({ row }: {
1046
1066
  row: {
1047
1067
  id: string;
1068
+ original: import("../types/index.js").GenericObject;
1069
+ index: number;
1048
1070
  };
1049
1071
  }) => import("vue/jsx-runtime").JSX.Element;
1050
1072
  enableHiding: boolean;
@@ -1281,6 +1303,10 @@ declare function useTableInternals(): {
1281
1303
  grid: import("vue").ComputedRef<boolean | null>;
1282
1304
  table: import("vue").ComputedRef<boolean | null>;
1283
1305
  };
1306
+ summary: {
1307
+ grid: import("vue").ComputedRef<boolean | null>;
1308
+ table: import("vue").ComputedRef<boolean | null>;
1309
+ };
1284
1310
  };
1285
1311
  setTableLayout: (layout: import("../types/index.js").TableLayout) => void;
1286
1312
  tableEnabled: import("vue").ComputedRef<boolean>;
@@ -1548,6 +1574,11 @@ declare function useTableInternals(): {
1548
1574
  } | null>;
1549
1575
  };
1550
1576
  resolvedFilterState: import("vue").ComputedRef<import("../types/index.js").TableResolvedFilterGroup<string>>;
1577
+ rowSummary: {
1578
+ active: import("vue").ComputedRef<boolean>;
1579
+ available: import("vue").ComputedRef<boolean>;
1580
+ setActive: (next: boolean) => void;
1581
+ };
1551
1582
  schema: import("vue").ComputedRef<TableSchemaView>;
1552
1583
  selection: {
1553
1584
  allSelected: import("vue").ComputedRef<boolean>;
@@ -1654,6 +1685,8 @@ declare function useTableInternals(): {
1654
1685
  cell: ({ row }: {
1655
1686
  row: {
1656
1687
  id: string;
1688
+ original: import("../types/index.js").GenericObject;
1689
+ index: number;
1657
1690
  };
1658
1691
  }) => import("vue/jsx-runtime").JSX.Element;
1659
1692
  enableHiding: boolean;
@@ -10,6 +10,7 @@ import { useTableFilters } from "./use-table-filters.js";
10
10
  import { useTableGrid } from "./use-table-grid.js";
11
11
  import { useTableLayout } from "./use-table-layout.js";
12
12
  import { useTablePagination } from "./use-table-pagination.js";
13
+ import { useTableRowSummary } from "./use-table-row-summary.js";
13
14
  import { useTableSelection } from "./use-table-selection.js";
14
15
  import { useTableStartup } from "./use-table-startup.js";
15
16
  import { useTableState } from "./use-table-state.js";
@@ -39,8 +40,14 @@ function createTableInternals(options) {
39
40
  schema,
40
41
  tree
41
42
  });
43
+ const rowSummary = useTableRowSummary({
44
+ layout,
45
+ schema,
46
+ tree
47
+ });
42
48
  const controls = useTableControls({
43
49
  layout,
50
+ rowSummary,
44
51
  schema
45
52
  });
46
53
  const filters = useTableFilters({
@@ -84,6 +91,7 @@ function createTableInternals(options) {
84
91
  pagination,
85
92
  publicSchema,
86
93
  queryContent,
94
+ rowSummary,
87
95
  runtimeSchema: schema,
88
96
  selection,
89
97
  state,
@@ -109,6 +117,7 @@ function createTableInternals(options) {
109
117
  queryContent,
110
118
  queryState: state.queryState,
111
119
  resolvedFilterState: state.resolvedFilterState,
120
+ rowSummary,
112
121
  schema,
113
122
  selection,
114
123
  startup,
@@ -0,0 +1,16 @@
1
+ import type { GenericObject } from '../types/index.js';
2
+ /**
3
+ * Accessible names for the controls of a record. A record is named by the schema's `rowLabel`;
4
+ * without one, or when it returns nothing for this record, by its position on the page.
5
+ */
6
+ export declare function useTableRowLabels(): {
7
+ rowActions: (params: {
8
+ row: GenericObject;
9
+ index: number;
10
+ }) => string;
11
+ selectAll: () => string;
12
+ selectRow: (params: {
13
+ row: GenericObject;
14
+ index: number;
15
+ }) => string;
16
+ };
@@ -0,0 +1,22 @@
1
+ import { useUiToolsLocale } from "#ui-tools/i18n";
2
+ import { isNullish } from "../../shared/utils/predicate.js";
3
+ import { useTableInternals } from "./use-table-internals.js";
4
+ const ROW_NAME_KEYS = {
5
+ actions: { named: "table.rowActions.label", positioned: "table.rowActions.labelAt" },
6
+ select: { named: "table.selection.selectRow", positioned: "table.selection.selectRowAt" }
7
+ };
8
+ export function useTableRowLabels() {
9
+ const internals = useTableInternals();
10
+ const { t } = useUiToolsLocale();
11
+ function name(kind, params) {
12
+ const keys = ROW_NAME_KEYS[kind];
13
+ const label = internals.schema.value.rowLabel?.(params.row);
14
+ const text = isNullish(label) ? "" : String(label).trim();
15
+ return text ? t(keys.named, { label: text }) : t(keys.positioned, { position: params.index + 1 });
16
+ }
17
+ return {
18
+ rowActions: (params) => name("actions", params),
19
+ selectAll: () => t("table.selection.selectAll"),
20
+ selectRow: (params) => name("select", params)
21
+ };
22
+ }
@@ -0,0 +1,18 @@
1
+ import type { ComputedRef } from 'vue';
2
+ import type { TableSchemaView } from '../types/index.js';
3
+ import type { useTableLayout } from './use-table-layout.js';
4
+ import type { useTableTree } from './use-table-tree.js';
5
+ export interface UseTableRowSummaryParams {
6
+ schema: ComputedRef<TableSchemaView>;
7
+ layout: ReturnType<typeof useTableLayout>;
8
+ tree: ReturnType<typeof useTableTree>;
9
+ }
10
+ /**
11
+ * Decides whether the table layout reads as summary rows. `available` is what the schema and the
12
+ * viewport allow; `active` also honours the reader's choice, which the toggle changes.
13
+ */
14
+ export declare function useTableRowSummary(params: UseTableRowSummaryParams): {
15
+ active: ComputedRef<boolean>;
16
+ available: ComputedRef<boolean>;
17
+ setActive: (next: boolean) => void;
18
+ };