@stonecrop/atable 0.13.14 → 0.14.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.
- package/README.md +12 -11
- package/dist/assets/index.css +1 -1
- package/dist/atable.d.ts +533 -20
- package/dist/atable.js +1557 -1552
- package/dist/atable.js.map +1 -1
- package/dist/probe.tsbuildinfo +1 -0
- package/dist/src/icons/index.d.ts.map +1 -1
- package/dist/src/icons/index.js +5 -0
- package/dist/src/index.d.ts +1 -2
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +1 -3
- package/dist/src/schemaToColumns.d.ts +2 -2
- package/dist/src/schemaToColumns.d.ts.map +1 -1
- package/dist/src/schemaToColumns.js +7 -10
- package/dist/src/stores/table.d.ts +523 -12
- package/dist/src/stores/table.d.ts.map +1 -1
- package/dist/src/stores/table.js +17 -12
- package/dist/src/types/index.d.ts +14 -3
- package/dist/src/types/index.d.ts.map +1 -1
- package/package.json +6 -4
- package/src/components/ACell.vue +12 -10
- package/src/components/ARow.vue +61 -11
- package/src/components/ARowActions.vue +43 -15
- package/src/components/ATable.vue +18 -2
- package/src/components/ATableColumnFilter.vue +19 -18
- package/src/components/ATableHeader.vue +0 -2
- package/src/components/ATableModal.vue +0 -2
- package/src/icons/index.ts +8 -0
- package/src/index.ts +0 -3
- package/src/schemaToColumns.ts +7 -9
- package/src/stores/table.ts +14 -12
- package/src/types/index.ts +16 -3
- package/src/components/AExpansionRow.vue +0 -105
package/src/icons/index.ts
CHANGED
|
@@ -12,6 +12,12 @@ import InsertBelowIcon from './stonecrop-ui-icon-insert-below.svg?raw'
|
|
|
12
12
|
import MoveIcon from './stonecrop-ui-icon-move.svg?raw'
|
|
13
13
|
import OpenIcon from './stonecrop-ui-icon-open.svg?raw'
|
|
14
14
|
|
|
15
|
+
// Directional move icons are inline (no dedicated SVG asset): simple up/down chevrons.
|
|
16
|
+
const MoveUpIcon =
|
|
17
|
+
'<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>'
|
|
18
|
+
const MoveDownIcon =
|
|
19
|
+
'<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>'
|
|
20
|
+
|
|
15
21
|
export { AddIcon, DeleteIcon, DuplicateIcon, InsertAboveIcon, InsertBelowIcon, MoveIcon, OpenIcon }
|
|
16
22
|
|
|
17
23
|
/**
|
|
@@ -26,5 +32,7 @@ export const actionIcons: Record<string, string> = {
|
|
|
26
32
|
insertAbove: InsertAboveIcon,
|
|
27
33
|
insertBelow: InsertBelowIcon,
|
|
28
34
|
move: MoveIcon,
|
|
35
|
+
moveUp: MoveUpIcon,
|
|
36
|
+
moveDown: MoveDownIcon,
|
|
29
37
|
open: OpenIcon,
|
|
30
38
|
}
|
package/src/index.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { App } from 'vue'
|
|
2
2
|
|
|
3
3
|
import ACell from './components/ACell.vue'
|
|
4
|
-
import AExpansionRow from './components/AExpansionRow.vue'
|
|
5
4
|
import AGanttCell from './components/AGanttCell.vue'
|
|
6
5
|
import ARow from './components/ARow.vue'
|
|
7
6
|
import ARowActions from './components/ARowActions.vue'
|
|
@@ -34,7 +33,6 @@ export {
|
|
|
34
33
|
*/
|
|
35
34
|
function install(app: App /* options */) {
|
|
36
35
|
app.component('ACell', ACell)
|
|
37
|
-
app.component('AExpansionRow', AExpansionRow)
|
|
38
36
|
app.component('AGanttCell', AGanttCell)
|
|
39
37
|
app.component('ARow', ARow)
|
|
40
38
|
app.component('ARowActions', ARowActions)
|
|
@@ -47,7 +45,6 @@ function install(app: App /* options */) {
|
|
|
47
45
|
|
|
48
46
|
export {
|
|
49
47
|
ACell,
|
|
50
|
-
AExpansionRow,
|
|
51
48
|
AGanttCell,
|
|
52
49
|
ARow,
|
|
53
50
|
ARowActions,
|
package/src/schemaToColumns.ts
CHANGED
|
@@ -7,12 +7,12 @@ import type { TableColumn } from './types'
|
|
|
7
7
|
*
|
|
8
8
|
* Fields are excluded when:
|
|
9
9
|
* - `hidden: true` — field should not be visible in any view
|
|
10
|
-
* - no `
|
|
10
|
+
* - no `component` — non-scalar entry (nested table or fieldset), no column equivalent
|
|
11
11
|
*
|
|
12
12
|
* `fieldname` is renamed to `name`; `hidden` is stripped. All other `ColumnSchema` properties
|
|
13
13
|
* spread through automatically.
|
|
14
14
|
*
|
|
15
|
-
* For
|
|
15
|
+
* For link fields (those carrying `doctype`) without an explicit `cellComponent`:
|
|
16
16
|
* - `linkDoctype` is set from the field's `doctype` property (used by ACell's async resolver).
|
|
17
17
|
* - A synchronous `format` function is added (unless the field already has one) that handles
|
|
18
18
|
* both bare ID strings and pre-resolved `{ id, displayText }` objects.
|
|
@@ -21,16 +21,14 @@ import type { TableColumn } from './types'
|
|
|
21
21
|
*/
|
|
22
22
|
export function schemaToColumns(schema: ColumnSchema[]): TableColumn[] {
|
|
23
23
|
return schema
|
|
24
|
-
.filter(f => !f.hidden && f.
|
|
24
|
+
.filter(f => !f.hidden && f.component)
|
|
25
25
|
.map(({ fieldname, hidden: _hidden, ...rest }) => {
|
|
26
26
|
const col: TableColumn = Object.assign({ name: fieldname }, rest)
|
|
27
27
|
|
|
28
|
-
// Link fields: store the linked doctype for async resolution by ACell,
|
|
29
|
-
//
|
|
30
|
-
if (rest.
|
|
31
|
-
|
|
32
|
-
const linkedDoctype = typeof fields.doctype === 'string' ? fields.doctype : undefined
|
|
33
|
-
if (linkedDoctype) col.linkDoctype = linkedDoctype
|
|
28
|
+
// Link fields: store the linked doctype for async resolution by ACell, and add a sync
|
|
29
|
+
// format that handles pre-resolved AFormLinkValue objects.
|
|
30
|
+
if (rest.doctype && !rest.cellComponent) {
|
|
31
|
+
col.linkDoctype = rest.doctype
|
|
34
32
|
|
|
35
33
|
if (!rest.format) {
|
|
36
34
|
col.format = (v: any): string => {
|
package/src/stores/table.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { defineStore } from 'pinia'
|
|
2
|
+
import { componentCategory } from '@stonecrop/schema'
|
|
2
3
|
import { type CSSProperties, computed, ref } from 'vue'
|
|
3
4
|
|
|
4
5
|
import type {
|
|
@@ -127,7 +128,12 @@ function applyFilter(cellValue: any, filter: FilterState, column: TableColumn):
|
|
|
127
128
|
}
|
|
128
129
|
}
|
|
129
130
|
|
|
130
|
-
|
|
131
|
+
/**
|
|
132
|
+
* Compute the CSS indentation for a tree-table cell. Pure helper (captures no store state);
|
|
133
|
+
* imported directly by cell components rather than exposed on the store's public return.
|
|
134
|
+
* @internal
|
|
135
|
+
*/
|
|
136
|
+
export function getIndent(colIndex: number, indentLevel?: number): string {
|
|
131
137
|
if (indentLevel && colIndex === 0 && indentLevel > 0) {
|
|
132
138
|
return `${indentLevel}ch`
|
|
133
139
|
} else {
|
|
@@ -509,16 +515,13 @@ export const createTableStore = (initData: {
|
|
|
509
515
|
const format = column.format
|
|
510
516
|
|
|
511
517
|
if (!format) {
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
default:
|
|
520
|
-
return value
|
|
521
|
-
}
|
|
518
|
+
// Default cell formatting comes from the component's category; anything without an
|
|
519
|
+
// opinion (including an unknown component) renders the raw value.
|
|
520
|
+
const category = componentCategory(column.component)
|
|
521
|
+
if (category === 'boolean') return value ? '✓' : '✗'
|
|
522
|
+
if (category === 'date') return value != null ? new Date(String(value)).toLocaleDateString() : value
|
|
523
|
+
if (category === 'datetime') return value != null ? new Date(String(value)).toLocaleString() : value
|
|
524
|
+
return value
|
|
522
525
|
}
|
|
523
526
|
|
|
524
527
|
if (typeof format === 'function') {
|
|
@@ -922,7 +925,6 @@ export const createTableStore = (initData: {
|
|
|
922
925
|
getFormattedValue,
|
|
923
926
|
getHandlesForBar,
|
|
924
927
|
getHeaderCellStyle,
|
|
925
|
-
getIndent,
|
|
926
928
|
getRowExpandSymbol,
|
|
927
929
|
insertRowAbove,
|
|
928
930
|
insertRowBelow,
|
package/src/types/index.ts
CHANGED
|
@@ -8,7 +8,7 @@ import { createTableStore } from '../stores/table'
|
|
|
8
8
|
/**
|
|
9
9
|
* Runtime column definition for ATable.
|
|
10
10
|
*
|
|
11
|
-
* Extends `ColumnSchema` from `@stonecrop/schema` — all authoring properties (`label`, `
|
|
11
|
+
* Extends `ColumnSchema` from `@stonecrop/schema` — all authoring properties (`label`, `component`, `width`,
|
|
12
12
|
* `pinned`, filter config, cell/modal component names, etc.) are inherited. The overrides
|
|
13
13
|
* below widen three properties for runtime use (live functions, broader alignment values)
|
|
14
14
|
* and add two runtime-only additions (`mask`, `originalIndex`).
|
|
@@ -45,7 +45,7 @@ export interface TableColumn extends Omit<ColumnSchema, 'fieldname' | 'hidden' |
|
|
|
45
45
|
mask?: (value: any) => any
|
|
46
46
|
|
|
47
47
|
/**
|
|
48
|
-
* For
|
|
48
|
+
* For link columns (those carrying `doctype`): the target doctype slug used by the `linkResolver`
|
|
49
49
|
* to look up display text for bare ID values. Set automatically by `schemaToColumns`
|
|
50
50
|
* from the field's `doctype` property.
|
|
51
51
|
*/
|
|
@@ -83,7 +83,8 @@ export interface CellContext {
|
|
|
83
83
|
* Row action type identifiers.
|
|
84
84
|
* @public
|
|
85
85
|
*/
|
|
86
|
-
export type RowActionType =
|
|
86
|
+
export type RowActionType =
|
|
87
|
+
'open' | 'add' | 'delete' | 'duplicate' | 'insertAbove' | 'insertBelow' | 'move' | 'moveUp' | 'moveDown'
|
|
87
88
|
|
|
88
89
|
/**
|
|
89
90
|
* Options for configuring individual row actions.
|
|
@@ -115,6 +116,16 @@ export interface RowActionOptions {
|
|
|
115
116
|
* @returns void or false to prevent default behavior
|
|
116
117
|
*/
|
|
117
118
|
handler?: (rowIndex: number, store: ReturnType<typeof createTableStore>) => void | boolean
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Per-row predicate to disable this action for specific rows (e.g. a lock-aware delete, or
|
|
122
|
+
* move-up on the first row). Returns true to render the action disabled. Evaluated reactively
|
|
123
|
+
* against the store, so it updates as rows change.
|
|
124
|
+
*
|
|
125
|
+
* @param rowIndex - The index of the row
|
|
126
|
+
* @param store - The table store instance
|
|
127
|
+
*/
|
|
128
|
+
disabled?: (rowIndex: number, store: ReturnType<typeof createTableStore>) => boolean
|
|
118
129
|
}
|
|
119
130
|
|
|
120
131
|
/**
|
|
@@ -163,6 +174,8 @@ export interface RowActionsConfig {
|
|
|
163
174
|
insertAbove?: boolean | RowActionOptions
|
|
164
175
|
insertBelow?: boolean | RowActionOptions
|
|
165
176
|
move?: boolean | RowActionOptions
|
|
177
|
+
moveUp?: boolean | RowActionOptions
|
|
178
|
+
moveDown?: boolean | RowActionOptions
|
|
166
179
|
}
|
|
167
180
|
}
|
|
168
181
|
|
|
@@ -1,105 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<tr v-bind="$attrs" ref="rowEl" :tabindex="tabIndex" class="expandable-row">
|
|
3
|
-
<td :tabIndex="-1" class="row-index" @click="store.toggleRowExpand(rowIndex)">
|
|
4
|
-
{{ rowExpandSymbol }}
|
|
5
|
-
</td>
|
|
6
|
-
<slot name="row" />
|
|
7
|
-
</tr>
|
|
8
|
-
<tr v-if="store.display[rowIndex].expanded" ref="rowExpanded" :tabindex="tabIndex" class="expanded-row">
|
|
9
|
-
<td :tabIndex="-1" :colspan="store.columns.length + 1" class="expanded-row-content">
|
|
10
|
-
<slot name="content" />
|
|
11
|
-
</td>
|
|
12
|
-
</tr>
|
|
13
|
-
</template>
|
|
14
|
-
|
|
15
|
-
<script setup lang="ts">
|
|
16
|
-
import { defaultKeypressHandlers, type KeypressHandlers, useKeyboardNav } from '@stonecrop/utilities'
|
|
17
|
-
import { computed, useTemplateRef } from 'vue'
|
|
18
|
-
|
|
19
|
-
import { createTableStore } from '../stores/table'
|
|
20
|
-
|
|
21
|
-
const {
|
|
22
|
-
rowIndex,
|
|
23
|
-
store,
|
|
24
|
-
tabIndex = -1,
|
|
25
|
-
addNavigation = defaultKeypressHandlers,
|
|
26
|
-
} = defineProps<{
|
|
27
|
-
rowIndex: number
|
|
28
|
-
store: ReturnType<typeof createTableStore>
|
|
29
|
-
tabIndex?: number
|
|
30
|
-
addNavigation?: boolean | KeypressHandlers
|
|
31
|
-
}>()
|
|
32
|
-
|
|
33
|
-
const rowRef = useTemplateRef<HTMLTableRowElement>('rowEl')
|
|
34
|
-
// const expandedRowRef = useTemplateRef<HTMLDivElement>('rowExpanded')
|
|
35
|
-
|
|
36
|
-
const rowExpandSymbol = computed(() => {
|
|
37
|
-
return store.display[rowIndex].expanded ? '▼' : '►'
|
|
38
|
-
})
|
|
39
|
-
|
|
40
|
-
if (addNavigation) {
|
|
41
|
-
const handlers: KeypressHandlers = {
|
|
42
|
-
'keydown.control.g': (event: KeyboardEvent) => {
|
|
43
|
-
event.stopPropagation()
|
|
44
|
-
event.preventDefault()
|
|
45
|
-
store.toggleRowExpand(rowIndex)
|
|
46
|
-
},
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
if (typeof addNavigation === 'object') {
|
|
50
|
-
Object.assign(handlers, addNavigation)
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
useKeyboardNav([
|
|
54
|
-
{
|
|
55
|
-
selectors: rowRef,
|
|
56
|
-
handlers: handlers,
|
|
57
|
-
},
|
|
58
|
-
])
|
|
59
|
-
}
|
|
60
|
-
</script>
|
|
61
|
-
|
|
62
|
-
<style>
|
|
63
|
-
@import url('@stonecrop/themes/default.css');
|
|
64
|
-
|
|
65
|
-
.row-index {
|
|
66
|
-
color: var(--sc-header-text-color);
|
|
67
|
-
font-weight: bold;
|
|
68
|
-
text-align: center;
|
|
69
|
-
user-select: none;
|
|
70
|
-
width: 2ch;
|
|
71
|
-
display: flex;
|
|
72
|
-
align-items: center;
|
|
73
|
-
justify-content: center;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
.expandable-row {
|
|
77
|
-
border-top: 1px solid var(--sc-row-border-color);
|
|
78
|
-
height: var(--sc-atable-row-height);
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
.expandable-row > td:first-child {
|
|
82
|
-
border-left: 4px solid var(--sc-row-border-color);
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
.expanded-row {
|
|
86
|
-
border-left: 2px solid var(--sc-row-border-color);
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
.expandable-row:last-child {
|
|
90
|
-
border-bottom: 1px solid var(--sc-row-border-color);
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
.expanded-row-content {
|
|
94
|
-
border-top: 1px solid var(--sc-row-border-color);
|
|
95
|
-
padding: 1.5rem;
|
|
96
|
-
}
|
|
97
|
-
</style>
|
|
98
|
-
|
|
99
|
-
<style scoped>
|
|
100
|
-
.expandable-row.changed-row-gradient:has(td.cell-modified) {
|
|
101
|
-
--cell-color-start: color-mix(in srgb, var(--sc-cell-changed-color), #fff 20%);
|
|
102
|
-
--cell-color-end: color-mix(in srgb, var(--sc-cell-changed-color), #fff 60%);
|
|
103
|
-
background: linear-gradient(90deg, var(--cell-color-start), var(--cell-color-end));
|
|
104
|
-
}
|
|
105
|
-
</style>
|