nuxt-ui-tools 0.1.0 → 0.1.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/module.d.mts +4 -0
- package/dist/module.json +1 -1
- package/dist/module.mjs +30 -15
- package/dist/runtime/form/components/actions/FormActions.d.vue.ts +0 -2
- package/dist/runtime/form/components/actions/FormActions.vue +5 -8
- package/dist/runtime/form/components/actions/FormActions.vue.d.ts +0 -2
- package/dist/runtime/form/components/layout/DrawerLayout.vue +5 -1
- package/dist/runtime/form/components/layout/ModalLayout.vue +5 -1
- package/dist/runtime/form/components/renderer/FormCompositeControl.d.vue.ts +15 -0
- package/dist/runtime/form/components/renderer/FormCompositeControl.vue +13 -0
- package/dist/runtime/form/components/renderer/FormCompositeControl.vue.d.ts +15 -0
- package/dist/runtime/form/components/renderer/FormFieldRenderer.d.vue.ts +1 -0
- package/dist/runtime/form/components/renderer/FormFieldRenderer.vue +19 -3
- package/dist/runtime/form/components/renderer/FormFieldRenderer.vue.d.ts +1 -0
- package/dist/runtime/form/components/renderer/FormFieldShell.d.vue.ts +4 -4
- package/dist/runtime/form/components/renderer/FormFieldShell.vue +15 -1
- package/dist/runtime/form/components/renderer/FormFieldShell.vue.d.ts +4 -4
- package/dist/runtime/form/components/root/Form.vue +5 -3
- package/dist/runtime/form/composables/use-field-control.d.ts +1 -1
- package/dist/runtime/form/composables/use-field-control.js +4 -0
- package/dist/runtime/form/composables/use-field-options.d.ts +1 -1
- package/dist/runtime/form/composables/use-field-options.js +75 -31
- package/dist/runtime/form/composables/use-form-field-chrome.d.ts +3 -0
- package/dist/runtime/form/composables/use-form-field-chrome.js +9 -0
- package/dist/runtime/form/composables/use-form-runtime.js +17 -5
- package/dist/runtime/form/fields/array-list/component.vue +4 -1
- package/dist/runtime/form/fields/auto-complete/component.vue +23 -16
- package/dist/runtime/form/fields/checkbox-card/component.vue +28 -29
- package/dist/runtime/form/fields/checkbox-group/component.vue +28 -29
- package/dist/runtime/form/fields/color-picker/component.vue +4 -2
- package/dist/runtime/form/fields/date-family/component.vue +9 -4
- package/dist/runtime/form/fields/hierarchy/SelectionCheckbox.d.vue.ts +13 -0
- package/dist/runtime/form/fields/hierarchy/SelectionCheckbox.vue +24 -0
- package/dist/runtime/form/fields/hierarchy/SelectionCheckbox.vue.d.ts +13 -0
- package/dist/runtime/form/fields/hierarchy/SelectionRadio.d.vue.ts +14 -0
- package/dist/runtime/form/fields/hierarchy/SelectionRadio.vue +27 -0
- package/dist/runtime/form/fields/hierarchy/SelectionRadio.vue.d.ts +14 -0
- package/dist/runtime/form/fields/hierarchy/component.vue +257 -142
- package/dist/runtime/form/fields/hierarchy/utils.d.ts +9 -0
- package/dist/runtime/form/fields/hierarchy/utils.js +32 -0
- package/dist/runtime/form/fields/input-group/component.vue +7 -30
- package/dist/runtime/form/fields/matrix/component.vue +9 -3
- package/dist/runtime/form/fields/phone-number/component.vue +7 -2
- package/dist/runtime/form/fields/rating/component.vue +25 -2
- package/dist/runtime/form/fields/select/component.vue +29 -21
- package/dist/runtime/form/fields/switch-group/component.vue +8 -3
- package/dist/runtime/form/fields/time/component.vue +7 -5
- package/dist/runtime/form/fields/upload/component.vue +5 -3
- package/dist/runtime/form/types/api.d.ts +9 -3
- package/dist/runtime/form/types/field-base.d.ts +3 -1
- package/dist/runtime/form/types/runtime.d.ts +2 -0
- package/dist/runtime/form/types/ui.d.ts +1 -0
- package/dist/runtime/form/utils/api.js +3 -0
- package/dist/runtime/form/utils/options.d.ts +11 -2
- package/dist/runtime/form/utils/options.js +57 -9
- package/dist/runtime/form/utils/state.js +10 -2
- package/dist/runtime/i18n/locales/en.js +38 -0
- package/dist/runtime/i18n/locales/fr.js +38 -0
- package/dist/runtime/i18n/types.d.ts +38 -0
- package/dist/runtime/i18n/use-locale.d.ts +2 -2
- package/dist/runtime/i18n/use-locale.js +3 -3
- package/dist/runtime/table/components/DataList.d.vue.ts +2 -0
- package/dist/runtime/table/components/DataList.vue.d.ts +2 -0
- package/dist/runtime/table/components/actions/RowActions.d.vue.ts +4 -2
- package/dist/runtime/table/components/actions/RowActions.vue +2 -0
- package/dist/runtime/table/components/actions/RowActions.vue.d.ts +4 -2
- package/dist/runtime/table/components/data-list/DataListAddFilter.d.vue.ts +5 -3
- package/dist/runtime/table/components/data-list/DataListAddFilter.vue +6 -1
- package/dist/runtime/table/components/data-list/DataListAddFilter.vue.d.ts +5 -3
- package/dist/runtime/table/components/data-list/DataListContent.d.vue.ts +24 -17
- package/dist/runtime/table/components/data-list/DataListContent.vue +70 -17
- package/dist/runtime/table/components/data-list/DataListContent.vue.d.ts +24 -17
- package/dist/runtime/table/components/data-list/DataListDefault.d.vue.ts +2 -0
- package/dist/runtime/table/components/data-list/DataListDefault.vue.d.ts +2 -0
- package/dist/runtime/table/components/data-list/DataListFilterTags.d.vue.ts +2 -0
- package/dist/runtime/table/components/data-list/DataListFilterTags.vue.d.ts +2 -0
- package/dist/runtime/table/components/data-list/DataListLayoutSwitch.vue +17 -11
- package/dist/runtime/table/components/data-list/DataListRoot.vue +2 -46
- package/dist/runtime/table/components/data-list/DataListSortMenu.vue +6 -0
- package/dist/runtime/table/components/filters/shared/DynamicFilterPicker.d.vue.ts +5 -0
- package/dist/runtime/table/components/filters/shared/DynamicFilterPicker.vue +182 -59
- package/dist/runtime/table/components/filters/shared/DynamicFilterPicker.vue.d.ts +5 -0
- package/dist/runtime/table/components/filters/shared/FilterMatchModeButton.d.vue.ts +3 -1
- package/dist/runtime/table/components/filters/shared/FilterMatchModeButton.vue +29 -5
- package/dist/runtime/table/components/filters/shared/FilterMatchModeButton.vue.d.ts +3 -1
- package/dist/runtime/table/components/filters/shared/FilterMatchModePanel.d.vue.ts +17 -0
- package/dist/runtime/table/components/filters/shared/FilterMatchModePanel.vue +47 -0
- package/dist/runtime/table/components/filters/shared/FilterMatchModePanel.vue.d.ts +17 -0
- package/dist/runtime/table/components/filters/shared/FilterOptionMultipleList.d.vue.ts +3 -1
- package/dist/runtime/table/components/filters/shared/FilterOptionMultipleList.vue +12 -3
- package/dist/runtime/table/components/filters/shared/FilterOptionMultipleList.vue.d.ts +3 -1
- package/dist/runtime/table/components/filters/shared/FilterOptionPickerContent.d.vue.ts +3 -0
- package/dist/runtime/table/components/filters/shared/FilterOptionPickerContent.vue +11 -1
- package/dist/runtime/table/components/filters/shared/FilterOptionPickerContent.vue.d.ts +3 -0
- package/dist/runtime/table/components/filters/shared/FilterOptionRow.d.vue.ts +3 -0
- package/dist/runtime/table/components/filters/shared/FilterOptionRow.vue +48 -9
- package/dist/runtime/table/components/filters/shared/FilterOptionRow.vue.d.ts +3 -0
- package/dist/runtime/table/components/filters/shared/FilterOptionSingleList.d.vue.ts +3 -0
- package/dist/runtime/table/components/filters/shared/FilterOptionSingleList.vue +35 -9
- package/dist/runtime/table/components/filters/shared/FilterOptionSingleList.vue.d.ts +3 -0
- package/dist/runtime/table/components/filters/shared/FilterOptionTreeContent.d.vue.ts +3 -0
- package/dist/runtime/table/components/filters/shared/FilterOptionTreeContent.vue +77 -20
- package/dist/runtime/table/components/filters/shared/FilterOptionTreeContent.vue.d.ts +3 -0
- package/dist/runtime/table/components/filters/shared/FilterPopoverShell.d.vue.ts +27 -0
- package/dist/runtime/table/components/filters/shared/FilterPopoverShell.vue +36 -0
- package/dist/runtime/table/components/filters/shared/FilterPopoverShell.vue.d.ts +27 -0
- package/dist/runtime/table/components/filters/shared/FilterSearchablePanel.d.vue.ts +3 -0
- package/dist/runtime/table/components/filters/shared/FilterSearchablePanel.vue +40 -10
- package/dist/runtime/table/components/filters/shared/FilterSearchablePanel.vue.d.ts +3 -0
- package/dist/runtime/table/components/filters/shared/FilterStageTransition.d.vue.ts +23 -0
- package/dist/runtime/table/components/filters/shared/FilterStageTransition.vue +21 -0
- package/dist/runtime/table/components/filters/shared/FilterStageTransition.vue.d.ts +23 -0
- package/dist/runtime/table/components/filters/shared/FilterTriggerTag.d.vue.ts +3 -2
- package/dist/runtime/table/components/filters/shared/FilterTriggerTag.vue +26 -25
- package/dist/runtime/table/components/filters/shared/FilterTriggerTag.vue.d.ts +3 -2
- package/dist/runtime/table/components/filters/tags/BooleanFilterTag.d.vue.ts +1 -1
- package/dist/runtime/table/components/filters/tags/BooleanFilterTag.vue +75 -22
- package/dist/runtime/table/components/filters/tags/BooleanFilterTag.vue.d.ts +1 -1
- package/dist/runtime/table/components/filters/tags/DateFilterTag.d.vue.ts +3 -1
- package/dist/runtime/table/components/filters/tags/DateFilterTag.vue +254 -160
- package/dist/runtime/table/components/filters/tags/DateFilterTag.vue.d.ts +3 -1
- package/dist/runtime/table/components/filters/tags/FilterTagsBar.d.vue.ts +7 -6
- package/dist/runtime/table/components/filters/tags/FilterTagsBar.vue +12 -27
- package/dist/runtime/table/components/filters/tags/FilterTagsBar.vue.d.ts +7 -6
- package/dist/runtime/table/components/filters/tags/NumberFilterTag.d.vue.ts +3 -2
- package/dist/runtime/table/components/filters/tags/NumberFilterTag.vue +192 -106
- package/dist/runtime/table/components/filters/tags/NumberFilterTag.vue.d.ts +3 -2
- package/dist/runtime/table/components/filters/tags/OptionFilterTag.d.vue.ts +3 -2
- package/dist/runtime/table/components/filters/tags/OptionFilterTag.vue +110 -48
- package/dist/runtime/table/components/filters/tags/OptionFilterTag.vue.d.ts +3 -2
- package/dist/runtime/table/components/filters/tags/TextFilterTag.d.vue.ts +3 -2
- package/dist/runtime/table/components/filters/tags/TextFilterTag.vue +120 -57
- package/dist/runtime/table/components/filters/tags/TextFilterTag.vue.d.ts +3 -2
- package/dist/runtime/table/components/grid/GridRenderer.vue +1 -1
- package/dist/runtime/table/components/layout/TableFooter.vue +1 -0
- package/dist/runtime/table/components/table/TableRenderer.vue +18 -9
- package/dist/runtime/table/composables/use-filter-tag-session.d.ts +3 -4
- package/dist/runtime/table/composables/use-filter-tag-session.js +12 -32
- package/dist/runtime/table/composables/use-query-state.d.ts +3 -3
- package/dist/runtime/table/composables/use-query-state.js +7 -32
- package/dist/runtime/table/composables/use-table-api.js +2 -2
- package/dist/runtime/table/composables/use-table-columns.d.ts +1 -11
- package/dist/runtime/table/composables/use-table-filter-presentation.d.ts +0 -3
- package/dist/runtime/table/composables/use-table-filter-presentation.js +0 -9
- package/dist/runtime/table/composables/use-table-filters.js +18 -7
- package/dist/runtime/table/composables/use-table-internals.d.ts +3 -42
- package/dist/runtime/table/types/actions.d.ts +1 -1
- package/dist/runtime/table/types/data-list.d.ts +41 -8
- package/dist/runtime/table/types/filters.d.ts +4 -0
- package/dist/runtime/table/utils/actions.d.ts +1 -1
- package/dist/runtime/table/utils/columns/menu.d.ts +2 -11
- package/dist/runtime/table/utils/columns/render.d.ts +2 -9
- package/dist/runtime/table/utils/columns/render.js +4 -4
- package/dist/runtime/table/utils/data-list-ui.d.ts +3 -1
- package/dist/runtime/table/utils/data-list-ui.js +45 -0
- package/dist/runtime/table/utils/filters/editor-size.d.ts +11 -0
- package/dist/runtime/table/utils/filters/editor-size.js +45 -0
- package/dist/runtime/table/utils/filters/index.d.ts +1 -1
- package/dist/runtime/table/utils/filters/index.js +1 -1
- package/dist/runtime/table/utils/query-state.d.ts +18 -1
- package/dist/runtime/table/utils/query-state.js +109 -0
- package/package.json +4 -2
- package/dist/runtime/table/utils/filters/operators.d.ts +0 -4
- package/dist/runtime/table/utils/filters/operators.js +0 -6
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import UCheckbox from "@nuxt/ui/components/Checkbox.vue";
|
|
3
|
+
import { formFieldInjectionKey, inputIdInjectionKey } from "@nuxt/ui/composables/useFormField";
|
|
4
|
+
import { provide, ref } from "vue";
|
|
5
|
+
defineProps({
|
|
6
|
+
modelValue: { type: [Boolean, String], required: true },
|
|
7
|
+
label: { type: String, required: true },
|
|
8
|
+
disabled: { type: Boolean, required: false },
|
|
9
|
+
controlClass: { type: String, required: false }
|
|
10
|
+
});
|
|
11
|
+
const emit = defineEmits(["update:modelValue"]);
|
|
12
|
+
provide(formFieldInjectionKey, void 0);
|
|
13
|
+
provide(inputIdInjectionKey, ref(void 0));
|
|
14
|
+
</script>
|
|
15
|
+
|
|
16
|
+
<template>
|
|
17
|
+
<UCheckbox
|
|
18
|
+
:model-value="modelValue"
|
|
19
|
+
:aria-label="label"
|
|
20
|
+
:disabled="disabled"
|
|
21
|
+
:ui="{ root: controlClass }"
|
|
22
|
+
@update:model-value="emit('update:modelValue', $event)"
|
|
23
|
+
/>
|
|
24
|
+
</template>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
type __VLS_Props = {
|
|
2
|
+
modelValue: boolean | 'indeterminate';
|
|
3
|
+
label: string;
|
|
4
|
+
disabled?: boolean;
|
|
5
|
+
controlClass?: string;
|
|
6
|
+
};
|
|
7
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
8
|
+
"update:modelValue": (value: boolean | "indeterminate") => any;
|
|
9
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
10
|
+
"onUpdate:modelValue"?: ((value: boolean | "indeterminate") => any) | undefined;
|
|
11
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
12
|
+
declare const _default: typeof __VLS_export;
|
|
13
|
+
export default _default;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
type __VLS_Props = {
|
|
2
|
+
value: string;
|
|
3
|
+
label: string;
|
|
4
|
+
selected: boolean;
|
|
5
|
+
disabled?: boolean;
|
|
6
|
+
controlClass?: string;
|
|
7
|
+
};
|
|
8
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
9
|
+
select: () => any;
|
|
10
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
11
|
+
onSelect?: (() => any) | undefined;
|
|
12
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
13
|
+
declare const _default: typeof __VLS_export;
|
|
14
|
+
export default _default;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import URadioGroup from "@nuxt/ui/components/RadioGroup.vue";
|
|
3
|
+
import { formFieldInjectionKey, inputIdInjectionKey } from "@nuxt/ui/composables/useFormField";
|
|
4
|
+
import { computed, provide, ref } from "vue";
|
|
5
|
+
const props = defineProps({
|
|
6
|
+
value: { type: String, required: true },
|
|
7
|
+
label: { type: String, required: true },
|
|
8
|
+
selected: { type: Boolean, required: true },
|
|
9
|
+
disabled: { type: Boolean, required: false },
|
|
10
|
+
controlClass: { type: String, required: false }
|
|
11
|
+
});
|
|
12
|
+
const emit = defineEmits(["select"]);
|
|
13
|
+
const items = computed(() => [{ value: props.value, label: props.label }]);
|
|
14
|
+
provide(formFieldInjectionKey, void 0);
|
|
15
|
+
provide(inputIdInjectionKey, ref(void 0));
|
|
16
|
+
</script>
|
|
17
|
+
|
|
18
|
+
<template>
|
|
19
|
+
<URadioGroup
|
|
20
|
+
:model-value="selected ? value : void 0"
|
|
21
|
+
:items="items"
|
|
22
|
+
:aria-label="label"
|
|
23
|
+
:disabled="disabled"
|
|
24
|
+
:ui="{ root: controlClass, label: 'sr-only' }"
|
|
25
|
+
@update:model-value="emit('select')"
|
|
26
|
+
/>
|
|
27
|
+
</template>
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
type __VLS_Props = {
|
|
2
|
+
value: string;
|
|
3
|
+
label: string;
|
|
4
|
+
selected: boolean;
|
|
5
|
+
disabled?: boolean;
|
|
6
|
+
controlClass?: string;
|
|
7
|
+
};
|
|
8
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
9
|
+
select: () => any;
|
|
10
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
11
|
+
onSelect?: (() => any) | undefined;
|
|
12
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
13
|
+
declare const _default: typeof __VLS_export;
|
|
14
|
+
export default _default;
|
|
@@ -6,14 +6,22 @@ import UPopover from "@nuxt/ui/components/Popover.vue";
|
|
|
6
6
|
import USelectMenu from "@nuxt/ui/components/SelectMenu.vue";
|
|
7
7
|
import UTree from "@nuxt/ui/components/Tree.vue";
|
|
8
8
|
import { computed, ref, watch } from "vue";
|
|
9
|
+
import { useUiToolsLocale } from "../../../i18n/use-locale";
|
|
10
|
+
import FormCompositeControl from "../../components/renderer/FormCompositeControl.vue";
|
|
9
11
|
import FormFieldShell from "../../components/renderer/FormFieldShell.vue";
|
|
10
12
|
import { useFieldControl } from "../../composables/use-field-control";
|
|
11
13
|
import { useFormUi } from "../../composables/use-form-ui";
|
|
14
|
+
import { formOptionKey } from "../../utils/options";
|
|
15
|
+
import { resolveFormText } from "../../utils/text";
|
|
12
16
|
import { mergeFormUiClass } from "../../utils/ui";
|
|
17
|
+
import SelectionCheckbox from "./SelectionCheckbox.vue";
|
|
18
|
+
import SelectionRadio from "./SelectionRadio.vue";
|
|
19
|
+
import { resolveHierarchySelection } from "./utils";
|
|
13
20
|
const props = defineProps({
|
|
14
21
|
field: { type: null, required: true },
|
|
15
22
|
path: { type: Array, required: true }
|
|
16
23
|
});
|
|
24
|
+
const { t } = useUiToolsLocale();
|
|
17
25
|
const { form, controlProps, controlSize, disabled, handleBlur, options, placeholder } = useFieldControl(
|
|
18
26
|
() => props.field,
|
|
19
27
|
() => props.path
|
|
@@ -36,6 +44,7 @@ const treeSelectionControl = computed(() => {
|
|
|
36
44
|
});
|
|
37
45
|
const treeSelectOpen = ref(false);
|
|
38
46
|
const treeSearch = ref("");
|
|
47
|
+
const expandedKeys = ref([]);
|
|
39
48
|
const separator = computed(
|
|
40
49
|
() => props.field.type === "cascader" ? props.field.separator ?? " / " : " / "
|
|
41
50
|
);
|
|
@@ -76,9 +85,14 @@ const treeSelectLabel = computed(() => {
|
|
|
76
85
|
if (!selected) return placeholder.value;
|
|
77
86
|
return props.field.type === "tree-select" && props.field.showPath ? selected.pathLabel : String(selected.label);
|
|
78
87
|
});
|
|
88
|
+
const fieldLabel = computed(() => resolveFormText(props.field.label));
|
|
79
89
|
watch(treeSelectOpen, (open) => {
|
|
80
90
|
if (!open) treeSearch.value = "";
|
|
81
91
|
});
|
|
92
|
+
watch(treeSearch, (query) => {
|
|
93
|
+
if (!query.trim()) return;
|
|
94
|
+
expandedKeys.value = flattenTreeItems(visibleTreeItems.value).filter((item) => item.children?.length).map((item) => treeKey(item));
|
|
95
|
+
});
|
|
82
96
|
function flattenOptions(items, labels = [], depth = 0) {
|
|
83
97
|
return items.flatMap((item) => {
|
|
84
98
|
const path = [...labels, item.label];
|
|
@@ -102,9 +116,13 @@ function toTreeItems(items, labels = []) {
|
|
|
102
116
|
...item,
|
|
103
117
|
label: treeItemLabel(item),
|
|
104
118
|
pathLabel: [...labels, item.label].join(separator.value),
|
|
105
|
-
children: item.children ? toTreeItems(item.children, [...labels, item.label]) : void 0
|
|
119
|
+
children: item.children ? toTreeItems(item.children, [...labels, item.label]) : void 0,
|
|
120
|
+
...treeSelectionControl.value === "none" ? {} : { onSelect: preventTreeSelection }
|
|
106
121
|
}));
|
|
107
122
|
}
|
|
123
|
+
function preventTreeSelection(event) {
|
|
124
|
+
event.preventDefault();
|
|
125
|
+
}
|
|
108
126
|
function treeItemLabel(item) {
|
|
109
127
|
if (props.field.type !== "tree-select" || !props.field.showChildrenCount) return item.label;
|
|
110
128
|
const count = item.children?.length ?? 0;
|
|
@@ -125,9 +143,16 @@ function flattenTreeItems(items) {
|
|
|
125
143
|
}
|
|
126
144
|
function updateTreeModel(value) {
|
|
127
145
|
if (Array.isArray(value)) {
|
|
146
|
+
const selected = /* @__PURE__ */ new Map();
|
|
147
|
+
for (const item of value) selected.set(formOptionKey(item.value), item.value);
|
|
128
148
|
form.setValue(
|
|
129
149
|
props.path,
|
|
130
|
-
|
|
150
|
+
resolveHierarchySelection({
|
|
151
|
+
next: [...selected.values()],
|
|
152
|
+
items: options.items.value,
|
|
153
|
+
propagate: treePropagateSelect(props.field) === true,
|
|
154
|
+
bubble: treeBubbleSelect(props.field) === true
|
|
155
|
+
})
|
|
131
156
|
);
|
|
132
157
|
return;
|
|
133
158
|
}
|
|
@@ -139,7 +164,35 @@ function clearTreeSelection() {
|
|
|
139
164
|
treeSelectOpen.value = false;
|
|
140
165
|
}
|
|
141
166
|
function treeKey(item) {
|
|
142
|
-
return
|
|
167
|
+
return formOptionKey(item.value);
|
|
168
|
+
}
|
|
169
|
+
function toggleTreeItem(item) {
|
|
170
|
+
const current = Array.isArray(model.value) ? model.value : [];
|
|
171
|
+
const selected = new Map(current.map((value) => [formOptionKey(value), value]));
|
|
172
|
+
const key = formOptionKey(item.value);
|
|
173
|
+
if (selected.has(key)) selected.delete(key);
|
|
174
|
+
else selected.set(key, item.value);
|
|
175
|
+
form.setValue(
|
|
176
|
+
props.path,
|
|
177
|
+
resolveHierarchySelection({
|
|
178
|
+
next: [...selected.values()],
|
|
179
|
+
intent: item.value,
|
|
180
|
+
items: options.items.value,
|
|
181
|
+
propagate: treePropagateSelect(props.field) === true,
|
|
182
|
+
bubble: treeBubbleSelect(props.field) === true
|
|
183
|
+
})
|
|
184
|
+
);
|
|
185
|
+
}
|
|
186
|
+
function selectRadioTreeItem(item) {
|
|
187
|
+
form.setValue(props.path, item.value);
|
|
188
|
+
if (isTreeSelect.value) treeSelectOpen.value = false;
|
|
189
|
+
}
|
|
190
|
+
function selectTreeRow(item) {
|
|
191
|
+
if (treeSelectionControl.value === "checkbox") {
|
|
192
|
+
toggleTreeItem(item);
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
if (treeSelectionControl.value === "radio") selectRadioTreeItem(item);
|
|
143
196
|
}
|
|
144
197
|
function hasShowPath(field) {
|
|
145
198
|
return field.type === "tree-select" && field.showPath === true;
|
|
@@ -154,12 +207,6 @@ function treeSelectionBehavior(field) {
|
|
|
154
207
|
if (field.type !== "tree" && field.type !== "tree-select") return void 0;
|
|
155
208
|
return field.selectionBehavior ?? (treeMultiple.value ? "toggle" : "replace");
|
|
156
209
|
}
|
|
157
|
-
function treeSelectionIcon(selected, indeterminate) {
|
|
158
|
-
if (treeSelectionControl.value === "radio")
|
|
159
|
-
return selected ? "i-lucide-circle-dot" : "i-lucide-circle";
|
|
160
|
-
if (indeterminate) return "i-lucide-square-minus";
|
|
161
|
-
return selected ? "i-lucide-square-check-big" : "i-lucide-square";
|
|
162
|
-
}
|
|
163
210
|
function treeVirtualize(field) {
|
|
164
211
|
return field.type === "tree" ? field.virtualize : void 0;
|
|
165
212
|
}
|
|
@@ -170,21 +217,24 @@ function isOptionValue(value) {
|
|
|
170
217
|
|
|
171
218
|
<template>
|
|
172
219
|
<FormFieldShell :field="field" :path="path">
|
|
173
|
-
<
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
220
|
+
<FormCompositeControl v-slot="{ attrs }">
|
|
221
|
+
<UTree
|
|
222
|
+
v-if="isTree"
|
|
223
|
+
v-bind="{ ...controlProps, ...attrs }"
|
|
224
|
+
:aria-label="fieldLabel"
|
|
225
|
+
:model-value="treeModel"
|
|
226
|
+
v-model:expanded="expandedKeys"
|
|
227
|
+
:items="treeItems"
|
|
228
|
+
:get-key="treeKey"
|
|
229
|
+
:multiple="treeMultiple"
|
|
230
|
+
:selection-behavior="treeSelectionBehavior(field)"
|
|
231
|
+
:propagate-select="treePropagateSelect(field)"
|
|
232
|
+
:bubble-select="treeBubbleSelect(field)"
|
|
233
|
+
:virtualize="treeVirtualize(field)"
|
|
234
|
+
:disabled="disabled"
|
|
235
|
+
:size="controlSize"
|
|
236
|
+
:class="mergeFormUiClass('w-full py-1', formUi.ui.value.tree?.ui?.root)"
|
|
237
|
+
:ui="{
|
|
188
238
|
item: formUi.ui.value.tree?.ui?.item,
|
|
189
239
|
itemWithChildren: formUi.ui.value.tree?.ui?.itemWithChildren,
|
|
190
240
|
listWithChildren: formUi.ui.value.tree?.ui?.listWithChildren,
|
|
@@ -194,86 +244,122 @@ function isOptionValue(value) {
|
|
|
194
244
|
linkTrailing: formUi.ui.value.tree?.ui?.linkTrailing,
|
|
195
245
|
linkTrailingIcon: formUi.ui.value.tree?.ui?.linkTrailingIcon
|
|
196
246
|
}"
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
"
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
247
|
+
@update:model-value="updateTreeModel"
|
|
248
|
+
@blur="handleBlur"
|
|
249
|
+
>
|
|
250
|
+
<template
|
|
251
|
+
v-if="treeSelectionControl !== 'none'"
|
|
252
|
+
#item-wrapper="{ item, selected, expanded, indeterminate, handleToggle, ui }"
|
|
253
|
+
>
|
|
254
|
+
<div
|
|
255
|
+
:class="ui.link({ selected, disabled: disabled || item.disabled })"
|
|
256
|
+
:data-selected="selected ? '' : void 0"
|
|
257
|
+
@click="selectTreeRow(item)"
|
|
258
|
+
>
|
|
259
|
+
<SelectionCheckbox
|
|
260
|
+
v-if="treeSelectionControl === 'checkbox'"
|
|
261
|
+
:model-value="indeterminate ? 'indeterminate' : selected"
|
|
262
|
+
:label="String(item.label)"
|
|
263
|
+
:disabled="disabled || item.disabled"
|
|
264
|
+
:control-class="formUi.ui.value.tree?.ui?.selectionControl"
|
|
265
|
+
@click.stop
|
|
266
|
+
@update:model-value="toggleTreeItem(item)"
|
|
267
|
+
/>
|
|
268
|
+
<SelectionRadio
|
|
269
|
+
v-else
|
|
270
|
+
:value="treeKey(item)"
|
|
271
|
+
:label="String(item.label)"
|
|
272
|
+
:selected="selected"
|
|
273
|
+
:disabled="disabled || item.disabled"
|
|
274
|
+
:control-class="formUi.ui.value.tree?.ui?.selectionControl"
|
|
275
|
+
@click.stop
|
|
276
|
+
@select="selectRadioTreeItem(item)"
|
|
277
|
+
/>
|
|
278
|
+
<span :class="ui.linkLabel()">{{ item.label }}</span>
|
|
279
|
+
<button
|
|
280
|
+
v-if="item.children?.length"
|
|
281
|
+
type="button"
|
|
282
|
+
:aria-label="String(item.label)"
|
|
283
|
+
class="ms-auto inline-flex rounded-sm p-0.5 focus-visible:outline-2 focus-visible:outline-primary"
|
|
284
|
+
@click.stop="handleToggle"
|
|
285
|
+
>
|
|
286
|
+
<UIcon
|
|
287
|
+
name="i-lucide-chevron-down"
|
|
288
|
+
aria-hidden="true"
|
|
289
|
+
:class="[ui.linkTrailingIcon(), expanded ? 'rotate-180' : '']"
|
|
290
|
+
/>
|
|
291
|
+
</button>
|
|
292
|
+
</div>
|
|
293
|
+
</template>
|
|
294
|
+
</UTree>
|
|
295
|
+
<UPopover
|
|
296
|
+
v-else-if="isTreeSelect"
|
|
297
|
+
v-model:open="treeSelectOpen"
|
|
298
|
+
:content="{ align: 'start', sideOffset: 6 }"
|
|
299
|
+
:ui="{
|
|
219
300
|
content: mergeFormUiClass(
|
|
220
301
|
'w-(--reka-popper-anchor-width) min-w-72 p-0',
|
|
221
302
|
formUi.ui.value.treeSelect?.ui?.content
|
|
222
303
|
)
|
|
223
304
|
}"
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
305
|
+
>
|
|
306
|
+
<UButton
|
|
307
|
+
v-bind="attrs"
|
|
308
|
+
type="button"
|
|
309
|
+
color="neutral"
|
|
310
|
+
variant="outline"
|
|
311
|
+
:size="controlSize"
|
|
312
|
+
:disabled="disabled"
|
|
313
|
+
:loading="options.loading.value"
|
|
314
|
+
:trailing-icon="treeSelectOpen ? 'i-lucide-chevron-up' : 'i-lucide-chevron-down'"
|
|
315
|
+
:class="
|
|
234
316
|
mergeFormUiClass(
|
|
235
317
|
'w-full justify-between font-normal',
|
|
236
318
|
formUi.ui.value.treeSelect?.ui?.trigger
|
|
237
319
|
)
|
|
238
320
|
"
|
|
239
|
-
|
|
321
|
+
:ui="{
|
|
240
322
|
label: mergeFormUiClass(
|
|
241
323
|
'min-w-0 flex-1 truncate text-left',
|
|
242
324
|
formUi.ui.value.treeSelect?.ui?.triggerLabel
|
|
243
325
|
)
|
|
244
326
|
}"
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
327
|
+
@blur="handleBlur"
|
|
328
|
+
>
|
|
329
|
+
{{ treeSelectLabel }}
|
|
330
|
+
</UButton>
|
|
249
331
|
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
332
|
+
<template #content>
|
|
333
|
+
<div :class="mergeFormUiClass('grid min-w-0', formUi.ui.value.treeSelect?.ui?.root)">
|
|
334
|
+
<div v-if="field.searchable !== false" class="border-b border-default p-2">
|
|
335
|
+
<UInput
|
|
336
|
+
v-model="treeSearch"
|
|
337
|
+
icon="i-lucide-search"
|
|
338
|
+
:size="controlSize"
|
|
339
|
+
:placeholder="t('form.fields.hierarchy.search')"
|
|
340
|
+
:class="mergeFormUiClass('w-full', formUi.ui.value.treeSelect?.ui?.search)"
|
|
341
|
+
autofocus
|
|
342
|
+
/>
|
|
343
|
+
</div>
|
|
344
|
+
<UTree
|
|
345
|
+
v-if="visibleTreeItems.length"
|
|
346
|
+
:model-value="treeModel"
|
|
347
|
+
v-model:expanded="expandedKeys"
|
|
348
|
+
:items="visibleTreeItems"
|
|
349
|
+
:get-key="treeKey"
|
|
350
|
+
:multiple="treeMultiple"
|
|
351
|
+
:selection-behavior="treeSelectionBehavior(field)"
|
|
352
|
+
:propagate-select="treeSearch ? false : treePropagateSelect(field)"
|
|
353
|
+
:bubble-select="treeSearch ? false : treeBubbleSelect(field)"
|
|
354
|
+
:disabled="disabled"
|
|
256
355
|
:size="controlSize"
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
<UTree
|
|
263
|
-
v-if="visibleTreeItems.length"
|
|
264
|
-
:model-value="treeModel"
|
|
265
|
-
:items="visibleTreeItems"
|
|
266
|
-
:get-key="treeKey"
|
|
267
|
-
:multiple="treeMultiple"
|
|
268
|
-
:selection-behavior="treeSelectionBehavior(field)"
|
|
269
|
-
:propagate-select="treePropagateSelect(field)"
|
|
270
|
-
:bubble-select="treeBubbleSelect(field)"
|
|
271
|
-
:disabled="disabled"
|
|
272
|
-
:size="controlSize"
|
|
273
|
-
:class="
|
|
274
|
-
mergeFormUiClass('max-h-72 overflow-y-auto p-2', formUi.ui.value.treeSelect?.ui?.tree)
|
|
356
|
+
:class="
|
|
357
|
+
mergeFormUiClass(
|
|
358
|
+
'max-h-72 overflow-y-auto p-2',
|
|
359
|
+
formUi.ui.value.treeSelect?.ui?.tree
|
|
360
|
+
)
|
|
275
361
|
"
|
|
276
|
-
|
|
362
|
+
:ui="{
|
|
277
363
|
item: formUi.ui.value.tree?.ui?.item,
|
|
278
364
|
itemWithChildren: formUi.ui.value.tree?.ui?.itemWithChildren,
|
|
279
365
|
listWithChildren: formUi.ui.value.tree?.ui?.listWithChildren,
|
|
@@ -283,68 +369,97 @@ function isOptionValue(value) {
|
|
|
283
369
|
linkTrailing: formUi.ui.value.tree?.ui?.linkTrailing,
|
|
284
370
|
linkTrailingIcon: formUi.ui.value.tree?.ui?.linkTrailingIcon
|
|
285
371
|
}"
|
|
286
|
-
|
|
287
|
-
>
|
|
288
|
-
<template
|
|
289
|
-
v-if="treeSelectionControl !== 'none'"
|
|
290
|
-
#item-leading="{ selected, indeterminate }"
|
|
372
|
+
@update:model-value="updateTreeModel"
|
|
291
373
|
>
|
|
292
|
-
<
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
374
|
+
<template
|
|
375
|
+
v-if="treeSelectionControl !== 'none'"
|
|
376
|
+
#item-wrapper="{ item, selected, expanded, indeterminate, handleToggle, ui }"
|
|
377
|
+
>
|
|
378
|
+
<div
|
|
379
|
+
:class="ui.link({ selected, disabled: disabled || item.disabled })"
|
|
380
|
+
:data-selected="selected ? '' : void 0"
|
|
381
|
+
@click="selectTreeRow(item)"
|
|
382
|
+
>
|
|
383
|
+
<SelectionCheckbox
|
|
384
|
+
v-if="treeSelectionControl === 'checkbox'"
|
|
385
|
+
:model-value="indeterminate ? 'indeterminate' : selected"
|
|
386
|
+
:label="String(item.label)"
|
|
387
|
+
:disabled="disabled || item.disabled"
|
|
388
|
+
:control-class="formUi.ui.value.tree?.ui?.selectionControl"
|
|
389
|
+
@click.stop
|
|
390
|
+
@update:model-value="toggleTreeItem(item)"
|
|
391
|
+
/>
|
|
392
|
+
<SelectionRadio
|
|
393
|
+
v-else
|
|
394
|
+
:value="treeKey(item)"
|
|
395
|
+
:label="String(item.label)"
|
|
396
|
+
:selected="selected"
|
|
397
|
+
:disabled="disabled || item.disabled"
|
|
398
|
+
:control-class="formUi.ui.value.tree?.ui?.selectionControl"
|
|
399
|
+
@click.stop
|
|
400
|
+
@select="selectRadioTreeItem(item)"
|
|
401
|
+
/>
|
|
402
|
+
<span :class="ui.linkLabel()">{{ item.label }}</span>
|
|
403
|
+
<button
|
|
404
|
+
v-if="item.children?.length"
|
|
405
|
+
type="button"
|
|
406
|
+
:aria-label="String(item.label)"
|
|
407
|
+
class="ms-auto inline-flex rounded-sm p-0.5 focus-visible:outline-2 focus-visible:outline-primary"
|
|
408
|
+
@click.stop="handleToggle"
|
|
409
|
+
>
|
|
410
|
+
<UIcon
|
|
411
|
+
name="i-lucide-chevron-down"
|
|
412
|
+
aria-hidden="true"
|
|
413
|
+
:class="[ui.linkTrailingIcon(), expanded ? 'rotate-180' : '']"
|
|
414
|
+
/>
|
|
415
|
+
</button>
|
|
416
|
+
</div>
|
|
417
|
+
</template>
|
|
418
|
+
</UTree>
|
|
419
|
+
<p
|
|
420
|
+
v-else
|
|
421
|
+
:class="
|
|
308
422
|
mergeFormUiClass(
|
|
309
423
|
'px-3 py-8 text-center text-sm text-muted',
|
|
310
424
|
formUi.ui.value.treeSelect?.ui?.empty
|
|
311
425
|
)
|
|
312
426
|
"
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
427
|
+
>
|
|
428
|
+
{{ t("form.fields.hierarchy.empty") }}
|
|
429
|
+
</p>
|
|
430
|
+
<div
|
|
431
|
+
v-if="field.clearable && selectedTreeItems.length"
|
|
432
|
+
class="flex justify-end border-t border-default p-2"
|
|
433
|
+
>
|
|
434
|
+
<UButton
|
|
435
|
+
type="button"
|
|
436
|
+
color="neutral"
|
|
437
|
+
variant="ghost"
|
|
438
|
+
size="xs"
|
|
439
|
+
icon="i-lucide-x"
|
|
440
|
+
:label="t('form.fields.hierarchy.clear')"
|
|
441
|
+
@click="clearTreeSelection"
|
|
442
|
+
/>
|
|
443
|
+
</div>
|
|
329
444
|
</div>
|
|
330
|
-
</
|
|
331
|
-
</
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
445
|
+
</template>
|
|
446
|
+
</UPopover>
|
|
447
|
+
<USelectMenu
|
|
448
|
+
v-else
|
|
449
|
+
v-model="model"
|
|
450
|
+
v-bind="controlProps"
|
|
451
|
+
class="w-full"
|
|
452
|
+
:items="selectItems"
|
|
453
|
+
value-key="value"
|
|
454
|
+
:label-key="field.type === 'cascader' || hasShowPath(field) ? 'pathLabel' : 'label'"
|
|
455
|
+
:multiple="field.multiple"
|
|
456
|
+
:search-input="field.searchable ?? true"
|
|
457
|
+
:clear="field.clearable === true"
|
|
458
|
+
:placeholder="placeholder"
|
|
459
|
+
:disabled="disabled"
|
|
460
|
+
:loading="options.loading.value"
|
|
461
|
+
@blur="handleBlur"
|
|
462
|
+
/>
|
|
463
|
+
</FormCompositeControl>
|
|
349
464
|
</FormFieldShell>
|
|
350
465
|
</template>
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { FormOptionValue } from '../../types/index.js';
|
|
2
|
+
import { type ResolvedFormOption } from '../../utils/options.js';
|
|
3
|
+
export declare function resolveHierarchySelection(params: {
|
|
4
|
+
next: readonly FormOptionValue[];
|
|
5
|
+
intent?: FormOptionValue;
|
|
6
|
+
items: readonly ResolvedFormOption[];
|
|
7
|
+
propagate: boolean;
|
|
8
|
+
bubble: boolean;
|
|
9
|
+
}): FormOptionValue[];
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { formOptionKey } from "../../utils/options.js";
|
|
2
|
+
export function resolveHierarchySelection(params) {
|
|
3
|
+
const values = /* @__PURE__ */ new Map();
|
|
4
|
+
for (const value of params.next) values.set(formOptionKey(value), value);
|
|
5
|
+
const intent = params.intent ? findOption(params.items, params.intent) : void 0;
|
|
6
|
+
if (params.propagate && intent) {
|
|
7
|
+
const selecting = values.has(formOptionKey(intent.value));
|
|
8
|
+
for (const descendant of flattenOptions(intent.children ?? [])) {
|
|
9
|
+
const key = formOptionKey(descendant.value);
|
|
10
|
+
if (selecting) values.set(key, descendant.value);
|
|
11
|
+
else values.delete(key);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
if (params.bubble)
|
|
15
|
+
for (const item of [...flattenOptions(params.items)].reverse()) {
|
|
16
|
+
if (!item.children?.length) continue;
|
|
17
|
+
const key = formOptionKey(item.value);
|
|
18
|
+
const allChildrenSelected = item.children.every(
|
|
19
|
+
(child) => values.has(formOptionKey(child.value))
|
|
20
|
+
);
|
|
21
|
+
if (allChildrenSelected) values.set(key, item.value);
|
|
22
|
+
else values.delete(key);
|
|
23
|
+
}
|
|
24
|
+
return [...values.values()];
|
|
25
|
+
}
|
|
26
|
+
function findOption(items, value) {
|
|
27
|
+
const key = formOptionKey(value);
|
|
28
|
+
return flattenOptions(items).find((item) => formOptionKey(item.value) === key);
|
|
29
|
+
}
|
|
30
|
+
function flattenOptions(items) {
|
|
31
|
+
return items.flatMap((item) => [item, ...flattenOptions(item.children ?? [])]);
|
|
32
|
+
}
|