@xy-planning-network/trees 0.15.5 → 0.16.0-dev-1
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/dist/trees.es.js +1517 -1582
- package/dist/trees.umd.js +13 -13
- package/package.json +1 -1
- package/src/lib-components/forms/FileUpload.vue +3 -5
- package/src/lib-components/lists/DataTable.vue +2 -84
- package/src/lib-components/lists/DynamicTable.vue +89 -16
- package/types/composables/forms.d.ts +1 -1
- package/types/composables/useActionItems.d.ts +12 -0
- package/types/composables/useTable.d.ts +0 -1
- package/types/helpers/DeleteProperty.d.ts +16 -0
- package/types/lib-components/forms/HiddenInput.vue.d.ts +3 -0
- package/types/lib-components/lists/DataTable.vue.d.ts +2 -16
- package/types/lib-components/lists/TableActionButtons.vue.d.ts +8 -0
- package/types/composables/useBulkActions.d.ts +0 -25
package/package.json
CHANGED
|
@@ -435,7 +435,7 @@ onBeforeUnmount(() => {
|
|
|
435
435
|
<div class="min-w-0 flex-1">
|
|
436
436
|
<template v-if="item.kind === 'uploaded'">
|
|
437
437
|
<span class="text-sm text-gray-800 [overflow-wrap:anywhere]">
|
|
438
|
-
{{ item.file.
|
|
438
|
+
{{ item.file.name }}
|
|
439
439
|
</span>
|
|
440
440
|
<p class="mt-0.5 text-xs text-gray-600">Uploaded</p>
|
|
441
441
|
</template>
|
|
@@ -468,7 +468,7 @@ onBeforeUnmount(() => {
|
|
|
468
468
|
:href="item.file.url"
|
|
469
469
|
target="_blank"
|
|
470
470
|
rel="noopener noreferrer"
|
|
471
|
-
:aria-label="`Open ${item.file.
|
|
471
|
+
:aria-label="`Open ${item.file.name} in a new window`"
|
|
472
472
|
>
|
|
473
473
|
<ArrowTopRightOnSquareIcon class="h-5 w-5" aria-hidden="true" />
|
|
474
474
|
</a>
|
|
@@ -493,9 +493,7 @@ onBeforeUnmount(() => {
|
|
|
493
493
|
(item.kind === 'pending' && item.upload.status === 'uploading')
|
|
494
494
|
"
|
|
495
495
|
:aria-label="`Remove ${
|
|
496
|
-
item.kind === 'uploaded'
|
|
497
|
-
? item.file.filename
|
|
498
|
-
: item.upload.file.name
|
|
496
|
+
item.kind === 'uploaded' ? item.file.name : item.upload.file.name
|
|
499
497
|
}`"
|
|
500
498
|
@click="
|
|
501
499
|
item.kind === 'uploaded'
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { useTable } from "@/composables/useTable"
|
|
3
|
-
import { useBulkActions } from "@/composables/useBulkActions"
|
|
4
3
|
import type {
|
|
5
4
|
TableActions,
|
|
6
|
-
TableBulkActions,
|
|
7
5
|
TableColumns,
|
|
8
6
|
TableRowsData,
|
|
9
7
|
} from "@/composables/table"
|
|
@@ -13,44 +11,19 @@ import { toRef } from "vue"
|
|
|
13
11
|
const props = withDefaults(
|
|
14
12
|
defineProps<{
|
|
15
13
|
tableActions?: TableActions<any>
|
|
16
|
-
tableBulkActions?: TableBulkActions<any>
|
|
17
14
|
tableColumns: TableColumns<any>
|
|
18
15
|
tableData: TableRowsData
|
|
19
16
|
}>(),
|
|
20
17
|
{
|
|
21
18
|
tableActions: () => ({ type: "dropdown", actions: [] }),
|
|
22
|
-
tableBulkActions: () => ({ actions: [] }),
|
|
23
19
|
}
|
|
24
20
|
)
|
|
25
21
|
|
|
26
|
-
const selected = defineModel<number[]>("selected", {
|
|
27
|
-
required: false,
|
|
28
|
-
default: [],
|
|
29
|
-
})
|
|
30
|
-
|
|
31
|
-
const {
|
|
32
|
-
bulkActions,
|
|
33
|
-
bulkSelectChecked,
|
|
34
|
-
bulkSelectIndeterminate,
|
|
35
|
-
bulkSelectOnChange,
|
|
36
|
-
hasBulkActions,
|
|
37
|
-
publicMethods,
|
|
38
|
-
selectable,
|
|
39
|
-
selectedOnPage,
|
|
40
|
-
} = useBulkActions(
|
|
41
|
-
toRef(props, "tableData"),
|
|
42
|
-
toRef(props, "tableBulkActions"),
|
|
43
|
-
selected
|
|
44
|
-
)
|
|
45
|
-
|
|
46
22
|
const { columns, hasActions, isEmptyCellValue, rows } = useTable(
|
|
47
23
|
toRef(props, "tableData"),
|
|
48
24
|
toRef(props, "tableColumns"),
|
|
49
|
-
toRef(props, "tableActions")
|
|
50
|
-
publicMethods
|
|
25
|
+
toRef(props, "tableActions")
|
|
51
26
|
)
|
|
52
|
-
|
|
53
|
-
defineExpose(publicMethods)
|
|
54
27
|
</script>
|
|
55
28
|
<template>
|
|
56
29
|
<div class="flex flex-col">
|
|
@@ -62,25 +35,6 @@ defineExpose(publicMethods)
|
|
|
62
35
|
<table class="min-w-full divide-y divide-gray-200">
|
|
63
36
|
<thead class="bg-gray-100">
|
|
64
37
|
<tr>
|
|
65
|
-
<th
|
|
66
|
-
v-if="hasBulkActions"
|
|
67
|
-
scope="col"
|
|
68
|
-
class="pl-6 w-4 leading-none"
|
|
69
|
-
>
|
|
70
|
-
<input
|
|
71
|
-
:class="[
|
|
72
|
-
'h-4 w-4 rounded cursor-pointer',
|
|
73
|
-
'disabled:bg-gray-100 disabled:border-gray-200 disabled:cursor-not-allowed disabled:opacity-100',
|
|
74
|
-
'checked:disabled:bg-xy-blue checked:disabled:border-xy-blue checked:disabled:opacity-50',
|
|
75
|
-
'border-gray-300 focus:ring-xy-blue-500',
|
|
76
|
-
]"
|
|
77
|
-
:checked="bulkSelectChecked"
|
|
78
|
-
:indeterminate="bulkSelectIndeterminate"
|
|
79
|
-
type="checkbox"
|
|
80
|
-
@change="bulkSelectOnChange"
|
|
81
|
-
/>
|
|
82
|
-
</th>
|
|
83
|
-
|
|
84
38
|
<th
|
|
85
39
|
v-for="(col, idx) in columns"
|
|
86
40
|
:key="idx"
|
|
@@ -96,23 +50,6 @@ defineExpose(publicMethods)
|
|
|
96
50
|
class="px-6 py-3 text-xs font-medium tracking-wider text-gray-900 uppercase leading-4"
|
|
97
51
|
/>
|
|
98
52
|
</tr>
|
|
99
|
-
|
|
100
|
-
<tr v-if="hasBulkActions && selected.length > 0">
|
|
101
|
-
<td colspan="100%" class="px-6 py-2.5 border-t bg-neutral-50">
|
|
102
|
-
<div class="flex items-center gap-x-3">
|
|
103
|
-
<div class="text-sm shrink-0">
|
|
104
|
-
Selected
|
|
105
|
-
<span class="font-medium">{{
|
|
106
|
-
selectedOnPage.length
|
|
107
|
-
}}</span>
|
|
108
|
-
of
|
|
109
|
-
<span class="font-medium">{{ selectable.length }}</span>
|
|
110
|
-
</div>
|
|
111
|
-
|
|
112
|
-
<ActionsButtonGroup :actions="bulkActions" />
|
|
113
|
-
</div>
|
|
114
|
-
</td>
|
|
115
|
-
</tr>
|
|
116
53
|
</thead>
|
|
117
54
|
<tbody class="bg-white">
|
|
118
55
|
<tr
|
|
@@ -120,21 +57,6 @@ defineExpose(publicMethods)
|
|
|
120
57
|
:key="rowIdx"
|
|
121
58
|
class="even:bg-gray-50"
|
|
122
59
|
>
|
|
123
|
-
<td v-if="hasBulkActions" class="pl-6 w-4 leading-none">
|
|
124
|
-
<input
|
|
125
|
-
v-model="selected"
|
|
126
|
-
:class="[
|
|
127
|
-
'h-4 w-4 rounded cursor-pointer',
|
|
128
|
-
'disabled:bg-gray-100 disabled:border-gray-200 disabled:cursor-not-allowed disabled:opacity-100',
|
|
129
|
-
'checked:disabled:bg-xy-blue checked:disabled:border-xy-blue checked:disabled:opacity-50',
|
|
130
|
-
'border-gray-300 focus:ring-xy-blue-500',
|
|
131
|
-
]"
|
|
132
|
-
:disabled="!selectable.includes(row.rowData?.id)"
|
|
133
|
-
type="checkbox"
|
|
134
|
-
:value="row.rowData?.id"
|
|
135
|
-
/>
|
|
136
|
-
</td>
|
|
137
|
-
|
|
138
60
|
<template v-for="(cell, cellIdx) in row.cells" :key="cellIdx">
|
|
139
61
|
<component
|
|
140
62
|
:is="'td'"
|
|
@@ -167,11 +89,7 @@ defineExpose(publicMethods)
|
|
|
167
89
|
|
|
168
90
|
<tr v-if="rows.length === 0">
|
|
169
91
|
<td
|
|
170
|
-
:colspan="
|
|
171
|
-
columns.length +
|
|
172
|
-
(hasActions ? 1 : 0) +
|
|
173
|
-
(hasBulkActions ? 1 : 0)
|
|
174
|
-
"
|
|
92
|
+
:colspan="columns.length + (hasActions ? 1 : 0)"
|
|
175
93
|
class="px-6 py-4 text-sm text-gray-700 whitespace-nowrap leading-5"
|
|
176
94
|
>
|
|
177
95
|
No items were found!
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
import DateRangePicker from "../forms/DateRangePicker.vue"
|
|
9
9
|
import BaseAPI from "../../api/base"
|
|
10
10
|
import type {
|
|
11
|
+
DynamicTableAPI,
|
|
11
12
|
DynamicTableOptions,
|
|
12
13
|
TableActions,
|
|
13
14
|
TableBulkActions,
|
|
@@ -18,7 +19,6 @@ import { useAppFlasher } from "@/composables/useFlashes"
|
|
|
18
19
|
import { TrailsRespPaged } from "@/api/client"
|
|
19
20
|
import { DateRange, DateRangeProps } from "@/composables/date"
|
|
20
21
|
import { useTable } from "@/composables/useTable"
|
|
21
|
-
import { useBulkActions } from "@/composables/useBulkActions"
|
|
22
22
|
|
|
23
23
|
const props = withDefaults(
|
|
24
24
|
defineProps<{
|
|
@@ -141,25 +141,100 @@ const hasContent = computed((): boolean => {
|
|
|
141
141
|
return rows.value.length ? true : false
|
|
142
142
|
})
|
|
143
143
|
|
|
144
|
+
const clearSelections = () => {
|
|
145
|
+
selected.value = []
|
|
146
|
+
}
|
|
147
|
+
|
|
144
148
|
const selected = defineModel<number[]>("selected", {
|
|
145
149
|
required: false,
|
|
146
150
|
default: [],
|
|
147
151
|
})
|
|
148
152
|
|
|
149
|
-
const {
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
}
|
|
153
|
+
const selectedData = computed((): TableRowData[] => {
|
|
154
|
+
return tableData.value.filter((data) => {
|
|
155
|
+
return selected.value.includes(data?.id)
|
|
156
|
+
})
|
|
157
|
+
})
|
|
158
|
+
|
|
159
|
+
const selectedOnPage = computed(() => {
|
|
160
|
+
return selected.value.filter((id) => {
|
|
161
|
+
return selectable.value.includes(id)
|
|
162
|
+
})
|
|
163
|
+
})
|
|
164
|
+
|
|
165
|
+
const bulkActions = computed(() => {
|
|
166
|
+
return props.tableBulkActions.actions
|
|
167
|
+
.filter((action) => {
|
|
168
|
+
return action.show ?? true
|
|
169
|
+
})
|
|
170
|
+
.map((action) => {
|
|
171
|
+
return {
|
|
172
|
+
...action,
|
|
173
|
+
disabled: selected.value.length === 0 || action.disabled,
|
|
174
|
+
onClick: (e?: Event) =>
|
|
175
|
+
action.onClick.apply(undefined, [
|
|
176
|
+
selected.value,
|
|
177
|
+
selectedData.value,
|
|
178
|
+
publicMethods,
|
|
179
|
+
e,
|
|
180
|
+
]),
|
|
181
|
+
}
|
|
182
|
+
})
|
|
183
|
+
})
|
|
184
|
+
|
|
185
|
+
const hasBulkActions = computed(() => bulkActions.value.length > 0)
|
|
186
|
+
|
|
187
|
+
const selectable = computed(() => {
|
|
188
|
+
return tableData.value
|
|
189
|
+
.filter((row) => {
|
|
190
|
+
// NOTE(spk): table data must have an "id" key for bulk actions.
|
|
191
|
+
if (row.id === undefined) {
|
|
192
|
+
return false
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
if (props.tableBulkActions.isSelectable === undefined) {
|
|
196
|
+
return true
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
if (props.tableBulkActions.isSelectable(row)) {
|
|
200
|
+
return true
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
return false
|
|
204
|
+
})
|
|
205
|
+
.map((d) => d["id"])
|
|
206
|
+
})
|
|
207
|
+
|
|
208
|
+
const bulkSelectChecked = computed(
|
|
209
|
+
() =>
|
|
210
|
+
selectedOnPage.value.length > 0 &&
|
|
211
|
+
selectedOnPage.value.length === selectable.value.length
|
|
212
|
+
)
|
|
213
|
+
|
|
214
|
+
const bulkSelectIndeterminate = computed(
|
|
215
|
+
() =>
|
|
216
|
+
selectedOnPage.value.length > 0 &&
|
|
217
|
+
selectedOnPage.value.length < selectable.value.length
|
|
218
|
+
)
|
|
219
|
+
|
|
220
|
+
const bulkSelectOnChange = (e: Event) => {
|
|
221
|
+
const isChecked = (e.target as HTMLInputElement).checked
|
|
222
|
+
|
|
223
|
+
// set all records on current page to selection
|
|
224
|
+
if (isChecked) {
|
|
225
|
+
selected.value = selectable.value.map((id) => id)
|
|
226
|
+
return
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
clearSelections()
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
const publicMethods: DynamicTableAPI = {
|
|
233
|
+
clearSelection: clearSelections,
|
|
234
|
+
selectedData: selectedData,
|
|
160
235
|
refresh: loadAndRender,
|
|
161
236
|
reset: reloadTable,
|
|
162
|
-
}
|
|
237
|
+
}
|
|
163
238
|
|
|
164
239
|
const { columns, hasActions, isEmptyCellValue, rows } = useTable(
|
|
165
240
|
tableData,
|
|
@@ -414,9 +489,7 @@ loadAndRender()
|
|
|
414
489
|
|
|
415
490
|
<tr v-if="!hasContent">
|
|
416
491
|
<td
|
|
417
|
-
:colspan="
|
|
418
|
-
columns.length + (hasActions ? 1 : 0) + (hasBulkActions ? 1 : 0)
|
|
419
|
-
"
|
|
492
|
+
:colspan="columns.length + (hasActions ? 1 : 0)"
|
|
420
493
|
class="px-6 py-4 text-sm text-gray-700 whitespace-nowrap leading-5"
|
|
421
494
|
>
|
|
422
495
|
No items were found!
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Ref } from "vue";
|
|
2
|
+
import { ActionItem } from "./nav";
|
|
3
|
+
export declare const useActionItems: (items: ActionItem[] | Ref<ActionItem[]>) => {
|
|
4
|
+
actions: import("vue").ComputedRef<{
|
|
5
|
+
disabled: boolean;
|
|
6
|
+
show: boolean;
|
|
7
|
+
onClick: (...args: any[]) => void;
|
|
8
|
+
icon?: import("vue").RenderFunction | import("vue").FunctionalComponent<{}, {}, any, {}> | undefined;
|
|
9
|
+
label: string;
|
|
10
|
+
}[]>;
|
|
11
|
+
hasActions: import("vue").ComputedRef<boolean>;
|
|
12
|
+
};
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { Ref } from "vue";
|
|
2
2
|
import { TableColumns, TableRowsData, TableActions, DynamicTableAPI } from "./table";
|
|
3
3
|
import { ActionItemButton, ActionItemLink } from "../entry";
|
|
4
|
-
export declare const tableAPIStub: DynamicTableAPI;
|
|
5
4
|
export declare const useTable: (rowData: TableRowsData | Ref<TableRowsData>, cols: TableColumns | Ref<TableColumns>, acts: TableActions | Ref<TableActions>, exposedAPI?: DynamicTableAPI) => {
|
|
6
5
|
columns: import("vue").ComputedRef<{
|
|
7
6
|
alignment: string;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* deleteProperty removes a value at a dot-separated path without mutating
|
|
3
|
+
* `obj`. Each container along the path is cloned, while containers outside
|
|
4
|
+
* the path retain their references.
|
|
5
|
+
*
|
|
6
|
+
* Empty parent containers are retained.
|
|
7
|
+
*
|
|
8
|
+
* NOTE(spk): deleting an array index is experimental because schema fields do not
|
|
9
|
+
* currently support applying `show` to an array item (but might with repeater fields).
|
|
10
|
+
* Array indexes are removed with `splice` so payloads contain compact arrays instead
|
|
11
|
+
* of entries that JSON would serialize as `null`.
|
|
12
|
+
*
|
|
13
|
+
* Missing and unsafe paths return the original object unchanged.
|
|
14
|
+
*/
|
|
15
|
+
declare function deleteProperty<O extends Record<string, any>>(obj: O, path: string): O;
|
|
16
|
+
export default deleteProperty;
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { HiddenInput } from "../../composables/forms";
|
|
2
|
+
declare const _default: import("vue").DefineComponent<HiddenInput, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<HiddenInput> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
3
|
+
export default _default;
|
|
@@ -1,24 +1,10 @@
|
|
|
1
|
-
import type { TableActions,
|
|
1
|
+
import type { TableActions, TableColumns, TableRowsData } from "../../composables/table";
|
|
2
2
|
type __VLS_Props = {
|
|
3
3
|
tableActions?: TableActions<any>;
|
|
4
|
-
tableBulkActions?: TableBulkActions<any>;
|
|
5
4
|
tableColumns: TableColumns<any>;
|
|
6
5
|
tableData: TableRowsData;
|
|
7
6
|
};
|
|
8
|
-
|
|
9
|
-
"selected"?: number[];
|
|
10
|
-
} & __VLS_Props;
|
|
11
|
-
declare const _default: import("vue").DefineComponent<__VLS_PublicProps, {
|
|
12
|
-
clearSelection: () => void;
|
|
13
|
-
refresh: () => void;
|
|
14
|
-
reset: () => void;
|
|
15
|
-
selectedData: import("vue").ComputedRef<import("../../composables/table").TableRowData[]>;
|
|
16
|
-
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
17
|
-
"update:selected": (value: number[]) => any;
|
|
18
|
-
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
19
|
-
"onUpdate:selected"?: ((value: number[]) => any) | undefined;
|
|
20
|
-
}>, {
|
|
7
|
+
declare const _default: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
|
|
21
8
|
tableActions: TableActions<any>;
|
|
22
|
-
tableBulkActions: TableBulkActions<any>;
|
|
23
9
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, HTMLDivElement>;
|
|
24
10
|
export default _default;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { TableActionItem } from "../../composables";
|
|
2
|
+
type __VLS_Props = {
|
|
3
|
+
actions?: TableActionItem[];
|
|
4
|
+
};
|
|
5
|
+
declare const _default: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
|
|
6
|
+
actions: TableActionItem<import("../../composables").TableRowData>[];
|
|
7
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
8
|
+
export default _default;
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import { type Ref } from "vue";
|
|
2
|
-
import type { DynamicTableAPI, TableBulkActions, TableRowData } from "./table";
|
|
3
|
-
interface UseBulkActionsOptions {
|
|
4
|
-
refresh?: () => void;
|
|
5
|
-
reset?: () => void;
|
|
6
|
-
}
|
|
7
|
-
export declare const useBulkActions: <T extends TableRowData>(tableData: Ref<T[]>, tableBulkActions: Ref<TableBulkActions<T>>, selected: Ref<number[]>, options?: UseBulkActionsOptions) => {
|
|
8
|
-
bulkActions: import("vue").ComputedRef<{
|
|
9
|
-
disabled: boolean | undefined;
|
|
10
|
-
onClick: (e?: Event) => void;
|
|
11
|
-
label: string;
|
|
12
|
-
icon?: import("vue").RenderFunction | import("vue").FunctionalComponent<{}, {}, any, {}> | undefined;
|
|
13
|
-
show?: boolean | undefined;
|
|
14
|
-
}[]>;
|
|
15
|
-
bulkSelectChecked: import("vue").ComputedRef<boolean>;
|
|
16
|
-
bulkSelectIndeterminate: import("vue").ComputedRef<boolean>;
|
|
17
|
-
bulkSelectOnChange: (e: Event) => void;
|
|
18
|
-
clearSelections: () => void;
|
|
19
|
-
hasBulkActions: import("vue").ComputedRef<boolean>;
|
|
20
|
-
publicMethods: DynamicTableAPI<T>;
|
|
21
|
-
selectable: import("vue").ComputedRef<any[]>;
|
|
22
|
-
selectedData: import("vue").ComputedRef<T[]>;
|
|
23
|
-
selectedOnPage: import("vue").ComputedRef<number[]>;
|
|
24
|
-
};
|
|
25
|
-
export {};
|