@rotki/ui-library 3.0.0-beta.1 → 3.0.0-beta.3
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/components/accordions/accordion/RuiAccordion.vue_vue_type_script_setup_true_lang.js +3 -3
- package/dist/components/accordions/accordion/RuiAccordion.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/accordions/accordions/RuiAccordions.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/components/avatars/RuiAvatar.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/components/avatars/RuiAvatarGroup.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/components/buttons/button/RuiButton.js.map +1 -1
- package/dist/components/buttons/button/RuiButton.vue_vue_type_script_setup_true_lang.js +10 -10
- package/dist/components/buttons/button/RuiButton.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/buttons/button/button-styles.js +10 -2
- package/dist/components/buttons/button/button-styles.js.map +1 -1
- package/dist/components/buttons/button-group/RuiButtonGroup.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/components/calendar/RuiCalendar.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/components/calendar/RuiCalendarGrid.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/components/calendar/RuiCalendarHeader.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/components/calendar/RuiCalendarMenu.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/components/chips/RuiChip.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/components/color-picker/RuiColorBoard.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/components/color-picker/RuiColorDisplay.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/components/color-picker/RuiColorHue.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/components/color-picker/RuiColorInput.vue_vue_type_script_setup_true_lang.js +9 -10
- package/dist/components/color-picker/RuiColorInput.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/color-picker/RuiColorPicker.vue_vue_type_script_setup_true_lang.js +3 -4
- package/dist/components/color-picker/RuiColorPicker.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/date-time-picker/RuiDateTimePicker.vue_vue_type_script_setup_true_lang.js +33 -33
- package/dist/components/date-time-picker/RuiDateTimePicker.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/date-time-picker/use-date-bounds.js +1 -1
- package/dist/components/date-time-picker/use-date-time-selection.js +65 -66
- package/dist/components/date-time-picker/use-date-time-selection.js.map +1 -1
- package/dist/components/date-time-picker/use-input-handler.js +1 -1
- package/dist/components/date-time-picker/use-keyboard-handler.js +29 -30
- package/dist/components/date-time-picker/use-keyboard-handler.js.map +1 -1
- package/dist/components/forms/auto-complete/RuiAutoComplete.js.map +1 -1
- package/dist/components/forms/auto-complete/RuiAutoComplete.vue_vue_type_script_setup_true_lang.js +25 -24
- package/dist/components/forms/auto-complete/RuiAutoComplete.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/forms/auto-complete/auto-complete-styles.d.ts +3 -53
- package/dist/components/forms/auto-complete/auto-complete-styles.js +2 -1
- package/dist/components/forms/auto-complete/auto-complete-styles.js.map +1 -1
- package/dist/components/forms/category-picker/RuiCategoryPicker.vue_vue_type_script_setup_true_lang.js +49 -49
- package/dist/components/forms/category-picker/RuiCategoryPicker.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/forms/checkbox/RuiCheckbox.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/components/forms/checkbox/checkbox-group/RuiCheckboxGroup.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/components/forms/file-upload/RuiFileUpload.js.map +1 -1
- package/dist/components/forms/file-upload/RuiFileUpload.vue_vue_type_script_setup_true_lang.js +19 -17
- package/dist/components/forms/file-upload/RuiFileUpload.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/forms/radio-button/radio/RuiRadio.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/components/forms/select/RuiMenuSelect.vue_vue_type_script_setup_true_lang.js +11 -11
- package/dist/components/forms/select/RuiMenuSelect.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/forms/slider/RuiSlider.vue_vue_type_script_setup_true_lang.js +17 -17
- package/dist/components/forms/slider/RuiSlider.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/forms/switch/RuiSwitch.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/components/forms/text-area/RuiTextArea.vue_vue_type_script_setup_true_lang.js +21 -21
- package/dist/components/forms/text-area/RuiTextArea.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/forms/text-field/RuiTextField.js.map +1 -1
- package/dist/components/forms/text-field/RuiTextField.vue.d.ts +2 -0
- package/dist/components/forms/text-field/RuiTextField.vue_vue_type_script_setup_true_lang.js +24 -20
- package/dist/components/forms/text-field/RuiTextField.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/forms/text-input-styles.js +1 -1
- package/dist/components/forms/text-input-styles.js.map +1 -1
- package/dist/components/helpers/RuiFormTextDetail.js.map +1 -1
- package/dist/components/helpers/RuiFormTextDetail.vue.d.ts +11 -1
- package/dist/components/helpers/RuiFormTextDetail.vue_vue_type_script_setup_true_lang.js +3 -3
- package/dist/components/helpers/RuiFormTextDetail.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/icons/RuiIcon.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/components/logos/RuiLogo.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/components/overlays/badge/RuiBadge.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/components/overlays/dialog/RuiDialog.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/components/overlays/menu/RuiMenu.vue_vue_type_script_setup_true_lang.js +17 -17
- package/dist/components/overlays/menu/RuiMenu.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/overlays/navigation-drawer/RuiNavigationDrawer.js.map +1 -1
- package/dist/components/overlays/navigation-drawer/RuiNavigationDrawer.vue_vue_type_script_setup_true_lang.js +9 -9
- package/dist/components/overlays/navigation-drawer/RuiNavigationDrawer.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/overlays/notification/RuiNotification.vue_vue_type_script_setup_true_lang.js +3 -4
- package/dist/components/overlays/notification/RuiNotification.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/overlays/tooltip/RuiTooltip.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/components/progress/RuiProgress.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/components/steppers/RuiFooterStepper.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/components/steppers/RuiStepper.js.map +1 -1
- package/dist/components/steppers/RuiStepper.vue_vue_type_script_setup_true_lang.js +13 -8
- package/dist/components/steppers/RuiStepper.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/tables/RuiDataTable.vue_vue_type_script_setup_true_lang.js +27 -27
- package/dist/components/tables/RuiDataTable.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/tables/RuiTableHead.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/components/tables/RuiTablePagination.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/components/tables/data-table/RuiDataTableCell.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/components/tables/data-table/RuiDataTableGroupRow.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/components/tables/data-table/RuiDataTableMobileSort.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/components/tables/data-table/RuiDataTableRow.vue_vue_type_script_setup_true_lang.js +23 -23
- package/dist/components/tables/data-table/RuiDataTableRow.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/tables/use-pagination-navigation.js +1 -1
- package/dist/components/tabs/tab/RuiTab.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/components/tabs/tab/use-tab-link.js +1 -1
- package/dist/components/tabs/tab-items/RuiTabItems.vue_vue_type_script_setup_true_lang.js +6 -6
- package/dist/components/tabs/tab-items/RuiTabItems.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/tabs/tabs/RuiTabs.vue_vue_type_script_setup_true_lang.js +11 -12
- package/dist/components/tabs/tabs/RuiTabs.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/tabs/tabs/use-tab-indicator.js +7 -7
- package/dist/components/tabs/tabs/use-tab-indicator.js.map +1 -1
- package/dist/components/tabs/tabs/use-tab-keyboard.js +1 -1
- package/dist/components/tabs/tabs/use-tab-scroll.js +15 -15
- package/dist/components/tabs/tabs/use-tab-scroll.js.map +1 -1
- package/dist/components/time-picker/RuiTimePicker.vue_vue_type_script_setup_true_lang.js +60 -61
- package/dist/components/time-picker/RuiTimePicker.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/composables/breakpoint.js +3 -3
- package/dist/composables/breakpoint.js.map +1 -1
- package/dist/composables/dropdown-menu.d.ts +9 -9
- package/dist/composables/dropdown-menu.js +32 -32
- package/dist/composables/dropdown-menu.js.map +1 -1
- package/dist/composables/floating.d.ts +1 -1
- package/dist/composables/floating.js +11 -11
- package/dist/composables/floating.js.map +1 -1
- package/dist/composables/forms/auto-complete/focus.js +16 -17
- package/dist/composables/forms/auto-complete/focus.js.map +1 -1
- package/dist/composables/forms/auto-complete/keyboard-navigation.js +1 -1
- package/dist/composables/forms/auto-complete/search.js +6 -7
- package/dist/composables/forms/auto-complete/search.js.map +1 -1
- package/dist/composables/forms/auto-complete/selection.js +1 -1
- package/dist/composables/forms/auto-complete/value.js +1 -1
- package/dist/composables/forms/category-picker/use-category-picker.js +1 -1
- package/dist/composables/forms/use-prepend-append-width.js +6 -6
- package/dist/composables/forms/use-prepend-append-width.js.map +1 -1
- package/dist/composables/keyboard-scroll.js +5 -5
- package/dist/composables/keyboard-scroll.js.map +1 -1
- package/dist/composables/overlay-stack.js +1 -1
- package/dist/composables/sticky-header.js +8 -8
- package/dist/composables/sticky-header.js.map +1 -1
- package/dist/composables/tables/data-table/columns.js +1 -1
- package/dist/composables/tables/data-table/expansion.js +1 -1
- package/dist/composables/tables/data-table/grouping.js +27 -28
- package/dist/composables/tables/data-table/grouping.js.map +1 -1
- package/dist/composables/tables/data-table/page-scroll.d.ts +7 -5
- package/dist/composables/tables/data-table/page-scroll.js +48 -17
- package/dist/composables/tables/data-table/page-scroll.js.map +1 -1
- package/dist/composables/tables/data-table/pagination.js +1 -1
- package/dist/composables/tables/data-table/selection.js +37 -38
- package/dist/composables/tables/data-table/selection.js.map +1 -1
- package/dist/composables/tables/data-table/sort.js +1 -1
- package/dist/composables/theme.js +12 -12
- package/dist/composables/theme.js.map +1 -1
- package/dist/composables/timeout-manager.js +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/style.css +6 -18
- package/dist/types/dom.d.ts +9 -0
- package/dist/types/theme.d.ts +2 -3
- package/dist/types/theme.js.map +1 -1
- package/dist/utils/form-text-detail.js +1 -1
- package/dist/utils/helpers.js +1 -1
- package/dist/vendor/@vueuse/core/dist/index.js +1577 -0
- package/dist/vendor/@vueuse/core/dist/index.js.map +1 -0
- package/dist/vendor/@vueuse/shared/dist/index.js +563 -0
- package/dist/vendor/@vueuse/shared/dist/index.js.map +1 -0
- package/dist/vite-plugin/index.js +5 -6
- package/dist/vite-plugin/index.js.map +1 -1
- package/dist/web-types.json +9 -2
- package/package.json +5 -4
|
@@ -1,6 +1,6 @@
|
|
|
1
|
+
import { get, set, useArrayMap } from "../vendor/@vueuse/shared/dist/index.js";
|
|
2
|
+
import { useVirtualList } from "../vendor/@vueuse/core/dist/index.js";
|
|
1
3
|
import { computed, nextTick, ref, shallowRef, toValue, watch } from "vue";
|
|
2
|
-
import { useArrayMap, useVirtualList } from "@vueuse/core";
|
|
3
|
-
import { get as get$1, set as set$1 } from "@vueuse/shared";
|
|
4
4
|
//#region src/composables/dropdown-menu.ts
|
|
5
5
|
/**
|
|
6
6
|
* The rendered height of a default option row, a `list` button at its default or `sm` size.
|
|
@@ -42,13 +42,13 @@ function useDropdownMenu({ appendWidth, autoSelectFirst, dense, disabled = false
|
|
|
42
42
|
const getIdentifier = externalGetIdentifier ?? defaultGetIdentifier;
|
|
43
43
|
const getText = externalGetText ?? defaultGetText;
|
|
44
44
|
const activeIdentifiers = computed(() => {
|
|
45
|
-
const selected = toSelectedArray(get
|
|
45
|
+
const selected = toSelectedArray(get(value));
|
|
46
46
|
const identifiers = /* @__PURE__ */ new Set();
|
|
47
47
|
for (const item of selected) identifiers.add(getIdentifier(item));
|
|
48
48
|
return identifiers;
|
|
49
49
|
});
|
|
50
50
|
function isActiveItem(item) {
|
|
51
|
-
return get
|
|
51
|
+
return get(activeIdentifiers).has(getIdentifier(item));
|
|
52
52
|
}
|
|
53
53
|
const options = computed(() => {
|
|
54
54
|
const options = toValue(allOptions);
|
|
@@ -69,9 +69,9 @@ function useDropdownMenu({ appendWidth, autoSelectFirst, dense, disabled = false
|
|
|
69
69
|
}
|
|
70
70
|
const isGrouped = computed(() => toValue(groupBy) !== void 0);
|
|
71
71
|
const groupedOptions = computed(() => {
|
|
72
|
-
if (!get
|
|
72
|
+
if (!get(isGrouped)) return [];
|
|
73
73
|
const buckets = /* @__PURE__ */ new Map();
|
|
74
|
-
for (const item of get
|
|
74
|
+
for (const item of get(options)) {
|
|
75
75
|
const key = getGroupKey(item);
|
|
76
76
|
const list = buckets.get(key);
|
|
77
77
|
if (list) list.push(item);
|
|
@@ -92,16 +92,16 @@ function useDropdownMenu({ appendWidth, autoSelectFirst, dense, disabled = false
|
|
|
92
92
|
}));
|
|
93
93
|
const isOpen = externalIsOpen ?? shallowRef(false);
|
|
94
94
|
const valueKey = computed(() => {
|
|
95
|
-
const selected = get
|
|
95
|
+
const selected = get(value);
|
|
96
96
|
if (!keyAttr || !selected) return selected;
|
|
97
97
|
return Array.isArray(selected) ? selected.map((item) => item[keyAttr]) : selected[keyAttr];
|
|
98
98
|
});
|
|
99
|
-
const modelHighlightedIndex = ref(get
|
|
99
|
+
const modelHighlightedIndex = ref(get(autoSelectFirst) ? 0 : -1);
|
|
100
100
|
const modelUserNavigated = shallowRef(false);
|
|
101
101
|
const optionWidthBounds = computed(() => {
|
|
102
102
|
let min = 0;
|
|
103
103
|
let max = 0;
|
|
104
|
-
for (const option of get
|
|
104
|
+
for (const option of get(options)) {
|
|
105
105
|
const length = getText(option)?.toString()?.length ?? 0;
|
|
106
106
|
if (min === 0 && max === 0) {
|
|
107
107
|
min = length;
|
|
@@ -115,7 +115,7 @@ function useDropdownMenu({ appendWidth, autoSelectFirst, dense, disabled = false
|
|
|
115
115
|
};
|
|
116
116
|
});
|
|
117
117
|
const menuWidth = computed(() => {
|
|
118
|
-
const { min, max } = get
|
|
118
|
+
const { min, max } = get(optionWidthBounds);
|
|
119
119
|
const maxWidth = 30;
|
|
120
120
|
const paddingX = 1.5;
|
|
121
121
|
const fontMultiplier = toValue(dense) ? 12 : 13;
|
|
@@ -128,22 +128,22 @@ function useDropdownMenu({ appendWidth, autoSelectFirst, dense, disabled = false
|
|
|
128
128
|
return computeValue(min + difference / 2);
|
|
129
129
|
});
|
|
130
130
|
function toggle(state = false) {
|
|
131
|
-
set
|
|
131
|
+
set(isOpen, state);
|
|
132
132
|
}
|
|
133
133
|
function itemIndexInValue(item) {
|
|
134
|
-
const selected = toSelectedArray(get
|
|
134
|
+
const selected = toSelectedArray(get(value));
|
|
135
135
|
if (selected.length === 0) return -1;
|
|
136
136
|
const itemId = getIdentifier(item);
|
|
137
137
|
return selected.findIndex((selectedItem) => getIdentifier(selectedItem) === itemId);
|
|
138
138
|
}
|
|
139
139
|
function scrollHighlightedIntoView() {
|
|
140
|
-
get
|
|
140
|
+
get(_menuRef)?.querySelector("[data-highlighted=\"true\"]")?.scrollIntoView({ block: "nearest" });
|
|
141
141
|
}
|
|
142
142
|
async function adjustScrollByHighlightedIndex() {
|
|
143
|
-
const index = get
|
|
143
|
+
const index = get(modelHighlightedIndex);
|
|
144
144
|
if (index === -1) return;
|
|
145
145
|
await nextTick();
|
|
146
|
-
if (get
|
|
146
|
+
if (get(_menuRef)?.querySelector("[data-highlighted=\"true\"]")) {
|
|
147
147
|
scrollHighlightedIntoView();
|
|
148
148
|
return;
|
|
149
149
|
}
|
|
@@ -153,10 +153,10 @@ function useDropdownMenu({ appendWidth, autoSelectFirst, dense, disabled = false
|
|
|
153
153
|
}
|
|
154
154
|
async function updateOpen(open) {
|
|
155
155
|
if (!open) return;
|
|
156
|
-
const val = get
|
|
156
|
+
const val = get(value);
|
|
157
157
|
if (Array.isArray(val) && val.length > 0 || val !== null && val !== void 0) {
|
|
158
|
-
const index = get
|
|
159
|
-
if (index > -1) set
|
|
158
|
+
const index = get(options).findIndex(isActiveItem);
|
|
159
|
+
if (index > -1) set(modelHighlightedIndex, index);
|
|
160
160
|
}
|
|
161
161
|
await adjustScrollByHighlightedIndex();
|
|
162
162
|
}
|
|
@@ -167,47 +167,47 @@ function useDropdownMenu({ appendWidth, autoSelectFirst, dense, disabled = false
|
|
|
167
167
|
await adjustScrollByHighlightedIndex();
|
|
168
168
|
});
|
|
169
169
|
watch(options, async () => {
|
|
170
|
-
set
|
|
171
|
-
if (get
|
|
172
|
-
if (get
|
|
173
|
-
set
|
|
170
|
+
set(modelUserNavigated, false);
|
|
171
|
+
if (get(modelHighlightedIndex) !== -1) {
|
|
172
|
+
if (get(autoSelectFirst)) {
|
|
173
|
+
set(modelHighlightedIndex, 0);
|
|
174
174
|
await adjustScrollByHighlightedIndex();
|
|
175
175
|
} else {
|
|
176
|
-
set
|
|
176
|
+
set(modelHighlightedIndex, -1);
|
|
177
177
|
scrollTo(0);
|
|
178
178
|
}
|
|
179
179
|
} else scrollTo(0);
|
|
180
180
|
});
|
|
181
181
|
watch(isOpen, (open) => {
|
|
182
|
-
if (!open) set
|
|
182
|
+
if (!open) set(modelUserNavigated, false);
|
|
183
183
|
});
|
|
184
184
|
const moveHighlight = (up) => {
|
|
185
|
-
if (!get
|
|
185
|
+
if (!get(isOpen)) {
|
|
186
186
|
toggle(true);
|
|
187
187
|
return;
|
|
188
188
|
}
|
|
189
|
-
set
|
|
190
|
-
const items = get
|
|
189
|
+
set(modelUserNavigated, true);
|
|
190
|
+
const items = get(options);
|
|
191
191
|
const total = items.length;
|
|
192
192
|
if (total === 0) return;
|
|
193
193
|
const move = up ? -1 : 1;
|
|
194
|
-
let position = get
|
|
194
|
+
let position = get(modelHighlightedIndex);
|
|
195
195
|
for (let step = 0; step < total; step++) {
|
|
196
196
|
position += move;
|
|
197
197
|
if (position >= total) position = 0;
|
|
198
198
|
else if (position < 0) position = total - 1;
|
|
199
199
|
const candidate = items[position];
|
|
200
200
|
if (candidate !== void 0 && !isItemDisabled(candidate)) {
|
|
201
|
-
set
|
|
201
|
+
set(modelHighlightedIndex, position);
|
|
202
202
|
return;
|
|
203
203
|
}
|
|
204
204
|
}
|
|
205
205
|
};
|
|
206
206
|
const applyHighlighted = () => {
|
|
207
|
-
if (!setValue || !get
|
|
208
|
-
const highlightedIndexVal = get
|
|
207
|
+
if (!setValue || !get(isOpen)) return;
|
|
208
|
+
const highlightedIndexVal = get(modelHighlightedIndex);
|
|
209
209
|
if (highlightedIndexVal === -1) return;
|
|
210
|
-
const entry = get
|
|
210
|
+
const entry = get(options)[highlightedIndexVal];
|
|
211
211
|
if (entry !== void 0 && !isItemDisabled(entry)) setValue(entry);
|
|
212
212
|
};
|
|
213
213
|
return {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dropdown-menu.js","names":[],"sources":["../../src/composables/dropdown-menu.ts"],"sourcesContent":["import type { MaybeRefOrGetter, Ref, TemplateRef } from 'vue';\n\nexport type KeyOfType<T, V> = T extends string | number | boolean | symbol | null | undefined\n ? never\n : V extends object\n ? keyof T\n : keyof {\n [P in keyof T as T[P] extends V ? P : V extends T[P] ? P : never]: any;\n };\n\nexport interface DropdownItemAttr<TValue, TItem> {\n keyAttr?: KeyOfType<TItem, TValue extends Array<infer U> ? U : TValue>;\n textAttr?: keyof TItem | ((item: TItem) => string);\n}\n\n/**\n * An item key or a resolver. `& string` lets Vue's compiler infer a String runtime type for the key\n * form; a bare generic `keyof` compiles to Function only, and a consumer's runtime warns.\n */\nexport type GroupBy<TItem> = (keyof TItem & string) | ((item: TItem) => string);\n\nexport type ItemDisabled<TItem> = (keyof TItem & string) | ((item: TItem) => boolean);\n\n/**\n * The rendered height of a default option row, a `list` button at its default or `sm` size.\n * The virtual list reserves this much per row, so a mismatch leaves a gap under the last option.\n *\n * @param dense - whether the options render at the dense size\n * @returns the row height in pixels\n */\nexport function getOptionHeight(dense: boolean | undefined): number {\n return dense ? 32 : 40;\n}\n\nexport interface DropdownOptionGroup<TItem> {\n group: string;\n items: TItem[];\n}\n\nexport interface DropdownOptions<TValue, TItem> {\n options: MaybeRefOrGetter<TItem[]>;\n dense?: MaybeRefOrGetter<boolean>;\n disabled?: MaybeRefOrGetter<boolean>;\n value: Ref<TItem | TItem[] | undefined>;\n menuRef: Ref<HTMLElement> | TemplateRef<HTMLElement>;\n keyAttr?: KeyOfType<TItem, TValue extends Array<infer U> ? U : TValue>;\n textAttr?: keyof TItem | ((item: TItem) => string);\n appendWidth?: number;\n prependWidth?: number;\n itemHeight?: number;\n overscan?: number;\n autoSelectFirst?: boolean;\n setValue?: (val: TItem) => void;\n hideSelected?: boolean;\n isOpen?: Ref<boolean>;\n getText?: (item: TItem) => string | undefined;\n getIdentifier?: (item: TItem) => any;\n groupBy?: MaybeRefOrGetter<GroupBy<TItem> | undefined>;\n itemDisabled?: MaybeRefOrGetter<ItemDisabled<TItem> | undefined>;\n}\n\nexport function useDropdownOptionProperty<TValue, TItem>({\n keyAttr,\n textAttr,\n}: DropdownItemAttr<TValue, TItem>) {\n function getText(item: TItem): string | undefined {\n if (textAttr) {\n if (typeof textAttr === 'function')\n return textAttr(item);\n else return item[textAttr]?.toString();\n }\n\n return item?.toString();\n }\n\n function getIdentifier(\n item: TItem,\n ): TItem | TItem[KeyOfType<TItem, TValue extends Array<infer U> ? U : TValue>] {\n if (keyAttr)\n return item[keyAttr];\n\n return item;\n }\n\n return {\n getIdentifier,\n getText,\n };\n}\n\nfunction toSelectedArray<TItem>(val: TItem | TItem[] | undefined): TItem[] {\n if (Array.isArray(val))\n return val;\n if (val !== null && val !== undefined)\n return [val];\n return [];\n}\n\nexport function useDropdownMenu<TValue, TItem>({\n appendWidth,\n autoSelectFirst,\n dense,\n disabled = false,\n getIdentifier: externalGetIdentifier,\n getText: externalGetText,\n hideSelected,\n isOpen: externalIsOpen,\n itemHeight = getOptionHeight(false),\n keyAttr,\n menuRef: _menuRef,\n options: allOptions,\n overscan = 5,\n prependWidth,\n setValue,\n textAttr,\n value,\n groupBy,\n itemDisabled,\n}: DropdownOptions<TValue, TItem>) {\n const { getIdentifier: defaultGetIdentifier, getText: defaultGetText } = useDropdownOptionProperty({\n keyAttr,\n textAttr,\n });\n\n const getIdentifier = externalGetIdentifier ?? defaultGetIdentifier;\n const getText = externalGetText ?? defaultGetText;\n\n const activeIdentifiers = computed<Set<any>>(() => {\n const val = get(value);\n const selected: TItem[] = toSelectedArray(val);\n const identifiers = new Set<any>();\n for (const item of selected) {\n identifiers.add(getIdentifier(item));\n }\n return identifiers;\n });\n\n function isActiveItem(item: TItem): boolean {\n return get(activeIdentifiers).has(getIdentifier(item));\n }\n\n const options = computed<TItem[]>(() => {\n const options = toValue(allOptions);\n if (!hideSelected)\n return options;\n\n return options.filter(item => !isActiveItem(item));\n });\n\n function getGroupKey(item: TItem): string {\n const group = toValue(groupBy);\n if (!group)\n return '';\n\n if (typeof group === 'function')\n return group(item);\n\n return String(item[group] ?? '');\n }\n\n function isItemDisabled(item: TItem): boolean {\n const itemDisabledValue = toValue(itemDisabled);\n if (!itemDisabledValue)\n return false;\n\n if (typeof itemDisabledValue === 'function')\n return itemDisabledValue(item);\n\n return Boolean(item[itemDisabledValue]);\n }\n\n const isGrouped = computed<boolean>(() => toValue(groupBy) !== undefined);\n\n const groupedOptions = computed<DropdownOptionGroup<TItem>[]>(() => {\n if (!get(isGrouped))\n return [];\n\n const buckets = new Map<string, TItem[]>();\n for (const item of get(options)) {\n const key = getGroupKey(item);\n const list = buckets.get(key);\n if (list)\n list.push(item);\n else\n buckets.set(key, [item]);\n }\n\n return Array.from(buckets.entries()).map(([group, items]) => ({ group, items }));\n });\n\n const { containerProps, list, scrollTo, wrapperProps } = useVirtualList<TItem>(options, {\n itemHeight,\n overscan,\n });\n\n const renderedData = useArrayMap(list, ({ data, index: _index }) => ({ _index, item: data }));\n\n const isOpen = externalIsOpen ?? shallowRef<boolean>(false);\n\n const valueKey = computed(() => {\n const selected = get(value);\n if (!keyAttr || !selected)\n return selected;\n return Array.isArray(selected) ? selected.map(item => item[keyAttr]) : selected[keyAttr];\n });\n\n const modelHighlightedIndex: Ref<number> = ref(get(autoSelectFirst) ? 0 : -1);\n const modelUserNavigated = shallowRef<boolean>(false);\n\n const optionWidthBounds = computed<{ min: number; max: number }>(() => {\n let min = 0;\n let max = 0;\n for (const option of get(options)) {\n const length = getText(option)?.toString()?.length ?? 0;\n if (min === 0 && max === 0) {\n min = length;\n max = length;\n }\n else if (length < min) {\n min = length;\n }\n else if (length > max) {\n max = length;\n }\n }\n return { min, max };\n });\n\n const menuWidth = computed<string>(() => {\n const { min, max } = get(optionWidthBounds);\n const maxWidth = 30;\n const paddingX = 1.5;\n const fontMultiplier = toValue(dense) ? 12 : 13;\n const difference = max - min;\n\n function computeValue(width: number): string {\n const additionalWidths =\n (prependWidth ? prependWidth + 0.5 : 0) + (appendWidth ? appendWidth + 0.5 : 0);\n return `${Math.min((width * fontMultiplier) / 16 + paddingX + additionalWidths, maxWidth)}rem`;\n }\n\n if (difference <= 5)\n return computeValue(max);\n\n return computeValue(min + difference / 2);\n });\n\n function toggle(state: boolean = false): void {\n set(isOpen, state);\n }\n\n function itemIndexInValue(item: TItem): number {\n const val = get(value);\n const selected: TItem[] = toSelectedArray(val);\n\n if (selected.length === 0)\n return -1;\n\n const itemId = getIdentifier(item);\n return selected.findIndex(selectedItem => getIdentifier(selectedItem) === itemId);\n }\n\n function scrollHighlightedIntoView(): void {\n get(_menuRef)\n ?.querySelector<HTMLElement>('[data-highlighted=\"true\"]')\n ?.scrollIntoView({ block: 'nearest' });\n }\n\n async function adjustScrollByHighlightedIndex(): Promise<void> {\n const index = get(modelHighlightedIndex);\n if (index === -1)\n return;\n\n await nextTick();\n if (get(_menuRef)?.querySelector('[data-highlighted=\"true\"]')) {\n scrollHighlightedIntoView();\n return;\n }\n\n // Outside the virtual list's rendered window, so render it first, then nudge it fully into view\n scrollTo(index);\n await nextTick();\n scrollHighlightedIntoView();\n }\n\n async function updateOpen(open: boolean): Promise<void> {\n if (!open)\n return;\n\n const val = get(value);\n\n // Set highlighted index to active item\n if ((Array.isArray(val) && val.length > 0) || (val !== null && val !== undefined)) {\n const index = get(options).findIndex(isActiveItem);\n if (index > -1)\n set(modelHighlightedIndex, index);\n }\n\n await adjustScrollByHighlightedIndex();\n }\n\n watch([isOpen, () => toValue(disabled)], async ([open, _]) => {\n await updateOpen(open);\n });\n\n watch(modelHighlightedIndex, async () => {\n await adjustScrollByHighlightedIndex();\n });\n\n watch(options, async () => {\n set(modelUserNavigated, false);\n if (get(modelHighlightedIndex) !== -1) {\n if (get(autoSelectFirst)) {\n set(modelHighlightedIndex, 0);\n await adjustScrollByHighlightedIndex();\n }\n else {\n set(modelHighlightedIndex, -1);\n scrollTo(0);\n }\n }\n else {\n scrollTo(0);\n }\n });\n\n watch(isOpen, (open) => {\n if (!open)\n set(modelUserNavigated, false);\n });\n\n const moveHighlight = (up: boolean): void => {\n if (!get(isOpen)) {\n toggle(true);\n return;\n }\n\n set(modelUserNavigated, true);\n\n const items = get(options);\n const total = items.length;\n if (total === 0)\n return;\n\n const move = up ? -1 : 1;\n let position = get(modelHighlightedIndex);\n\n for (let step = 0; step < total; step++) {\n position += move;\n if (position >= total)\n position = 0;\n else if (position < 0)\n position = total - 1;\n\n const candidate = items[position];\n if (candidate !== undefined && !isItemDisabled(candidate)) {\n set(modelHighlightedIndex, position);\n return;\n }\n }\n };\n\n const applyHighlighted = (): void => {\n if (!setValue || !get(isOpen))\n return;\n\n const highlightedIndexVal = get(modelHighlightedIndex);\n if (highlightedIndexVal === -1)\n return;\n\n const entry = get(options)[highlightedIndexVal];\n if (entry !== undefined && !isItemDisabled(entry))\n setValue(entry);\n };\n\n return {\n applyHighlighted,\n containerProps,\n getIdentifier,\n getText,\n groupedOptions,\n modelHighlightedIndex,\n isActiveItem,\n isGrouped,\n isItemDisabled,\n isOpen,\n itemIndexInValue,\n menuWidth,\n moveHighlight,\n optionsWithSelectedHidden: options,\n renderedData,\n toggle,\n modelUserNavigated,\n valueKey,\n wrapperProps,\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"dropdown-menu.js","names":[],"sources":["../../src/composables/dropdown-menu.ts"],"sourcesContent":["import type { ComputedRef, MaybeRefOrGetter, Ref, TemplateRef } from 'vue';\n\nexport type KeyOfType<T, V> = T extends string | number | boolean | symbol | null | undefined\n ? never\n : V extends object\n ? keyof T\n : keyof {\n [P in keyof T as T[P] extends V ? P : V extends T[P] ? P : never]: any;\n };\n\nexport interface DropdownItemAttr<TValue, TItem> {\n keyAttr?: KeyOfType<TItem, TValue extends Array<infer U> ? U : TValue>;\n textAttr?: keyof TItem | ((item: TItem) => string);\n}\n\n/**\n * An item key or a resolver. `& string` lets Vue's compiler infer a String runtime type for the key\n * form; a bare generic `keyof` compiles to Function only, and a consumer's runtime warns.\n */\nexport type GroupBy<TItem> = (keyof TItem & string) | ((item: TItem) => string);\n\nexport type ItemDisabled<TItem> = (keyof TItem & string) | ((item: TItem) => boolean);\n\n/**\n * The rendered height of a default option row, a `list` button at its default or `sm` size.\n * The virtual list reserves this much per row, so a mismatch leaves a gap under the last option.\n *\n * @param dense - whether the options render at the dense size\n * @returns the row height in pixels\n */\nexport function getOptionHeight(dense: boolean | undefined): number {\n return dense ? 32 : 40;\n}\n\nexport interface DropdownOptionGroup<TItem> {\n group: string;\n items: TItem[];\n}\n\nexport interface DropdownOptions<TValue, TItem> {\n options: MaybeRefOrGetter<TItem[]>;\n dense?: MaybeRefOrGetter<boolean>;\n disabled?: MaybeRefOrGetter<boolean>;\n value: Ref<TItem | TItem[] | undefined>;\n menuRef: Ref<HTMLElement> | TemplateRef<HTMLElement>;\n keyAttr?: KeyOfType<TItem, TValue extends Array<infer U> ? U : TValue>;\n textAttr?: keyof TItem | ((item: TItem) => string);\n appendWidth?: number;\n prependWidth?: number;\n itemHeight?: number;\n overscan?: number;\n autoSelectFirst?: boolean;\n setValue?: (val: TItem) => void;\n hideSelected?: boolean;\n isOpen?: Ref<boolean>;\n getText?: (item: TItem) => string | undefined;\n getIdentifier?: (item: TItem) => any;\n groupBy?: MaybeRefOrGetter<GroupBy<TItem> | undefined>;\n itemDisabled?: MaybeRefOrGetter<ItemDisabled<TItem> | undefined>;\n}\n\nexport function useDropdownOptionProperty<TValue, TItem>({\n keyAttr,\n textAttr,\n}: DropdownItemAttr<TValue, TItem>) {\n function getText(item: TItem): string | undefined {\n if (textAttr) {\n if (typeof textAttr === 'function')\n return textAttr(item);\n else return item[textAttr]?.toString();\n }\n\n return item?.toString();\n }\n\n function getIdentifier(\n item: TItem,\n ): TItem | TItem[KeyOfType<TItem, TValue extends Array<infer U> ? U : TValue>] {\n if (keyAttr)\n return item[keyAttr];\n\n return item;\n }\n\n return {\n getIdentifier,\n getText,\n };\n}\n\nfunction toSelectedArray<TItem>(val: TItem | TItem[] | undefined): TItem[] {\n if (Array.isArray(val))\n return val;\n if (val !== null && val !== undefined)\n return [val];\n return [];\n}\n\nexport function useDropdownMenu<TValue, TItem>({\n appendWidth,\n autoSelectFirst,\n dense,\n disabled = false,\n getIdentifier: externalGetIdentifier,\n getText: externalGetText,\n hideSelected,\n isOpen: externalIsOpen,\n itemHeight = getOptionHeight(false),\n keyAttr,\n menuRef: _menuRef,\n options: allOptions,\n overscan = 5,\n prependWidth,\n setValue,\n textAttr,\n value,\n groupBy,\n itemDisabled,\n}: DropdownOptions<TValue, TItem>) {\n const { getIdentifier: defaultGetIdentifier, getText: defaultGetText } = useDropdownOptionProperty({\n keyAttr,\n textAttr,\n });\n\n const getIdentifier = externalGetIdentifier ?? defaultGetIdentifier;\n const getText = externalGetText ?? defaultGetText;\n\n const activeIdentifiers = computed<Set<any>>(() => {\n const val = get(value);\n const selected: TItem[] = toSelectedArray(val);\n const identifiers = new Set<any>();\n for (const item of selected) {\n identifiers.add(getIdentifier(item));\n }\n return identifiers;\n });\n\n function isActiveItem(item: TItem): boolean {\n return get(activeIdentifiers).has(getIdentifier(item));\n }\n\n const options = computed<TItem[]>(() => {\n const options = toValue(allOptions);\n if (!hideSelected)\n return options;\n\n return options.filter(item => !isActiveItem(item));\n });\n\n function getGroupKey(item: TItem): string {\n const group = toValue(groupBy);\n if (!group)\n return '';\n\n if (typeof group === 'function')\n return group(item);\n\n return String(item[group] ?? '');\n }\n\n function isItemDisabled(item: TItem): boolean {\n const itemDisabledValue = toValue(itemDisabled);\n if (!itemDisabledValue)\n return false;\n\n if (typeof itemDisabledValue === 'function')\n return itemDisabledValue(item);\n\n return Boolean(item[itemDisabledValue]);\n }\n\n const isGrouped = computed<boolean>(() => toValue(groupBy) !== undefined);\n\n const groupedOptions = computed<DropdownOptionGroup<TItem>[]>(() => {\n if (!get(isGrouped))\n return [];\n\n const buckets = new Map<string, TItem[]>();\n for (const item of get(options)) {\n const key = getGroupKey(item);\n const list = buckets.get(key);\n if (list)\n list.push(item);\n else\n buckets.set(key, [item]);\n }\n\n return Array.from(buckets.entries()).map(([group, items]) => ({ group, items }));\n });\n\n const { containerProps, list, scrollTo, wrapperProps } = useVirtualList<TItem>(options, {\n itemHeight,\n overscan,\n });\n\n // typed as a plain ComputedRef so the published return type names nothing from VueUse\n const renderedData: ComputedRef<{ _index: number; item: TItem }[]> = useArrayMap(list, ({ data, index: _index }) => ({ _index, item: data }));\n\n const isOpen = externalIsOpen ?? shallowRef<boolean>(false);\n\n const valueKey = computed(() => {\n const selected = get(value);\n if (!keyAttr || !selected)\n return selected;\n return Array.isArray(selected) ? selected.map(item => item[keyAttr]) : selected[keyAttr];\n });\n\n const modelHighlightedIndex: Ref<number> = ref(get(autoSelectFirst) ? 0 : -1);\n const modelUserNavigated = shallowRef<boolean>(false);\n\n const optionWidthBounds = computed<{ min: number; max: number }>(() => {\n let min = 0;\n let max = 0;\n for (const option of get(options)) {\n const length = getText(option)?.toString()?.length ?? 0;\n if (min === 0 && max === 0) {\n min = length;\n max = length;\n }\n else if (length < min) {\n min = length;\n }\n else if (length > max) {\n max = length;\n }\n }\n return { min, max };\n });\n\n const menuWidth = computed<string>(() => {\n const { min, max } = get(optionWidthBounds);\n const maxWidth = 30;\n const paddingX = 1.5;\n const fontMultiplier = toValue(dense) ? 12 : 13;\n const difference = max - min;\n\n function computeValue(width: number): string {\n const additionalWidths =\n (prependWidth ? prependWidth + 0.5 : 0) + (appendWidth ? appendWidth + 0.5 : 0);\n return `${Math.min((width * fontMultiplier) / 16 + paddingX + additionalWidths, maxWidth)}rem`;\n }\n\n if (difference <= 5)\n return computeValue(max);\n\n return computeValue(min + difference / 2);\n });\n\n function toggle(state: boolean = false): void {\n set(isOpen, state);\n }\n\n function itemIndexInValue(item: TItem): number {\n const val = get(value);\n const selected: TItem[] = toSelectedArray(val);\n\n if (selected.length === 0)\n return -1;\n\n const itemId = getIdentifier(item);\n return selected.findIndex(selectedItem => getIdentifier(selectedItem) === itemId);\n }\n\n function scrollHighlightedIntoView(): void {\n get(_menuRef)\n ?.querySelector<HTMLElement>('[data-highlighted=\"true\"]')\n ?.scrollIntoView({ block: 'nearest' });\n }\n\n async function adjustScrollByHighlightedIndex(): Promise<void> {\n const index = get(modelHighlightedIndex);\n if (index === -1)\n return;\n\n await nextTick();\n if (get(_menuRef)?.querySelector('[data-highlighted=\"true\"]')) {\n scrollHighlightedIntoView();\n return;\n }\n\n // Outside the virtual list's rendered window, so render it first, then nudge it fully into view\n scrollTo(index);\n await nextTick();\n scrollHighlightedIntoView();\n }\n\n async function updateOpen(open: boolean): Promise<void> {\n if (!open)\n return;\n\n const val = get(value);\n\n // Set highlighted index to active item\n if ((Array.isArray(val) && val.length > 0) || (val !== null && val !== undefined)) {\n const index = get(options).findIndex(isActiveItem);\n if (index > -1)\n set(modelHighlightedIndex, index);\n }\n\n await adjustScrollByHighlightedIndex();\n }\n\n watch([isOpen, () => toValue(disabled)], async ([open, _]) => {\n await updateOpen(open);\n });\n\n watch(modelHighlightedIndex, async () => {\n await adjustScrollByHighlightedIndex();\n });\n\n watch(options, async () => {\n set(modelUserNavigated, false);\n if (get(modelHighlightedIndex) !== -1) {\n if (get(autoSelectFirst)) {\n set(modelHighlightedIndex, 0);\n await adjustScrollByHighlightedIndex();\n }\n else {\n set(modelHighlightedIndex, -1);\n scrollTo(0);\n }\n }\n else {\n scrollTo(0);\n }\n });\n\n watch(isOpen, (open) => {\n if (!open)\n set(modelUserNavigated, false);\n });\n\n const moveHighlight = (up: boolean): void => {\n if (!get(isOpen)) {\n toggle(true);\n return;\n }\n\n set(modelUserNavigated, true);\n\n const items = get(options);\n const total = items.length;\n if (total === 0)\n return;\n\n const move = up ? -1 : 1;\n let position = get(modelHighlightedIndex);\n\n for (let step = 0; step < total; step++) {\n position += move;\n if (position >= total)\n position = 0;\n else if (position < 0)\n position = total - 1;\n\n const candidate = items[position];\n if (candidate !== undefined && !isItemDisabled(candidate)) {\n set(modelHighlightedIndex, position);\n return;\n }\n }\n };\n\n const applyHighlighted = (): void => {\n if (!setValue || !get(isOpen))\n return;\n\n const highlightedIndexVal = get(modelHighlightedIndex);\n if (highlightedIndexVal === -1)\n return;\n\n const entry = get(options)[highlightedIndexVal];\n if (entry !== undefined && !isItemDisabled(entry))\n setValue(entry);\n };\n\n return {\n applyHighlighted,\n containerProps,\n getIdentifier,\n getText,\n groupedOptions,\n modelHighlightedIndex,\n isActiveItem,\n isGrouped,\n isItemDisabled,\n isOpen,\n itemIndexInValue,\n menuWidth,\n moveHighlight,\n optionsWithSelectedHidden: options,\n renderedData,\n toggle,\n modelUserNavigated,\n valueKey,\n wrapperProps,\n };\n}\n"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
import type { MaybeElement } from '../types/dom';
|
|
1
2
|
import { type VirtualElement as FloatingVirtualElement } from '@floating-ui/dom';
|
|
2
|
-
import { type MaybeElement } from '@vueuse/core';
|
|
3
3
|
import { type MaybeRefOrGetter, type Ref } from 'vue';
|
|
4
4
|
type VirtualElement = FloatingVirtualElement;
|
|
5
5
|
export declare const Placement: {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
+
import { get, set } from "../vendor/@vueuse/shared/dist/index.js";
|
|
2
|
+
import { unrefElement } from "../vendor/@vueuse/core/dist/index.js";
|
|
1
3
|
import { useTimeoutManager } from "./timeout-manager.js";
|
|
2
4
|
import { onMounted, readonly, ref, shallowRef, toValue, watchEffect } from "vue";
|
|
3
|
-
import { unrefElement } from "@vueuse/core";
|
|
4
|
-
import { get as get$1, set as set$1 } from "@vueuse/shared";
|
|
5
5
|
import { arrow, autoUpdate, computePosition, flip, offset, shift, size } from "@floating-ui/dom";
|
|
6
6
|
//#region src/composables/floating.ts
|
|
7
7
|
var Placement = {
|
|
@@ -94,16 +94,16 @@ function useFloating(options, disabled = false, openDelay = 0, closeDelay = 0, v
|
|
|
94
94
|
const openTimeoutManager = useTimeoutManager();
|
|
95
95
|
const closeTimeoutManager = useTimeoutManager();
|
|
96
96
|
function onLeaveComplete() {
|
|
97
|
-
set
|
|
97
|
+
set(visible, false);
|
|
98
98
|
}
|
|
99
99
|
function onOpen(immediate = false) {
|
|
100
100
|
if (toValue(disabled)) return;
|
|
101
101
|
closeTimeoutManager.clear();
|
|
102
|
-
set
|
|
102
|
+
set(leavePending, false);
|
|
103
103
|
if (!openTimeoutManager.isActive()) {
|
|
104
|
-
set
|
|
104
|
+
set(visible, true);
|
|
105
105
|
openTimeoutManager.create(() => {
|
|
106
|
-
set
|
|
106
|
+
set(open, true);
|
|
107
107
|
}, immediate ? 0 : toValue(openDelay));
|
|
108
108
|
}
|
|
109
109
|
}
|
|
@@ -111,15 +111,15 @@ function useFloating(options, disabled = false, openDelay = 0, closeDelay = 0, v
|
|
|
111
111
|
if (toValue(disabled)) return;
|
|
112
112
|
openTimeoutManager.clear();
|
|
113
113
|
if (!closeTimeoutManager.isActive()) closeTimeoutManager.create(() => {
|
|
114
|
-
if (!get
|
|
115
|
-
set
|
|
114
|
+
if (!get(open)) onLeaveComplete();
|
|
115
|
+
set(open, false);
|
|
116
116
|
}, immediate ? 0 : toValue(closeDelay));
|
|
117
117
|
}
|
|
118
118
|
function onLeavePending() {
|
|
119
|
-
set
|
|
119
|
+
set(leavePending, true);
|
|
120
120
|
}
|
|
121
121
|
function getValidElements() {
|
|
122
|
-
if (!get
|
|
122
|
+
if (!get(popover) || !get(reference) && !toValue(virtualReference)) return null;
|
|
123
123
|
const popoverEl = unrefElement(popover);
|
|
124
124
|
const referenceEl = toValue(virtualReference) || unrefElement(reference);
|
|
125
125
|
if (!(popoverEl instanceof HTMLElement) || !referenceEl) return null;
|
|
@@ -145,7 +145,7 @@ function useFloating(options, disabled = false, openDelay = 0, closeDelay = 0, v
|
|
|
145
145
|
position: strategy,
|
|
146
146
|
top: `${result.y}px`
|
|
147
147
|
});
|
|
148
|
-
set
|
|
148
|
+
set(currentPlacement, result.placement);
|
|
149
149
|
applyArrowStyles(arrowEl, result);
|
|
150
150
|
}
|
|
151
151
|
function startAutoUpdate() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"floating.js","names":[],"sources":["../../src/composables/floating.ts"],"sourcesContent":["import {\n arrow,\n autoUpdate,\n computePosition,\n type ComputePositionReturn,\n flip,\n type VirtualElement as FloatingVirtualElement,\n type Middleware,\n offset,\n shift,\n size,\n} from '@floating-ui/dom';\nimport { type MaybeElement, unrefElement } from '@vueuse/core';\nimport { type MaybeRefOrGetter, onMounted, type Ref, ref, watchEffect } from 'vue';\nimport { useTimeoutManager } from './timeout-manager';\n\ntype VirtualElement = FloatingVirtualElement;\n\nexport const Placement = {\n bottom: 'bottom',\n bottomEnd: 'bottom-end',\n bottomStart: 'bottom-start',\n left: 'left',\n leftEnd: 'left-end',\n leftStart: 'left-start',\n right: 'right',\n rightEnd: 'right-end',\n rightStart: 'right-start',\n top: 'top',\n topEnd: 'top-end',\n topStart: 'top-start',\n} as const;\n\nexport type Placement = (typeof Placement)[keyof typeof Placement];\n\nexport const Strategy = {\n absolute: 'absolute',\n fixed: 'fixed',\n} as const;\n\nexport type Strategy = (typeof Strategy)[keyof typeof Strategy];\n\nexport interface FloatingOptions {\n /** Preferred placement relative to the reference element; defaults to `Placement.bottom`. */\n placement?: Placement;\n /** CSS positioning strategy; defaults to `Strategy.absolute`. */\n strategy?: Strategy;\n /** Main-axis and/or cross-axis offset from the reference element; defaults to 2. */\n offset?: number | { mainAxis?: number; crossAxis?: number };\n /** Whether to flip to the opposite side when overflowing; defaults to true. */\n flip?: boolean;\n /** Padding from viewport edges for shift middleware; defaults to 8. */\n shiftPadding?: number;\n /** Whether to auto-update position on scroll/resize; defaults to true. */\n autoUpdate?: boolean | { scroll?: boolean; resize?: boolean };\n /**\n * Cap the floating element to the space available toward the viewport edge so\n * it never overflows the window. Exposes the measured space as the\n * `--rui-floating-max-height` custom property on the floating element; the\n * content is responsible for consuming it by capping its own max-height to\n * that variable and scrolling internally. Defaults to false.\n */\n size?: boolean;\n}\n\n/** Custom property carrying the space-aware max height set by the size middleware. */\nconst FLOATING_MAX_HEIGHT_VAR = '--rui-floating-max-height';\n\nexport const DEFAULT_FLOATING_OPTIONS: Required<FloatingOptions> = {\n autoUpdate: true,\n flip: true,\n offset: 2,\n placement: Placement.bottom,\n shiftPadding: 8,\n size: false,\n strategy: Strategy.absolute,\n};\n\nexport interface UseFloatingReturn {\n currentPlacement: Readonly<Ref<Placement>>;\n leavePending: Ref<boolean>;\n onClose: (immediate?: boolean) => void;\n onLeaveComplete: () => void;\n onLeavePending: () => void;\n onOpen: (immediate?: boolean) => void;\n open: Ref<boolean>;\n popover: Ref<MaybeElement>;\n reference: Ref<HTMLElement | undefined>;\n updatePosition: () => Promise<void>;\n visible: Ref<boolean>;\n}\n\n/**\n * Cap the floating element to the space available toward the viewport edge and\n * expose it as {@link FLOATING_MAX_HEIGHT_VAR}. The content decides how to use\n * it (cap its own height and scroll internally); writing a custom property\n * instead of a hard max-height keeps this non-invasive for elements that opt in\n * but size themselves differently.\n */\nfunction buildSizeMiddleware(padding: number): Middleware {\n return size({\n padding,\n apply({ availableHeight, elements }) {\n elements.floating.style.setProperty(FLOATING_MAX_HEIGHT_VAR, `${Math.max(0, Math.floor(availableHeight))}px`);\n },\n });\n}\n\n/**\n * The offset middleware, from either the shorthand distance or the per-axis\n * form, falling back to the default distance on the main axis.\n */\nfunction buildOffsetMiddleware(opts: FloatingOptions): Middleware {\n const off = opts.offset ?? DEFAULT_FLOATING_OPTIONS.offset;\n\n if (typeof off === 'number')\n return offset(off);\n\n const defaultOffset = typeof DEFAULT_FLOATING_OPTIONS.offset === 'number' ? DEFAULT_FLOATING_OPTIONS.offset : 0;\n return offset({ mainAxis: off.mainAxis ?? defaultOffset, crossAxis: off.crossAxis ?? 0 });\n}\n\nfunction buildMiddleware(opts: FloatingOptions, arrowEl: HTMLElement | null): Middleware[] {\n const mw: Middleware[] = [buildOffsetMiddleware(opts)];\n\n if (opts.flip !== false)\n mw.push(flip());\n\n // `crossAxis`: when neither side fits, overlap the activator rather than open past the viewport edge\n mw.push(shift({ padding: opts.shiftPadding ?? DEFAULT_FLOATING_OPTIONS.shiftPadding, crossAxis: true }));\n\n if (arrowEl)\n mw.push(arrow({ element: arrowEl, padding: 4 }));\n\n if (opts.size === true)\n mw.push(buildSizeMiddleware(opts.shiftPadding ?? DEFAULT_FLOATING_OPTIONS.shiftPadding));\n\n return mw;\n}\n\nfunction applyArrowStyles(arrowEl: HTMLElement | null, result: ComputePositionReturn): void {\n const arrowData = result.middlewareData.arrow;\n if (!arrowEl || !arrowData)\n return;\n\n Object.assign(arrowEl.style, {\n left: arrowData.x != null ? `${arrowData.x}px` : '',\n top: arrowData.y != null ? `${arrowData.y}px` : '',\n });\n}\n\nexport function useFloating(\n options: MaybeRefOrGetter<FloatingOptions>,\n disabled: MaybeRefOrGetter<boolean> = false,\n openDelay: MaybeRefOrGetter<number> = 0,\n closeDelay: MaybeRefOrGetter<number> = 0,\n virtualReference?: MaybeRefOrGetter<Element | VirtualElement | undefined>,\n): UseFloatingReturn {\n const reference = ref<HTMLElement>();\n const popover = ref<MaybeElement>();\n const open = shallowRef<boolean>(false);\n const visible = shallowRef<boolean>(false);\n const leavePending = shallowRef<boolean>(false);\n const currentPlacement = shallowRef<Placement>(toValue(options).placement ?? DEFAULT_FLOATING_OPTIONS.placement);\n\n let cleanupAutoUpdate: (() => void) | null = null;\n\n const openTimeoutManager = useTimeoutManager();\n const closeTimeoutManager = useTimeoutManager();\n\n function onLeaveComplete(): void {\n set(visible, false);\n }\n\n function onOpen(immediate: boolean = false): void {\n if (toValue(disabled))\n return;\n\n closeTimeoutManager.clear();\n\n set(leavePending, false);\n if (!openTimeoutManager.isActive()) {\n set(visible, true);\n\n openTimeoutManager.create(\n () => {\n set(open, true);\n },\n immediate ? 0 : toValue(openDelay),\n );\n }\n }\n\n function onClose(immediate: boolean = false): void {\n if (toValue(disabled))\n return;\n\n openTimeoutManager.clear();\n\n if (!closeTimeoutManager.isActive()) {\n closeTimeoutManager.create(\n () => {\n if (!get(open))\n onLeaveComplete();\n\n set(open, false);\n },\n immediate ? 0 : toValue(closeDelay),\n );\n }\n }\n\n function onLeavePending(): void {\n set(leavePending, true);\n }\n\n function getValidElements(): { popoverEl: HTMLElement; referenceEl: Element | VirtualElement } | null {\n if (!get(popover) || (!get(reference) && !toValue(virtualReference)))\n return null;\n\n const popoverEl = unrefElement(popover);\n const referenceEl = toValue(virtualReference) || unrefElement(reference);\n\n if (!(popoverEl instanceof HTMLElement) || !referenceEl)\n return null;\n\n return { popoverEl, referenceEl };\n }\n\n async function updatePosition(): Promise<void> {\n const elements = getValidElements();\n if (!elements)\n return;\n\n const { popoverEl, referenceEl } = elements;\n const opts = toValue(options);\n const arrowEl = popoverEl.querySelector<HTMLElement>('[data-id=\"arrow\"]');\n const strategy = opts.strategy ?? DEFAULT_FLOATING_OPTIONS.strategy;\n\n const result = await computePosition(referenceEl, popoverEl, {\n middleware: buildMiddleware(opts, arrowEl),\n placement: opts.placement ?? DEFAULT_FLOATING_OPTIONS.placement,\n strategy,\n });\n\n Object.assign(popoverEl.style, {\n left: `${result.x}px`,\n position: strategy,\n top: `${result.y}px`,\n });\n\n set(currentPlacement, result.placement);\n applyArrowStyles(arrowEl, result);\n }\n\n function startAutoUpdate(): void {\n stopAutoUpdate();\n const elements = getValidElements();\n if (!elements)\n return;\n\n const { popoverEl, referenceEl } = elements;\n const opts = toValue(options);\n const autoUpdateOpt = opts.autoUpdate ?? DEFAULT_FLOATING_OPTIONS.autoUpdate;\n\n if (autoUpdateOpt === false)\n return;\n\n const autoUpdateOptions = typeof autoUpdateOpt === 'object'\n ? {\n ancestorResize: autoUpdateOpt.resize ?? true,\n ancestorScroll: autoUpdateOpt.scroll ?? true,\n elementResize: true,\n }\n : undefined;\n\n cleanupAutoUpdate = autoUpdate(\n referenceEl,\n popoverEl,\n () => { updatePosition().catch(() => {}); },\n autoUpdateOptions,\n );\n }\n\n function stopAutoUpdate(): void {\n cleanupAutoUpdate?.();\n cleanupAutoUpdate = null;\n }\n\n onMounted(() => {\n watchEffect((onCleanup) => {\n startAutoUpdate();\n onCleanup(stopAutoUpdate);\n });\n });\n\n return {\n currentPlacement: readonly(currentPlacement),\n leavePending, // eslint-disable-line @rotki/composable-return-readonly -- written by consumer transition hooks\n onClose,\n onLeaveComplete,\n onLeavePending,\n onOpen,\n open, // eslint-disable-line @rotki/composable-return-readonly -- v-model bound by consumers\n popover, // eslint-disable-line @rotki/composable-return-readonly -- template ref bound by consumers\n reference, // eslint-disable-line @rotki/composable-return-readonly -- template ref bound by consumers\n updatePosition,\n visible, // eslint-disable-line @rotki/composable-return-readonly -- used as v-if condition by consumers\n };\n}\n"],"mappings":";;;;;;AAkBA,IAAa,YAAY;CACvB,QAAQ;CACR,WAAW;CACX,aAAa;CACb,MAAM;CACN,SAAS;CACT,WAAW;CACX,OAAO;CACP,UAAU;CACV,YAAY;CACZ,KAAK;CACL,QAAQ;CACR,UAAU;AACZ;AAIA,IAAa,WAAW;CACtB,UAAU;CACV,OAAO;AACT;;AA4BA,IAAM,0BAA0B;AAEhC,IAAa,2BAAsD;CACjE,YAAY;CACZ,MAAM;CACN,QAAQ;CACR,WAAW,UAAU;CACrB,cAAc;CACd,MAAM;CACN,UAAU,SAAS;AACrB;;;;;;;;AAuBA,SAAS,oBAAoB,SAA6B;CACxD,OAAO,KAAK;EACV;EACA,MAAM,EAAE,iBAAiB,YAAY;GACnC,SAAS,SAAS,MAAM,YAAY,yBAAyB,GAAG,KAAK,IAAI,GAAG,KAAK,MAAM,eAAe,CAAC,EAAE,GAAG;EAC9G;CACF,CAAC;AACH;;;;;AAMA,SAAS,sBAAsB,MAAmC;CAChE,MAAM,MAAM,KAAK,UAAU,yBAAyB;CAEpD,IAAI,OAAO,QAAQ,UACjB,OAAO,OAAO,GAAG;CAEnB,MAAM,gBAAgB,OAAO,yBAAyB,WAAW,WAAW,yBAAyB,SAAS;CAC9G,OAAO,OAAO;EAAE,UAAU,IAAI,YAAY;EAAe,WAAW,IAAI,aAAa;CAAE,CAAC;AAC1F;AAEA,SAAS,gBAAgB,MAAuB,SAA2C;CACzF,MAAM,KAAmB,CAAC,sBAAsB,IAAI,CAAC;CAErD,IAAI,KAAK,SAAS,OAChB,GAAG,KAAK,KAAK,CAAC;CAGhB,GAAG,KAAK,MAAM;EAAE,SAAS,KAAK,gBAAgB,yBAAyB;EAAc,WAAW;CAAK,CAAC,CAAC;CAEvG,IAAI,SACF,GAAG,KAAK,MAAM;EAAE,SAAS;EAAS,SAAS;CAAE,CAAC,CAAC;CAEjD,IAAI,KAAK,SAAS,MAChB,GAAG,KAAK,oBAAoB,KAAK,gBAAgB,yBAAyB,YAAY,CAAC;CAEzF,OAAO;AACT;AAEA,SAAS,iBAAiB,SAA6B,QAAqC;CAC1F,MAAM,YAAY,OAAO,eAAe;CACxC,IAAI,CAAC,WAAW,CAAC,WACf;CAEF,OAAO,OAAO,QAAQ,OAAO;EAC3B,MAAM,UAAU,KAAK,OAAO,GAAG,UAAU,EAAE,MAAM;EACjD,KAAK,UAAU,KAAK,OAAO,GAAG,UAAU,EAAE,MAAM;CAClD,CAAC;AACH;AAEA,SAAgB,YACd,SACA,WAAsC,OACtC,YAAsC,GACtC,aAAuC,GACvC,kBACmB;CACnB,MAAM,YAAY,IAAiB;CACnC,MAAM,UAAU,IAAkB;CAClC,MAAM,OAAO,WAAoB,KAAK;CACtC,MAAM,UAAU,WAAoB,KAAK;CACzC,MAAM,eAAe,WAAoB,KAAK;CAC9C,MAAM,mBAAmB,WAAsB,QAAQ,OAAO,CAAC,CAAC,aAAa,yBAAyB,SAAS;CAE/G,IAAI,oBAAyC;CAE7C,MAAM,qBAAqB,kBAAkB;CAC7C,MAAM,sBAAsB,kBAAkB;CAE9C,SAAS,kBAAwB;EAC/B,MAAI,SAAS,KAAK;CACpB;CAEA,SAAS,OAAO,YAAqB,OAAa;EAChD,IAAI,QAAQ,QAAQ,GAClB;EAEF,oBAAoB,MAAM;EAE1B,MAAI,cAAc,KAAK;EACvB,IAAI,CAAC,mBAAmB,SAAS,GAAG;GAClC,MAAI,SAAS,IAAI;GAEjB,mBAAmB,aACX;IACJ,MAAI,MAAM,IAAI;GAChB,GACA,YAAY,IAAI,QAAQ,SAAS,CACnC;EACF;CACF;CAEA,SAAS,QAAQ,YAAqB,OAAa;EACjD,IAAI,QAAQ,QAAQ,GAClB;EAEF,mBAAmB,MAAM;EAEzB,IAAI,CAAC,oBAAoB,SAAS,GAChC,oBAAoB,aACZ;GACJ,IAAI,CAAC,MAAI,IAAI,GACX,gBAAgB;GAElB,MAAI,MAAM,KAAK;EACjB,GACA,YAAY,IAAI,QAAQ,UAAU,CACpC;CAEJ;CAEA,SAAS,iBAAuB;EAC9B,MAAI,cAAc,IAAI;CACxB;CAEA,SAAS,mBAA6F;EACpG,IAAI,CAAC,MAAI,OAAO,KAAM,CAAC,MAAI,SAAS,KAAK,CAAC,QAAQ,gBAAgB,GAChE,OAAO;EAET,MAAM,YAAY,aAAa,OAAO;EACtC,MAAM,cAAc,QAAQ,gBAAgB,KAAK,aAAa,SAAS;EAEvE,IAAI,EAAE,qBAAqB,gBAAgB,CAAC,aAC1C,OAAO;EAET,OAAO;GAAE;GAAW;EAAY;CAClC;CAEA,eAAe,iBAAgC;EAC7C,MAAM,WAAW,iBAAiB;EAClC,IAAI,CAAC,UACH;EAEF,MAAM,EAAE,WAAW,gBAAgB;EACnC,MAAM,OAAO,QAAQ,OAAO;EAC5B,MAAM,UAAU,UAAU,cAA2B,qBAAmB;EACxE,MAAM,WAAW,KAAK,YAAY,yBAAyB;EAE3D,MAAM,SAAS,MAAM,gBAAgB,aAAa,WAAW;GAC3D,YAAY,gBAAgB,MAAM,OAAO;GACzC,WAAW,KAAK,aAAa,yBAAyB;GACtD;EACF,CAAC;EAED,OAAO,OAAO,UAAU,OAAO;GAC7B,MAAM,GAAG,OAAO,EAAE;GAClB,UAAU;GACV,KAAK,GAAG,OAAO,EAAE;EACnB,CAAC;EAED,MAAI,kBAAkB,OAAO,SAAS;EACtC,iBAAiB,SAAS,MAAM;CAClC;CAEA,SAAS,kBAAwB;EAC/B,eAAe;EACf,MAAM,WAAW,iBAAiB;EAClC,IAAI,CAAC,UACH;EAEF,MAAM,EAAE,WAAW,gBAAgB;EAEnC,MAAM,gBADO,QAAQ,OACC,CAAA,CAAK,cAAc,yBAAyB;EAElE,IAAI,kBAAkB,OACpB;EAEF,MAAM,oBAAoB,OAAO,kBAAkB,WAC/C;GACE,gBAAgB,cAAc,UAAU;GACxC,gBAAgB,cAAc,UAAU;GACxC,eAAe;EACjB,IACA,KAAA;EAEJ,oBAAoB,WAClB,aACA,iBACM;GAAE,eAAe,CAAC,CAAC,YAAY,CAAC,CAAC;EAAG,GAC1C,iBACF;CACF;CAEA,SAAS,iBAAuB;EAC9B,oBAAoB;EACpB,oBAAoB;CACtB;CAEA,gBAAgB;EACd,aAAa,cAAc;GACzB,gBAAgB;GAChB,UAAU,cAAc;EAC1B,CAAC;CACH,CAAC;CAED,OAAO;EACL,kBAAkB,SAAS,gBAAgB;EAC3C;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF;AACF"}
|
|
1
|
+
{"version":3,"file":"floating.js","names":[],"sources":["../../src/composables/floating.ts"],"sourcesContent":["import type { MaybeElement } from '@/types/dom';\nimport {\n arrow,\n autoUpdate,\n computePosition,\n type ComputePositionReturn,\n flip,\n type VirtualElement as FloatingVirtualElement,\n type Middleware,\n offset,\n shift,\n size,\n} from '@floating-ui/dom';\nimport { unrefElement } from '@vueuse/core';\nimport { type MaybeRefOrGetter, onMounted, type Ref, ref, watchEffect } from 'vue';\nimport { useTimeoutManager } from './timeout-manager';\n\ntype VirtualElement = FloatingVirtualElement;\n\nexport const Placement = {\n bottom: 'bottom',\n bottomEnd: 'bottom-end',\n bottomStart: 'bottom-start',\n left: 'left',\n leftEnd: 'left-end',\n leftStart: 'left-start',\n right: 'right',\n rightEnd: 'right-end',\n rightStart: 'right-start',\n top: 'top',\n topEnd: 'top-end',\n topStart: 'top-start',\n} as const;\n\nexport type Placement = (typeof Placement)[keyof typeof Placement];\n\nexport const Strategy = {\n absolute: 'absolute',\n fixed: 'fixed',\n} as const;\n\nexport type Strategy = (typeof Strategy)[keyof typeof Strategy];\n\nexport interface FloatingOptions {\n /** Preferred placement relative to the reference element; defaults to `Placement.bottom`. */\n placement?: Placement;\n /** CSS positioning strategy; defaults to `Strategy.absolute`. */\n strategy?: Strategy;\n /** Main-axis and/or cross-axis offset from the reference element; defaults to 2. */\n offset?: number | { mainAxis?: number; crossAxis?: number };\n /** Whether to flip to the opposite side when overflowing; defaults to true. */\n flip?: boolean;\n /** Padding from viewport edges for shift middleware; defaults to 8. */\n shiftPadding?: number;\n /** Whether to auto-update position on scroll/resize; defaults to true. */\n autoUpdate?: boolean | { scroll?: boolean; resize?: boolean };\n /**\n * Cap the floating element to the space available toward the viewport edge so\n * it never overflows the window. Exposes the measured space as the\n * `--rui-floating-max-height` custom property on the floating element; the\n * content is responsible for consuming it by capping its own max-height to\n * that variable and scrolling internally. Defaults to false.\n */\n size?: boolean;\n}\n\n/** Custom property carrying the space-aware max height set by the size middleware. */\nconst FLOATING_MAX_HEIGHT_VAR = '--rui-floating-max-height';\n\nexport const DEFAULT_FLOATING_OPTIONS: Required<FloatingOptions> = {\n autoUpdate: true,\n flip: true,\n offset: 2,\n placement: Placement.bottom,\n shiftPadding: 8,\n size: false,\n strategy: Strategy.absolute,\n};\n\nexport interface UseFloatingReturn {\n currentPlacement: Readonly<Ref<Placement>>;\n leavePending: Ref<boolean>;\n onClose: (immediate?: boolean) => void;\n onLeaveComplete: () => void;\n onLeavePending: () => void;\n onOpen: (immediate?: boolean) => void;\n open: Ref<boolean>;\n popover: Ref<MaybeElement>;\n reference: Ref<HTMLElement | undefined>;\n updatePosition: () => Promise<void>;\n visible: Ref<boolean>;\n}\n\n/**\n * Cap the floating element to the space available toward the viewport edge and\n * expose it as {@link FLOATING_MAX_HEIGHT_VAR}. The content decides how to use\n * it (cap its own height and scroll internally); writing a custom property\n * instead of a hard max-height keeps this non-invasive for elements that opt in\n * but size themselves differently.\n */\nfunction buildSizeMiddleware(padding: number): Middleware {\n return size({\n padding,\n apply({ availableHeight, elements }) {\n elements.floating.style.setProperty(FLOATING_MAX_HEIGHT_VAR, `${Math.max(0, Math.floor(availableHeight))}px`);\n },\n });\n}\n\n/**\n * The offset middleware, from either the shorthand distance or the per-axis\n * form, falling back to the default distance on the main axis.\n */\nfunction buildOffsetMiddleware(opts: FloatingOptions): Middleware {\n const off = opts.offset ?? DEFAULT_FLOATING_OPTIONS.offset;\n\n if (typeof off === 'number')\n return offset(off);\n\n const defaultOffset = typeof DEFAULT_FLOATING_OPTIONS.offset === 'number' ? DEFAULT_FLOATING_OPTIONS.offset : 0;\n return offset({ mainAxis: off.mainAxis ?? defaultOffset, crossAxis: off.crossAxis ?? 0 });\n}\n\nfunction buildMiddleware(opts: FloatingOptions, arrowEl: HTMLElement | null): Middleware[] {\n const mw: Middleware[] = [buildOffsetMiddleware(opts)];\n\n if (opts.flip !== false)\n mw.push(flip());\n\n // `crossAxis`: when neither side fits, overlap the activator rather than open past the viewport edge\n mw.push(shift({ padding: opts.shiftPadding ?? DEFAULT_FLOATING_OPTIONS.shiftPadding, crossAxis: true }));\n\n if (arrowEl)\n mw.push(arrow({ element: arrowEl, padding: 4 }));\n\n if (opts.size === true)\n mw.push(buildSizeMiddleware(opts.shiftPadding ?? DEFAULT_FLOATING_OPTIONS.shiftPadding));\n\n return mw;\n}\n\nfunction applyArrowStyles(arrowEl: HTMLElement | null, result: ComputePositionReturn): void {\n const arrowData = result.middlewareData.arrow;\n if (!arrowEl || !arrowData)\n return;\n\n Object.assign(arrowEl.style, {\n left: arrowData.x != null ? `${arrowData.x}px` : '',\n top: arrowData.y != null ? `${arrowData.y}px` : '',\n });\n}\n\nexport function useFloating(\n options: MaybeRefOrGetter<FloatingOptions>,\n disabled: MaybeRefOrGetter<boolean> = false,\n openDelay: MaybeRefOrGetter<number> = 0,\n closeDelay: MaybeRefOrGetter<number> = 0,\n virtualReference?: MaybeRefOrGetter<Element | VirtualElement | undefined>,\n): UseFloatingReturn {\n const reference = ref<HTMLElement>();\n const popover = ref<MaybeElement>();\n const open = shallowRef<boolean>(false);\n const visible = shallowRef<boolean>(false);\n const leavePending = shallowRef<boolean>(false);\n const currentPlacement = shallowRef<Placement>(toValue(options).placement ?? DEFAULT_FLOATING_OPTIONS.placement);\n\n let cleanupAutoUpdate: (() => void) | null = null;\n\n const openTimeoutManager = useTimeoutManager();\n const closeTimeoutManager = useTimeoutManager();\n\n function onLeaveComplete(): void {\n set(visible, false);\n }\n\n function onOpen(immediate: boolean = false): void {\n if (toValue(disabled))\n return;\n\n closeTimeoutManager.clear();\n\n set(leavePending, false);\n if (!openTimeoutManager.isActive()) {\n set(visible, true);\n\n openTimeoutManager.create(\n () => {\n set(open, true);\n },\n immediate ? 0 : toValue(openDelay),\n );\n }\n }\n\n function onClose(immediate: boolean = false): void {\n if (toValue(disabled))\n return;\n\n openTimeoutManager.clear();\n\n if (!closeTimeoutManager.isActive()) {\n closeTimeoutManager.create(\n () => {\n if (!get(open))\n onLeaveComplete();\n\n set(open, false);\n },\n immediate ? 0 : toValue(closeDelay),\n );\n }\n }\n\n function onLeavePending(): void {\n set(leavePending, true);\n }\n\n function getValidElements(): { popoverEl: HTMLElement; referenceEl: Element | VirtualElement } | null {\n if (!get(popover) || (!get(reference) && !toValue(virtualReference)))\n return null;\n\n const popoverEl = unrefElement(popover);\n const referenceEl = toValue(virtualReference) || unrefElement(reference);\n\n if (!(popoverEl instanceof HTMLElement) || !referenceEl)\n return null;\n\n return { popoverEl, referenceEl };\n }\n\n async function updatePosition(): Promise<void> {\n const elements = getValidElements();\n if (!elements)\n return;\n\n const { popoverEl, referenceEl } = elements;\n const opts = toValue(options);\n const arrowEl = popoverEl.querySelector<HTMLElement>('[data-id=\"arrow\"]');\n const strategy = opts.strategy ?? DEFAULT_FLOATING_OPTIONS.strategy;\n\n const result = await computePosition(referenceEl, popoverEl, {\n middleware: buildMiddleware(opts, arrowEl),\n placement: opts.placement ?? DEFAULT_FLOATING_OPTIONS.placement,\n strategy,\n });\n\n Object.assign(popoverEl.style, {\n left: `${result.x}px`,\n position: strategy,\n top: `${result.y}px`,\n });\n\n set(currentPlacement, result.placement);\n applyArrowStyles(arrowEl, result);\n }\n\n function startAutoUpdate(): void {\n stopAutoUpdate();\n const elements = getValidElements();\n if (!elements)\n return;\n\n const { popoverEl, referenceEl } = elements;\n const opts = toValue(options);\n const autoUpdateOpt = opts.autoUpdate ?? DEFAULT_FLOATING_OPTIONS.autoUpdate;\n\n if (autoUpdateOpt === false)\n return;\n\n const autoUpdateOptions = typeof autoUpdateOpt === 'object'\n ? {\n ancestorResize: autoUpdateOpt.resize ?? true,\n ancestorScroll: autoUpdateOpt.scroll ?? true,\n elementResize: true,\n }\n : undefined;\n\n cleanupAutoUpdate = autoUpdate(\n referenceEl,\n popoverEl,\n () => { updatePosition().catch(() => {}); },\n autoUpdateOptions,\n );\n }\n\n function stopAutoUpdate(): void {\n cleanupAutoUpdate?.();\n cleanupAutoUpdate = null;\n }\n\n onMounted(() => {\n watchEffect((onCleanup) => {\n startAutoUpdate();\n onCleanup(stopAutoUpdate);\n });\n });\n\n return {\n currentPlacement: readonly(currentPlacement),\n leavePending, // eslint-disable-line @rotki/composable-return-readonly -- written by consumer transition hooks\n onClose,\n onLeaveComplete,\n onLeavePending,\n onOpen,\n open, // eslint-disable-line @rotki/composable-return-readonly -- v-model bound by consumers\n popover, // eslint-disable-line @rotki/composable-return-readonly -- template ref bound by consumers\n reference, // eslint-disable-line @rotki/composable-return-readonly -- template ref bound by consumers\n updatePosition,\n visible, // eslint-disable-line @rotki/composable-return-readonly -- used as v-if condition by consumers\n };\n}\n"],"mappings":"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"}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
+
import { get, set, watchDebounced } from "../../../vendor/@vueuse/shared/dist/index.js";
|
|
1
2
|
import { computed, nextTick, shallowRef, toValue, watch } from "vue";
|
|
2
|
-
import { watchDebounced } from "@vueuse/core";
|
|
3
|
-
import { get as get$1, set as set$1 } from "@vueuse/shared";
|
|
4
3
|
//#region src/composables/forms/auto-complete/focus.ts
|
|
5
4
|
function useAutoCompleteFocus(options, deps) {
|
|
6
5
|
/**
|
|
@@ -8,24 +7,24 @@ function useAutoCompleteFocus(options, deps) {
|
|
|
8
7
|
* empty search until the user types, clicks or opens the list again.
|
|
9
8
|
*/
|
|
10
9
|
const settled = shallowRef(false);
|
|
11
|
-
const anyFocused = computed(() => get
|
|
12
|
-
const editing = computed(() => get
|
|
10
|
+
const anyFocused = computed(() => get(deps.activatorFocusedWithin) || get(deps.menuWrapperFocusedWithin));
|
|
11
|
+
const editing = computed(() => get(deps.searchInputFocused) && !get(settled));
|
|
13
12
|
const inputClass = computed(() => {
|
|
14
|
-
const isFocused = get
|
|
13
|
+
const isFocused = get(anyFocused);
|
|
15
14
|
const isDisabled = toValue(options.disabled);
|
|
16
15
|
const shouldApply = toValue(options.shouldApplyValueAsSearch);
|
|
17
|
-
const hasSearch = get
|
|
16
|
+
const hasSearch = get(deps.internalSearch);
|
|
18
17
|
if ((!isFocused || isDisabled) && !shouldApply) return "w-0 h-0";
|
|
19
18
|
if (hasSearch) return "flex-1 min-w-[4rem]";
|
|
20
19
|
return "flex-1 min-w-0";
|
|
21
20
|
});
|
|
22
21
|
function unsettle() {
|
|
23
|
-
set
|
|
22
|
+
set(settled, false);
|
|
24
23
|
}
|
|
25
24
|
/** Puts focus on the input, as the combobox, while it keeps showing the value just picked. */
|
|
26
25
|
function settleOnInput() {
|
|
27
|
-
set
|
|
28
|
-
set
|
|
26
|
+
set(settled, true);
|
|
27
|
+
set(deps.searchInputFocused, true);
|
|
29
28
|
}
|
|
30
29
|
/**
|
|
31
30
|
* The first character typed after a pick replaces the shown value, as it would after tabbing in,
|
|
@@ -34,20 +33,20 @@ function useAutoCompleteFocus(options, deps) {
|
|
|
34
33
|
* @param event - the key press on the input
|
|
35
34
|
*/
|
|
36
35
|
function onSettledKeydown(event) {
|
|
37
|
-
if (!get
|
|
38
|
-
get
|
|
36
|
+
if (!get(settled) || event.key.length !== 1 || event.ctrlKey || event.metaKey || event.altKey) return;
|
|
37
|
+
get(deps.textInput)?.select();
|
|
39
38
|
unsettle();
|
|
40
39
|
}
|
|
41
40
|
async function setInputFocus() {
|
|
42
41
|
unsettle();
|
|
43
42
|
await nextTick(() => {
|
|
44
|
-
set
|
|
43
|
+
set(deps.searchInputFocused, true);
|
|
45
44
|
});
|
|
46
45
|
}
|
|
47
46
|
function onInputFocused() {
|
|
48
|
-
set
|
|
49
|
-
if (toValue(options.shouldApplyValueAsSearch) && !get
|
|
50
|
-
if (!get
|
|
47
|
+
set(deps.focusedValueIndex, -1);
|
|
48
|
+
if (toValue(options.shouldApplyValueAsSearch) && !get(settled)) get(deps.textInput)?.select();
|
|
49
|
+
if (!get(deps.isOpen)) set(deps.justOpened, true);
|
|
51
50
|
}
|
|
52
51
|
/**
|
|
53
52
|
* The search text as it stood when focus was lost, kept for the custom-value
|
|
@@ -58,11 +57,11 @@ function useAutoCompleteFocus(options, deps) {
|
|
|
58
57
|
watch(anyFocused, (focused) => {
|
|
59
58
|
if (focused) return;
|
|
60
59
|
unsettle();
|
|
61
|
-
if (toValue(options.customValue)) pendingCustomSearch = get
|
|
60
|
+
if (toValue(options.customValue)) pendingCustomSearch = get(deps.internalSearch);
|
|
62
61
|
});
|
|
63
62
|
watchDebounced(anyFocused, (focused) => {
|
|
64
63
|
if (!focused) {
|
|
65
|
-
set
|
|
64
|
+
set(deps.isOpen, false);
|
|
66
65
|
const customValue = toValue(options.customValue);
|
|
67
66
|
const searchToUse = pendingCustomSearch;
|
|
68
67
|
pendingCustomSearch = "";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"focus.js","names":[],"sources":["../../../../src/composables/forms/auto-complete/focus.ts"],"sourcesContent":["import type { ComputedRef, MaybeRefOrGetter, Ref, TemplateRef } from 'vue';\n\nexport interface UseAutoCompleteFocusOptions {\n /** Whether custom (free-text) values are allowed. */\n customValue: MaybeRefOrGetter<boolean>;\n /** Whether to apply the current value as the search text when focused. */\n shouldApplyValueAsSearch: MaybeRefOrGetter<boolean>;\n /** Whether the autocomplete is disabled. */\n disabled: MaybeRefOrGetter<boolean>;\n}\n\nexport interface UseAutoCompleteFocusDeps {\n activatorFocusedWithin: Ref<boolean>;\n focusedValueIndex: Ref<number>;\n internalSearch: Ref<string>;\n isOpen: Ref<boolean>;\n justOpened: Ref<boolean>;\n menuWrapperFocusedWithin: Ref<boolean>;\n searchInputFocused: Ref<boolean>;\n textInput: Ref<HTMLInputElement | undefined> | TemplateRef<HTMLInputElement>;\n setSearchAsValue: () => void;\n updateInternalSearch: (value?: string) => void;\n}\n\nexport interface UseAutoCompleteFocusReturn {\n anyFocused: ComputedRef<boolean>;\n /** Whether the user is searching: the input has focus and is not just showing a picked value. */\n editing: ComputedRef<boolean>;\n inputClass: ComputedRef<string>;\n onInputFocused: () => void;\n onSettledKeydown: (event: KeyboardEvent) => void;\n setInputFocus: () => Promise<void>;\n settleOnInput: () => void;\n unsettle: () => void;\n}\n\nexport function useAutoCompleteFocus(\n options: UseAutoCompleteFocusOptions,\n deps: UseAutoCompleteFocusDeps,\n): UseAutoCompleteFocusReturn {\n /**\n * The input holds focus after a pick, as the combobox, but shows the picked value rather than an\n * empty search until the user types, clicks or opens the list again.\n */\n const settled = shallowRef<boolean>(false);\n\n const anyFocused = computed<boolean>(\n () => get(deps.activatorFocusedWithin) || get(deps.menuWrapperFocusedWithin),\n );\n\n const editing = computed<boolean>(() => get(deps.searchInputFocused) && !get(settled));\n\n const inputClass = computed<string>(() => {\n const isFocused = get(anyFocused);\n const isDisabled = toValue(options.disabled);\n const shouldApply = toValue(options.shouldApplyValueAsSearch);\n const hasSearch = get(deps.internalSearch);\n\n if ((!isFocused || isDisabled) && !shouldApply)\n return 'w-0 h-0';\n if (hasSearch)\n return 'flex-1 min-w-[4rem]';\n return 'flex-1 min-w-0';\n });\n\n function unsettle(): void {\n set(settled, false);\n }\n\n /** Puts focus on the input, as the combobox, while it keeps showing the value just picked. */\n function settleOnInput(): void {\n set(settled, true);\n set(deps.searchInputFocused, true);\n }\n\n /**\n * The first character typed after a pick replaces the shown value, as it would after tabbing in,\n * rather than adding to it.\n *\n * @param event - the key press on the input\n */\n function onSettledKeydown(event: KeyboardEvent): void {\n if (!get(settled) || event.key.length !== 1 || event.ctrlKey || event.metaKey || event.altKey)\n return;\n get(deps.textInput)?.select();\n unsettle();\n }\n\n async function setInputFocus(): Promise<void> {\n unsettle();\n await nextTick(() => {\n set(deps.searchInputFocused, true);\n });\n }\n\n function onInputFocused(): void {\n set(deps.focusedValueIndex, -1);\n\n // focus coming back after a pick keeps the value as it is, unselected\n const shouldApply = toValue(options.shouldApplyValueAsSearch);\n if (shouldApply && !get(settled)) {\n const textInput = get(deps.textInput);\n textInput?.select();\n }\n\n if (!get(deps.isOpen)) {\n set(deps.justOpened, true);\n }\n }\n\n /**\n * The search text as it stood when focus was lost, kept for the custom-value\n * blur flow: it is captured before the debounced handler runs, because the\n * watchers in value.ts clear the search when the menu closes.\n */\n let pendingCustomSearch = '';\n\n watch(anyFocused, (focused) => {\n if (focused)\n return;\n unsettle();\n if (toValue(options.customValue))\n pendingCustomSearch = get(deps.internalSearch);\n });\n\n // Debounced, so the menu does not close for a moment while focus moves between its own elements\n watchDebounced(\n anyFocused,\n (focused) => {\n if (!focused) {\n set(deps.isOpen, false);\n\n const customValue = toValue(options.customValue);\n const searchToUse = pendingCustomSearch;\n pendingCustomSearch = '';\n\n if (customValue && searchToUse) {\n deps.updateInternalSearch(searchToUse);\n deps.setSearchAsValue();\n }\n\n const shouldApply = toValue(options.shouldApplyValueAsSearch);\n if (!shouldApply) {\n deps.updateInternalSearch();\n }\n }\n },\n {\n debounce: 100,\n maxWait: 200,\n },\n );\n\n return {\n anyFocused,\n editing,\n inputClass,\n onInputFocused,\n onSettledKeydown,\n setInputFocus,\n settleOnInput,\n unsettle,\n };\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"focus.js","names":[],"sources":["../../../../src/composables/forms/auto-complete/focus.ts"],"sourcesContent":["import type { ComputedRef, MaybeRefOrGetter, Ref, TemplateRef } from 'vue';\n\nexport interface UseAutoCompleteFocusOptions {\n /** Whether custom (free-text) values are allowed. */\n customValue: MaybeRefOrGetter<boolean>;\n /** Whether to apply the current value as the search text when focused. */\n shouldApplyValueAsSearch: MaybeRefOrGetter<boolean>;\n /** Whether the autocomplete is disabled. */\n disabled: MaybeRefOrGetter<boolean>;\n}\n\nexport interface UseAutoCompleteFocusDeps {\n activatorFocusedWithin: Ref<boolean>;\n focusedValueIndex: Ref<number>;\n internalSearch: Ref<string>;\n isOpen: Ref<boolean>;\n justOpened: Ref<boolean>;\n menuWrapperFocusedWithin: Ref<boolean>;\n searchInputFocused: Ref<boolean>;\n textInput: Ref<HTMLInputElement | undefined> | TemplateRef<HTMLInputElement>;\n setSearchAsValue: () => void;\n updateInternalSearch: (value?: string) => void;\n}\n\nexport interface UseAutoCompleteFocusReturn {\n anyFocused: ComputedRef<boolean>;\n /** Whether the user is searching: the input has focus and is not just showing a picked value. */\n editing: ComputedRef<boolean>;\n inputClass: ComputedRef<string>;\n onInputFocused: () => void;\n onSettledKeydown: (event: KeyboardEvent) => void;\n setInputFocus: () => Promise<void>;\n settleOnInput: () => void;\n unsettle: () => void;\n}\n\nexport function useAutoCompleteFocus(\n options: UseAutoCompleteFocusOptions,\n deps: UseAutoCompleteFocusDeps,\n): UseAutoCompleteFocusReturn {\n /**\n * The input holds focus after a pick, as the combobox, but shows the picked value rather than an\n * empty search until the user types, clicks or opens the list again.\n */\n const settled = shallowRef<boolean>(false);\n\n const anyFocused = computed<boolean>(\n () => get(deps.activatorFocusedWithin) || get(deps.menuWrapperFocusedWithin),\n );\n\n const editing = computed<boolean>(() => get(deps.searchInputFocused) && !get(settled));\n\n const inputClass = computed<string>(() => {\n const isFocused = get(anyFocused);\n const isDisabled = toValue(options.disabled);\n const shouldApply = toValue(options.shouldApplyValueAsSearch);\n const hasSearch = get(deps.internalSearch);\n\n if ((!isFocused || isDisabled) && !shouldApply)\n return 'w-0 h-0';\n if (hasSearch)\n return 'flex-1 min-w-[4rem]';\n return 'flex-1 min-w-0';\n });\n\n function unsettle(): void {\n set(settled, false);\n }\n\n /** Puts focus on the input, as the combobox, while it keeps showing the value just picked. */\n function settleOnInput(): void {\n set(settled, true);\n set(deps.searchInputFocused, true);\n }\n\n /**\n * The first character typed after a pick replaces the shown value, as it would after tabbing in,\n * rather than adding to it.\n *\n * @param event - the key press on the input\n */\n function onSettledKeydown(event: KeyboardEvent): void {\n if (!get(settled) || event.key.length !== 1 || event.ctrlKey || event.metaKey || event.altKey)\n return;\n get(deps.textInput)?.select();\n unsettle();\n }\n\n async function setInputFocus(): Promise<void> {\n unsettle();\n await nextTick(() => {\n set(deps.searchInputFocused, true);\n });\n }\n\n function onInputFocused(): void {\n set(deps.focusedValueIndex, -1);\n\n // focus coming back after a pick keeps the value as it is, unselected\n const shouldApply = toValue(options.shouldApplyValueAsSearch);\n if (shouldApply && !get(settled)) {\n const textInput = get(deps.textInput);\n textInput?.select();\n }\n\n if (!get(deps.isOpen)) {\n set(deps.justOpened, true);\n }\n }\n\n /**\n * The search text as it stood when focus was lost, kept for the custom-value\n * blur flow: it is captured before the debounced handler runs, because the\n * watchers in value.ts clear the search when the menu closes.\n */\n let pendingCustomSearch = '';\n\n watch(anyFocused, (focused) => {\n if (focused)\n return;\n unsettle();\n if (toValue(options.customValue))\n pendingCustomSearch = get(deps.internalSearch);\n });\n\n // Debounced, so the menu does not close for a moment while focus moves between its own elements\n watchDebounced(\n anyFocused,\n (focused) => {\n if (!focused) {\n set(deps.isOpen, false);\n\n const customValue = toValue(options.customValue);\n const searchToUse = pendingCustomSearch;\n pendingCustomSearch = '';\n\n if (customValue && searchToUse) {\n deps.updateInternalSearch(searchToUse);\n deps.setSearchAsValue();\n }\n\n const shouldApply = toValue(options.shouldApplyValueAsSearch);\n if (!shouldApply) {\n deps.updateInternalSearch();\n }\n }\n },\n {\n debounce: 100,\n maxWait: 200,\n },\n );\n\n return {\n anyFocused,\n editing,\n inputClass,\n onInputFocused,\n onSettledKeydown,\n setInputFocus,\n settleOnInput,\n unsettle,\n };\n}\n"],"mappings":";;;AAoCA,SAAgB,qBACd,SACA,MAC4B;;;;;CAK5B,MAAM,UAAU,WAAoB,KAAK;CAEzC,MAAM,aAAa,eACX,IAAI,KAAK,sBAAsB,KAAK,IAAI,KAAK,wBAAwB,CAC7E;CAEA,MAAM,UAAU,eAAwB,IAAI,KAAK,kBAAkB,KAAK,CAAC,IAAI,OAAO,CAAC;CAErF,MAAM,aAAa,eAAuB;EACxC,MAAM,YAAY,IAAI,UAAU;EAChC,MAAM,aAAa,QAAQ,QAAQ,QAAQ;EAC3C,MAAM,cAAc,QAAQ,QAAQ,wBAAwB;EAC5D,MAAM,YAAY,IAAI,KAAK,cAAc;EAEzC,KAAK,CAAC,aAAa,eAAe,CAAC,aACjC,OAAO;EACT,IAAI,WACF,OAAO;EACT,OAAO;CACT,CAAC;CAED,SAAS,WAAiB;EACxB,IAAI,SAAS,KAAK;CACpB;;CAGA,SAAS,gBAAsB;EAC7B,IAAI,SAAS,IAAI;EACjB,IAAI,KAAK,oBAAoB,IAAI;CACnC;;;;;;;CAQA,SAAS,iBAAiB,OAA4B;EACpD,IAAI,CAAC,IAAI,OAAO,KAAK,MAAM,IAAI,WAAW,KAAK,MAAM,WAAW,MAAM,WAAW,MAAM,QACrF;EACF,IAAI,KAAK,SAAS,CAAC,EAAE,OAAO;EAC5B,SAAS;CACX;CAEA,eAAe,gBAA+B;EAC5C,SAAS;EACT,MAAM,eAAe;GACnB,IAAI,KAAK,oBAAoB,IAAI;EACnC,CAAC;CACH;CAEA,SAAS,iBAAuB;EAC9B,IAAI,KAAK,mBAAmB,EAAE;EAI9B,IADoB,QAAQ,QAAQ,wBAChC,KAAe,CAAC,IAAI,OAAO,GAE7B,IADsB,KAAK,SAC3B,CAAA,EAAW,OAAO;EAGpB,IAAI,CAAC,IAAI,KAAK,MAAM,GAClB,IAAI,KAAK,YAAY,IAAI;CAE7B;;;;;;CAOA,IAAI,sBAAsB;CAE1B,MAAM,aAAa,YAAY;EAC7B,IAAI,SACF;EACF,SAAS;EACT,IAAI,QAAQ,QAAQ,WAAW,GAC7B,sBAAsB,IAAI,KAAK,cAAc;CACjD,CAAC;CAGD,eACE,aACC,YAAY;EACX,IAAI,CAAC,SAAS;GACZ,IAAI,KAAK,QAAQ,KAAK;GAEtB,MAAM,cAAc,QAAQ,QAAQ,WAAW;GAC/C,MAAM,cAAc;GACpB,sBAAsB;GAEtB,IAAI,eAAe,aAAa;IAC9B,KAAK,qBAAqB,WAAW;IACrC,KAAK,iBAAiB;GACxB;GAGA,IAAI,CADgB,QAAQ,QAAQ,wBAC/B,GACH,KAAK,qBAAqB;EAE9B;CACF,GACA;EACE,UAAU;EACV,SAAS;CACX,CACF;CAEA,OAAO;EACL;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF;AACF"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
import { get, set } from "../../../vendor/@vueuse/shared/dist/index.js";
|
|
1
2
|
import { ref, toValue, watch } from "vue";
|
|
2
|
-
import { get, set } from "@vueuse/shared";
|
|
3
3
|
//#region src/composables/forms/auto-complete/keyboard-navigation.ts
|
|
4
4
|
function useAutoCompleteKeyboardNavigation(options, deps) {
|
|
5
5
|
const focusedValueIndex = ref(-1);
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
+
import { get, refDebounced, set } from "../../../vendor/@vueuse/shared/dist/index.js";
|
|
1
2
|
import { getTextToken } from "../../../utils/helpers.js";
|
|
2
3
|
import { computed, onUnmounted, readonly, shallowRef, toValue, watch } from "vue";
|
|
3
|
-
import { refDebounced } from "@vueuse/core";
|
|
4
|
-
import { get as get$1, set as set$1 } from "@vueuse/shared";
|
|
5
4
|
//#region src/composables/forms/auto-complete/search.ts
|
|
6
5
|
function useAutoCompleteSearch(options, searchModel, opts) {
|
|
7
6
|
const internalSearch = shallowRef("");
|
|
@@ -31,9 +30,9 @@ function useAutoCompleteSearch(options, searchModel, opts) {
|
|
|
31
30
|
return String(item?.[groupBy] ?? "");
|
|
32
31
|
};
|
|
33
32
|
const filteredOptions = computed(() => {
|
|
34
|
-
const search = get
|
|
33
|
+
const search = get(debouncedInternalSearch);
|
|
35
34
|
const optionsValue = toValue(options);
|
|
36
|
-
if (toValue(opts.noFilter) || !search || get
|
|
35
|
+
if (toValue(opts.noFilter) || !search || get(justOpened)) return optionsValue;
|
|
37
36
|
const keyAttr = toValue(opts.keyAttr);
|
|
38
37
|
const textAttr = toValue(opts.textAttr);
|
|
39
38
|
const filter = toValue(opts.filter);
|
|
@@ -72,11 +71,11 @@ function useAutoCompleteSearch(options, searchModel, opts) {
|
|
|
72
71
|
};
|
|
73
72
|
}
|
|
74
73
|
function updateInternalSearch(value = "") {
|
|
75
|
-
set
|
|
76
|
-
set
|
|
74
|
+
set(searchModel, value);
|
|
75
|
+
set(internalSearch, value);
|
|
77
76
|
}
|
|
78
77
|
watch(searchModel, (search) => {
|
|
79
|
-
set
|
|
78
|
+
set(internalSearch, search);
|
|
80
79
|
}, { immediate: true });
|
|
81
80
|
onUnmounted(() => {
|
|
82
81
|
tokenCache.clear();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"search.js","names":[],"sources":["../../../../src/composables/forms/auto-complete/search.ts"],"sourcesContent":["import type { MaybeRefOrGetter, Ref } from 'vue';\nimport type { GroupBy } from '@/composables/dropdown-menu';\nimport { get, set } from '@vueuse/shared';\nimport { getTextToken } from '@/utils/helpers';\n\nexport interface UseAutoCompleteSearchOptions<TItem> {\n /** The property used as the unique identifier for each item. */\n keyAttr?: MaybeRefOrGetter<keyof TItem | undefined>;\n /** The property used to display text for each item. */\n textAttr?: MaybeRefOrGetter<keyof TItem | undefined>;\n /** Whether to disable client-side filtering of options. */\n noFilter?: MaybeRefOrGetter<boolean>;\n /** Custom filter function to match items against the search query. */\n filter?: MaybeRefOrGetter<((item: TItem, queryText: string, group?: string) => boolean) | undefined>;\n /** Whether custom (free-text) values are allowed. */\n customValue?: MaybeRefOrGetter<boolean>;\n /** Whether to hide the custom value option from the dropdown. */\n hideCustomValue?: MaybeRefOrGetter<boolean>;\n /** Whether to return the full item object instead of just the key. */\n returnObject?: MaybeRefOrGetter<boolean>;\n /** How items are grouped, used to resolve group labels for filtering. */\n groupBy?: MaybeRefOrGetter<GroupBy<TItem> | undefined>;\n /** When true and `groupBy` is set, the default filter also matches the resolved group label. */\n searchIncludesGroupLabel?: MaybeRefOrGetter<boolean>;\n}\n\nexport interface UseAutoCompleteSearchReturn<TItem> {\n internalSearch: Readonly<Ref<string>>;\n debouncedInternalSearch: Readonly<Ref<string>>;\n filteredOptions: Readonly<Ref<TItem[]>>;\n justOpened: Ref<boolean>;\n updateInternalSearch: (value?: string) => void;\n textValueToProperValue: (val: any, returnObject?: boolean) => TItem;\n}\n\nexport function useAutoCompleteSearch<TItem>(\n options: MaybeRefOrGetter<TItem[]>,\n searchModel: Ref<string>,\n opts: UseAutoCompleteSearchOptions<TItem>,\n): UseAutoCompleteSearchReturn<TItem> {\n const internalSearch = shallowRef<string>('');\n const debouncedInternalSearch = refDebounced(internalSearch, 50);\n const justOpened = shallowRef<boolean>(false);\n\n // Map iteration order is insertion order, so deleting the first key evicts the oldest token\n const MAX_CACHE_SIZE = 100;\n const tokenCache = new Map<string, string>();\n const getCachedTextToken = (text: string): string => {\n const cached = tokenCache.get(text);\n if (cached !== undefined)\n return cached;\n\n if (tokenCache.size >= MAX_CACHE_SIZE) {\n const oldest = tokenCache.keys().next().value;\n if (oldest !== undefined)\n tokenCache.delete(oldest);\n }\n\n const token = getTextToken(text);\n tokenCache.set(text, token);\n return token;\n };\n\n /**\n * The group label an item sits under. Mirrors `getGroupKey` in\n * dropdown-menu.ts, so the filter matches the labels the rendered group\n * headers show.\n */\n const resolveGroup = (item: TItem, groupBy: GroupBy<TItem> | undefined): string | undefined => {\n if (!groupBy)\n return undefined;\n\n if (typeof groupBy === 'function')\n return groupBy(item);\n\n return String((item as any)?.[groupBy] ?? '');\n };\n\n const filteredOptions = computed<TItem[]>(() => {\n const search = get(debouncedInternalSearch);\n const optionsValue = toValue(options);\n\n const noFilter = toValue(opts.noFilter);\n if (noFilter || !search || get(justOpened))\n return optionsValue;\n\n const keyAttr = toValue(opts.keyAttr);\n const textAttr = toValue(opts.textAttr);\n const filter = toValue(opts.filter);\n const groupBy = toValue(opts.groupBy);\n const searchIncludesGroupLabel = toValue(opts.searchIncludesGroupLabel);\n\n // Cache the search token once\n const searchToken = getCachedTextToken(search);\n\n const filtered = filter\n ? optionsValue.filter(item => filter(item, search, resolveGroup(item, groupBy)))\n : optionsValue.filter((item) => {\n if (!item)\n return false;\n\n const keywords: string[] = [getCachedTextToken(keyAttr ? String((item as any)[keyAttr]) : item.toString())];\n\n if (textAttr && typeof item === 'object')\n keywords.push(getCachedTextToken(String((item as any)[textAttr])));\n\n // Matching the group label too surfaces every item under a \"Trade\" section for \"trade\"\n if (searchIncludesGroupLabel && groupBy) {\n const group = resolveGroup(item, groupBy);\n if (group)\n keywords.push(getCachedTextToken(group));\n }\n\n return keywords.some(keyword => keyword.includes(searchToken));\n });\n\n const customValue = toValue(opts.customValue);\n const hideCustomValue = toValue(opts.hideCustomValue);\n if (!customValue || hideCustomValue || !search) {\n return filtered;\n }\n\n // Use a more efficient check for custom value inclusion\n const isCustomValueIncluded = filtered.some((item) => {\n if (!item) {\n return false;\n }\n\n const val = textAttr ? (item as any)[textAttr] : item.toString();\n return val === search;\n });\n\n if (isCustomValueIncluded) {\n return filtered;\n }\n\n return [textValueToProperValue(search, {\n keyAttr,\n returnObject: toValue(opts.returnObject),\n textAttr,\n }), ...filtered];\n });\n\n function textValueToProperValue(val: any, options: { keyAttr?: keyof TItem; textAttr?: keyof TItem; returnObject?: boolean }): TItem {\n const { keyAttr, returnObject, textAttr } = options;\n if (!keyAttr || returnObject)\n return val;\n\n return {\n [keyAttr]: val,\n ...(\n textAttr\n ? { [textAttr]: val }\n : {}\n ),\n } as TItem;\n }\n\n function updateInternalSearch(value: string = ''): void {\n set(searchModel, value);\n set(internalSearch, value);\n }\n\n watch(searchModel, (search) => {\n set(internalSearch, search);\n }, { immediate: true });\n\n // Clear token cache when component unmounts to prevent memory leaks\n onUnmounted(() => {\n tokenCache.clear();\n });\n\n return {\n debouncedInternalSearch,\n filteredOptions,\n internalSearch: readonly(internalSearch),\n justOpened, // eslint-disable-line @rotki/composable-return-readonly -- written by focus.ts onInputFocused and component setValue\n textValueToProperValue: (val: any, returnObjectOverride: boolean = false) => textValueToProperValue(val, {\n keyAttr: toValue(opts.keyAttr),\n returnObject: returnObjectOverride || toValue(opts.returnObject),\n textAttr: toValue(opts.textAttr),\n }),\n updateInternalSearch,\n };\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"search.js","names":[],"sources":["../../../../src/composables/forms/auto-complete/search.ts"],"sourcesContent":["import type { MaybeRefOrGetter, Ref } from 'vue';\nimport type { GroupBy } from '@/composables/dropdown-menu';\nimport { get, set } from '@vueuse/shared';\nimport { getTextToken } from '@/utils/helpers';\n\nexport interface UseAutoCompleteSearchOptions<TItem> {\n /** The property used as the unique identifier for each item. */\n keyAttr?: MaybeRefOrGetter<keyof TItem | undefined>;\n /** The property used to display text for each item. */\n textAttr?: MaybeRefOrGetter<keyof TItem | undefined>;\n /** Whether to disable client-side filtering of options. */\n noFilter?: MaybeRefOrGetter<boolean>;\n /** Custom filter function to match items against the search query. */\n filter?: MaybeRefOrGetter<((item: TItem, queryText: string, group?: string) => boolean) | undefined>;\n /** Whether custom (free-text) values are allowed. */\n customValue?: MaybeRefOrGetter<boolean>;\n /** Whether to hide the custom value option from the dropdown. */\n hideCustomValue?: MaybeRefOrGetter<boolean>;\n /** Whether to return the full item object instead of just the key. */\n returnObject?: MaybeRefOrGetter<boolean>;\n /** How items are grouped, used to resolve group labels for filtering. */\n groupBy?: MaybeRefOrGetter<GroupBy<TItem> | undefined>;\n /** When true and `groupBy` is set, the default filter also matches the resolved group label. */\n searchIncludesGroupLabel?: MaybeRefOrGetter<boolean>;\n}\n\nexport interface UseAutoCompleteSearchReturn<TItem> {\n internalSearch: Readonly<Ref<string>>;\n debouncedInternalSearch: Readonly<Ref<string>>;\n filteredOptions: Readonly<Ref<TItem[]>>;\n justOpened: Ref<boolean>;\n updateInternalSearch: (value?: string) => void;\n textValueToProperValue: (val: any, returnObject?: boolean) => TItem;\n}\n\nexport function useAutoCompleteSearch<TItem>(\n options: MaybeRefOrGetter<TItem[]>,\n searchModel: Ref<string>,\n opts: UseAutoCompleteSearchOptions<TItem>,\n): UseAutoCompleteSearchReturn<TItem> {\n const internalSearch = shallowRef<string>('');\n const debouncedInternalSearch = refDebounced(internalSearch, 50);\n const justOpened = shallowRef<boolean>(false);\n\n // Map iteration order is insertion order, so deleting the first key evicts the oldest token\n const MAX_CACHE_SIZE = 100;\n const tokenCache = new Map<string, string>();\n const getCachedTextToken = (text: string): string => {\n const cached = tokenCache.get(text);\n if (cached !== undefined)\n return cached;\n\n if (tokenCache.size >= MAX_CACHE_SIZE) {\n const oldest = tokenCache.keys().next().value;\n if (oldest !== undefined)\n tokenCache.delete(oldest);\n }\n\n const token = getTextToken(text);\n tokenCache.set(text, token);\n return token;\n };\n\n /**\n * The group label an item sits under. Mirrors `getGroupKey` in\n * dropdown-menu.ts, so the filter matches the labels the rendered group\n * headers show.\n */\n const resolveGroup = (item: TItem, groupBy: GroupBy<TItem> | undefined): string | undefined => {\n if (!groupBy)\n return undefined;\n\n if (typeof groupBy === 'function')\n return groupBy(item);\n\n return String((item as any)?.[groupBy] ?? '');\n };\n\n const filteredOptions = computed<TItem[]>(() => {\n const search = get(debouncedInternalSearch);\n const optionsValue = toValue(options);\n\n const noFilter = toValue(opts.noFilter);\n if (noFilter || !search || get(justOpened))\n return optionsValue;\n\n const keyAttr = toValue(opts.keyAttr);\n const textAttr = toValue(opts.textAttr);\n const filter = toValue(opts.filter);\n const groupBy = toValue(opts.groupBy);\n const searchIncludesGroupLabel = toValue(opts.searchIncludesGroupLabel);\n\n // Cache the search token once\n const searchToken = getCachedTextToken(search);\n\n const filtered = filter\n ? optionsValue.filter(item => filter(item, search, resolveGroup(item, groupBy)))\n : optionsValue.filter((item) => {\n if (!item)\n return false;\n\n const keywords: string[] = [getCachedTextToken(keyAttr ? String((item as any)[keyAttr]) : item.toString())];\n\n if (textAttr && typeof item === 'object')\n keywords.push(getCachedTextToken(String((item as any)[textAttr])));\n\n // Matching the group label too surfaces every item under a \"Trade\" section for \"trade\"\n if (searchIncludesGroupLabel && groupBy) {\n const group = resolveGroup(item, groupBy);\n if (group)\n keywords.push(getCachedTextToken(group));\n }\n\n return keywords.some(keyword => keyword.includes(searchToken));\n });\n\n const customValue = toValue(opts.customValue);\n const hideCustomValue = toValue(opts.hideCustomValue);\n if (!customValue || hideCustomValue || !search) {\n return filtered;\n }\n\n // Use a more efficient check for custom value inclusion\n const isCustomValueIncluded = filtered.some((item) => {\n if (!item) {\n return false;\n }\n\n const val = textAttr ? (item as any)[textAttr] : item.toString();\n return val === search;\n });\n\n if (isCustomValueIncluded) {\n return filtered;\n }\n\n return [textValueToProperValue(search, {\n keyAttr,\n returnObject: toValue(opts.returnObject),\n textAttr,\n }), ...filtered];\n });\n\n function textValueToProperValue(val: any, options: { keyAttr?: keyof TItem; textAttr?: keyof TItem; returnObject?: boolean }): TItem {\n const { keyAttr, returnObject, textAttr } = options;\n if (!keyAttr || returnObject)\n return val;\n\n return {\n [keyAttr]: val,\n ...(\n textAttr\n ? { [textAttr]: val }\n : {}\n ),\n } as TItem;\n }\n\n function updateInternalSearch(value: string = ''): void {\n set(searchModel, value);\n set(internalSearch, value);\n }\n\n watch(searchModel, (search) => {\n set(internalSearch, search);\n }, { immediate: true });\n\n // Clear token cache when component unmounts to prevent memory leaks\n onUnmounted(() => {\n tokenCache.clear();\n });\n\n return {\n debouncedInternalSearch,\n filteredOptions,\n internalSearch: readonly(internalSearch),\n justOpened, // eslint-disable-line @rotki/composable-return-readonly -- written by focus.ts onInputFocused and component setValue\n textValueToProperValue: (val: any, returnObjectOverride: boolean = false) => textValueToProperValue(val, {\n keyAttr: toValue(opts.keyAttr),\n returnObject: returnObjectOverride || toValue(opts.returnObject),\n textAttr: toValue(opts.textAttr),\n }),\n updateInternalSearch,\n };\n}\n"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
import { get, set } from "../../../vendor/@vueuse/shared/dist/index.js";
|
|
1
2
|
import { nextTick } from "vue";
|
|
2
|
-
import { get, set } from "@vueuse/shared";
|
|
3
3
|
//#region src/composables/forms/auto-complete/selection.ts
|
|
4
4
|
/**
|
|
5
5
|
* The changes to the auto-complete's selection: picking or dropping an item, taking the typed text
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { assert } from "../../../utils/assert.js";
|
|
2
|
+
import { get, set } from "../../../vendor/@vueuse/shared/dist/index.js";
|
|
2
3
|
import { isEqual } from "../../../utils/is-equal.js";
|
|
3
4
|
import { computed, toValue, watch } from "vue";
|
|
4
|
-
import { get, set } from "@vueuse/shared";
|
|
5
5
|
//#region src/composables/forms/auto-complete/value.ts
|
|
6
6
|
function useAutoCompleteValue(modelValue, options, opts, deps) {
|
|
7
7
|
function buildOptionsMap(optionsData) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
+
import { get, set } from "../../../vendor/@vueuse/shared/dist/index.js";
|
|
1
2
|
import { useDropdownOptionProperty } from "../../dropdown-menu.js";
|
|
2
3
|
import { computed, readonly, shallowRef, toValue, watch } from "vue";
|
|
3
|
-
import { get, set } from "@vueuse/shared";
|
|
4
4
|
//#region src/composables/forms/category-picker/use-category-picker.ts
|
|
5
5
|
/**
|
|
6
6
|
* Owns the grouping, filtering and selection state for `RuiCategoryPicker`.
|