@stonecrop/atable 0.30.0 → 0.32.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 (79) hide show
  1. package/dist/assets/index.css +804 -1
  2. package/dist/atable.js +2809 -1944
  3. package/dist/atable.js.map +1 -1
  4. package/dist/src/components/ACell.vue.d.ts +17 -0
  5. package/dist/src/components/ACell.vue.d.ts.map +1 -0
  6. package/dist/src/components/AGanttCell.vue.d.ts +34 -0
  7. package/dist/src/components/AGanttCell.vue.d.ts.map +1 -0
  8. package/dist/src/components/AGanttConnection.vue.d.ts +13 -0
  9. package/dist/src/components/AGanttConnection.vue.d.ts.map +1 -0
  10. package/dist/src/components/ARow.vue.d.ts +2693 -0
  11. package/dist/src/components/ARow.vue.d.ts.map +1 -0
  12. package/dist/src/components/ARowActions.vue.d.ts +16 -0
  13. package/dist/src/components/ARowActions.vue.d.ts.map +1 -0
  14. package/dist/src/components/ATable.vue.d.ts +13358 -0
  15. package/dist/src/components/ATable.vue.d.ts.map +1 -0
  16. package/dist/src/components/ATableColumnFilter.vue.d.ts +11 -0
  17. package/dist/src/components/ATableColumnFilter.vue.d.ts.map +1 -0
  18. package/dist/src/components/ATableHeader.vue.d.ts +20 -0
  19. package/dist/src/components/ATableHeader.vue.d.ts.map +1 -0
  20. package/dist/src/components/ATableLoading.vue.d.ts +14 -0
  21. package/dist/src/components/ATableLoading.vue.d.ts.map +1 -0
  22. package/dist/src/components/ATableLoadingBar.vue.d.ts +14 -0
  23. package/dist/src/components/ATableLoadingBar.vue.d.ts.map +1 -0
  24. package/dist/src/components/ATableModal.vue.d.ts +18 -0
  25. package/dist/src/components/ATableModal.vue.d.ts.map +1 -0
  26. package/dist/src/components/ATablePaginationFooter.vue.d.ts +17 -0
  27. package/dist/src/components/ATablePaginationFooter.vue.d.ts.map +1 -0
  28. package/dist/src/icons/index.d.ts +14 -7
  29. package/dist/src/icons/index.d.ts.map +1 -1
  30. package/dist/{tsdoc-metadata.json → src/tsdoc-metadata.json} +1 -1
  31. package/dist/src/types/index.d.ts.map +1 -1
  32. package/package.json +35 -29
  33. package/dist/atable.d.ts +0 -3560
  34. package/dist/atable.tsbuildinfo +0 -1
  35. package/dist/icons/stonecrop-ui-icon-add.svg +0 -5
  36. package/dist/icons/stonecrop-ui-icon-delete.svg +0 -5
  37. package/dist/icons/stonecrop-ui-icon-duplicate.svg +0 -5
  38. package/dist/icons/stonecrop-ui-icon-insert-above.svg +0 -15
  39. package/dist/icons/stonecrop-ui-icon-insert-below.svg +0 -15
  40. package/dist/icons/stonecrop-ui-icon-move.svg +0 -4
  41. package/dist/icons/stonecrop-ui-icon-open.svg +0 -5
  42. package/dist/src/composables/table-pagination.js +0 -108
  43. package/dist/src/icons/index.js +0 -32
  44. package/dist/src/index.js +0 -33
  45. package/dist/src/linkSearchableText.js +0 -44
  46. package/dist/src/resolveFilterType.js +0 -27
  47. package/dist/src/schemaToColumns.js +0 -59
  48. package/dist/src/stores/table.js +0 -833
  49. package/dist/src/types/index.js +0 -0
  50. package/dist/src/utils.js +0 -39
  51. package/src/components/ACell.vue +0 -410
  52. package/src/components/AGanttCell.vue +0 -638
  53. package/src/components/AGanttConnection.vue +0 -164
  54. package/src/components/ARow.vue +0 -251
  55. package/src/components/ARowActions.vue +0 -407
  56. package/src/components/ATable.vue +0 -538
  57. package/src/components/ATableColumnFilter.vue +0 -216
  58. package/src/components/ATableHeader.vue +0 -141
  59. package/src/components/ATableLoading.vue +0 -86
  60. package/src/components/ATableLoadingBar.vue +0 -81
  61. package/src/components/ATableModal.vue +0 -52
  62. package/src/components/ATablePaginationFooter.vue +0 -100
  63. package/src/composables/table-pagination.ts +0 -172
  64. package/src/icons/index.ts +0 -38
  65. package/src/icons/stonecrop-ui-icon-add.svg +0 -5
  66. package/src/icons/stonecrop-ui-icon-delete.svg +0 -5
  67. package/src/icons/stonecrop-ui-icon-duplicate.svg +0 -5
  68. package/src/icons/stonecrop-ui-icon-insert-above.svg +0 -15
  69. package/src/icons/stonecrop-ui-icon-insert-below.svg +0 -15
  70. package/src/icons/stonecrop-ui-icon-move.svg +0 -4
  71. package/src/icons/stonecrop-ui-icon-open.svg +0 -5
  72. package/src/index.ts +0 -62
  73. package/src/linkSearchableText.ts +0 -42
  74. package/src/resolveFilterType.ts +0 -32
  75. package/src/schemaToColumns.ts +0 -67
  76. package/src/shims-vue.d.ts +0 -10
  77. package/src/stores/table.ts +0 -978
  78. package/src/types/index.ts +0 -794
  79. package/src/utils.ts +0 -40
@@ -1 +0,0 @@
1
- {"version":"6.0.3"}
@@ -1,5 +0,0 @@
1
- <?xml version="1.0" encoding="UTF-8"?>
2
- <svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">
3
- <path d="M32,64C14.35,64,0,49.65,0,32S14.35,0,32,0s32,14.35,32,32-14.35,32-32,32ZM32,4c-15.44,0-28,12.56-28,28s12.56,28,28,28,28-12.56,28-28S47.44,4,32,4Z" style="fill: #000; stroke-width: 0px;"/>
4
- <polygon points="34 18 30 18 30 30 18 30 18 34 30 34 30 46 34 46 34 34 46 34 46 30 34 30 34 18" style="fill: #000; stroke-width: 0px;"/>
5
- </svg>
@@ -1,5 +0,0 @@
1
- <?xml version="1.0" encoding="UTF-8"?>
2
- <svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">
3
- <path d="M32,64C14.35,64,0,49.65,0,32S14.35,0,32,0s32,14.35,32,32-14.35,32-32,32ZM32,4c-15.44,0-28,12.56-28,28s12.56,28,28,28,28-12.56,28-28S47.44,4,32,4Z" style="fill: #000; stroke-width: 0px;"/>
4
- <polygon points="46.84 19.99 44.01 17.16 32 29.17 19.99 17.16 17.16 19.99 29.17 32 17.16 44.01 19.99 46.84 32 34.83 44.01 46.84 46.84 44.01 34.83 32 46.84 19.99" style="fill: #000; stroke-width: 0px;"/>
5
- </svg>
@@ -1,5 +0,0 @@
1
- <?xml version="1.0" encoding="UTF-8"?>
2
- <svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 70.67 70.67">
3
- <path d="M68.67,16.67h-14.67V2c0-1.1-.9-2-2-2H2C.9,0,0,.9,0,2v50c0,1.1.9,2,2,2h14.67v14.67c0,1.1.9,2,2,2h50c1.1,0,2-.9,2-2V18.67c0-1.1-.9-2-2-2ZM4,4h46v46H4V4ZM66.67,66.67H20.67v-12.67h31.33c1.1,0,2-.9,2-2v-31.33h12.67v46Z" style="fill: #000; stroke-width: 0px;"/>
4
- <polygon points="41 25 29 25 29 13 25 13 25 25 13 25 13 29 25 29 25 41 29 41 29 29 41 29 41 25" style="fill: #000; stroke-width: 0px;"/>
5
- </svg>
@@ -1,15 +0,0 @@
1
- <?xml version="1.0" encoding="UTF-8"?>
2
- <svg id="Layer_1" xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 70.6 61.5">
3
- <path d="M68.6,45.8v13.7H2v-13.7h66.6M70.6,43.8H0v17.7h70.6v-17.7h0Z"/>
4
- <path d="M68.6,24.2v13.7H2v-13.7h66.6M70.6,22.2H0v17.7h70.6v-17.7h0Z"/>
5
- <g>
6
- <polygon points="70.6 2.5 68.6 2.5 68.6 2 68.1 2 68.1 0 70.6 0 70.6 2.5"/>
7
- <path d="M65.3,2h-2.9V0h2.9v2ZM59.6,2h-2.9V0h2.9v2ZM53.9,2h-2.9V0h2.9v2ZM48.2,2h-2.9V0h2.9v2ZM42.4,2h-2.9V0h2.9v2ZM36.7,2h-2.9V0h2.9v2ZM31,2h-2.9V0h2.9v2ZM25.3,2h-2.9V0h2.9v2ZM19.6,2h-2.9V0h2.9v2ZM13.9,2h-2.9V0h2.9v2ZM8.2,2h-2.9V0h2.9v2Z"/>
8
- <polygon points="2 2.5 0 2.5 0 0 2.5 0 2.5 2 2 2 2 2.5"/>
9
- <path d="M2,13.4H0v-2.7h2v2.7ZM2,8H0v-2.7h2v2.7Z"/>
10
- <polygon points="2.5 18.7 0 18.7 0 16.2 2 16.2 2 16.7 2.5 16.7 2.5 18.7"/>
11
- <path d="M65.3,18.7h-2.9v-2h2.9v2ZM59.6,18.7h-2.9v-2h2.9v2ZM53.9,18.7h-2.9v-2h2.9v2ZM48.2,18.7h-2.9v-2h2.9v2ZM42.4,18.7h-2.9v-2h2.9v2ZM36.7,18.7h-2.9v-2h2.9v2ZM31,18.7h-2.9v-2h2.9v2ZM25.3,18.7h-2.9v-2h2.9v2ZM19.6,18.7h-2.9v-2h2.9v2ZM13.9,18.7h-2.9v-2h2.9v2ZM8.2,18.7h-2.9v-2h2.9v2Z"/>
12
- <polygon points="70.6 18.7 68.1 18.7 68.1 16.7 68.6 16.7 68.6 16.2 70.6 16.2 70.6 18.7"/>
13
- <path d="M70.6,13.4h-2v-2.7h2v2.7ZM70.6,8h-2v-2.7h2v2.7Z"/>
14
- </g>
15
- </svg>
@@ -1,15 +0,0 @@
1
- <?xml version="1.0" encoding="UTF-8"?>
2
- <svg id="Layer_1" xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 70.6 61.5">
3
- <g>
4
- <polygon points="70.6 45.3 68.6 45.3 68.6 44.8 68.1 44.8 68.1 42.8 70.6 42.8 70.6 45.3"/>
5
- <path d="M65.3,44.8h-2.9v-2h2.9v2ZM59.6,44.8h-2.9v-2h2.9v2ZM53.9,44.8h-2.9v-2h2.9v2ZM48.2,44.8h-2.9v-2h2.9v2ZM42.4,44.8h-2.9v-2h2.9v2ZM36.7,44.8h-2.9v-2h2.9v2ZM31,44.8h-2.9v-2h2.9v2ZM25.3,44.8h-2.9v-2h2.9v2ZM19.6,44.8h-2.9v-2h2.9v2ZM13.9,44.8h-2.9v-2h2.9v2ZM8.2,44.8h-2.9v-2h2.9v2Z"/>
6
- <polygon points="2 45.3 0 45.3 0 42.8 2.5 42.8 2.5 44.8 2 44.8 2 45.3"/>
7
- <path d="M2,56.3H0v-2.7h2v2.7ZM2,50.8H0v-2.7h2v2.7Z"/>
8
- <polygon points="2.5 61.5 0 61.5 0 59 2 59 2 59.5 2.5 59.5 2.5 61.5"/>
9
- <path d="M65.3,61.5h-2.9v-2h2.9v2ZM59.6,61.5h-2.9v-2h2.9v2ZM53.9,61.5h-2.9v-2h2.9v2ZM48.2,61.5h-2.9v-2h2.9v2ZM42.4,61.5h-2.9v-2h2.9v2ZM36.7,61.5h-2.9v-2h2.9v2ZM31,61.5h-2.9v-2h2.9v2ZM25.3,61.5h-2.9v-2h2.9v2ZM19.6,61.5h-2.9v-2h2.9v2ZM13.9,61.5h-2.9v-2h2.9v2ZM8.2,61.5h-2.9v-2h2.9v2Z"/>
10
- <polygon points="70.6 61.5 68.1 61.5 68.1 59.5 68.6 59.5 68.6 59 70.6 59 70.6 61.5"/>
11
- <path d="M70.6,56.3h-2v-2.7h2v2.7ZM70.6,50.8h-2v-2.7h2v2.7Z"/>
12
- </g>
13
- <path d="M68.6,23.7v13.7H2v-13.7h66.6M70.6,21.7H0v17.7h70.6v-17.7h0Z"/>
14
- <path d="M68.6,2v13.7H2V2h66.6M70.6,0H0v17.7h70.6V0h0Z"/>
15
- </svg>
@@ -1,4 +0,0 @@
1
- <?xml version="1.0" encoding="UTF-8"?>
2
- <svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 70.67 70.64">
3
- <path d="M70.08,33.9l-9.75-9.75-2.83,2.83,6.33,6.33h-26.51V6.81l6.33,6.33,2.83-2.83L36.75.56c-.75-.75-2.08-.75-2.83,0l-9.75,9.75,2.83,2.83,6.33-6.33v26.5H6.83l6.33-6.33-2.83-2.83L.59,33.9c-.38.38-.59.88-.59,1.41s.21,1.04.59,1.41l9.75,9.75,2.83-2.83-6.33-6.33h26.5v26.51l-6.33-6.33-2.83,2.83,9.75,9.75c.38.38.88.59,1.41.59s1.04-.21,1.41-.59l9.75-9.75-2.83-2.83-6.33,6.33v-26.51h26.51l-6.33,6.33,2.83,2.83,9.75-9.75c.38-.38.59-.88.59-1.41s-.21-1.04-.59-1.41Z" style="fill: #000; stroke-width: 0px;"/>
4
- </svg>
@@ -1,5 +0,0 @@
1
- <?xml version="1.0" encoding="UTF-8"?>
2
- <svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">
3
- <path d="M32,64C14.35,64,0,49.65,0,32S14.35,0,32,0s32,14.35,32,32-14.35,32-32,32ZM32,4c-15.44,0-28,12.56-28,28s12.56,28,28,28,28-12.56,28-28S47.44,4,32,4Z" style="fill: #000; stroke-width: 0px;"/>
4
- <polygon points="18,20 18,44 46,32" style="fill: #000; stroke-width: 0px;"/>
5
- </svg>
@@ -1,108 +0,0 @@
1
- import { computed, nextTick, ref, toValue, watch } from 'vue';
2
- /**
3
- * Window rows after filter/sort, and optionally walk {@link @stonecrop/schema#GetRecordsOptions} for the next page.
4
- * Pagination is not a filter — pass already-filtered rows.
5
- * @public
6
- */
7
- export function useTablePagination(options) {
8
- const heldRows = computed(() => toValue(options.rows));
9
- const pageSize = computed(() => toValue(options.pageSize));
10
- const sourceKey = computed(() => toValue(options.sourceKey));
11
- const windowIndex = ref(0);
12
- const loading = ref(false);
13
- const serverHasMore = ref(false);
14
- const hasEverHadMore = ref(false);
15
- const lastFetchOffset = ref(0);
16
- const lastPageLength = ref(0);
17
- const loadedCount = computed(() => heldRows.value.length);
18
- const effectivePageSize = computed(() => {
19
- const size = pageSize.value;
20
- if (size != null && size > 0) {
21
- return size;
22
- }
23
- // No pageSize: one window over everything held (server list or full child table).
24
- const count = heldRows.value.length;
25
- return count > 0 ? count : 1;
26
- });
27
- const windowCount = computed(() => Math.max(1, Math.ceil(heldRows.value.length / effectivePageSize.value)));
28
- const visibleRows = computed(() => {
29
- const start = windowIndex.value * effectivePageSize.value;
30
- return heldRows.value.slice(start, start + effectivePageSize.value);
31
- });
32
- const hasLocalNext = computed(() => windowIndex.value < windowCount.value - 1);
33
- const hasPrev = computed(() => windowIndex.value > 0);
34
- const hasNext = computed(() => hasLocalNext.value || (Boolean(options.getRecords) && serverHasMore.value));
35
- const hasMore = computed(() => serverHasMore.value);
36
- const showFooter = computed(() => {
37
- if (options.getRecords) {
38
- // Keep the footer after the last "Load more" so completion is visible, not silent.
39
- return serverHasMore.value || hasPrev.value || loading.value || (hasEverHadMore.value && !serverHasMore.value);
40
- }
41
- const size = pageSize.value;
42
- return size != null && size > 0 && heldRows.value.length > size;
43
- });
44
- const resetWindow = () => {
45
- windowIndex.value = 0;
46
- hasEverHadMore.value = false;
47
- };
48
- const fetchFromServer = async (fetchOptions) => {
49
- if (!options.getRecords) {
50
- return;
51
- }
52
- loading.value = true;
53
- try {
54
- const result = await options.getRecords(fetchOptions);
55
- serverHasMore.value = result.hasMore;
56
- if (result.hasMore) {
57
- hasEverHadMore.value = true;
58
- }
59
- lastFetchOffset.value = fetchOptions?.offset ?? 0;
60
- lastPageLength.value = result.data.length;
61
- }
62
- finally {
63
- loading.value = false;
64
- }
65
- };
66
- watch(() => sourceKey.value, () => {
67
- resetWindow();
68
- if (options.getRecords) {
69
- void fetchFromServer();
70
- }
71
- }, { immediate: true });
72
- watch(heldRows, () => {
73
- // Shrinking the held set can leave the window past the end.
74
- if (windowIndex.value >= windowCount.value) {
75
- windowIndex.value = Math.max(0, windowCount.value - 1);
76
- }
77
- });
78
- const next = async () => {
79
- if (hasLocalNext.value) {
80
- windowIndex.value += 1;
81
- return;
82
- }
83
- if (options.getRecords && serverHasMore.value) {
84
- await fetchFromServer({ offset: lastFetchOffset.value + lastPageLength.value });
85
- await nextTick();
86
- // Parent/HST grows rows; show the newly appended tail.
87
- windowIndex.value = Math.max(0, windowCount.value - 1);
88
- }
89
- };
90
- const prev = () => {
91
- if (windowIndex.value > 0) {
92
- windowIndex.value -= 1;
93
- }
94
- };
95
- return {
96
- visibleRows,
97
- hasPrev,
98
- hasNext,
99
- hasMore,
100
- loading,
101
- next,
102
- prev,
103
- showFooter,
104
- hasLocalNext,
105
- loadedCount,
106
- hasEverHadMore,
107
- };
108
- }
@@ -1,32 +0,0 @@
1
- /**
2
- * Icon exports for ATable row actions.
3
- * Icons are exported as raw SVG strings for flexibility in rendering.
4
- * @packageDocumentation
5
- */
6
- import AddIcon from './stonecrop-ui-icon-add.svg?raw';
7
- import DeleteIcon from './stonecrop-ui-icon-delete.svg?raw';
8
- import DuplicateIcon from './stonecrop-ui-icon-duplicate.svg?raw';
9
- import InsertAboveIcon from './stonecrop-ui-icon-insert-above.svg?raw';
10
- import InsertBelowIcon from './stonecrop-ui-icon-insert-below.svg?raw';
11
- import MoveIcon from './stonecrop-ui-icon-move.svg?raw';
12
- import OpenIcon from './stonecrop-ui-icon-open.svg?raw';
13
- // Directional move icons are inline (no dedicated SVG asset): simple up/down chevrons.
14
- const MoveUpIcon = '<svg viewBox="0 0 16 16" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M8 13V3.5M4.5 7 8 3.5 11.5 7" stroke-linecap="round" stroke-linejoin="round"/></svg>';
15
- const MoveDownIcon = '<svg viewBox="0 0 16 16" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M8 3v9.5M4.5 9 8 12.5 11.5 9" stroke-linecap="round" stroke-linejoin="round"/></svg>';
16
- export { AddIcon, DeleteIcon, DuplicateIcon, InsertAboveIcon, InsertBelowIcon, MoveIcon, OpenIcon };
17
- /**
18
- * Map of action types to their default icons.
19
- *
20
- * @public
21
- */
22
- export const actionIcons = {
23
- add: AddIcon,
24
- delete: DeleteIcon,
25
- duplicate: DuplicateIcon,
26
- insertAbove: InsertAboveIcon,
27
- insertBelow: InsertBelowIcon,
28
- move: MoveIcon,
29
- moveUp: MoveUpIcon,
30
- moveDown: MoveDownIcon,
31
- open: OpenIcon,
32
- };
package/dist/src/index.js DELETED
@@ -1,33 +0,0 @@
1
- import ACell from './components/ACell.vue';
2
- import AGanttCell from './components/AGanttCell.vue';
3
- import ARow from './components/ARow.vue';
4
- import ARowActions from './components/ARowActions.vue';
5
- import ATable from './components/ATable.vue';
6
- import ATableHeader from './components/ATableHeader.vue';
7
- import ATableLoading from './components/ATableLoading.vue';
8
- import ATableLoadingBar from './components/ATableLoadingBar.vue';
9
- import ATableModal from './components/ATableModal.vue';
10
- import ATablePaginationFooter from './components/ATablePaginationFooter.vue';
11
- export { createTableStore } from './stores/table';
12
- export { useTablePagination } from './composables/table-pagination';
13
- export { schemaToColumns } from './schemaToColumns';
14
- // Icon exports
15
- export { AddIcon, DeleteIcon, DuplicateIcon, InsertAboveIcon, InsertBelowIcon, MoveIcon, OpenIcon, actionIcons, } from './icons';
16
- /**
17
- * Install all ATable components
18
- * @param app - Vue app instance
19
- * @public
20
- */
21
- function install(app /* options */) {
22
- app.component('ACell', ACell);
23
- app.component('AGanttCell', AGanttCell);
24
- app.component('ARow', ARow);
25
- app.component('ARowActions', ARowActions);
26
- app.component('ATable', ATable);
27
- app.component('ATableHeader', ATableHeader);
28
- app.component('ATableLoading', ATableLoading);
29
- app.component('ATableLoadingBar', ATableLoadingBar);
30
- app.component('ATableModal', ATableModal);
31
- app.component('ATablePaginationFooter', ATablePaginationFooter);
32
- }
33
- export { ACell, AGanttCell, ARow, ARowActions, ATable, ATableHeader, ATableLoading, ATableLoadingBar, ATableModal, ATablePaginationFooter, install, };
@@ -1,44 +0,0 @@
1
- /**
2
- * Normalize a scalar cell value to a non-empty string, or nothing.
3
- *
4
- * Rejecting objects is what the haystack wants: a nested value has no single textual form, and
5
- * `String()` on one contributes `[object Object]`, which matches a search for "object" and nothing
6
- * a user would actually type.
7
- */
8
- function scalarText(value) {
9
- if (value == null || typeof value === 'object')
10
- return undefined;
11
- if (typeof value === 'string')
12
- return value === '' ? undefined : value;
13
- if (typeof value === 'number' || typeof value === 'boolean' || typeof value === 'bigint') {
14
- return String(value);
15
- }
16
- return undefined;
17
- }
18
- /**
19
- * Build the substring-search haystack for a link column cell.
20
- * Server middleware enriches inline FKs to `{ id, displayText }`; search both.
21
- * @public
22
- */
23
- export function linkSearchableText(cellValue) {
24
- if (cellValue == null || cellValue === '')
25
- return '';
26
- // `in` rather than an assertion to `Record<string, unknown>`: the assertion claims the value has
27
- // string keys of unknown type, which is narrower than `object` and so is a claim this function
28
- // cannot make about a cell it did not build.
29
- if (typeof cellValue === 'object') {
30
- const parts = [];
31
- if ('id' in cellValue) {
32
- const id = scalarText(cellValue.id);
33
- if (id !== undefined)
34
- parts.push(id);
35
- }
36
- if ('displayText' in cellValue) {
37
- const displayText = scalarText(cellValue.displayText);
38
- if (displayText !== undefined)
39
- parts.push(displayText);
40
- }
41
- return parts.join(' ');
42
- }
43
- return scalarText(cellValue) ?? '';
44
- }
@@ -1,27 +0,0 @@
1
- import { componentCategory } from '@stonecrop/schema';
2
- const CATEGORY_FILTER = {
3
- text: 'text',
4
- number: 'number',
5
- boolean: 'checkbox',
6
- date: 'date',
7
- datetime: 'dateRange',
8
- select: 'select',
9
- code: 'text',
10
- link: 'text',
11
- attach: 'text',
12
- quantity: 'number',
13
- currency: 'number',
14
- };
15
- /**
16
- * Resolve the filter widget and filter logic type for a column.
17
- * Explicit `filterType` wins; otherwise derive from the component category.
18
- * @public
19
- */
20
- export function resolveFilterType(column) {
21
- if (column.filterType)
22
- return column.filterType;
23
- const category = componentCategory(column.component);
24
- if (category)
25
- return CATEGORY_FILTER[category];
26
- return 'text';
27
- }
@@ -1,59 +0,0 @@
1
- import { componentCategory } from '@stonecrop/schema';
2
- import { formatCurrency, formatQuantity } from './utils';
3
- /**
4
- * Convert an array of doctype field descriptors into ATable column definitions.
5
- *
6
- * Fields are excluded when:
7
- * - `hidden: true` — field should not be visible in any view
8
- * - no `component` — non-scalar entry (nested table or fieldset), no column equivalent
9
- *
10
- * `fieldname` is renamed to `name`; `hidden` is stripped. All other `ColumnSchema` properties
11
- * spread through automatically.
12
- *
13
- * For link fields (those carrying `doctype`) without an explicit `cellComponent`:
14
- * - `linkDoctype` is set from the field's `doctype` property (used by ACell's async resolver).
15
- * - A synchronous `format` function is added (unless the field already has one) that handles
16
- * both bare ID strings and pre-resolved `{ id, displayText }` objects.
17
- *
18
- * For quantity fields — those whose `component` carries the `'quantity'` category — without an
19
- * explicit `format`, a synchronous `format` is added that renders the `{ qty, uom }` value (see
20
- * `QuantityValue` in `@stonecrop/aform`) as `"<qty> <uom>"`.
21
- *
22
- * For currency fields — those whose `component` carries the `'currency'` category — without an
23
- * explicit `format`, a synchronous `format` is added that renders the `{ amount, currency }` value
24
- * (see `CurrencyValue` in `@stonecrop/aform`) as `"<amount> <currency>"`.
25
- *
26
- * @public
27
- */
28
- export function schemaToColumns(schema) {
29
- return schema
30
- .filter(f => !f.hidden && f.component)
31
- .map(({ fieldname, hidden: _hidden, ...rest }) => {
32
- const col = Object.assign({ name: fieldname }, rest);
33
- // Link fields: store the linked doctype for async resolution by ACell, and add a sync
34
- // format that handles pre-resolved AFormLinkValue objects.
35
- if (rest.doctype && !rest.cellComponent) {
36
- col.linkDoctype = rest.doctype;
37
- if (!rest.format) {
38
- col.format = (v) => {
39
- if (v === null || v === undefined)
40
- return '';
41
- if (typeof v === 'object') {
42
- const display = v.displayText ?? v.id ?? '';
43
- return typeof display === 'string' || typeof display === 'number' ? String(display) : '';
44
- }
45
- return String(v);
46
- };
47
- }
48
- }
49
- // Quantity fields: render the composite { qty, uom } value as "<qty> <uom>".
50
- if (componentCategory(rest.component) === 'quantity' && !rest.format) {
51
- col.format = formatQuantity;
52
- }
53
- // Currency fields: render the composite { amount, currency } value as "<amount> <currency>".
54
- if (componentCategory(rest.component) === 'currency' && !rest.format) {
55
- col.format = formatCurrency;
56
- }
57
- return col;
58
- });
59
- }