@xy-planning-network/trees 0.16.0-dev-1 → 0.16.0-dev-2
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 +1582 -1517
- package/dist/trees.umd.js +13 -13
- package/package.json +1 -1
- package/src/lib-components/forms/FileUpload.vue +5 -3
- package/src/lib-components/lists/DataTable.vue +84 -2
- package/src/lib-components/lists/DynamicTable.vue +16 -89
- package/types/composables/forms.d.ts +1 -1
- package/types/composables/useBulkActions.d.ts +25 -0
- package/types/composables/useTable.d.ts +1 -0
- package/types/lib-components/lists/DataTable.vue.d.ts +16 -2
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.filename }}
|
|
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.filename} in a new window`"
|
|
472
472
|
>
|
|
473
473
|
<ArrowTopRightOnSquareIcon class="h-5 w-5" aria-hidden="true" />
|
|
474
474
|
</a>
|
|
@@ -493,7 +493,9 @@ onBeforeUnmount(() => {
|
|
|
493
493
|
(item.kind === 'pending' && item.upload.status === 'uploading')
|
|
494
494
|
"
|
|
495
495
|
:aria-label="`Remove ${
|
|
496
|
-
item.kind === 'uploaded'
|
|
496
|
+
item.kind === 'uploaded'
|
|
497
|
+
? item.file.filename
|
|
498
|
+
: item.upload.file.name
|
|
497
499
|
}`"
|
|
498
500
|
@click="
|
|
499
501
|
item.kind === 'uploaded'
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { useTable } from "@/composables/useTable"
|
|
3
|
+
import { useBulkActions } from "@/composables/useBulkActions"
|
|
3
4
|
import type {
|
|
4
5
|
TableActions,
|
|
6
|
+
TableBulkActions,
|
|
5
7
|
TableColumns,
|
|
6
8
|
TableRowsData,
|
|
7
9
|
} from "@/composables/table"
|
|
@@ -11,19 +13,44 @@ import { toRef } from "vue"
|
|
|
11
13
|
const props = withDefaults(
|
|
12
14
|
defineProps<{
|
|
13
15
|
tableActions?: TableActions<any>
|
|
16
|
+
tableBulkActions?: TableBulkActions<any>
|
|
14
17
|
tableColumns: TableColumns<any>
|
|
15
18
|
tableData: TableRowsData
|
|
16
19
|
}>(),
|
|
17
20
|
{
|
|
18
21
|
tableActions: () => ({ type: "dropdown", actions: [] }),
|
|
22
|
+
tableBulkActions: () => ({ actions: [] }),
|
|
19
23
|
}
|
|
20
24
|
)
|
|
21
25
|
|
|
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
|
+
|
|
22
46
|
const { columns, hasActions, isEmptyCellValue, rows } = useTable(
|
|
23
47
|
toRef(props, "tableData"),
|
|
24
48
|
toRef(props, "tableColumns"),
|
|
25
|
-
toRef(props, "tableActions")
|
|
49
|
+
toRef(props, "tableActions"),
|
|
50
|
+
publicMethods
|
|
26
51
|
)
|
|
52
|
+
|
|
53
|
+
defineExpose(publicMethods)
|
|
27
54
|
</script>
|
|
28
55
|
<template>
|
|
29
56
|
<div class="flex flex-col">
|
|
@@ -35,6 +62,25 @@ const { columns, hasActions, isEmptyCellValue, rows } = useTable(
|
|
|
35
62
|
<table class="min-w-full divide-y divide-gray-200">
|
|
36
63
|
<thead class="bg-gray-100">
|
|
37
64
|
<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
|
+
|
|
38
84
|
<th
|
|
39
85
|
v-for="(col, idx) in columns"
|
|
40
86
|
:key="idx"
|
|
@@ -50,6 +96,23 @@ const { columns, hasActions, isEmptyCellValue, rows } = useTable(
|
|
|
50
96
|
class="px-6 py-3 text-xs font-medium tracking-wider text-gray-900 uppercase leading-4"
|
|
51
97
|
/>
|
|
52
98
|
</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>
|
|
53
116
|
</thead>
|
|
54
117
|
<tbody class="bg-white">
|
|
55
118
|
<tr
|
|
@@ -57,6 +120,21 @@ const { columns, hasActions, isEmptyCellValue, rows } = useTable(
|
|
|
57
120
|
:key="rowIdx"
|
|
58
121
|
class="even:bg-gray-50"
|
|
59
122
|
>
|
|
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
|
+
|
|
60
138
|
<template v-for="(cell, cellIdx) in row.cells" :key="cellIdx">
|
|
61
139
|
<component
|
|
62
140
|
:is="'td'"
|
|
@@ -89,7 +167,11 @@ const { columns, hasActions, isEmptyCellValue, rows } = useTable(
|
|
|
89
167
|
|
|
90
168
|
<tr v-if="rows.length === 0">
|
|
91
169
|
<td
|
|
92
|
-
:colspan="
|
|
170
|
+
:colspan="
|
|
171
|
+
columns.length +
|
|
172
|
+
(hasActions ? 1 : 0) +
|
|
173
|
+
(hasBulkActions ? 1 : 0)
|
|
174
|
+
"
|
|
93
175
|
class="px-6 py-4 text-sm text-gray-700 whitespace-nowrap leading-5"
|
|
94
176
|
>
|
|
95
177
|
No items were found!
|
|
@@ -8,7 +8,6 @@ import {
|
|
|
8
8
|
import DateRangePicker from "../forms/DateRangePicker.vue"
|
|
9
9
|
import BaseAPI from "../../api/base"
|
|
10
10
|
import type {
|
|
11
|
-
DynamicTableAPI,
|
|
12
11
|
DynamicTableOptions,
|
|
13
12
|
TableActions,
|
|
14
13
|
TableBulkActions,
|
|
@@ -19,6 +18,7 @@ import { useAppFlasher } from "@/composables/useFlashes"
|
|
|
19
18
|
import { TrailsRespPaged } from "@/api/client"
|
|
20
19
|
import { DateRange, DateRangeProps } from "@/composables/date"
|
|
21
20
|
import { useTable } from "@/composables/useTable"
|
|
21
|
+
import { useBulkActions } from "@/composables/useBulkActions"
|
|
22
22
|
|
|
23
23
|
const props = withDefaults(
|
|
24
24
|
defineProps<{
|
|
@@ -141,100 +141,25 @@ const hasContent = computed((): boolean => {
|
|
|
141
141
|
return rows.value.length ? true : false
|
|
142
142
|
})
|
|
143
143
|
|
|
144
|
-
const clearSelections = () => {
|
|
145
|
-
selected.value = []
|
|
146
|
-
}
|
|
147
|
-
|
|
148
144
|
const selected = defineModel<number[]>("selected", {
|
|
149
145
|
required: false,
|
|
150
146
|
default: [],
|
|
151
147
|
})
|
|
152
148
|
|
|
153
|
-
const
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
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,
|
|
149
|
+
const {
|
|
150
|
+
bulkActions,
|
|
151
|
+
bulkSelectChecked,
|
|
152
|
+
bulkSelectIndeterminate,
|
|
153
|
+
bulkSelectOnChange,
|
|
154
|
+
clearSelections,
|
|
155
|
+
hasBulkActions,
|
|
156
|
+
publicMethods,
|
|
157
|
+
selectable,
|
|
158
|
+
selectedOnPage,
|
|
159
|
+
} = useBulkActions(tableData, toRef(props, "tableBulkActions"), selected, {
|
|
235
160
|
refresh: loadAndRender,
|
|
236
161
|
reset: reloadTable,
|
|
237
|
-
}
|
|
162
|
+
})
|
|
238
163
|
|
|
239
164
|
const { columns, hasActions, isEmptyCellValue, rows } = useTable(
|
|
240
165
|
tableData,
|
|
@@ -489,7 +414,9 @@ loadAndRender()
|
|
|
489
414
|
|
|
490
415
|
<tr v-if="!hasContent">
|
|
491
416
|
<td
|
|
492
|
-
:colspan="
|
|
417
|
+
:colspan="
|
|
418
|
+
columns.length + (hasActions ? 1 : 0) + (hasBulkActions ? 1 : 0)
|
|
419
|
+
"
|
|
493
420
|
class="px-6 py-4 text-sm text-gray-700 whitespace-nowrap leading-5"
|
|
494
421
|
>
|
|
495
422
|
No items were found!
|
|
@@ -0,0 +1,25 @@
|
|
|
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 {};
|
|
@@ -1,6 +1,7 @@
|
|
|
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;
|
|
4
5
|
export declare const useTable: (rowData: TableRowsData | Ref<TableRowsData>, cols: TableColumns | Ref<TableColumns>, acts: TableActions | Ref<TableActions>, exposedAPI?: DynamicTableAPI) => {
|
|
5
6
|
columns: import("vue").ComputedRef<{
|
|
6
7
|
alignment: string;
|
|
@@ -1,10 +1,24 @@
|
|
|
1
|
-
import type { TableActions, TableColumns, TableRowsData } from "../../composables/table";
|
|
1
|
+
import type { TableActions, TableBulkActions, TableColumns, TableRowsData } from "../../composables/table";
|
|
2
2
|
type __VLS_Props = {
|
|
3
3
|
tableActions?: TableActions<any>;
|
|
4
|
+
tableBulkActions?: TableBulkActions<any>;
|
|
4
5
|
tableColumns: TableColumns<any>;
|
|
5
6
|
tableData: TableRowsData;
|
|
6
7
|
};
|
|
7
|
-
|
|
8
|
+
type __VLS_PublicProps = {
|
|
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
|
+
}>, {
|
|
8
21
|
tableActions: TableActions<any>;
|
|
22
|
+
tableBulkActions: TableBulkActions<any>;
|
|
9
23
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, HTMLDivElement>;
|
|
10
24
|
export default _default;
|