@stonecrop/atable 0.2.63 → 0.2.64

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.
@@ -0,0 +1,208 @@
1
+ import { defineStore } from 'pinia'
2
+ import { type CSSProperties, computed, ref } from 'vue'
3
+
4
+ import type { CellContext, TableColumn, TableConfig, TableDisplay, TableModal, TableRow } from '@/types'
5
+
6
+ export const createTableStore = (initData: {
7
+ columns: TableColumn[]
8
+ rows: TableRow[]
9
+ id?: string
10
+ config?: TableConfig
11
+ table?: { [key: string]: any }
12
+ display?: TableDisplay[]
13
+ modal?: TableModal
14
+ }) => {
15
+ const id = initData.id || crypto.randomUUID()
16
+ const createStore = defineStore(`table-${id}`, () => {
17
+ // util functions
18
+ const createTableObject = () => {
19
+ const table = {}
20
+ for (const [colIndex, column] of columns.value.entries()) {
21
+ for (const [rowIndex, row] of rows.value.entries()) {
22
+ table[`${colIndex}:${rowIndex}`] = row[column.name]
23
+ }
24
+ }
25
+ return table
26
+ }
27
+
28
+ const createDisplayObject = (display?: TableDisplay[]) => {
29
+ const defaultDisplay: TableDisplay[] = [Object.assign({}, { rowModified: false })]
30
+
31
+ // TODO: (typing) what is the type of `display` here?
32
+ if (display) {
33
+ if ('0:0' in display) {
34
+ return display
35
+ }
36
+ // else if ('default' in display) {
37
+ // // TODO: (typing) what is the possible input here for 'default'?
38
+ // defaultDisplay = display.default
39
+ // }
40
+ }
41
+
42
+ // TODO: (typing) is this type correct for the parent set?
43
+ const parents = new Set<string | number>()
44
+ for (let rowIndex = rows.value.length - 1; rowIndex >= 0; rowIndex--) {
45
+ const row = rows.value[rowIndex]
46
+ if (row.parent) {
47
+ parents.add(row.parent)
48
+ }
49
+
50
+ defaultDisplay[rowIndex] = {
51
+ childrenOpen: false,
52
+ expanded: false,
53
+ indent: row.indent || null,
54
+ isParent: parents.has(rowIndex),
55
+ isRoot: row.parent === null || row.parent === undefined,
56
+ rowModified: false,
57
+ open: row.parent === null || row.parent === undefined,
58
+ parent: row.parent,
59
+ }
60
+ }
61
+
62
+ return defaultDisplay
63
+ }
64
+
65
+ // state
66
+ const columns = ref(initData.columns)
67
+ const rows = ref(initData.rows)
68
+ const config = ref(initData.config || {})
69
+ const table = ref(initData.table || createTableObject())
70
+ const display = ref(createDisplayObject(initData.display))
71
+ const modal = ref(initData.modal || { visible: false })
72
+
73
+ // getters
74
+ const hasPinnedColumns = computed(() => columns.value.some(col => col.pinned))
75
+
76
+ const numberedRowWidth = computed(() => {
77
+ const indent = Math.ceil(rows.value.length / 100 + 1)
78
+ return `${indent}ch`
79
+ })
80
+
81
+ const zeroColumn = computed(() => ['list', 'tree', 'list-expansion'].includes(config.value.view))
82
+
83
+ // actions
84
+ const getCellData = <T = any>(colIndex: number, rowIndex: number): T => table.value[`${colIndex}:${rowIndex}`]
85
+ const setCellData = (colIndex: number, rowIndex: number, value: any) => {
86
+ const index = `${colIndex}:${rowIndex}`
87
+ const col = columns.value[colIndex]
88
+
89
+ if (table.value[index] !== value) {
90
+ display.value[rowIndex].rowModified = true
91
+ }
92
+
93
+ table.value[index] = value
94
+ rows.value[rowIndex][col.name] = value
95
+ }
96
+
97
+ const getHeaderCellStyle = (column: TableColumn): CSSProperties => ({
98
+ minWidth: column.width || '40ch',
99
+ textAlign: column.align || 'center',
100
+ width: config.value.fullWidth ? 'auto' : null,
101
+ })
102
+
103
+ const isRowVisible = (rowIndex: number) => {
104
+ return config.value.view !== 'tree' || display.value[rowIndex].isRoot || display.value[rowIndex].open
105
+ }
106
+
107
+ const getRowExpandSymbol = (rowIndex: number) => {
108
+ if (config.value.view !== 'tree') {
109
+ return ''
110
+ }
111
+
112
+ if (display.value[rowIndex].isRoot || display.value[rowIndex].isParent) {
113
+ return display.value[rowIndex].childrenOpen ? '-' : '+'
114
+ }
115
+
116
+ return ''
117
+ }
118
+
119
+ const toggleRowExpand = (rowIndex: number) => {
120
+ if (config.value.view === 'tree') {
121
+ display.value[rowIndex].childrenOpen = !display.value[rowIndex].childrenOpen
122
+ for (let index = rows.value.length - 1; index >= 0; index--) {
123
+ if (display.value[index].parent === rowIndex) {
124
+ display.value[index].open = !display.value[index].open
125
+ if (display.value[index].childrenOpen) {
126
+ toggleRowExpand(index)
127
+ }
128
+ }
129
+ }
130
+ } else if (config.value.view === 'list-expansion') {
131
+ display.value[rowIndex].expanded = !display.value[rowIndex].expanded
132
+ }
133
+ }
134
+
135
+ const getCellDisplayValue = (colIndex: number, rowIndex: number) => {
136
+ const cellData = getCellData(colIndex, rowIndex)
137
+ return getFormattedValue(colIndex, rowIndex, cellData)
138
+ }
139
+
140
+ const getFormattedValue = (colIndex: number, rowIndex: number, value: any) => {
141
+ const column = columns.value[colIndex]
142
+ const row = rows.value[rowIndex]
143
+ const format = column.format
144
+
145
+ if (!format) {
146
+ return value
147
+ }
148
+
149
+ if (typeof format === 'function') {
150
+ return format(value, { table: table.value, row, column })
151
+ } else if (typeof format === 'string') {
152
+ // parse format function from string
153
+ // eslint-disable-next-line @typescript-eslint/no-implied-eval
154
+ const formatFn: (value: any, context?: CellContext) => string = Function(`"use strict";return (${format})`)()
155
+ return formatFn(value, { table: table.value, row, column })
156
+ }
157
+
158
+ return value
159
+ }
160
+
161
+ const closeModal = (event: MouseEvent) => {
162
+ if (!(event.target instanceof Node)) {
163
+ // if the target is not a node, it's probably a custom click event to Document or Window
164
+ // err on the side of closing the modal in that case
165
+ if (modal.value.visible) modal.value.visible = false
166
+ } else if (!modal.value.parent?.contains(event.target)) {
167
+ if (modal.value.visible) modal.value.visible = false
168
+ }
169
+ }
170
+
171
+ const getIndent = (colIndex: number, indentLevel?: number) => {
172
+ if (indentLevel && colIndex === 0 && indentLevel > 0) {
173
+ return `${indentLevel}ch`
174
+ } else {
175
+ return 'inherit'
176
+ }
177
+ }
178
+
179
+ return {
180
+ // state
181
+ columns,
182
+ rows,
183
+ config,
184
+ table,
185
+ display,
186
+ modal,
187
+
188
+ // getters
189
+ hasPinnedColumns,
190
+ numberedRowWidth,
191
+ zeroColumn,
192
+
193
+ // actions
194
+ closeModal,
195
+ getCellData,
196
+ getCellDisplayValue,
197
+ getFormattedValue,
198
+ getHeaderCellStyle,
199
+ getIndent,
200
+ getRowExpandSymbol,
201
+ isRowVisible,
202
+ setCellData,
203
+ toggleRowExpand,
204
+ }
205
+ })
206
+
207
+ return createStore()
208
+ }
@@ -1,5 +1,3 @@
1
- import TableDataStore from '@/components'
2
-
3
1
  export type TableColumn = {
4
2
  name: string
5
3
 
@@ -22,7 +20,7 @@ export type TableColumn = {
22
20
  export type CellContext = {
23
21
  row: TableRow
24
22
  column: TableColumn
25
- table: TableDataStore['table']
23
+ table: { [key: string]: any }
26
24
  }
27
25
 
28
26
  export type TableConfig = {
@@ -1,97 +0,0 @@
1
- import { computed, reactive } from 'vue';
2
- export default class TableDataStore {
3
- id;
4
- rows;
5
- columns;
6
- config;
7
- table;
8
- display;
9
- modal;
10
- constructor(id, columns, rows, config, table, display) {
11
- this.id = id || crypto.randomUUID();
12
- this.rows = rows;
13
- this.columns = reactive(columns);
14
- this.config = reactive(config);
15
- this.table = table || reactive(this.createTableObject());
16
- this.display = this.createDisplayObject(display);
17
- this.modal = reactive({ visible: false });
18
- }
19
- createTableObject() {
20
- const table = {};
21
- for (const [colIndex, column] of this.columns.entries()) {
22
- for (const [rowIndex, row] of this.rows.entries()) {
23
- table[`${colIndex}:${rowIndex}`] = row[column.name];
24
- }
25
- }
26
- return table;
27
- }
28
- createDisplayObject(display) {
29
- const defaultDisplay = [Object.assign({}, { rowModified: false })];
30
- // TODO: (typing) what is the type of `display` here?
31
- if (display) {
32
- if ('0:0' in display) {
33
- return display;
34
- }
35
- // else if ('default' in display) {
36
- // // TODO: (typing) what is the possible input here for 'default'?
37
- // defaultDisplay = display.default
38
- // }
39
- }
40
- // TODO: (typing) is this type correct for the parent set?
41
- const parents = new Set();
42
- for (let rowIndex = this.rows.length - 1; rowIndex >= 0; rowIndex--) {
43
- const row = this.rows[rowIndex];
44
- if (row.parent) {
45
- parents.add(row.parent);
46
- }
47
- defaultDisplay[rowIndex] = {
48
- childrenOpen: false,
49
- expanded: false,
50
- indent: row.indent || null,
51
- isParent: parents.has(rowIndex),
52
- isRoot: row.parent === null || row.parent === undefined,
53
- rowModified: false,
54
- open: row.parent === null || row.parent === undefined,
55
- parent: row.parent,
56
- };
57
- }
58
- return reactive(defaultDisplay);
59
- }
60
- get zeroColumn() {
61
- return ['list', 'tree', 'list-expansion'].includes(this.config.view);
62
- }
63
- get numberedRowWidth() {
64
- return computed(() => {
65
- return String(Math.ceil(this.rows.length / 100) + 1) + 'ch';
66
- });
67
- }
68
- cellData(colIndex, rowIndex) {
69
- return this.table[`${colIndex}:${rowIndex}`];
70
- }
71
- setCellData(rowIndex, colIndex, value) {
72
- const index = `${colIndex}:${rowIndex}`;
73
- const col = this.columns[colIndex];
74
- if (this.table[index] !== value) {
75
- this.display[rowIndex].rowModified = true;
76
- }
77
- this.table[index] = value;
78
- this.rows[rowIndex][col.name] = value;
79
- return this.table[index];
80
- }
81
- toggleRowExpand(rowIndex) {
82
- if (this.config.view === 'tree') {
83
- this.display[rowIndex].childrenOpen = !this.display[rowIndex].childrenOpen;
84
- for (let index = this.rows.length - 1; index >= 0; index--) {
85
- if (this.display[index].parent === rowIndex) {
86
- this.display[index].open = !this.display[index].open;
87
- if (this.display[index].childrenOpen) {
88
- this.toggleRowExpand(index);
89
- }
90
- }
91
- }
92
- }
93
- else if (this.config.view === 'list-expansion') {
94
- this.display[rowIndex].expanded = !this.display[rowIndex].expanded;
95
- }
96
- }
97
- }
@@ -1,23 +0,0 @@
1
- import type { TableDisplay, TableRow, TableColumn, TableConfig, TableModal } from '@/types';
2
- export default class TableDataStore {
3
- id: string;
4
- rows: TableRow[];
5
- columns: TableColumn[];
6
- config: TableConfig;
7
- table: {
8
- [key: string]: any;
9
- };
10
- display: TableDisplay[];
11
- modal: TableModal;
12
- constructor(id?: string, columns?: TableColumn[], rows?: TableRow[], config?: TableConfig, table?: {
13
- [key: string]: any;
14
- }, display?: TableDisplay[]);
15
- createTableObject(): {};
16
- createDisplayObject(display?: TableDisplay[]): (TableDisplay[] & Record<"0:0", unknown>) | import("vue").Reactive<TableDisplay[]>;
17
- get zeroColumn(): boolean;
18
- get numberedRowWidth(): import("vue").ComputedRef<string>;
19
- cellData<T>(colIndex: number, rowIndex: number): T;
20
- setCellData(rowIndex: number, colIndex: number, value: any): any;
21
- toggleRowExpand(rowIndex: number): void;
22
- }
23
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,QAAQ,EAAE,WAAW,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AAE3F,MAAM,CAAC,OAAO,OAAO,cAAc;IAClC,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,QAAQ,EAAE,CAAA;IAChB,OAAO,EAAE,WAAW,EAAE,CAAA;IACtB,MAAM,EAAE,WAAW,CAAA;IACnB,KAAK,EAAE;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;KAAE,CAAA;IAC7B,OAAO,EAAE,YAAY,EAAE,CAAA;IACvB,KAAK,EAAE,UAAU,CAAA;gBAGhB,EAAE,CAAC,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,WAAW,EAAE,EACvB,IAAI,CAAC,EAAE,QAAQ,EAAE,EACjB,MAAM,CAAC,EAAE,WAAW,EACpB,KAAK,CAAC,EAAE;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;KAAE,EAC9B,OAAO,CAAC,EAAE,YAAY,EAAE;IAWzB,iBAAiB;IAUjB,mBAAmB,CAAC,OAAO,CAAC,EAAE,YAAY,EAAE;IAqC5C,IAAI,UAAU,YAEb;IAED,IAAI,gBAAgB,sCAInB;IAED,QAAQ,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,CAAC;IAIlD,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG;IAa1D,eAAe,CAAC,QAAQ,EAAE,MAAM;CAehC"}
@@ -1,120 +0,0 @@
1
- import { computed, reactive } from 'vue'
2
-
3
- import type { TableDisplay, TableRow, TableColumn, TableConfig, TableModal } from '@/types'
4
-
5
- export default class TableDataStore {
6
- id: string
7
- rows: TableRow[]
8
- columns: TableColumn[]
9
- config: TableConfig
10
- table: { [key: string]: any }
11
- display: TableDisplay[]
12
- modal: TableModal
13
-
14
- constructor(
15
- id?: string,
16
- columns?: TableColumn[],
17
- rows?: TableRow[],
18
- config?: TableConfig,
19
- table?: { [key: string]: any },
20
- display?: TableDisplay[]
21
- ) {
22
- this.id = id || crypto.randomUUID()
23
- this.rows = rows
24
- this.columns = reactive(columns)
25
- this.config = reactive(config)
26
- this.table = table || reactive(this.createTableObject())
27
- this.display = this.createDisplayObject(display)
28
- this.modal = reactive({ visible: false })
29
- }
30
-
31
- createTableObject() {
32
- const table = {}
33
- for (const [colIndex, column] of this.columns.entries()) {
34
- for (const [rowIndex, row] of this.rows.entries()) {
35
- table[`${colIndex}:${rowIndex}`] = row[column.name]
36
- }
37
- }
38
- return table
39
- }
40
-
41
- createDisplayObject(display?: TableDisplay[]) {
42
- const defaultDisplay: TableDisplay[] = [Object.assign({}, { rowModified: false })]
43
-
44
- // TODO: (typing) what is the type of `display` here?
45
- if (display) {
46
- if ('0:0' in display) {
47
- return display
48
- }
49
- // else if ('default' in display) {
50
- // // TODO: (typing) what is the possible input here for 'default'?
51
- // defaultDisplay = display.default
52
- // }
53
- }
54
-
55
- // TODO: (typing) is this type correct for the parent set?
56
- const parents = new Set<string | number>()
57
- for (let rowIndex = this.rows.length - 1; rowIndex >= 0; rowIndex--) {
58
- const row = this.rows[rowIndex]
59
- if (row.parent) {
60
- parents.add(row.parent)
61
- }
62
-
63
- defaultDisplay[rowIndex] = {
64
- childrenOpen: false,
65
- expanded: false,
66
- indent: row.indent || null,
67
- isParent: parents.has(rowIndex),
68
- isRoot: row.parent === null || row.parent === undefined,
69
- rowModified: false,
70
- open: row.parent === null || row.parent === undefined,
71
- parent: row.parent,
72
- }
73
- }
74
-
75
- return reactive(defaultDisplay)
76
- }
77
-
78
- get zeroColumn() {
79
- return ['list', 'tree', 'list-expansion'].includes(this.config.view)
80
- }
81
-
82
- get numberedRowWidth() {
83
- return computed(() => {
84
- return String(Math.ceil(this.rows.length / 100) + 1) + 'ch'
85
- })
86
- }
87
-
88
- cellData<T>(colIndex: number, rowIndex: number): T {
89
- return this.table[`${colIndex}:${rowIndex}`]
90
- }
91
-
92
- setCellData(rowIndex: number, colIndex: number, value: any) {
93
- const index = `${colIndex}:${rowIndex}`
94
- const col = this.columns[colIndex]
95
-
96
- if (this.table[index] !== value) {
97
- this.display[rowIndex].rowModified = true
98
- }
99
-
100
- this.table[index] = value
101
- this.rows[rowIndex][col.name] = value
102
- return this.table[index]
103
- }
104
-
105
- toggleRowExpand(rowIndex: number) {
106
- if (this.config.view === 'tree') {
107
- this.display[rowIndex].childrenOpen = !this.display[rowIndex].childrenOpen
108
- for (let index = this.rows.length - 1; index >= 0; index--) {
109
- if (this.display[index].parent === rowIndex) {
110
- this.display[index].open = !this.display[index].open
111
- if (this.display[index].childrenOpen) {
112
- this.toggleRowExpand(index)
113
- }
114
- }
115
- }
116
- } else if (this.config.view === 'list-expansion') {
117
- this.display[rowIndex].expanded = !this.display[rowIndex].expanded
118
- }
119
- }
120
- }