@nexdom/uimed-vue 2.0.0-beta.25 → 2.0.0-beta.26
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.d.ts +1 -1
- package/dist/components.js +118 -9
- package/package.json +1 -1
package/dist/components.d.ts
CHANGED
|
@@ -433,8 +433,8 @@ declare const __VLS_export$14: import("vue", { with: { "resolution-mode": "impor
|
|
|
433
433
|
"onUpdate:modelValue"?: ((value: string) => any) | undefined;
|
|
434
434
|
}>, {
|
|
435
435
|
variant: TextFieldVariant;
|
|
436
|
-
clearable: boolean;
|
|
437
436
|
type: TextFieldType;
|
|
437
|
+
clearable: boolean;
|
|
438
438
|
}, {}, {}, {}, string, import("vue", { with: { "resolution-mode": "import" } }).ComponentProvideOptions, false, {}, any>;
|
|
439
439
|
//#endregion
|
|
440
440
|
//#region src/components/inputs/checkbox/types.d.ts
|
package/dist/components.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { a as messages, n as owners, r as requests, s as useVuetifyColor } from "./use-dialog-Ck2_ZW7T.js";
|
|
2
|
-
import { Fragment, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createSlots, createTextVNode, createVNode, defineComponent, guardReactiveProps, inject, isRef, mergeModels, mergeProps, normalizeClass, normalizeProps, onMounted, onScopeDispose, onUnmounted, openBlock, provide, ref, renderList, renderSlot, resolveDynamicComponent, shallowRef, toDisplayString, toValue, unref, useId, useModel, useSlots, useTemplateRef, watch, withCtx, withModifiers } from "vue";
|
|
1
|
+
import { a as messages, n as owners$1, r as requests, s as useVuetifyColor } from "./use-dialog-Ck2_ZW7T.js";
|
|
2
|
+
import { Fragment, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createSlots, createTextVNode, createVNode, defineComponent, guardReactiveProps, inject, isRef, mergeModels, mergeProps, nextTick, normalizeClass, normalizeProps, onMounted, onScopeDispose, onUnmounted, openBlock, provide, ref, renderList, renderSlot, resolveDynamicComponent, shallowRef, toDisplayString, toValue, unref, useId, useModel, useSlots, useTemplateRef, watch, withCtx, withKeys, withModifiers } from "vue";
|
|
3
3
|
import { pt } from "vuetify/locale";
|
|
4
4
|
import { VApp, VAppBar, VAppBarNavIcon, VAppBarTitle, VAutocomplete, VAvatar, VBadge, VBtn, VCard, VCardActions, VCardText, VCheckboxBtn, VCol, VCombobox, VContainer, VDataIterator, VDatePicker, VDialog, VDivider, VEmptyState, VExpansionPanel, VExpansionPanelText, VExpansionPanelTitle, VExpansionPanels, VForm, VIcon, VIconBtn, VImg, VList, VListGroup, VListItem, VListItemAction, VListSubheader, VLocaleProvider, VMain, VMenu, VNavigationDrawer, VPagination, VProgressLinear, VRow, VSkeletonLoader, VSnackbarQueue, VTable, VTextField, VTimePicker } from "vuetify/components";
|
|
5
5
|
import { formatDateTime, isEmail, isEmpty, isPhone, isUrl } from "@nexdom/shared/utils";
|
|
@@ -15,6 +15,101 @@ function isExternalRoute(route) {
|
|
|
15
15
|
return typeof route === "string" && route.startsWith("http");
|
|
16
16
|
}
|
|
17
17
|
//#endregion
|
|
18
|
+
//#region src/composables/navigation/use-navigation-search-shortcut.ts
|
|
19
|
+
/**
|
|
20
|
+
* Mounted navigation menus, in mounting order. Only the first one answers the shortcut, so pages
|
|
21
|
+
* with more than one `UMain` (like the docs) don't open every menu at once.
|
|
22
|
+
*/
|
|
23
|
+
const owners = ref([]);
|
|
24
|
+
/**
|
|
25
|
+
* Focus targets where the shortcut is left to the page: overlays (dialogs, confirmations and
|
|
26
|
+
* menus) and other modals, the activators of open menus (which keep the focus when opened by a
|
|
27
|
+
* click, and would pull it back from the navigation menu) and rich text editors, which usually
|
|
28
|
+
* take Ctrl+K to insert links.
|
|
29
|
+
*/
|
|
30
|
+
const IGNORED_TARGETS = [
|
|
31
|
+
".v-overlay",
|
|
32
|
+
"dialog",
|
|
33
|
+
"[aria-modal='true']",
|
|
34
|
+
"[aria-haspopup][aria-expanded='true']",
|
|
35
|
+
"[contenteditable]:not([contenteditable='false'])"
|
|
36
|
+
].join(", ");
|
|
37
|
+
/** Accessible name of the search field, whose placeholder also shows the shortcut. */
|
|
38
|
+
const SEARCH_NAME = "Buscar";
|
|
39
|
+
/**
|
|
40
|
+
* Shortcut keys for the current platform. Starts with the non-macOS keys and switches on mount,
|
|
41
|
+
* so server-rendered pages (the docs) hydrate without mismatches.
|
|
42
|
+
*/
|
|
43
|
+
function useNavigationShortcutKeys() {
|
|
44
|
+
const isMac = ref(false);
|
|
45
|
+
onMounted(() => isMac.value = isMacOS());
|
|
46
|
+
return {
|
|
47
|
+
label: computed(() => isMac.value ? "⌘K" : "Ctrl+K"),
|
|
48
|
+
ariaKeyshortcuts: computed(() => isMac.value ? "Meta+K" : "Control+K")
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Listens to Ctrl+K (⌘K on macOS) on `window` while mounted: opens the menu, waits for it to
|
|
53
|
+
* render (the drawer is `inert` while closed) and focuses the search field (a disabled field, as
|
|
54
|
+
* while loading, can't take the focus). When the menu opened by the shortcut closes with the focus
|
|
55
|
+
* inside it, the focus goes back to where it was.
|
|
56
|
+
*/
|
|
57
|
+
function useNavigationSearchShortcut(options) {
|
|
58
|
+
const { open, field } = options;
|
|
59
|
+
const owner = Symbol("navigation-search-shortcut");
|
|
60
|
+
/** Element focused before the shortcut opened the menu, which gets the focus back on close. */
|
|
61
|
+
let origin = null;
|
|
62
|
+
onMounted(() => {
|
|
63
|
+
owners.value.push(owner);
|
|
64
|
+
globalThis.addEventListener("keydown", onKeydown, { capture: true });
|
|
65
|
+
findInput().setAttribute("aria-label", SEARCH_NAME);
|
|
66
|
+
});
|
|
67
|
+
onUnmounted(() => {
|
|
68
|
+
owners.value = owners.value.filter((item) => item !== owner);
|
|
69
|
+
globalThis.removeEventListener("keydown", onKeydown, { capture: true });
|
|
70
|
+
});
|
|
71
|
+
watch(open, (isOpen) => {
|
|
72
|
+
if (isOpen) return;
|
|
73
|
+
const target = origin;
|
|
74
|
+
origin = null;
|
|
75
|
+
if (!findInput().closest(".v-navigation-drawer").contains(document.activeElement)) return;
|
|
76
|
+
if (target instanceof HTMLElement || target instanceof SVGElement) target.focus();
|
|
77
|
+
});
|
|
78
|
+
function onKeydown(event) {
|
|
79
|
+
if (owners.value[0] !== owner || isIgnoredTarget(event)) return;
|
|
80
|
+
if (isShortcut(event)) openAndFocus(event);
|
|
81
|
+
else if (event.key === "Escape" && origin) close();
|
|
82
|
+
}
|
|
83
|
+
async function openAndFocus(event) {
|
|
84
|
+
event.preventDefault();
|
|
85
|
+
if (!open.value) origin = document.activeElement;
|
|
86
|
+
open.value = true;
|
|
87
|
+
await nextTick();
|
|
88
|
+
const input = findInput();
|
|
89
|
+
input.focus({ preventScroll: true });
|
|
90
|
+
input.select();
|
|
91
|
+
}
|
|
92
|
+
function findInput() {
|
|
93
|
+
return field.value.$el.querySelector("input");
|
|
94
|
+
}
|
|
95
|
+
function close() {
|
|
96
|
+
open.value = false;
|
|
97
|
+
}
|
|
98
|
+
return {
|
|
99
|
+
...useNavigationShortcutKeys(),
|
|
100
|
+
close
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
function isMacOS() {
|
|
104
|
+
return navigator.userAgent.includes("Macintosh");
|
|
105
|
+
}
|
|
106
|
+
function isShortcut(event) {
|
|
107
|
+
return (isMacOS() ? event.metaKey : event.ctrlKey) && !event.shiftKey && !event.altKey && !event.isComposing && event.key.toLowerCase() === "k";
|
|
108
|
+
}
|
|
109
|
+
function isIgnoredTarget(event) {
|
|
110
|
+
return event.target instanceof Element && event.target.closest(IGNORED_TARGETS) !== null;
|
|
111
|
+
}
|
|
112
|
+
//#endregion
|
|
18
113
|
//#region src/components/app-bar/app-bar.vue?vue&type=script&setup=true&lang.ts
|
|
19
114
|
const _hoisted_1$3 = { class: "opacity-60" };
|
|
20
115
|
//#endregion
|
|
@@ -69,6 +164,7 @@ var app_bar_default = /* @__PURE__ */ defineComponent({
|
|
|
69
164
|
const props = __props;
|
|
70
165
|
const notificationsOpen = useModel(__props, "notificationsOpen");
|
|
71
166
|
const navigationOpen = useModel(__props, "navigationOpen");
|
|
167
|
+
const { ariaKeyshortcuts: navigationKeyshortcuts } = useNavigationShortcutKeys();
|
|
72
168
|
const helpBtnDataTestid = computed(() => `${props.dataTestid}-help`);
|
|
73
169
|
const notificationsBtnDataTestid = computed(() => `${props.dataTestid}-notifications`);
|
|
74
170
|
const navigationBtnDataTestid = computed(() => `${props.dataTestid}-navigation`);
|
|
@@ -221,8 +317,13 @@ var app_bar_default = /* @__PURE__ */ defineComponent({
|
|
|
221
317
|
"data-testid": navigationBtnDataTestid.value,
|
|
222
318
|
"aria-expanded": navigationOpen.value,
|
|
223
319
|
"aria-label": "Menu de navegação",
|
|
320
|
+
"aria-keyshortcuts": unref(navigationKeyshortcuts),
|
|
224
321
|
onClick: _cache[0] || (_cache[0] = ($event) => navigationOpen.value = !navigationOpen.value)
|
|
225
|
-
}, null, 8, [
|
|
322
|
+
}, null, 8, [
|
|
323
|
+
"data-testid",
|
|
324
|
+
"aria-expanded",
|
|
325
|
+
"aria-keyshortcuts"
|
|
326
|
+
])) : createCommentVNode("v-if", true),
|
|
226
327
|
__props.logo ? (openBlock(), createBlock(unref(VImg), {
|
|
227
328
|
key: 1,
|
|
228
329
|
src: props.logo,
|
|
@@ -488,6 +589,10 @@ var navigation_menu_default = /* @__PURE__ */ defineComponent({
|
|
|
488
589
|
const props = __props;
|
|
489
590
|
const open = useModel(__props, "modelValue");
|
|
490
591
|
const search = ref("");
|
|
592
|
+
const { label: shortcutLabel, close } = useNavigationSearchShortcut({
|
|
593
|
+
open,
|
|
594
|
+
field: useTemplateRef("searchField")
|
|
595
|
+
});
|
|
491
596
|
const filteredItems = computed(() => filterItems());
|
|
492
597
|
const searchDataTestid = computed(() => `${props.dataTestid}-search`);
|
|
493
598
|
const query = computed(() => search.value.toLowerCase());
|
|
@@ -518,17 +623,20 @@ var navigation_menu_default = /* @__PURE__ */ defineComponent({
|
|
|
518
623
|
"data-testid": props.dataTestid,
|
|
519
624
|
"aria-busy": props.loading || void 0,
|
|
520
625
|
absolute: "",
|
|
521
|
-
temporary: ""
|
|
626
|
+
temporary: "",
|
|
627
|
+
onKeydown: withKeys(unref(close), ["esc"])
|
|
522
628
|
}, {
|
|
523
629
|
prepend: withCtx(() => [createElementVNode("div", _hoisted_1$2, [createVNode(text_field_default, {
|
|
630
|
+
ref: "searchField",
|
|
524
631
|
modelValue: search.value,
|
|
525
632
|
"onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => search.value = $event),
|
|
526
633
|
type: "search",
|
|
527
|
-
|
|
634
|
+
placeholder: `Buscar (${unref(shortcutLabel)})`,
|
|
528
635
|
"data-testid": searchDataTestid.value,
|
|
529
636
|
disabled: props.loading
|
|
530
637
|
}, null, 8, [
|
|
531
638
|
"modelValue",
|
|
639
|
+
"placeholder",
|
|
532
640
|
"data-testid",
|
|
533
641
|
"disabled"
|
|
534
642
|
])])]),
|
|
@@ -561,7 +669,8 @@ var navigation_menu_default = /* @__PURE__ */ defineComponent({
|
|
|
561
669
|
}, 8, [
|
|
562
670
|
"modelValue",
|
|
563
671
|
"data-testid",
|
|
564
|
-
"aria-busy"
|
|
672
|
+
"aria-busy",
|
|
673
|
+
"onKeydown"
|
|
565
674
|
]);
|
|
566
675
|
};
|
|
567
676
|
}
|
|
@@ -892,7 +1001,7 @@ var dialog_host_default = /* @__PURE__ */ defineComponent({
|
|
|
892
1001
|
__name: "dialog-host",
|
|
893
1002
|
setup(__props) {
|
|
894
1003
|
const owner = Symbol("dialog");
|
|
895
|
-
const isOwner = computed(() => owners.value[0] === owner);
|
|
1004
|
+
const isOwner = computed(() => owners$1.value[0] === owner);
|
|
896
1005
|
const next = computed(() => isOwner.value ? requests.value[0] : void 0);
|
|
897
1006
|
/** Dialog on display, kept until its leave transition ends. */
|
|
898
1007
|
const request = shallowRef();
|
|
@@ -921,8 +1030,8 @@ var dialog_host_default = /* @__PURE__ */ defineComponent({
|
|
|
921
1030
|
persistent: () => isRunning.value,
|
|
922
1031
|
afterLeave: showNext
|
|
923
1032
|
});
|
|
924
|
-
onMounted(() => owners.value.push(owner));
|
|
925
|
-
onUnmounted(() => owners.value = owners.value.filter((item) => item !== owner));
|
|
1033
|
+
onMounted(() => owners$1.value.push(owner));
|
|
1034
|
+
onUnmounted(() => owners$1.value = owners$1.value.filter((item) => item !== owner));
|
|
926
1035
|
watch(next, show);
|
|
927
1036
|
function show() {
|
|
928
1037
|
if (request.value) return;
|