@nexdom/uimed-vue 2.0.0-beta.3 → 2.0.0-beta.30
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/AGENTS.md +121 -15
- package/README.md +1 -1
- package/dist/components.d.ts +820 -79
- package/dist/components.js +1837 -287
- package/dist/composables.d.ts +130 -4
- package/dist/composables.js +55 -3
- package/dist/index.d.ts +3 -15
- package/dist/index.js +22 -13
- package/dist/locale-CM4o8cD_.js +12 -0
- package/dist/plugins.d.ts +17 -7
- package/dist/plugins.js +55 -4
- package/dist/styles/fonts/UnimedSlab-Regular.woff2 +0 -0
- package/dist/styles/fonts/fonts.css +4 -0
- package/dist/styles/settings.scss +6 -0
- package/dist/types-DNT_odv7.d.ts +57 -0
- package/dist/unit-test.d.ts +2 -3
- package/dist/unit-test.js +3 -1
- package/dist/use-dialog-Ck2_ZW7T.js +124 -0
- package/package.json +6 -8
- package/dist/types-BPXXtbmW.d.ts +0 -5
- package/dist/use-toast-CACuYhK_.js +0 -53
package/dist/components.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { r as
|
|
2
|
-
import { Fragment, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createSlots, createTextVNode, createVNode, defineComponent, isRef, mergeModels, mergeProps, openBlock, ref, renderList, renderSlot, toDisplayString, toValue, unref, useModel, withCtx, withModifiers } from "vue";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
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
|
+
import { pt } from "vuetify/locale";
|
|
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, VProgressCircular, VProgressLinear, VRow, VSkeletonLoader, VSnackbarQueue, VTable, VTextField, VTimePicker } from "vuetify/components";
|
|
5
|
+
import { formatDateTime, isEmail, isEmpty, isPhone, isUrl } from "@nexdom/shared/utils";
|
|
5
6
|
//#region src/composables/navigation/use-route-props.ts
|
|
6
7
|
function useRouteProps(route) {
|
|
7
8
|
return computed(() => routeToProps(route));
|
|
@@ -14,8 +15,103 @@ function isExternalRoute(route) {
|
|
|
14
15
|
return typeof route === "string" && route.startsWith("http");
|
|
15
16
|
}
|
|
16
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
|
|
17
113
|
//#region src/components/app-bar/app-bar.vue?vue&type=script&setup=true&lang.ts
|
|
18
|
-
const _hoisted_1$
|
|
114
|
+
const _hoisted_1$3 = { class: "opacity-60" };
|
|
19
115
|
//#endregion
|
|
20
116
|
//#region src/components/app-bar/app-bar.vue
|
|
21
117
|
var app_bar_default = /* @__PURE__ */ defineComponent({
|
|
@@ -49,6 +145,10 @@ var app_bar_default = /* @__PURE__ */ defineComponent({
|
|
|
49
145
|
logo: {
|
|
50
146
|
type: String,
|
|
51
147
|
required: false
|
|
148
|
+
},
|
|
149
|
+
loading: {
|
|
150
|
+
type: Boolean,
|
|
151
|
+
required: false
|
|
52
152
|
}
|
|
53
153
|
}, {
|
|
54
154
|
"notificationsOpen": {
|
|
@@ -64,6 +164,7 @@ var app_bar_default = /* @__PURE__ */ defineComponent({
|
|
|
64
164
|
const props = __props;
|
|
65
165
|
const notificationsOpen = useModel(__props, "notificationsOpen");
|
|
66
166
|
const navigationOpen = useModel(__props, "navigationOpen");
|
|
167
|
+
const { ariaKeyshortcuts: navigationKeyshortcuts } = useNavigationShortcutKeys();
|
|
67
168
|
const helpBtnDataTestid = computed(() => `${props.dataTestid}-help`);
|
|
68
169
|
const notificationsBtnDataTestid = computed(() => `${props.dataTestid}-notifications`);
|
|
69
170
|
const navigationBtnDataTestid = computed(() => `${props.dataTestid}-navigation`);
|
|
@@ -75,145 +176,158 @@ var app_bar_default = /* @__PURE__ */ defineComponent({
|
|
|
75
176
|
const showNotifications = computed(() => !!props.notifications);
|
|
76
177
|
const unreadCount = computed(() => props.notifications.filter((notification) => !notification.read).length);
|
|
77
178
|
const hasUnreadNotifications = computed(() => unreadCount.value > 0);
|
|
179
|
+
const unreadLabel = computed(() => unreadCount.value === 1 ? "1 não lida" : `${unreadCount.value} não lidas`);
|
|
180
|
+
const notificationsLabel = computed(() => hasUnreadNotifications.value ? `Notificações (${unreadLabel.value})` : "Notificações");
|
|
181
|
+
watch(() => props.loading, (loading) => {
|
|
182
|
+
if (loading) notificationsOpen.value = false;
|
|
183
|
+
});
|
|
78
184
|
const showUser = computed(() => !!props.user);
|
|
79
185
|
const userAvatarProps = computed(() => props.user.img ? { image: props.user.img } : { icon: "mdi-account-outline" });
|
|
80
186
|
function isParentOption(option) {
|
|
81
187
|
return "items" in option;
|
|
82
188
|
}
|
|
83
|
-
function formatNotificationDate(date) {
|
|
84
|
-
const interval = toPeriodInterval(date);
|
|
85
|
-
if (wasThisMonth(interval)) {
|
|
86
|
-
if (wasToday(interval)) return formatDateTime(date, "HH:mm");
|
|
87
|
-
else if (wasYesterday(interval)) return "Ontem";
|
|
88
|
-
}
|
|
89
|
-
return formatDateTime(date, "DD/MM/YYYY");
|
|
90
|
-
}
|
|
91
|
-
function wasThisMonth(interval) {
|
|
92
|
-
return interval.months === 0 && interval.years === 0;
|
|
93
|
-
}
|
|
94
|
-
function wasToday(interval) {
|
|
95
|
-
return interval.days === 0;
|
|
96
|
-
}
|
|
97
|
-
function wasYesterday(interval) {
|
|
98
|
-
return interval.days === 1;
|
|
99
|
-
}
|
|
100
189
|
return (_ctx, _cache) => {
|
|
101
|
-
return openBlock(), createBlock(unref(VAppBar), {
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
}, {
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
190
|
+
return openBlock(), createBlock(unref(VAppBar), {
|
|
191
|
+
"data-testid": props.dataTestid,
|
|
192
|
+
"aria-busy": props.loading || void 0
|
|
193
|
+
}, {
|
|
194
|
+
append: withCtx(() => [createVNode(unref(VSkeletonLoader), {
|
|
195
|
+
loading: props.loading,
|
|
196
|
+
type: "avatar"
|
|
197
|
+
}, {
|
|
198
|
+
default: withCtx(() => [
|
|
199
|
+
showHelp.value ? (openBlock(), createBlock(unref(VBtn), mergeProps({ key: 0 }, unref(routeProps), {
|
|
200
|
+
"data-testid": helpBtnDataTestid.value,
|
|
201
|
+
"aria-label": "Ajuda",
|
|
202
|
+
icon: "mdi-help-circle-outline"
|
|
203
|
+
}), null, 16, ["data-testid"])) : createCommentVNode("v-if", true),
|
|
204
|
+
showNotifications.value ? (openBlock(), createBlock(unref(VMenu), {
|
|
205
|
+
key: 1,
|
|
206
|
+
modelValue: notificationsOpen.value,
|
|
207
|
+
"onUpdate:modelValue": _cache[1] || (_cache[1] = ($event) => notificationsOpen.value = $event),
|
|
208
|
+
"close-on-content-click": false
|
|
209
|
+
}, {
|
|
210
|
+
activator: withCtx(({ props }) => [createVNode(unref(VBtn), mergeProps(props, {
|
|
211
|
+
"data-testid": notificationsBtnDataTestid.value,
|
|
212
|
+
"aria-label": notificationsLabel.value,
|
|
213
|
+
icon: ""
|
|
214
|
+
}), {
|
|
215
|
+
default: withCtx(() => [createVNode(unref(VBadge), {
|
|
216
|
+
"model-value": hasUnreadNotifications.value,
|
|
217
|
+
content: unreadCount.value,
|
|
218
|
+
label: unreadLabel.value,
|
|
219
|
+
color: "error"
|
|
220
|
+
}, {
|
|
221
|
+
default: withCtx(() => [createVNode(unref(VIcon), { icon: "mdi-bell-outline" })]),
|
|
131
222
|
_: 1
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
subtitle: notification.subtitle,
|
|
138
|
-
"active-class": "text-primary"
|
|
139
|
-
}, createSlots({ _: 2 }, [notification.date ? {
|
|
140
|
-
name: "append",
|
|
141
|
-
fn: withCtx(() => [createVNode(unref(VListItemAction), { end: "" }, {
|
|
142
|
-
default: withCtx(() => [createElementVNode("small", _hoisted_1$2, toDisplayString(formatNotificationDate(notification.date)), 1)]),
|
|
143
|
-
_: 2
|
|
144
|
-
}, 1024)]),
|
|
145
|
-
key: "0"
|
|
146
|
-
} : void 0]), 1032, [
|
|
147
|
-
"active",
|
|
148
|
-
"title",
|
|
149
|
-
"subtitle"
|
|
150
|
-
]);
|
|
151
|
-
}), 128))]),
|
|
223
|
+
}, 8, [
|
|
224
|
+
"model-value",
|
|
225
|
+
"content",
|
|
226
|
+
"label"
|
|
227
|
+
])]),
|
|
152
228
|
_: 1
|
|
153
|
-
}
|
|
154
|
-
|
|
229
|
+
}, 16, ["data-testid", "aria-label"])]),
|
|
230
|
+
default: withCtx(() => [createVNode(unref(VCard), { "data-testid": notificationsMenuDataTestid.value }, {
|
|
231
|
+
default: withCtx(() => [props.notifications?.length ? (openBlock(), createBlock(unref(VList), { key: 0 }, {
|
|
232
|
+
default: withCtx(() => [createVNode(unref(VListSubheader), null, {
|
|
233
|
+
default: withCtx(() => [..._cache[2] || (_cache[2] = [createTextVNode("Notificações", -1)])]),
|
|
234
|
+
_: 1
|
|
235
|
+
}), (openBlock(true), createElementBlock(Fragment, null, renderList(props.notifications, (notification, index) => {
|
|
236
|
+
return openBlock(), createBlock(unref(VListItem), {
|
|
237
|
+
key: index,
|
|
238
|
+
active: !notification.read,
|
|
239
|
+
title: notification.title,
|
|
240
|
+
subtitle: notification.subtitle,
|
|
241
|
+
"active-class": "text-primary"
|
|
242
|
+
}, createSlots({ _: 2 }, [notification.when ? {
|
|
243
|
+
name: "append",
|
|
244
|
+
fn: withCtx(() => [createVNode(unref(VListItemAction), { end: "" }, {
|
|
245
|
+
default: withCtx(() => [createElementVNode("small", _hoisted_1$3, toDisplayString(notification.when), 1)]),
|
|
246
|
+
_: 2
|
|
247
|
+
}, 1024)]),
|
|
248
|
+
key: "0"
|
|
249
|
+
} : void 0]), 1032, [
|
|
250
|
+
"active",
|
|
251
|
+
"title",
|
|
252
|
+
"subtitle"
|
|
253
|
+
]);
|
|
254
|
+
}), 128))]),
|
|
255
|
+
_: 1
|
|
256
|
+
})) : (openBlock(), createBlock(unref(VCardText), { key: 1 }, {
|
|
257
|
+
default: withCtx(() => [..._cache[3] || (_cache[3] = [createTextVNode("Nenhuma notificação", -1)])]),
|
|
258
|
+
_: 1
|
|
259
|
+
}))]),
|
|
155
260
|
_: 1
|
|
156
|
-
})
|
|
261
|
+
}, 8, ["data-testid"])]),
|
|
157
262
|
_: 1
|
|
158
|
-
}, 8, ["
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
key: 2,
|
|
163
|
-
"close-on-content-click": false
|
|
164
|
-
}, {
|
|
165
|
-
activator: withCtx(({ props }) => [createVNode(unref(VBtn), mergeProps(props, {
|
|
166
|
-
"data-testid": userBtnDataTestid.value,
|
|
167
|
-
icon: ""
|
|
168
|
-
}), {
|
|
169
|
-
default: withCtx(() => [createVNode(unref(VAvatar), mergeProps(userAvatarProps.value, { color: "primary" }), null, 16)]),
|
|
170
|
-
_: 1
|
|
171
|
-
}, 16, ["data-testid"])]),
|
|
172
|
-
default: withCtx(() => [createVNode(unref(VCard), {
|
|
173
|
-
title: __props.user?.title,
|
|
174
|
-
subtitle: __props.user?.subtitle,
|
|
175
|
-
"data-testid": userMenuDataTestid.value
|
|
263
|
+
}, 8, ["modelValue"])) : createCommentVNode("v-if", true),
|
|
264
|
+
showUser.value ? (openBlock(), createBlock(unref(VMenu), {
|
|
265
|
+
key: 2,
|
|
266
|
+
"close-on-content-click": false
|
|
176
267
|
}, {
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
})) : createCommentVNode("v-if", true), isParentOption(option) ? (openBlock(), createBlock(unref(VListGroup), { key: 1 }, {
|
|
184
|
-
activator: withCtx(({ props }) => [createVNode(unref(VListItem), mergeProps({ ref_for: true }, props, { title: option.description }), null, 16, ["title"])]),
|
|
185
|
-
default: withCtx(() => [(openBlock(true), createElementBlock(Fragment, null, renderList(option.items, (childOption, index) => {
|
|
186
|
-
return openBlock(), createBlock(unref(VListItem), mergeProps({ key: index }, { ref_for: true }, unref(routeToProps)(childOption.route), {
|
|
187
|
-
title: childOption.description,
|
|
188
|
-
onClick: childOption.action
|
|
189
|
-
}), null, 16, ["title", "onClick"]);
|
|
190
|
-
}), 128))]),
|
|
191
|
-
_: 2
|
|
192
|
-
}, 1024)) : (openBlock(), createBlock(unref(VListItem), mergeProps({
|
|
193
|
-
key: 2,
|
|
194
|
-
title: option.description
|
|
195
|
-
}, { ref_for: true }, unref(routeToProps)(option.route), { onClick: option.action }), null, 16, ["title", "onClick"]))], 64);
|
|
196
|
-
}), 128))]),
|
|
268
|
+
activator: withCtx(({ props }) => [createVNode(unref(VBtn), mergeProps(props, {
|
|
269
|
+
"data-testid": userBtnDataTestid.value,
|
|
270
|
+
"aria-label": "Menu do usuário",
|
|
271
|
+
icon: ""
|
|
272
|
+
}), {
|
|
273
|
+
default: withCtx(() => [createVNode(unref(VAvatar), mergeProps(userAvatarProps.value, { color: "primary" }), null, 16)]),
|
|
197
274
|
_: 1
|
|
198
|
-
})]),
|
|
275
|
+
}, 16, ["data-testid"])]),
|
|
276
|
+
default: withCtx(() => [createVNode(unref(VCard), {
|
|
277
|
+
title: __props.user?.title,
|
|
278
|
+
subtitle: __props.user?.subtitle,
|
|
279
|
+
"data-testid": userMenuDataTestid.value
|
|
280
|
+
}, {
|
|
281
|
+
prepend: withCtx(() => [createVNode(unref(VAvatar), mergeProps(userAvatarProps.value, { color: "primary" }), null, 16)]),
|
|
282
|
+
default: withCtx(() => [createVNode(unref(VDivider)), createVNode(unref(VList), { nav: "" }, {
|
|
283
|
+
default: withCtx(() => [(openBlock(true), createElementBlock(Fragment, null, renderList(props.user?.options, (option, index) => {
|
|
284
|
+
return openBlock(), createElementBlock(Fragment, { key: index }, [index > 0 ? (openBlock(), createBlock(unref(VDivider), {
|
|
285
|
+
key: 0,
|
|
286
|
+
class: "mt-1"
|
|
287
|
+
})) : createCommentVNode("v-if", true), isParentOption(option) ? (openBlock(), createBlock(unref(VListGroup), { key: 1 }, {
|
|
288
|
+
activator: withCtx(({ props }) => [createVNode(unref(VListItem), mergeProps({ ref_for: true }, props, { title: option.description }), null, 16, ["title"])]),
|
|
289
|
+
default: withCtx(() => [(openBlock(true), createElementBlock(Fragment, null, renderList(option.items, (childOption, index) => {
|
|
290
|
+
return openBlock(), createBlock(unref(VListItem), mergeProps({ key: index }, { ref_for: true }, unref(routeToProps)(childOption.route), {
|
|
291
|
+
title: childOption.description,
|
|
292
|
+
onClick: childOption.action
|
|
293
|
+
}), null, 16, ["title", "onClick"]);
|
|
294
|
+
}), 128))]),
|
|
295
|
+
_: 2
|
|
296
|
+
}, 1024)) : (openBlock(), createBlock(unref(VListItem), mergeProps({
|
|
297
|
+
key: 2,
|
|
298
|
+
title: option.description
|
|
299
|
+
}, { ref_for: true }, unref(routeToProps)(option.route), { onClick: option.action }), null, 16, ["title", "onClick"]))], 64);
|
|
300
|
+
}), 128))]),
|
|
301
|
+
_: 1
|
|
302
|
+
})]),
|
|
303
|
+
_: 1
|
|
304
|
+
}, 8, [
|
|
305
|
+
"title",
|
|
306
|
+
"subtitle",
|
|
307
|
+
"data-testid"
|
|
308
|
+
])]),
|
|
199
309
|
_: 1
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
])]),
|
|
205
|
-
_: 1
|
|
206
|
-
})) : createCommentVNode("v-if", true)
|
|
207
|
-
]),
|
|
310
|
+
})) : createCommentVNode("v-if", true)
|
|
311
|
+
]),
|
|
312
|
+
_: 1
|
|
313
|
+
}, 8, ["loading"])]),
|
|
208
314
|
default: withCtx(() => [
|
|
209
315
|
__props.navigation ? (openBlock(), createBlock(unref(VAppBarNavIcon), {
|
|
210
316
|
key: 0,
|
|
211
317
|
"data-testid": navigationBtnDataTestid.value,
|
|
318
|
+
"aria-expanded": navigationOpen.value,
|
|
319
|
+
"aria-label": "Menu de navegação",
|
|
320
|
+
"aria-keyshortcuts": unref(navigationKeyshortcuts),
|
|
212
321
|
onClick: _cache[0] || (_cache[0] = ($event) => navigationOpen.value = !navigationOpen.value)
|
|
213
|
-
}, null, 8, [
|
|
322
|
+
}, null, 8, [
|
|
323
|
+
"data-testid",
|
|
324
|
+
"aria-expanded",
|
|
325
|
+
"aria-keyshortcuts"
|
|
326
|
+
])) : createCommentVNode("v-if", true),
|
|
214
327
|
__props.logo ? (openBlock(), createBlock(unref(VImg), {
|
|
215
328
|
key: 1,
|
|
216
329
|
src: props.logo,
|
|
330
|
+
alt: "",
|
|
217
331
|
height: "100%",
|
|
218
332
|
width: "fit-content",
|
|
219
333
|
class: "py-2 ml-5 mr-n3",
|
|
@@ -225,7 +339,7 @@ var app_bar_default = /* @__PURE__ */ defineComponent({
|
|
|
225
339
|
})) : createCommentVNode("v-if", true)
|
|
226
340
|
]),
|
|
227
341
|
_: 1
|
|
228
|
-
}, 8, ["data-testid"]);
|
|
342
|
+
}, 8, ["data-testid", "aria-busy"]);
|
|
229
343
|
};
|
|
230
344
|
}
|
|
231
345
|
});
|
|
@@ -244,7 +358,23 @@ function url(value) {
|
|
|
244
358
|
return isEmpty(value) || isUrl(value) || "URL inválida";
|
|
245
359
|
}
|
|
246
360
|
//#endregion
|
|
247
|
-
//#region src/composables/inputs/
|
|
361
|
+
//#region src/composables/inputs/fields.ts
|
|
362
|
+
const textFieldVariantToVuetifyVariant = {
|
|
363
|
+
primary: "underlined",
|
|
364
|
+
secondary: "outlined"
|
|
365
|
+
};
|
|
366
|
+
function useTextFieldVariant(variant) {
|
|
367
|
+
return computed(() => {
|
|
368
|
+
const variantValue = toValue(variant);
|
|
369
|
+
return textFieldVariantToVuetifyVariant[variantValue];
|
|
370
|
+
});
|
|
371
|
+
}
|
|
372
|
+
function createRequiredRule(required, isPresent) {
|
|
373
|
+
return (value) => {
|
|
374
|
+
if (!required) return true;
|
|
375
|
+
return isPresent(value) || "Campo obrigatório";
|
|
376
|
+
};
|
|
377
|
+
}
|
|
248
378
|
function useRules(options) {
|
|
249
379
|
return computed(() => {
|
|
250
380
|
const rules = [];
|
|
@@ -254,10 +384,6 @@ function useRules(options) {
|
|
|
254
384
|
}
|
|
255
385
|
//#endregion
|
|
256
386
|
//#region src/composables/inputs/text-field.ts
|
|
257
|
-
const textFieldVariantToVuetifyVariant = {
|
|
258
|
-
primary: "underlined",
|
|
259
|
-
secondary: "outlined"
|
|
260
|
-
};
|
|
261
387
|
const textFieldTypeToVuetifyType = {
|
|
262
388
|
text: "text",
|
|
263
389
|
phone: "tel",
|
|
@@ -271,12 +397,6 @@ const textFieldTypeToVuetifyRule = {
|
|
|
271
397
|
email,
|
|
272
398
|
url
|
|
273
399
|
};
|
|
274
|
-
function useTextFieldVariant(variant) {
|
|
275
|
-
return computed(() => {
|
|
276
|
-
const variantValue = toValue(variant);
|
|
277
|
-
return textFieldVariantToVuetifyVariant[variantValue];
|
|
278
|
-
});
|
|
279
|
-
}
|
|
280
400
|
function useTextFieldType(type) {
|
|
281
401
|
return computed(() => {
|
|
282
402
|
const typeValue = toValue(type);
|
|
@@ -296,6 +416,34 @@ function associatedRuleType(type) {
|
|
|
296
416
|
return type in textFieldTypeToVuetifyRule;
|
|
297
417
|
}
|
|
298
418
|
//#endregion
|
|
419
|
+
//#region src/components/inputs/field-loader.vue
|
|
420
|
+
var field_loader_default = /* @__PURE__ */ defineComponent({
|
|
421
|
+
inheritAttrs: false,
|
|
422
|
+
__name: "field-loader",
|
|
423
|
+
props: {
|
|
424
|
+
color: {
|
|
425
|
+
type: String,
|
|
426
|
+
required: false
|
|
427
|
+
},
|
|
428
|
+
isActive: {
|
|
429
|
+
type: Boolean,
|
|
430
|
+
required: true
|
|
431
|
+
}
|
|
432
|
+
},
|
|
433
|
+
setup(__props) {
|
|
434
|
+
const props = __props;
|
|
435
|
+
return (_ctx, _cache) => {
|
|
436
|
+
return openBlock(), createBlock(unref(VProgressLinear), {
|
|
437
|
+
active: props.isActive,
|
|
438
|
+
color: props.color,
|
|
439
|
+
height: "2",
|
|
440
|
+
indeterminate: "",
|
|
441
|
+
"aria-hidden": "true"
|
|
442
|
+
}, null, 8, ["active", "color"]);
|
|
443
|
+
};
|
|
444
|
+
}
|
|
445
|
+
});
|
|
446
|
+
//#endregion
|
|
299
447
|
//#region src/components/inputs/text-field/text-field.vue
|
|
300
448
|
var text_field_default = /* @__PURE__ */ defineComponent({
|
|
301
449
|
inheritAttrs: false,
|
|
@@ -379,13 +527,17 @@ var text_field_default = /* @__PURE__ */ defineComponent({
|
|
|
379
527
|
"data-testid": props.dataTestid,
|
|
380
528
|
disabled: props.disabled,
|
|
381
529
|
loading: props.loading,
|
|
530
|
+
"aria-busy": props.loading || void 0,
|
|
382
531
|
readonly: props.readonly,
|
|
383
532
|
label: props.label,
|
|
384
533
|
placeholder: props.placeholder,
|
|
385
534
|
hint: props.hint,
|
|
386
535
|
clearable: computedClearable.value,
|
|
387
536
|
"onClick:clear": clear
|
|
388
|
-
},
|
|
537
|
+
}, {
|
|
538
|
+
loader: withCtx((loader) => [createVNode(field_loader_default, normalizeProps(guardReactiveProps(loader)), null, 16)]),
|
|
539
|
+
_: 1
|
|
540
|
+
}, 8, [
|
|
389
541
|
"modelValue",
|
|
390
542
|
"variant",
|
|
391
543
|
"type",
|
|
@@ -394,6 +546,7 @@ var text_field_default = /* @__PURE__ */ defineComponent({
|
|
|
394
546
|
"data-testid",
|
|
395
547
|
"disabled",
|
|
396
548
|
"loading",
|
|
549
|
+
"aria-busy",
|
|
397
550
|
"readonly",
|
|
398
551
|
"label",
|
|
399
552
|
"placeholder",
|
|
@@ -405,7 +558,7 @@ var text_field_default = /* @__PURE__ */ defineComponent({
|
|
|
405
558
|
});
|
|
406
559
|
//#endregion
|
|
407
560
|
//#region src/components/navigation-menu/navigation-menu.vue?vue&type=script&setup=true&lang.ts
|
|
408
|
-
const _hoisted_1$
|
|
561
|
+
const _hoisted_1$2 = { class: "px-4 pt-2" };
|
|
409
562
|
//#endregion
|
|
410
563
|
//#region src/components/navigation-menu/navigation-menu.vue
|
|
411
564
|
var navigation_menu_default = /* @__PURE__ */ defineComponent({
|
|
@@ -419,6 +572,10 @@ var navigation_menu_default = /* @__PURE__ */ defineComponent({
|
|
|
419
572
|
items: {
|
|
420
573
|
type: Array,
|
|
421
574
|
required: false
|
|
575
|
+
},
|
|
576
|
+
loading: {
|
|
577
|
+
type: Boolean,
|
|
578
|
+
required: false
|
|
422
579
|
}
|
|
423
580
|
}, {
|
|
424
581
|
"modelValue": {
|
|
@@ -432,6 +589,10 @@ var navigation_menu_default = /* @__PURE__ */ defineComponent({
|
|
|
432
589
|
const props = __props;
|
|
433
590
|
const open = useModel(__props, "modelValue");
|
|
434
591
|
const search = ref("");
|
|
592
|
+
const { label: shortcutLabel, close } = useNavigationSearchShortcut({
|
|
593
|
+
open,
|
|
594
|
+
field: useTemplateRef("searchField")
|
|
595
|
+
});
|
|
435
596
|
const filteredItems = computed(() => filterItems());
|
|
436
597
|
const searchDataTestid = computed(() => `${props.dataTestid}-search`);
|
|
437
598
|
const query = computed(() => search.value.toLowerCase());
|
|
@@ -458,59 +619,105 @@ var navigation_menu_default = /* @__PURE__ */ defineComponent({
|
|
|
458
619
|
return openBlock(), createBlock(unref(VNavigationDrawer), {
|
|
459
620
|
modelValue: open.value,
|
|
460
621
|
"onUpdate:modelValue": _cache[1] || (_cache[1] = ($event) => open.value = $event),
|
|
622
|
+
color: "primary",
|
|
461
623
|
"data-testid": props.dataTestid,
|
|
624
|
+
"aria-busy": props.loading || void 0,
|
|
462
625
|
absolute: "",
|
|
463
|
-
temporary: ""
|
|
626
|
+
temporary: "",
|
|
627
|
+
onKeydown: withKeys(unref(close), ["esc"])
|
|
464
628
|
}, {
|
|
465
|
-
prepend: withCtx(() => [createElementVNode("div", _hoisted_1$
|
|
629
|
+
prepend: withCtx(() => [createElementVNode("div", _hoisted_1$2, [createVNode(text_field_default, {
|
|
630
|
+
ref: "searchField",
|
|
466
631
|
modelValue: search.value,
|
|
467
632
|
"onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => search.value = $event),
|
|
468
633
|
type: "search",
|
|
469
|
-
|
|
470
|
-
"data-testid": searchDataTestid.value
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
634
|
+
placeholder: `Buscar (${unref(shortcutLabel)})`,
|
|
635
|
+
"data-testid": searchDataTestid.value,
|
|
636
|
+
disabled: props.loading
|
|
637
|
+
}, null, 8, [
|
|
638
|
+
"modelValue",
|
|
639
|
+
"placeholder",
|
|
640
|
+
"data-testid",
|
|
641
|
+
"disabled"
|
|
642
|
+
])])]),
|
|
643
|
+
default: withCtx(() => [createVNode(unref(VDivider)), createVNode(unref(VSkeletonLoader), {
|
|
644
|
+
loading: props.loading,
|
|
645
|
+
type: "list-item@6",
|
|
646
|
+
color: "primary"
|
|
647
|
+
}, {
|
|
648
|
+
default: withCtx(() => [createVNode(unref(VList), { nav: "" }, {
|
|
649
|
+
default: withCtx(() => [(openBlock(true), createElementBlock(Fragment, null, renderList(filteredItems.value, (item, index) => {
|
|
650
|
+
return openBlock(), createElementBlock(Fragment, { key: index }, [isParentItem(item) ? (openBlock(), createBlock(unref(VListGroup), { key: 0 }, {
|
|
651
|
+
activator: withCtx(({ props: activatorProps }) => [createVNode(unref(VListItem), mergeProps({ ref_for: true }, activatorProps, { title: item.description }), null, 16, ["title"])]),
|
|
652
|
+
default: withCtx(() => [(openBlock(true), createElementBlock(Fragment, null, renderList(item.items, (childItem, childIndex) => {
|
|
653
|
+
return openBlock(), createBlock(unref(VListItem), mergeProps({ key: childIndex }, { ref_for: true }, unref(routeToProps)(childItem.route), {
|
|
654
|
+
title: childItem.description,
|
|
655
|
+
onClick: childItem.action
|
|
656
|
+
}), null, 16, ["title", "onClick"]);
|
|
657
|
+
}), 128))]),
|
|
658
|
+
_: 2
|
|
659
|
+
}, 1024)) : (openBlock(), createBlock(unref(VListItem), mergeProps({
|
|
660
|
+
key: 1,
|
|
661
|
+
title: item.description
|
|
662
|
+
}, { ref_for: true }, unref(routeToProps)(item.route), { onClick: item.action }), null, 16, ["title", "onClick"]))], 64);
|
|
663
|
+
}), 128))]),
|
|
664
|
+
_: 1
|
|
665
|
+
})]),
|
|
488
666
|
_: 1
|
|
489
|
-
})]),
|
|
667
|
+
}, 8, ["loading"])]),
|
|
490
668
|
_: 1
|
|
491
|
-
}, 8, [
|
|
669
|
+
}, 8, [
|
|
670
|
+
"modelValue",
|
|
671
|
+
"data-testid",
|
|
672
|
+
"aria-busy",
|
|
673
|
+
"onKeydown"
|
|
674
|
+
]);
|
|
492
675
|
};
|
|
493
676
|
}
|
|
494
677
|
});
|
|
495
678
|
//#endregion
|
|
679
|
+
//#region src/composables/dimensions/dimensions.ts
|
|
680
|
+
/**
|
|
681
|
+
* Vuetify's utility class that stretches a component to the whole width of its parent, for
|
|
682
|
+
* components with a `fullWidth` prop.
|
|
683
|
+
*/
|
|
684
|
+
function useFullWidth(fullWidth) {
|
|
685
|
+
return computed(() => toValue(fullWidth) ? "w-100" : void 0);
|
|
686
|
+
}
|
|
687
|
+
/**
|
|
688
|
+
* Vuetify's utility class that stretches a component to the whole height of its parent, for
|
|
689
|
+
* components with a `fullHeight` prop. The parent must have a height of its own.
|
|
690
|
+
*/
|
|
691
|
+
function useFullHeight(fullHeight) {
|
|
692
|
+
return computed(() => toValue(fullHeight) ? "h-100" : void 0);
|
|
693
|
+
}
|
|
694
|
+
//#endregion
|
|
496
695
|
//#region src/components/grid/container/container.vue
|
|
497
696
|
var container_default = /* @__PURE__ */ defineComponent({
|
|
498
697
|
inheritAttrs: false,
|
|
499
698
|
__name: "container",
|
|
500
|
-
props: {
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
699
|
+
props: {
|
|
700
|
+
fullHeight: {
|
|
701
|
+
type: Boolean,
|
|
702
|
+
required: false
|
|
703
|
+
},
|
|
704
|
+
dataTestid: {
|
|
705
|
+
type: String,
|
|
706
|
+
required: false
|
|
707
|
+
}
|
|
708
|
+
},
|
|
504
709
|
setup(__props) {
|
|
505
710
|
const props = __props;
|
|
711
|
+
const heightClass = useFullHeight(() => props.fullHeight);
|
|
506
712
|
return (_ctx, _cache) => {
|
|
507
713
|
return openBlock(), createBlock(unref(VContainer), {
|
|
714
|
+
class: normalizeClass(unref(heightClass)),
|
|
508
715
|
"data-testid": props.dataTestid,
|
|
509
716
|
fluid: ""
|
|
510
717
|
}, {
|
|
511
718
|
default: withCtx(() => [renderSlot(_ctx.$slots, "default")]),
|
|
512
719
|
_: 3
|
|
513
|
-
}, 8, ["data-testid"]);
|
|
720
|
+
}, 8, ["class", "data-testid"]);
|
|
514
721
|
};
|
|
515
722
|
}
|
|
516
723
|
});
|
|
@@ -543,76 +750,11 @@ var toast_default = /* @__PURE__ */ defineComponent({
|
|
|
543
750
|
}
|
|
544
751
|
});
|
|
545
752
|
//#endregion
|
|
546
|
-
//#region src/components/main/main.vue
|
|
547
|
-
var main_default = /* @__PURE__ */ defineComponent({
|
|
548
|
-
inheritAttrs: false,
|
|
549
|
-
__name: "main",
|
|
550
|
-
props: /*@__PURE__*/ mergeModels({
|
|
551
|
-
dataTestid: {
|
|
552
|
-
type: String,
|
|
553
|
-
required: false
|
|
554
|
-
},
|
|
555
|
-
logo: {
|
|
556
|
-
type: String,
|
|
557
|
-
required: false
|
|
558
|
-
},
|
|
559
|
-
appBar: {
|
|
560
|
-
type: Object,
|
|
561
|
-
required: false
|
|
562
|
-
},
|
|
563
|
-
navigationMenu: {
|
|
564
|
-
type: Object,
|
|
565
|
-
required: false
|
|
566
|
-
}
|
|
567
|
-
}, {
|
|
568
|
-
"notificationsOpen": {
|
|
569
|
-
type: Boolean,
|
|
570
|
-
default: false
|
|
571
|
-
},
|
|
572
|
-
"notificationsOpenModifiers": {}
|
|
573
|
-
}),
|
|
574
|
-
emits: ["update:notificationsOpen"],
|
|
575
|
-
setup(__props) {
|
|
576
|
-
const props = __props;
|
|
577
|
-
const appBarProps = computed(() => props.appBar ? {
|
|
578
|
-
...props.appBar,
|
|
579
|
-
logo: props.logo,
|
|
580
|
-
navigation: props.navigationMenu !== void 0
|
|
581
|
-
} : void 0);
|
|
582
|
-
const notificationsOpen = useModel(__props, "notificationsOpen");
|
|
583
|
-
const navigationMenuOpen = ref(false);
|
|
584
|
-
return (_ctx, _cache) => {
|
|
585
|
-
return openBlock(), createBlock(unref(VApp), { "data-testid": props.dataTestid }, {
|
|
586
|
-
default: withCtx(() => [
|
|
587
|
-
appBarProps.value ? (openBlock(), createBlock(app_bar_default, mergeProps({ key: 0 }, appBarProps.value, {
|
|
588
|
-
"notifications-open": notificationsOpen.value,
|
|
589
|
-
"onUpdate:notificationsOpen": _cache[0] || (_cache[0] = ($event) => notificationsOpen.value = $event),
|
|
590
|
-
"navigation-open": navigationMenuOpen.value,
|
|
591
|
-
"onUpdate:navigationOpen": _cache[1] || (_cache[1] = ($event) => navigationMenuOpen.value = $event)
|
|
592
|
-
}), null, 16, ["notifications-open", "navigation-open"])) : createCommentVNode("v-if", true),
|
|
593
|
-
props.navigationMenu ? (openBlock(), createBlock(navigation_menu_default, mergeProps({ key: 1 }, props.navigationMenu, {
|
|
594
|
-
modelValue: navigationMenuOpen.value,
|
|
595
|
-
"onUpdate:modelValue": _cache[2] || (_cache[2] = ($event) => navigationMenuOpen.value = $event)
|
|
596
|
-
}), null, 16, ["modelValue"])) : createCommentVNode("v-if", true),
|
|
597
|
-
createVNode(unref(VMain), null, {
|
|
598
|
-
default: withCtx(() => [createVNode(container_default, null, {
|
|
599
|
-
default: withCtx(() => [renderSlot(_ctx.$slots, "default"), createVNode(toast_default)]),
|
|
600
|
-
_: 3
|
|
601
|
-
})]),
|
|
602
|
-
_: 3
|
|
603
|
-
})
|
|
604
|
-
]),
|
|
605
|
-
_: 3
|
|
606
|
-
}, 8, ["data-testid"]);
|
|
607
|
-
};
|
|
608
|
-
}
|
|
609
|
-
});
|
|
610
|
-
//#endregion
|
|
611
753
|
//#region src/composables/button/button.ts
|
|
612
754
|
const buttonVariantToVuetifyVariant = {
|
|
613
755
|
primary: "elevated",
|
|
614
756
|
secondary: "flat",
|
|
615
|
-
ghost: "
|
|
757
|
+
ghost: "text"
|
|
616
758
|
};
|
|
617
759
|
function useButtonVariant(variant) {
|
|
618
760
|
return computed(() => {
|
|
@@ -654,6 +796,10 @@ var button_default = /* @__PURE__ */ defineComponent({
|
|
|
654
796
|
type: Boolean,
|
|
655
797
|
required: false
|
|
656
798
|
},
|
|
799
|
+
fullWidth: {
|
|
800
|
+
type: Boolean,
|
|
801
|
+
required: false
|
|
802
|
+
},
|
|
657
803
|
form: {
|
|
658
804
|
type: String,
|
|
659
805
|
required: false
|
|
@@ -671,6 +817,7 @@ var button_default = /* @__PURE__ */ defineComponent({
|
|
|
671
817
|
const color = useVuetifyColor(() => props.color);
|
|
672
818
|
const type = useButtonType(() => props.type);
|
|
673
819
|
const form = useButtonForm(() => props.form);
|
|
820
|
+
const widthClass = useFullWidth(() => props.fullWidth);
|
|
674
821
|
function onClick(event) {
|
|
675
822
|
emit("click", event);
|
|
676
823
|
}
|
|
@@ -683,8 +830,14 @@ var button_default = /* @__PURE__ */ defineComponent({
|
|
|
683
830
|
color: unref(color),
|
|
684
831
|
type: unref(type),
|
|
685
832
|
form: unref(form),
|
|
833
|
+
class: normalizeClass(unref(widthClass)),
|
|
686
834
|
onClick
|
|
687
835
|
}, {
|
|
836
|
+
loader: withCtx(() => [createVNode(unref(VProgressCircular), {
|
|
837
|
+
indeterminate: "",
|
|
838
|
+
width: "2",
|
|
839
|
+
"aria-hidden": "true"
|
|
840
|
+
})]),
|
|
688
841
|
default: withCtx(() => [renderSlot(_ctx.$slots, "default")]),
|
|
689
842
|
_: 3
|
|
690
843
|
}, 8, [
|
|
@@ -694,70 +847,1027 @@ var button_default = /* @__PURE__ */ defineComponent({
|
|
|
694
847
|
"variant",
|
|
695
848
|
"color",
|
|
696
849
|
"type",
|
|
697
|
-
"form"
|
|
850
|
+
"form",
|
|
851
|
+
"class"
|
|
698
852
|
]);
|
|
699
853
|
};
|
|
700
854
|
}
|
|
701
855
|
});
|
|
702
856
|
//#endregion
|
|
703
|
-
//#region src/components/
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
857
|
+
//#region src/components/dialogs/dialog/dialog-host-key.ts
|
|
858
|
+
/**
|
|
859
|
+
* Injection key of {@link DialogHostContext}, provided by the internal `DialogHost`. Besides the
|
|
860
|
+
* role, the blocking while an action runs and the end of the leave transitions, it makes the
|
|
861
|
+
* dialog's content describe the dialog (`aria-describedby`), since `DialogHost` only displays text
|
|
862
|
+
* messages. Not part of the public API.
|
|
863
|
+
*/
|
|
864
|
+
const dialogHostKey = Symbol("dialog-host");
|
|
865
|
+
//#endregion
|
|
866
|
+
//#region src/composables/dialogs/use-dialog-focus.ts
|
|
867
|
+
/** Focus state of the closed dialogs, by their card, for the dialogs opened from them. */
|
|
868
|
+
const closedDialogs = /* @__PURE__ */ new WeakMap();
|
|
869
|
+
/** Elements that can get the focus when the dialog opens. The first one in the dialog gets it. */
|
|
870
|
+
const focusable = [
|
|
871
|
+
"button:not([disabled])",
|
|
872
|
+
"[href]",
|
|
873
|
+
"input:not([disabled]):not([type=\"hidden\"])",
|
|
874
|
+
"select:not([disabled])",
|
|
875
|
+
"textarea:not([disabled])",
|
|
876
|
+
"[tabindex]:not([tabindex=\"-1\"])"
|
|
877
|
+
].join(", ");
|
|
878
|
+
/**
|
|
879
|
+
* Moves the focus into a dialog once it opens and back to where it was when it closes, including
|
|
880
|
+
* when dialogs are opened from others. Internal to the dialog components.
|
|
881
|
+
* @param isActive - Whether the dialog is displayed. It turns `false` as soon as the dialog starts
|
|
882
|
+
* leaving, so the focus returns right away.
|
|
883
|
+
* @param card - The dialog's card, marked with `data-u-dialog`, or nothing while it isn't rendered.
|
|
884
|
+
* @returns `focusFirstElement`, to call once the dialog finishes entering.
|
|
885
|
+
*/
|
|
886
|
+
function useDialogFocus(isActive, card) {
|
|
887
|
+
/** Focus state of this dialog, shared with the dialogs opened from it. */
|
|
888
|
+
const focusState = {
|
|
889
|
+
isOpen: isActive,
|
|
890
|
+
origin: null
|
|
891
|
+
};
|
|
892
|
+
onMounted(() => onActiveChange(isActive()));
|
|
893
|
+
watch(isActive, onActiveChange);
|
|
894
|
+
function onActiveChange(active) {
|
|
895
|
+
if (active) {
|
|
896
|
+
focusState.origin = document.activeElement;
|
|
897
|
+
return;
|
|
898
|
+
}
|
|
899
|
+
const element = card();
|
|
900
|
+
if (element) closedDialogs.set(element, focusState);
|
|
901
|
+
const target = findFocusTarget(focusState.origin);
|
|
902
|
+
if (hasFocus(element) && (target instanceof HTMLElement || target instanceof SVGElement)) target.focus();
|
|
719
903
|
}
|
|
720
|
-
|
|
904
|
+
function focusFirstElement() {
|
|
905
|
+
card()?.querySelector(focusable)?.focus();
|
|
906
|
+
}
|
|
907
|
+
return { focusFirstElement };
|
|
908
|
+
}
|
|
909
|
+
/**
|
|
910
|
+
* Element that gets the focus back when a dialog closes: its origin or, when the origin is inside
|
|
911
|
+
* another dialog that closed meanwhile (and can't get the focus anymore), that dialog's.
|
|
912
|
+
*/
|
|
913
|
+
function findFocusTarget(origin) {
|
|
914
|
+
const card = origin?.closest("[data-u-dialog]");
|
|
915
|
+
const owner = card && closedDialogs.get(card);
|
|
916
|
+
return owner && !owner.isOpen() ? findFocusTarget(owner.origin) : origin;
|
|
917
|
+
}
|
|
918
|
+
/**
|
|
919
|
+
* Whether the focus is on the dialog or lost (on nothing or on the page's body), so it can move.
|
|
920
|
+
* Otherwise it moved elsewhere, e.g. to another dialog opened over this one.
|
|
921
|
+
*/
|
|
922
|
+
function hasFocus(card) {
|
|
923
|
+
const active = document.activeElement;
|
|
924
|
+
if (!active) return true;
|
|
925
|
+
return !!card && (card.contains(active) || active.contains(card));
|
|
926
|
+
}
|
|
721
927
|
//#endregion
|
|
722
|
-
//#region src/components/
|
|
723
|
-
|
|
928
|
+
//#region src/components/dialogs/dialog/dialog.vue?vue&type=script&setup=true&lang.ts
|
|
929
|
+
const _hoisted_1$1 = ["id"];
|
|
930
|
+
//#endregion
|
|
931
|
+
//#region src/components/dialogs/dialog/dialog.vue
|
|
932
|
+
var dialog_default = /* @__PURE__ */ defineComponent({
|
|
724
933
|
inheritAttrs: false,
|
|
725
|
-
__name: "
|
|
726
|
-
props: {
|
|
727
|
-
|
|
934
|
+
__name: "dialog",
|
|
935
|
+
props: /*@__PURE__*/ mergeModels({
|
|
936
|
+
title: {
|
|
728
937
|
type: String,
|
|
729
|
-
required: false
|
|
730
|
-
|
|
938
|
+
required: false
|
|
939
|
+
},
|
|
940
|
+
actions: {
|
|
941
|
+
type: Array,
|
|
942
|
+
required: false
|
|
943
|
+
},
|
|
944
|
+
size: {
|
|
945
|
+
type: String,
|
|
946
|
+
required: false
|
|
731
947
|
},
|
|
732
948
|
dataTestid: {
|
|
733
949
|
type: String,
|
|
734
950
|
required: false
|
|
735
951
|
}
|
|
736
|
-
},
|
|
952
|
+
}, {
|
|
953
|
+
"modelValue": {
|
|
954
|
+
type: Boolean,
|
|
955
|
+
default: false
|
|
956
|
+
},
|
|
957
|
+
"modelModifiers": {}
|
|
958
|
+
}),
|
|
959
|
+
emits: ["update:modelValue"],
|
|
737
960
|
setup(__props) {
|
|
738
961
|
const props = __props;
|
|
962
|
+
const model = useModel(__props, "modelValue");
|
|
963
|
+
const maxWidths = {
|
|
964
|
+
small: 400,
|
|
965
|
+
medium: 560,
|
|
966
|
+
large: 800
|
|
967
|
+
};
|
|
968
|
+
const host = inject(dialogHostKey, null);
|
|
969
|
+
const contentId = useId();
|
|
970
|
+
const card = useTemplateRef("card");
|
|
971
|
+
const title = computed(() => props.title || void 0);
|
|
972
|
+
const maxWidth = computed(() => maxWidths[props.size ?? "medium"]);
|
|
973
|
+
const role = computed(() => host?.role() ?? "dialog");
|
|
974
|
+
/**
|
|
975
|
+
* Whether the dialog is displayed. It follows `v-model`, but turns `false` as soon as the user
|
|
976
|
+
* closes the dialog, while `v-model` only does once the leave transition ends.
|
|
977
|
+
*/
|
|
978
|
+
const isActive = ref(model.value);
|
|
979
|
+
watch(model, (value) => isActive.value = value);
|
|
980
|
+
const { focusFirstElement } = useDialogFocus(() => isActive.value, () => card.value?.$el);
|
|
981
|
+
function onAfterLeave() {
|
|
982
|
+
model.value = false;
|
|
983
|
+
host?.afterLeave();
|
|
984
|
+
}
|
|
739
985
|
return (_ctx, _cache) => {
|
|
740
|
-
return openBlock(), createBlock(unref(
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
986
|
+
return openBlock(), createBlock(unref(VDialog), {
|
|
987
|
+
modelValue: isActive.value,
|
|
988
|
+
"onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => isActive.value = $event),
|
|
989
|
+
persistent: unref(host)?.persistent(),
|
|
990
|
+
"max-width": maxWidth.value,
|
|
991
|
+
role: role.value,
|
|
992
|
+
"aria-label": title.value,
|
|
993
|
+
"aria-labelledby": title.value ? void 0 : unref(contentId),
|
|
994
|
+
"aria-describedby": unref(host) ? unref(contentId) : void 0,
|
|
995
|
+
"data-testid": props.dataTestid,
|
|
996
|
+
scrollable: "",
|
|
997
|
+
onAfterEnter: unref(focusFirstElement),
|
|
998
|
+
onAfterLeave
|
|
744
999
|
}, {
|
|
745
|
-
default: withCtx(() => [
|
|
1000
|
+
default: withCtx(() => [createCommentVNode(" `data-u-dialog` identifies the card to the dialogs opened from this one "), createVNode(unref(VCard), {
|
|
1001
|
+
ref_key: "card",
|
|
1002
|
+
ref: card,
|
|
1003
|
+
title: title.value,
|
|
1004
|
+
"data-u-dialog": ""
|
|
1005
|
+
}, createSlots({
|
|
1006
|
+
text: withCtx(() => [createElementVNode("div", { id: unref(contentId) }, [renderSlot(_ctx.$slots, "default")], 8, _hoisted_1$1)]),
|
|
1007
|
+
_: 2
|
|
1008
|
+
}, [props.actions?.length ? {
|
|
1009
|
+
name: "actions",
|
|
1010
|
+
fn: withCtx(() => [(openBlock(true), createElementBlock(Fragment, null, renderList(props.actions, ({ label, onClick, ...action }, index) => {
|
|
1011
|
+
return openBlock(), createBlock(button_default, mergeProps({ key: index }, { ref_for: true }, action, { onClick }), {
|
|
1012
|
+
default: withCtx(() => [createTextVNode(toDisplayString(label), 1)]),
|
|
1013
|
+
_: 2
|
|
1014
|
+
}, 1040, ["onClick"]);
|
|
1015
|
+
}), 128))]),
|
|
1016
|
+
key: "0"
|
|
1017
|
+
} : void 0]), 1032, ["title"])]),
|
|
746
1018
|
_: 3
|
|
747
|
-
}, 8, [
|
|
1019
|
+
}, 8, [
|
|
1020
|
+
"modelValue",
|
|
1021
|
+
"persistent",
|
|
1022
|
+
"max-width",
|
|
1023
|
+
"role",
|
|
1024
|
+
"aria-label",
|
|
1025
|
+
"aria-labelledby",
|
|
1026
|
+
"aria-describedby",
|
|
1027
|
+
"data-testid",
|
|
1028
|
+
"onAfterEnter"
|
|
1029
|
+
]);
|
|
748
1030
|
};
|
|
749
1031
|
}
|
|
750
1032
|
});
|
|
751
1033
|
//#endregion
|
|
752
|
-
//#region src/components/
|
|
753
|
-
var
|
|
1034
|
+
//#region src/components/dialogs/dialog-host.vue
|
|
1035
|
+
var dialog_host_default = /* @__PURE__ */ defineComponent({
|
|
754
1036
|
inheritAttrs: false,
|
|
755
|
-
__name: "
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
1037
|
+
__name: "dialog-host",
|
|
1038
|
+
setup(__props) {
|
|
1039
|
+
const owner = Symbol("dialog");
|
|
1040
|
+
const isOwner = computed(() => owners$1.value[0] === owner);
|
|
1041
|
+
const next = computed(() => isOwner.value ? requests.value[0] : void 0);
|
|
1042
|
+
/** Dialog on display, kept until its leave transition ends. */
|
|
1043
|
+
const request = shallowRef();
|
|
1044
|
+
/**
|
|
1045
|
+
* Changes for every dialog on display, so each one gets its own `Dialog`, open from the start.
|
|
1046
|
+
* The next dialog can then open right after a dismissed one, whose `v-model` stays `true`.
|
|
1047
|
+
*/
|
|
1048
|
+
const key = shallowRef();
|
|
1049
|
+
const isOpen = ref(false);
|
|
1050
|
+
const selected = shallowRef();
|
|
1051
|
+
const isRunning = computed(() => selected.value !== void 0);
|
|
1052
|
+
const actions = computed(() => {
|
|
1053
|
+
const current = request.value;
|
|
1054
|
+
if (!current) return void 0;
|
|
1055
|
+
return current.actions.map((action) => ({
|
|
1056
|
+
label: action.text,
|
|
1057
|
+
variant: action.variant,
|
|
1058
|
+
color: action.color,
|
|
1059
|
+
loading: selected.value === action,
|
|
1060
|
+
disabled: isRunning.value && selected.value !== action,
|
|
1061
|
+
onClick: () => void select(current, action)
|
|
1062
|
+
}));
|
|
1063
|
+
});
|
|
1064
|
+
provide(dialogHostKey, {
|
|
1065
|
+
role: () => request.value?.role,
|
|
1066
|
+
persistent: () => isRunning.value,
|
|
1067
|
+
afterLeave: showNext
|
|
1068
|
+
});
|
|
1069
|
+
onMounted(() => owners$1.value.push(owner));
|
|
1070
|
+
onUnmounted(() => owners$1.value = owners$1.value.filter((item) => item !== owner));
|
|
1071
|
+
watch(next, show);
|
|
1072
|
+
function show() {
|
|
1073
|
+
if (request.value) return;
|
|
1074
|
+
request.value = next.value;
|
|
1075
|
+
key.value = Symbol();
|
|
1076
|
+
isOpen.value = next.value !== void 0;
|
|
1077
|
+
}
|
|
1078
|
+
function showNext() {
|
|
1079
|
+
request.value = void 0;
|
|
1080
|
+
show();
|
|
1081
|
+
}
|
|
1082
|
+
async function select(current, action) {
|
|
1083
|
+
if (isRunning.value) return;
|
|
1084
|
+
requests.value.shift();
|
|
1085
|
+
selected.value = action;
|
|
1086
|
+
await current.select(action?.value);
|
|
1087
|
+
selected.value = void 0;
|
|
1088
|
+
if (action) isOpen.value = false;
|
|
1089
|
+
}
|
|
1090
|
+
/** Called once a dialog closed by the user leaves, right before the next one is displayed. */
|
|
1091
|
+
function dismiss() {
|
|
1092
|
+
if (request.value) select(request.value);
|
|
1093
|
+
}
|
|
1094
|
+
return (_ctx, _cache) => {
|
|
1095
|
+
return openBlock(), createElementBlock(Fragment, null, [createCommentVNode(" PascalCase, since `<dialog>` in the template would render the native HTML element instead "), (openBlock(), createBlock(dialog_default, {
|
|
1096
|
+
key: key.value,
|
|
1097
|
+
"model-value": isOpen.value,
|
|
1098
|
+
title: request.value?.title,
|
|
1099
|
+
actions: actions.value,
|
|
1100
|
+
"onUpdate:modelValue": dismiss
|
|
1101
|
+
}, {
|
|
1102
|
+
default: withCtx(() => [createTextVNode(toDisplayString(request.value?.message), 1)]),
|
|
1103
|
+
_: 1
|
|
1104
|
+
}, 8, [
|
|
1105
|
+
"model-value",
|
|
1106
|
+
"title",
|
|
1107
|
+
"actions"
|
|
1108
|
+
]))], 2112);
|
|
1109
|
+
};
|
|
1110
|
+
}
|
|
1111
|
+
});
|
|
1112
|
+
//#endregion
|
|
1113
|
+
//#region src/components/main/main.vue
|
|
1114
|
+
var main_default = /* @__PURE__ */ defineComponent({
|
|
1115
|
+
inheritAttrs: false,
|
|
1116
|
+
__name: "main",
|
|
1117
|
+
props: /*@__PURE__*/ mergeModels({
|
|
1118
|
+
dataTestid: {
|
|
1119
|
+
type: String,
|
|
1120
|
+
required: false
|
|
1121
|
+
},
|
|
1122
|
+
logo: {
|
|
1123
|
+
type: String,
|
|
1124
|
+
required: false
|
|
1125
|
+
},
|
|
1126
|
+
appBar: {
|
|
1127
|
+
type: Object,
|
|
1128
|
+
required: false
|
|
1129
|
+
},
|
|
1130
|
+
navigationMenu: {
|
|
1131
|
+
type: Object,
|
|
1132
|
+
required: false
|
|
1133
|
+
},
|
|
1134
|
+
loading: {
|
|
1135
|
+
type: Boolean,
|
|
1136
|
+
required: false
|
|
1137
|
+
}
|
|
1138
|
+
}, {
|
|
1139
|
+
"notificationsOpen": {
|
|
1140
|
+
type: Boolean,
|
|
1141
|
+
default: false
|
|
1142
|
+
},
|
|
1143
|
+
"notificationsOpenModifiers": {}
|
|
1144
|
+
}),
|
|
1145
|
+
emits: ["update:notificationsOpen"],
|
|
1146
|
+
setup(__props) {
|
|
1147
|
+
const props = __props;
|
|
1148
|
+
const appBarProps = computed(() => props.appBar ? {
|
|
1149
|
+
...props.appBar,
|
|
1150
|
+
logo: props.logo,
|
|
1151
|
+
navigation: props.navigationMenu !== void 0,
|
|
1152
|
+
loading: props.loading
|
|
1153
|
+
} : void 0);
|
|
1154
|
+
const notificationsOpen = useModel(__props, "notificationsOpen");
|
|
1155
|
+
const navigationMenuOpen = ref(false);
|
|
1156
|
+
return (_ctx, _cache) => {
|
|
1157
|
+
return openBlock(), createBlock(unref(VApp), { "data-testid": props.dataTestid }, {
|
|
1158
|
+
default: withCtx(() => [
|
|
1159
|
+
appBarProps.value ? (openBlock(), createBlock(app_bar_default, mergeProps({ key: 0 }, appBarProps.value, {
|
|
1160
|
+
"notifications-open": notificationsOpen.value,
|
|
1161
|
+
"onUpdate:notificationsOpen": _cache[0] || (_cache[0] = ($event) => notificationsOpen.value = $event),
|
|
1162
|
+
"navigation-open": navigationMenuOpen.value,
|
|
1163
|
+
"onUpdate:navigationOpen": _cache[1] || (_cache[1] = ($event) => navigationMenuOpen.value = $event)
|
|
1164
|
+
}), null, 16, ["notifications-open", "navigation-open"])) : createCommentVNode("v-if", true),
|
|
1165
|
+
props.navigationMenu ? (openBlock(), createBlock(navigation_menu_default, mergeProps({ key: 1 }, props.navigationMenu, {
|
|
1166
|
+
modelValue: navigationMenuOpen.value,
|
|
1167
|
+
"onUpdate:modelValue": _cache[2] || (_cache[2] = ($event) => navigationMenuOpen.value = $event),
|
|
1168
|
+
loading: props.loading
|
|
1169
|
+
}), null, 16, ["modelValue", "loading"])) : createCommentVNode("v-if", true),
|
|
1170
|
+
createVNode(unref(VMain), null, {
|
|
1171
|
+
default: withCtx(() => [createCommentVNode(" Full height, so the page's rows and containers with `fullHeight` have a height to fill "), createVNode(container_default, { "full-height": "" }, {
|
|
1172
|
+
default: withCtx(() => [
|
|
1173
|
+
renderSlot(_ctx.$slots, "default"),
|
|
1174
|
+
createVNode(toast_default),
|
|
1175
|
+
createVNode(dialog_host_default)
|
|
1176
|
+
]),
|
|
1177
|
+
_: 3
|
|
1178
|
+
})]),
|
|
1179
|
+
_: 3
|
|
1180
|
+
})
|
|
1181
|
+
]),
|
|
1182
|
+
_: 3
|
|
1183
|
+
}, 8, ["data-testid"]);
|
|
1184
|
+
};
|
|
1185
|
+
}
|
|
1186
|
+
});
|
|
1187
|
+
//#endregion
|
|
1188
|
+
//#region src/composables/inputs/autocomplete-field.ts
|
|
1189
|
+
function createAutocompleteRequiredRule(options) {
|
|
1190
|
+
return createRequiredRule(options.required, (value) => {
|
|
1191
|
+
if (options.multiple) return (Array.isArray(value) ? value : []).length > 0;
|
|
1192
|
+
return !isEmpty(String(value ?? ""));
|
|
1193
|
+
});
|
|
1194
|
+
}
|
|
1195
|
+
function useAutocompleteRules(options) {
|
|
1196
|
+
return computed(() => {
|
|
1197
|
+
const opts = toValue(options);
|
|
1198
|
+
const rules = [];
|
|
1199
|
+
if (opts.required) rules.push(createAutocompleteRequiredRule(opts));
|
|
1200
|
+
return rules;
|
|
1201
|
+
});
|
|
1202
|
+
}
|
|
1203
|
+
/**
|
|
1204
|
+
* Menu props that keep the combobox semantics only on the field's `<input>`.
|
|
1205
|
+
*
|
|
1206
|
+
* The field's container gets `role="combobox"` from the field, which passes its
|
|
1207
|
+
* role to both the container and the input, and the menu's ARIA attributes,
|
|
1208
|
+
* since it's the menu's activator. Without these props, the container is
|
|
1209
|
+
* exposed as an unnamed combobox wrapping the input. The menu removes from its
|
|
1210
|
+
* activator the attributes set to `undefined`, role included, and the field
|
|
1211
|
+
* never sets that role again, since its value doesn't change. The input keeps
|
|
1212
|
+
* its role, label, `aria-expanded` and `aria-controls`. This only happens in
|
|
1213
|
+
* the browser: server-rendered HTML still has the role on the container.
|
|
1214
|
+
*/
|
|
1215
|
+
const autocompleteFieldMenuProps = { activatorProps: {
|
|
1216
|
+
role: void 0,
|
|
1217
|
+
"aria-haspopup": void 0,
|
|
1218
|
+
"aria-expanded": void 0,
|
|
1219
|
+
"aria-controls": void 0,
|
|
1220
|
+
"aria-owns": void 0
|
|
1221
|
+
} };
|
|
1222
|
+
//#endregion
|
|
1223
|
+
//#region src/components/inputs/autocomplete-field/autocomplete-field.vue
|
|
1224
|
+
var autocomplete_field_default = /* @__PURE__ */ defineComponent({
|
|
1225
|
+
inheritAttrs: false,
|
|
1226
|
+
__name: "autocomplete-field",
|
|
1227
|
+
props: /*@__PURE__*/ mergeModels({
|
|
1228
|
+
variant: {
|
|
1229
|
+
type: String,
|
|
1230
|
+
required: false,
|
|
1231
|
+
default: "primary"
|
|
1232
|
+
},
|
|
1233
|
+
disabled: {
|
|
1234
|
+
type: Boolean,
|
|
1235
|
+
required: false
|
|
1236
|
+
},
|
|
1237
|
+
loading: {
|
|
1238
|
+
type: Boolean,
|
|
1239
|
+
required: false
|
|
1240
|
+
},
|
|
1241
|
+
clearable: {
|
|
1242
|
+
type: Boolean,
|
|
1243
|
+
required: false
|
|
1244
|
+
},
|
|
1245
|
+
readonly: {
|
|
1246
|
+
type: Boolean,
|
|
1247
|
+
required: false
|
|
1248
|
+
},
|
|
1249
|
+
required: {
|
|
1250
|
+
type: Boolean,
|
|
1251
|
+
required: false
|
|
1252
|
+
},
|
|
1253
|
+
label: {
|
|
1254
|
+
type: String,
|
|
1255
|
+
required: false
|
|
1256
|
+
},
|
|
1257
|
+
placeholder: {
|
|
1258
|
+
type: String,
|
|
1259
|
+
required: false
|
|
1260
|
+
},
|
|
1261
|
+
hint: {
|
|
1262
|
+
type: String,
|
|
1263
|
+
required: false
|
|
1264
|
+
},
|
|
1265
|
+
dataTestid: {
|
|
1266
|
+
type: String,
|
|
1267
|
+
required: false
|
|
1268
|
+
},
|
|
1269
|
+
strict: {
|
|
1270
|
+
type: Boolean,
|
|
1271
|
+
required: false
|
|
1272
|
+
},
|
|
1273
|
+
multiple: {
|
|
1274
|
+
type: null,
|
|
1275
|
+
required: false
|
|
1276
|
+
},
|
|
1277
|
+
items: {
|
|
1278
|
+
type: Array,
|
|
1279
|
+
required: false,
|
|
1280
|
+
default: () => []
|
|
1281
|
+
}
|
|
1282
|
+
}, {
|
|
1283
|
+
"modelValue": { type: null },
|
|
1284
|
+
"modelModifiers": {}
|
|
1285
|
+
}),
|
|
1286
|
+
emits: ["update:modelValue"],
|
|
1287
|
+
setup(__props) {
|
|
1288
|
+
const modelValue = useModel(__props, "modelValue");
|
|
1289
|
+
const props = __props;
|
|
1290
|
+
const vuetifyVariant = useTextFieldVariant(() => props.variant);
|
|
1291
|
+
const isMultiple = computed(() => props.multiple ?? false);
|
|
1292
|
+
const rules = useAutocompleteRules(() => ({
|
|
1293
|
+
required: props.required,
|
|
1294
|
+
multiple: isMultiple.value
|
|
1295
|
+
}));
|
|
1296
|
+
const vuetifyComponent = computed(() => props.strict ? VAutocomplete : VCombobox);
|
|
1297
|
+
const normalizedItems = computed(() => {
|
|
1298
|
+
return props.items.map((item) => {
|
|
1299
|
+
if (typeof item === "string") return {
|
|
1300
|
+
label: item,
|
|
1301
|
+
value: item
|
|
1302
|
+
};
|
|
1303
|
+
return item;
|
|
1304
|
+
});
|
|
1305
|
+
});
|
|
1306
|
+
return (_ctx, _cache) => {
|
|
1307
|
+
return openBlock(), createBlock(resolveDynamicComponent(vuetifyComponent.value), {
|
|
1308
|
+
modelValue: modelValue.value,
|
|
1309
|
+
"onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => modelValue.value = $event),
|
|
1310
|
+
variant: unref(vuetifyVariant),
|
|
1311
|
+
items: normalizedItems.value,
|
|
1312
|
+
"data-testid": props.dataTestid,
|
|
1313
|
+
disabled: props.disabled,
|
|
1314
|
+
loading: props.loading,
|
|
1315
|
+
"aria-busy": props.loading || void 0,
|
|
1316
|
+
readonly: props.readonly,
|
|
1317
|
+
label: props.label,
|
|
1318
|
+
placeholder: props.placeholder,
|
|
1319
|
+
hint: props.hint,
|
|
1320
|
+
clearable: props.clearable,
|
|
1321
|
+
multiple: isMultiple.value,
|
|
1322
|
+
"item-title": "label",
|
|
1323
|
+
rules: unref(rules),
|
|
1324
|
+
"menu-props": unref(autocompleteFieldMenuProps),
|
|
1325
|
+
chips: ""
|
|
1326
|
+
}, {
|
|
1327
|
+
loader: withCtx((loader) => [createVNode(field_loader_default, normalizeProps(guardReactiveProps(loader)), null, 16)]),
|
|
1328
|
+
_: 1
|
|
1329
|
+
}, 8, [
|
|
1330
|
+
"modelValue",
|
|
1331
|
+
"variant",
|
|
1332
|
+
"items",
|
|
1333
|
+
"data-testid",
|
|
1334
|
+
"disabled",
|
|
1335
|
+
"loading",
|
|
1336
|
+
"aria-busy",
|
|
1337
|
+
"readonly",
|
|
1338
|
+
"label",
|
|
1339
|
+
"placeholder",
|
|
1340
|
+
"hint",
|
|
1341
|
+
"clearable",
|
|
1342
|
+
"multiple",
|
|
1343
|
+
"rules",
|
|
1344
|
+
"menu-props"
|
|
1345
|
+
]);
|
|
1346
|
+
};
|
|
1347
|
+
}
|
|
1348
|
+
});
|
|
1349
|
+
//#endregion
|
|
1350
|
+
//#region src/components/inputs/checkbox/checkbox.vue
|
|
1351
|
+
var checkbox_default = /* @__PURE__ */ defineComponent({
|
|
1352
|
+
inheritAttrs: false,
|
|
1353
|
+
__name: "checkbox",
|
|
1354
|
+
props: /*@__PURE__*/ mergeModels({
|
|
1355
|
+
label: {
|
|
1356
|
+
type: String,
|
|
1357
|
+
required: false
|
|
1358
|
+
},
|
|
1359
|
+
disabled: {
|
|
1360
|
+
type: Boolean,
|
|
1361
|
+
required: false
|
|
1362
|
+
},
|
|
1363
|
+
readonly: {
|
|
1364
|
+
type: Boolean,
|
|
1365
|
+
required: false
|
|
1366
|
+
},
|
|
1367
|
+
trueValue: {
|
|
1368
|
+
type: Boolean,
|
|
1369
|
+
required: false,
|
|
1370
|
+
skipCheck: true,
|
|
1371
|
+
default: true
|
|
1372
|
+
},
|
|
1373
|
+
falseValue: {
|
|
1374
|
+
type: Boolean,
|
|
1375
|
+
required: false,
|
|
1376
|
+
skipCheck: true,
|
|
1377
|
+
default: false
|
|
1378
|
+
},
|
|
1379
|
+
dataTestid: {
|
|
1380
|
+
type: String,
|
|
1381
|
+
required: false
|
|
1382
|
+
}
|
|
1383
|
+
}, {
|
|
1384
|
+
"modelValue": {
|
|
1385
|
+
type: null,
|
|
1386
|
+
default: (props) => props.falseValue
|
|
1387
|
+
},
|
|
1388
|
+
"modelModifiers": {}
|
|
1389
|
+
}),
|
|
1390
|
+
emits: ["update:modelValue"],
|
|
1391
|
+
setup(__props) {
|
|
1392
|
+
const props = __props;
|
|
1393
|
+
const modelValue = useModel(__props, "modelValue");
|
|
1394
|
+
return (_ctx, _cache) => {
|
|
1395
|
+
return openBlock(), createBlock(unref(VCheckboxBtn), {
|
|
1396
|
+
modelValue: modelValue.value,
|
|
1397
|
+
"onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => modelValue.value = $event),
|
|
1398
|
+
"true-value": props.trueValue,
|
|
1399
|
+
"false-value": props.falseValue,
|
|
1400
|
+
"data-testid": props.dataTestid,
|
|
1401
|
+
disabled: props.disabled,
|
|
1402
|
+
readonly: props.readonly,
|
|
1403
|
+
label: props.label,
|
|
1404
|
+
class: "flex-0-1",
|
|
1405
|
+
"hide-details": ""
|
|
1406
|
+
}, null, 8, [
|
|
1407
|
+
"modelValue",
|
|
1408
|
+
"true-value",
|
|
1409
|
+
"false-value",
|
|
1410
|
+
"data-testid",
|
|
1411
|
+
"disabled",
|
|
1412
|
+
"readonly",
|
|
1413
|
+
"label"
|
|
1414
|
+
]);
|
|
1415
|
+
};
|
|
1416
|
+
}
|
|
1417
|
+
});
|
|
1418
|
+
//#endregion
|
|
1419
|
+
//#region src/composables/inputs/date-time-field.ts
|
|
1420
|
+
/**
|
|
1421
|
+
* The menu's content is a dialog with the pickers. `aria-owns` is removed since the input can't
|
|
1422
|
+
* own the content, and the menu still adds `aria-expanded` and `aria-controls`.
|
|
1423
|
+
*/
|
|
1424
|
+
const activatorProps = {
|
|
1425
|
+
role: "combobox",
|
|
1426
|
+
"aria-haspopup": "dialog",
|
|
1427
|
+
"aria-owns": void 0
|
|
1428
|
+
};
|
|
1429
|
+
/**
|
|
1430
|
+
* Extracts the date part (`YYYY-MM-DD`) of a value, or an empty string when
|
|
1431
|
+
* the type has no date.
|
|
1432
|
+
*/
|
|
1433
|
+
function getDatePart(value, type) {
|
|
1434
|
+
return type === "time" ? "" : value.split("T")[0];
|
|
1435
|
+
}
|
|
1436
|
+
/**
|
|
1437
|
+
* Extracts the time part (`HH:mm`) of a value, or an empty string when the
|
|
1438
|
+
* value has no time.
|
|
1439
|
+
*/
|
|
1440
|
+
function getTimePart(value, type) {
|
|
1441
|
+
if (type === "time") return value;
|
|
1442
|
+
const [, time = ""] = value.split("T");
|
|
1443
|
+
return time;
|
|
1444
|
+
}
|
|
1445
|
+
/**
|
|
1446
|
+
* Builds a value for the given type, or an empty string while any required
|
|
1447
|
+
* part is missing.
|
|
1448
|
+
*/
|
|
1449
|
+
function joinDateTime(type, date, time) {
|
|
1450
|
+
if (type === "date") return date;
|
|
1451
|
+
if (type === "time") return time;
|
|
1452
|
+
return date && time ? `${date}T${time}` : "";
|
|
1453
|
+
}
|
|
1454
|
+
/**
|
|
1455
|
+
* Formats a value to be displayed in pt-BR, like `24/09/2026`, `14:30` or
|
|
1456
|
+
* `24/09/2026 14:30`.
|
|
1457
|
+
*/
|
|
1458
|
+
function formatDateTime$1(value, type) {
|
|
1459
|
+
return [getDatePart(value, type).split("-").reverse().join("/"), getTimePart(value, type)].filter(Boolean).join(" ");
|
|
1460
|
+
}
|
|
1461
|
+
function useDateTimeFieldRules(props) {
|
|
1462
|
+
const defaultRules = useRules(props);
|
|
1463
|
+
return computed(() => {
|
|
1464
|
+
const rules = [...defaultRules.value];
|
|
1465
|
+
if (props.min) rules.push(minRule(props.min, props.type));
|
|
1466
|
+
if (props.max) rules.push(maxRule(props.max, props.type));
|
|
1467
|
+
return rules;
|
|
1468
|
+
});
|
|
1469
|
+
}
|
|
1470
|
+
/**
|
|
1471
|
+
* Computes the limits of each picker. For `datetime`, time limits only apply
|
|
1472
|
+
* when the selected date is the limit's own date.
|
|
1473
|
+
*/
|
|
1474
|
+
function useDateTimeFieldPickerBounds(props, selectedDate) {
|
|
1475
|
+
return computed(() => {
|
|
1476
|
+
const min = props.min ?? "";
|
|
1477
|
+
const max = props.max ?? "";
|
|
1478
|
+
const date = toValue(selectedDate);
|
|
1479
|
+
return {
|
|
1480
|
+
dateMin: getDatePart(min, props.type),
|
|
1481
|
+
dateMax: getDatePart(max, props.type),
|
|
1482
|
+
timeMin: getTimeBound(min, props.type, date),
|
|
1483
|
+
timeMax: getTimeBound(max, props.type, date)
|
|
1484
|
+
};
|
|
1485
|
+
});
|
|
1486
|
+
}
|
|
1487
|
+
/**
|
|
1488
|
+
* Makes the field's input the activator of the pickers' menu, so the menu's attributes are on an
|
|
1489
|
+
* element whose role accepts them.
|
|
1490
|
+
* @param isOpen - Whether the menu is open.
|
|
1491
|
+
* @param isDisabled - Whether the menu can't open, as when the field is disabled or readonly.
|
|
1492
|
+
* @param hasLabel - Whether the field has a label, which names the menu's dialog.
|
|
1493
|
+
*/
|
|
1494
|
+
function useDateTimeFieldMenu(isOpen, isDisabled, hasLabel) {
|
|
1495
|
+
const inputId = useId();
|
|
1496
|
+
const activator = computed(() => toValue(isDisabled) ? void 0 : `#${inputId}`);
|
|
1497
|
+
const contentProps = computed(() => ({
|
|
1498
|
+
role: "dialog",
|
|
1499
|
+
"aria-labelledby": toValue(hasLabel) ? `${inputId}-label` : void 0
|
|
1500
|
+
}));
|
|
1501
|
+
function open() {
|
|
1502
|
+
if (!toValue(isDisabled)) isOpen.value = true;
|
|
1503
|
+
}
|
|
1504
|
+
return {
|
|
1505
|
+
inputId,
|
|
1506
|
+
activator,
|
|
1507
|
+
activatorProps,
|
|
1508
|
+
contentProps,
|
|
1509
|
+
open
|
|
1510
|
+
};
|
|
1511
|
+
}
|
|
1512
|
+
function getTimeBound(bound, type, selectedDate) {
|
|
1513
|
+
if (type === "datetime" && getDatePart(bound, type) !== selectedDate) return "";
|
|
1514
|
+
return getTimePart(bound, type);
|
|
1515
|
+
}
|
|
1516
|
+
function minRule(min, type) {
|
|
1517
|
+
const message = `Valor anterior ao mínimo permitido (${formatDateTime$1(min, type)})`;
|
|
1518
|
+
return (value) => !value || value >= min || message;
|
|
1519
|
+
}
|
|
1520
|
+
function maxRule(max, type) {
|
|
1521
|
+
const message = `Valor posterior ao máximo permitido (${formatDateTime$1(max, type)})`;
|
|
1522
|
+
return (value) => !value || value <= max || message;
|
|
1523
|
+
}
|
|
1524
|
+
//#endregion
|
|
1525
|
+
//#region src/components/inputs/date-time-field/date-time-field.vue
|
|
1526
|
+
var date_time_field_default = /* @__PURE__ */ defineComponent({
|
|
1527
|
+
inheritAttrs: false,
|
|
1528
|
+
__name: "date-time-field",
|
|
1529
|
+
props: /*@__PURE__*/ mergeModels({
|
|
1530
|
+
variant: {
|
|
1531
|
+
type: String,
|
|
1532
|
+
required: false,
|
|
1533
|
+
default: "primary"
|
|
1534
|
+
},
|
|
1535
|
+
type: {
|
|
1536
|
+
type: String,
|
|
1537
|
+
required: false,
|
|
1538
|
+
default: "datetime"
|
|
1539
|
+
},
|
|
1540
|
+
min: {
|
|
1541
|
+
type: String,
|
|
1542
|
+
required: false
|
|
1543
|
+
},
|
|
1544
|
+
max: {
|
|
1545
|
+
type: String,
|
|
1546
|
+
required: false
|
|
1547
|
+
},
|
|
1548
|
+
disabled: {
|
|
1549
|
+
type: Boolean,
|
|
1550
|
+
required: false
|
|
1551
|
+
},
|
|
1552
|
+
loading: {
|
|
1553
|
+
type: Boolean,
|
|
1554
|
+
required: false
|
|
1555
|
+
},
|
|
1556
|
+
clearable: {
|
|
1557
|
+
type: Boolean,
|
|
1558
|
+
required: false
|
|
1559
|
+
},
|
|
1560
|
+
readonly: {
|
|
1561
|
+
type: Boolean,
|
|
1562
|
+
required: false
|
|
1563
|
+
},
|
|
1564
|
+
required: {
|
|
1565
|
+
type: Boolean,
|
|
1566
|
+
required: false
|
|
1567
|
+
},
|
|
1568
|
+
label: {
|
|
1569
|
+
type: String,
|
|
1570
|
+
required: false
|
|
1571
|
+
},
|
|
1572
|
+
placeholder: {
|
|
1573
|
+
type: String,
|
|
1574
|
+
required: false
|
|
1575
|
+
},
|
|
1576
|
+
hint: {
|
|
1577
|
+
type: String,
|
|
1578
|
+
required: false
|
|
1579
|
+
},
|
|
1580
|
+
dataTestid: {
|
|
1581
|
+
type: String,
|
|
1582
|
+
required: false
|
|
1583
|
+
}
|
|
1584
|
+
}, {
|
|
1585
|
+
"modelValue": {
|
|
1586
|
+
type: String,
|
|
1587
|
+
default: ""
|
|
1588
|
+
},
|
|
1589
|
+
"modelModifiers": {}
|
|
1590
|
+
}),
|
|
1591
|
+
emits: ["update:modelValue"],
|
|
1592
|
+
setup(__props) {
|
|
1593
|
+
const modelValue = useModel(__props, "modelValue");
|
|
1594
|
+
const props = __props;
|
|
1595
|
+
const messages = { "pt-BR": pt };
|
|
1596
|
+
const vuetifyVariant = useTextFieldVariant(() => props.variant);
|
|
1597
|
+
const rules = useDateTimeFieldRules(props);
|
|
1598
|
+
const displayValue = computed(() => formatDateTime$1(modelValue.value, props.type));
|
|
1599
|
+
const isClearable = computed(() => props.clearable && !props.readonly);
|
|
1600
|
+
const isMenuDisabled = computed(() => props.disabled || props.readonly);
|
|
1601
|
+
const isMenuOpen = ref(false);
|
|
1602
|
+
const draft = ref({});
|
|
1603
|
+
const draftDate = computed(() => draft.value.date ?? getDatePart(modelValue.value, props.type));
|
|
1604
|
+
const draftTime = computed(() => draft.value.time ?? getTimePart(modelValue.value, props.type));
|
|
1605
|
+
const draftValue = computed(() => joinDateTime(props.type, draftDate.value, draftTime.value));
|
|
1606
|
+
const bounds = useDateTimeFieldPickerBounds(props, draftDate);
|
|
1607
|
+
const { inputId, activator, activatorProps, contentProps, open: openMenu } = useDateTimeFieldMenu(isMenuOpen, isMenuDisabled, () => !!props.label);
|
|
1608
|
+
watch(isMenuOpen, () => {
|
|
1609
|
+
draft.value = {};
|
|
1610
|
+
});
|
|
1611
|
+
function onDateUpdate(date) {
|
|
1612
|
+
draft.value.date = formatDateTime(date, "YYYY-MM-DD");
|
|
1613
|
+
commitDraft();
|
|
1614
|
+
closeIfComplete();
|
|
1615
|
+
}
|
|
1616
|
+
function onTimeUpdate(time) {
|
|
1617
|
+
draft.value.time = time ?? "";
|
|
1618
|
+
commitDraft();
|
|
1619
|
+
}
|
|
1620
|
+
function commitDraft() {
|
|
1621
|
+
if (draftValue.value) modelValue.value = draftValue.value;
|
|
1622
|
+
}
|
|
1623
|
+
function closeIfComplete() {
|
|
1624
|
+
if (draftValue.value) isMenuOpen.value = false;
|
|
1625
|
+
}
|
|
1626
|
+
function clear() {
|
|
1627
|
+
modelValue.value = "";
|
|
1628
|
+
}
|
|
1629
|
+
return (_ctx, _cache) => {
|
|
1630
|
+
return openBlock(), createBlock(unref(VTextField), {
|
|
1631
|
+
id: unref(inputId),
|
|
1632
|
+
"model-value": displayValue.value,
|
|
1633
|
+
"validation-value": modelValue.value,
|
|
1634
|
+
variant: unref(vuetifyVariant),
|
|
1635
|
+
rules: unref(rules),
|
|
1636
|
+
"data-testid": props.dataTestid,
|
|
1637
|
+
disabled: props.disabled,
|
|
1638
|
+
loading: props.loading,
|
|
1639
|
+
"aria-busy": props.loading || void 0,
|
|
1640
|
+
label: props.label,
|
|
1641
|
+
placeholder: props.placeholder,
|
|
1642
|
+
hint: props.hint,
|
|
1643
|
+
clearable: isClearable.value,
|
|
1644
|
+
readonly: "",
|
|
1645
|
+
"onClick:clear": clear,
|
|
1646
|
+
"onClick:control": unref(openMenu)
|
|
1647
|
+
}, {
|
|
1648
|
+
loader: withCtx((loader) => [createVNode(field_loader_default, normalizeProps(guardReactiveProps(loader)), null, 16)]),
|
|
1649
|
+
default: withCtx(() => [createVNode(unref(VMenu), {
|
|
1650
|
+
modelValue: isMenuOpen.value,
|
|
1651
|
+
"onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => isMenuOpen.value = $event),
|
|
1652
|
+
activator: unref(activator),
|
|
1653
|
+
target: "parent",
|
|
1654
|
+
"activator-props": unref(activatorProps),
|
|
1655
|
+
"content-props": unref(contentProps),
|
|
1656
|
+
location: "bottom start",
|
|
1657
|
+
"min-width": "0",
|
|
1658
|
+
disabled: isMenuDisabled.value,
|
|
1659
|
+
"close-on-content-click": false
|
|
1660
|
+
}, {
|
|
1661
|
+
default: withCtx(() => [createVNode(unref(VCard), null, {
|
|
1662
|
+
default: withCtx(() => [createVNode(unref(VLocaleProvider), {
|
|
1663
|
+
locale: "pt-BR",
|
|
1664
|
+
messages,
|
|
1665
|
+
class: "d-flex flex-wrap"
|
|
1666
|
+
}, {
|
|
1667
|
+
default: withCtx(() => [props.type !== "time" ? (openBlock(), createBlock(unref(VDatePicker), {
|
|
1668
|
+
key: 0,
|
|
1669
|
+
"model-value": draftDate.value || null,
|
|
1670
|
+
min: unref(bounds).dateMin,
|
|
1671
|
+
max: unref(bounds).dateMax,
|
|
1672
|
+
"onUpdate:modelValue": onDateUpdate
|
|
1673
|
+
}, null, 8, [
|
|
1674
|
+
"model-value",
|
|
1675
|
+
"min",
|
|
1676
|
+
"max"
|
|
1677
|
+
])) : createCommentVNode("v-if", true), props.type !== "date" ? (openBlock(), createBlock(unref(VTimePicker), {
|
|
1678
|
+
key: 1,
|
|
1679
|
+
"model-value": draftTime.value,
|
|
1680
|
+
min: unref(bounds).timeMin,
|
|
1681
|
+
max: unref(bounds).timeMax,
|
|
1682
|
+
format: "24hr",
|
|
1683
|
+
"onUpdate:modelValue": onTimeUpdate,
|
|
1684
|
+
"onUpdate:minute": closeIfComplete
|
|
1685
|
+
}, null, 8, [
|
|
1686
|
+
"model-value",
|
|
1687
|
+
"min",
|
|
1688
|
+
"max"
|
|
1689
|
+
])) : createCommentVNode("v-if", true)]),
|
|
1690
|
+
_: 1
|
|
1691
|
+
})]),
|
|
1692
|
+
_: 1
|
|
1693
|
+
})]),
|
|
1694
|
+
_: 1
|
|
1695
|
+
}, 8, [
|
|
1696
|
+
"modelValue",
|
|
1697
|
+
"activator",
|
|
1698
|
+
"activator-props",
|
|
1699
|
+
"content-props",
|
|
1700
|
+
"disabled"
|
|
1701
|
+
])]),
|
|
1702
|
+
_: 1
|
|
1703
|
+
}, 8, [
|
|
1704
|
+
"id",
|
|
1705
|
+
"model-value",
|
|
1706
|
+
"validation-value",
|
|
1707
|
+
"variant",
|
|
1708
|
+
"rules",
|
|
1709
|
+
"data-testid",
|
|
1710
|
+
"disabled",
|
|
1711
|
+
"loading",
|
|
1712
|
+
"aria-busy",
|
|
1713
|
+
"label",
|
|
1714
|
+
"placeholder",
|
|
1715
|
+
"hint",
|
|
1716
|
+
"clearable",
|
|
1717
|
+
"onClick:control"
|
|
1718
|
+
]);
|
|
1719
|
+
};
|
|
1720
|
+
}
|
|
1721
|
+
});
|
|
1722
|
+
//#endregion
|
|
1723
|
+
//#region src/composables/alignment/alignment.ts
|
|
1724
|
+
const alignXToClass = {
|
|
1725
|
+
start: "justify-start",
|
|
1726
|
+
center: "justify-center",
|
|
1727
|
+
end: "justify-end"
|
|
1728
|
+
};
|
|
1729
|
+
const alignYToClasses = {
|
|
1730
|
+
start: {
|
|
1731
|
+
items: "align-start",
|
|
1732
|
+
content: "align-content-start"
|
|
1733
|
+
},
|
|
1734
|
+
center: {
|
|
1735
|
+
items: "align-center",
|
|
1736
|
+
content: "align-content-center"
|
|
1737
|
+
},
|
|
1738
|
+
end: {
|
|
1739
|
+
items: "align-end",
|
|
1740
|
+
content: "align-content-end"
|
|
1741
|
+
},
|
|
1742
|
+
stretch: {
|
|
1743
|
+
items: "align-stretch",
|
|
1744
|
+
content: "align-content-stretch"
|
|
1745
|
+
}
|
|
1746
|
+
};
|
|
1747
|
+
/**
|
|
1748
|
+
* Vuetify's `justify-*` utility class for components with an `alignX` prop, laid out with flexbox.
|
|
1749
|
+
* Falls back to `"start"`.
|
|
1750
|
+
*/
|
|
1751
|
+
function useAlignX(alignX) {
|
|
1752
|
+
return computed(() => alignXToClass[toValue(alignX) ?? "start"]);
|
|
1753
|
+
}
|
|
1754
|
+
/**
|
|
1755
|
+
* Vuetify's `align-*` and `align-content-*` utility classes for components with an `alignY` prop,
|
|
1756
|
+
* laid out with flexbox. Falls back to `"start"`.
|
|
1757
|
+
*/
|
|
1758
|
+
function useAlignY(alignY) {
|
|
1759
|
+
return computed(() => alignYToClasses[toValue(alignY) ?? "start"]);
|
|
1760
|
+
}
|
|
1761
|
+
//#endregion
|
|
1762
|
+
//#region src/components/grid/row/row.vue
|
|
1763
|
+
var row_default = /* @__PURE__ */ defineComponent({
|
|
1764
|
+
inheritAttrs: false,
|
|
1765
|
+
__name: "row",
|
|
1766
|
+
props: {
|
|
1767
|
+
alignX: {
|
|
1768
|
+
type: String,
|
|
1769
|
+
required: false
|
|
1770
|
+
},
|
|
1771
|
+
alignY: {
|
|
1772
|
+
type: String,
|
|
1773
|
+
required: false
|
|
1774
|
+
},
|
|
1775
|
+
fullHeight: {
|
|
1776
|
+
type: Boolean,
|
|
1777
|
+
required: false
|
|
1778
|
+
},
|
|
1779
|
+
list: {
|
|
1780
|
+
type: Boolean,
|
|
1781
|
+
required: false
|
|
1782
|
+
},
|
|
1783
|
+
dataTestid: {
|
|
1784
|
+
type: String,
|
|
1785
|
+
required: false
|
|
1786
|
+
}
|
|
1787
|
+
},
|
|
1788
|
+
setup(__props) {
|
|
1789
|
+
const props = __props;
|
|
1790
|
+
const alignXClass = useAlignX(() => props.alignX);
|
|
1791
|
+
const alignYClasses = useAlignY(() => props.alignY);
|
|
1792
|
+
const heightClass = useFullHeight(() => props.fullHeight);
|
|
1793
|
+
const alignContentClass = computed(() => props.fullHeight ? alignYClasses.value.content : void 0);
|
|
1794
|
+
const tag = computed(() => props.list ? "ul" : void 0);
|
|
1795
|
+
const listClasses = computed(() => props.list ? "pa-0 ma-0" : void 0);
|
|
1796
|
+
return (_ctx, _cache) => {
|
|
1797
|
+
return openBlock(), createBlock(unref(VRow), {
|
|
1798
|
+
tag: tag.value,
|
|
1799
|
+
class: normalizeClass([
|
|
1800
|
+
unref(alignXClass),
|
|
1801
|
+
unref(alignYClasses).items,
|
|
1802
|
+
unref(heightClass),
|
|
1803
|
+
alignContentClass.value,
|
|
1804
|
+
listClasses.value
|
|
1805
|
+
]),
|
|
1806
|
+
"data-testid": props.dataTestid
|
|
1807
|
+
}, {
|
|
1808
|
+
default: withCtx(() => [renderSlot(_ctx.$slots, "default")]),
|
|
1809
|
+
_: 3
|
|
1810
|
+
}, 8, [
|
|
1811
|
+
"tag",
|
|
1812
|
+
"class",
|
|
1813
|
+
"data-testid"
|
|
1814
|
+
]);
|
|
1815
|
+
};
|
|
1816
|
+
}
|
|
1817
|
+
});
|
|
1818
|
+
//#endregion
|
|
1819
|
+
//#region src/components/grid/column/column.vue
|
|
1820
|
+
var column_default = /* @__PURE__ */ defineComponent({
|
|
1821
|
+
inheritAttrs: false,
|
|
1822
|
+
__name: "column",
|
|
1823
|
+
props: {
|
|
1824
|
+
cols: {
|
|
1825
|
+
type: String,
|
|
1826
|
+
required: false,
|
|
1827
|
+
default: "12"
|
|
1828
|
+
},
|
|
1829
|
+
listItem: {
|
|
1830
|
+
type: Boolean,
|
|
1831
|
+
required: false
|
|
1832
|
+
},
|
|
1833
|
+
dataTestid: {
|
|
1834
|
+
type: String,
|
|
1835
|
+
required: false
|
|
1836
|
+
}
|
|
1837
|
+
},
|
|
1838
|
+
setup(__props) {
|
|
1839
|
+
const props = __props;
|
|
1840
|
+
const tag = computed(() => props.listItem ? "li" : void 0);
|
|
1841
|
+
const listItemClasses = computed(() => props.listItem ? "d-block" : void 0);
|
|
1842
|
+
return (_ctx, _cache) => {
|
|
1843
|
+
return openBlock(), createBlock(unref(VCol), {
|
|
1844
|
+
cols: "12",
|
|
1845
|
+
sm: props.cols,
|
|
1846
|
+
tag: tag.value,
|
|
1847
|
+
class: normalizeClass(listItemClasses.value),
|
|
1848
|
+
"data-testid": props.dataTestid
|
|
1849
|
+
}, {
|
|
1850
|
+
default: withCtx(() => [renderSlot(_ctx.$slots, "default")]),
|
|
1851
|
+
_: 3
|
|
1852
|
+
}, 8, [
|
|
1853
|
+
"sm",
|
|
1854
|
+
"tag",
|
|
1855
|
+
"class",
|
|
1856
|
+
"data-testid"
|
|
1857
|
+
]);
|
|
1858
|
+
};
|
|
1859
|
+
}
|
|
1860
|
+
});
|
|
1861
|
+
//#endregion
|
|
1862
|
+
//#region src/components/form/form.vue
|
|
1863
|
+
var form_default = /* @__PURE__ */ defineComponent({
|
|
1864
|
+
inheritAttrs: false,
|
|
1865
|
+
__name: "form",
|
|
1866
|
+
props: {
|
|
1867
|
+
id: {
|
|
1868
|
+
type: String,
|
|
1869
|
+
required: false
|
|
1870
|
+
},
|
|
761
1871
|
dataTestid: {
|
|
762
1872
|
type: String,
|
|
763
1873
|
required: false
|
|
@@ -809,6 +1919,26 @@ function useSectionVariant(variant) {
|
|
|
809
1919
|
return variantValue ? sectionVariantToVuetifyVariant[variantValue] : sectionVariantToVuetifyVariant.primary;
|
|
810
1920
|
});
|
|
811
1921
|
}
|
|
1922
|
+
const sectionTextAlignToClasses = {
|
|
1923
|
+
start: {
|
|
1924
|
+
content: "text-start",
|
|
1925
|
+
actions: "justify-end"
|
|
1926
|
+
},
|
|
1927
|
+
center: {
|
|
1928
|
+
content: "text-center",
|
|
1929
|
+
actions: "justify-center"
|
|
1930
|
+
},
|
|
1931
|
+
end: {
|
|
1932
|
+
content: "text-end",
|
|
1933
|
+
actions: "justify-end"
|
|
1934
|
+
}
|
|
1935
|
+
};
|
|
1936
|
+
function useSectionTextAlign(textAlign) {
|
|
1937
|
+
return computed(() => {
|
|
1938
|
+
const textAlignValue = toValue(textAlign);
|
|
1939
|
+
return textAlignValue ? sectionTextAlignToClasses[textAlignValue] : sectionTextAlignToClasses.start;
|
|
1940
|
+
});
|
|
1941
|
+
}
|
|
812
1942
|
//#endregion
|
|
813
1943
|
//#region src/components/sections/section/section.vue
|
|
814
1944
|
var section_default = /* @__PURE__ */ defineComponent({
|
|
@@ -827,6 +1957,10 @@ var section_default = /* @__PURE__ */ defineComponent({
|
|
|
827
1957
|
type: String,
|
|
828
1958
|
required: false
|
|
829
1959
|
},
|
|
1960
|
+
textAlign: {
|
|
1961
|
+
type: String,
|
|
1962
|
+
required: false
|
|
1963
|
+
},
|
|
830
1964
|
actions: {
|
|
831
1965
|
type: Array,
|
|
832
1966
|
required: false
|
|
@@ -851,31 +1985,34 @@ var section_default = /* @__PURE__ */ defineComponent({
|
|
|
851
1985
|
setup(__props) {
|
|
852
1986
|
const props = __props;
|
|
853
1987
|
const variant = useSectionVariant(() => props.variant);
|
|
1988
|
+
const textAlignClasses = useSectionTextAlign(() => props.textAlign);
|
|
854
1989
|
const title = computed(() => props.title || void 0);
|
|
855
1990
|
const subtitle = computed(() => props.subtitle || void 0);
|
|
856
|
-
const
|
|
857
|
-
const
|
|
1991
|
+
const widthClass = useFullWidth(() => props.fullWidth);
|
|
1992
|
+
const heightClass = useFullHeight(() => props.fullHeight);
|
|
858
1993
|
const showActions = computed(() => !!props.actions?.length);
|
|
859
1994
|
const skeletonType = computed(() => showActions.value ? "image, actions" : "image");
|
|
860
1995
|
return (_ctx, _cache) => {
|
|
861
1996
|
return openBlock(), createBlock(unref(VSkeletonLoader), {
|
|
862
1997
|
loading: props.loading,
|
|
863
1998
|
type: skeletonType.value,
|
|
864
|
-
|
|
865
|
-
height: height.value
|
|
1999
|
+
class: normalizeClass([unref(widthClass), unref(heightClass)])
|
|
866
2000
|
}, {
|
|
867
|
-
default: withCtx(() => [createVNode(unref(VCard), {
|
|
2001
|
+
default: withCtx(() => [createCommentVNode(" The card and its actions have no alignment props, so `textAlign` uses utility classes "), createVNode(unref(VCard), {
|
|
868
2002
|
title: title.value,
|
|
869
2003
|
subtitle: subtitle.value,
|
|
870
2004
|
variant: unref(variant),
|
|
871
|
-
width: width.value,
|
|
872
|
-
height: height.value,
|
|
873
2005
|
"data-testid": props.dataTestid,
|
|
874
|
-
class:
|
|
2006
|
+
class: normalizeClass([
|
|
2007
|
+
"d-flex flex-column",
|
|
2008
|
+
unref(widthClass),
|
|
2009
|
+
unref(heightClass),
|
|
2010
|
+
unref(textAlignClasses).content
|
|
2011
|
+
])
|
|
875
2012
|
}, {
|
|
876
2013
|
default: withCtx(() => [renderSlot(_ctx.$slots, "default"), showActions.value ? (openBlock(), createBlock(unref(VCardActions), {
|
|
877
2014
|
key: 0,
|
|
878
|
-
class: "mt-auto"
|
|
2015
|
+
class: normalizeClass(["mt-auto", unref(textAlignClasses).actions])
|
|
879
2016
|
}, {
|
|
880
2017
|
default: withCtx(() => [(openBlock(true), createElementBlock(Fragment, null, renderList(props.actions, ({ label, onClick, ...action }, index) => {
|
|
881
2018
|
return openBlock(), createBlock(button_default, mergeProps({ key: index }, { ref_for: true }, action, { onClick }), {
|
|
@@ -884,22 +2021,20 @@ var section_default = /* @__PURE__ */ defineComponent({
|
|
|
884
2021
|
}, 1040, ["onClick"]);
|
|
885
2022
|
}), 128))]),
|
|
886
2023
|
_: 1
|
|
887
|
-
})) : createCommentVNode("v-if", true)]),
|
|
2024
|
+
}, 8, ["class"])) : createCommentVNode("v-if", true)]),
|
|
888
2025
|
_: 3
|
|
889
2026
|
}, 8, [
|
|
890
2027
|
"title",
|
|
891
2028
|
"subtitle",
|
|
892
2029
|
"variant",
|
|
893
|
-
"
|
|
894
|
-
"
|
|
895
|
-
"data-testid"
|
|
2030
|
+
"data-testid",
|
|
2031
|
+
"class"
|
|
896
2032
|
])]),
|
|
897
2033
|
_: 3
|
|
898
2034
|
}, 8, [
|
|
899
2035
|
"loading",
|
|
900
2036
|
"type",
|
|
901
|
-
"
|
|
902
|
-
"height"
|
|
2037
|
+
"class"
|
|
903
2038
|
]);
|
|
904
2039
|
};
|
|
905
2040
|
}
|
|
@@ -987,4 +2122,419 @@ var table_default = /* @__PURE__ */ defineComponent({
|
|
|
987
2122
|
}
|
|
988
2123
|
});
|
|
989
2124
|
//#endregion
|
|
990
|
-
|
|
2125
|
+
//#region src/components/details/details.vue
|
|
2126
|
+
var details_default = /* @__PURE__ */ defineComponent({
|
|
2127
|
+
inheritAttrs: false,
|
|
2128
|
+
__name: "details",
|
|
2129
|
+
props: {
|
|
2130
|
+
variant: {
|
|
2131
|
+
type: String,
|
|
2132
|
+
required: false
|
|
2133
|
+
},
|
|
2134
|
+
title: {
|
|
2135
|
+
type: String,
|
|
2136
|
+
required: false
|
|
2137
|
+
},
|
|
2138
|
+
loading: {
|
|
2139
|
+
type: Boolean,
|
|
2140
|
+
required: false
|
|
2141
|
+
},
|
|
2142
|
+
dataTestid: {
|
|
2143
|
+
type: String,
|
|
2144
|
+
required: false
|
|
2145
|
+
}
|
|
2146
|
+
},
|
|
2147
|
+
setup(__props) {
|
|
2148
|
+
const props = __props;
|
|
2149
|
+
const outlined = computed(() => props.variant === "secondary");
|
|
2150
|
+
return (_ctx, _cache) => {
|
|
2151
|
+
return openBlock(), createBlock(unref(VSkeletonLoader), {
|
|
2152
|
+
loading: props.loading,
|
|
2153
|
+
type: "heading",
|
|
2154
|
+
width: "100%"
|
|
2155
|
+
}, {
|
|
2156
|
+
default: withCtx(() => [createVNode(unref(VExpansionPanels), {
|
|
2157
|
+
flat: outlined.value,
|
|
2158
|
+
"data-testid": props.dataTestid
|
|
2159
|
+
}, {
|
|
2160
|
+
default: withCtx(() => [createVNode(unref(VExpansionPanel), { class: normalizeClass({ border: outlined.value }) }, {
|
|
2161
|
+
default: withCtx(() => [createVNode(unref(VExpansionPanelTitle), null, {
|
|
2162
|
+
default: withCtx(() => [createTextVNode(toDisplayString(props.title), 1)]),
|
|
2163
|
+
_: 1
|
|
2164
|
+
}), createVNode(unref(VExpansionPanelText), null, {
|
|
2165
|
+
default: withCtx(() => [renderSlot(_ctx.$slots, "default")]),
|
|
2166
|
+
_: 3
|
|
2167
|
+
})]),
|
|
2168
|
+
_: 3
|
|
2169
|
+
}, 8, ["class"])]),
|
|
2170
|
+
_: 3
|
|
2171
|
+
}, 8, ["flat", "data-testid"])]),
|
|
2172
|
+
_: 3
|
|
2173
|
+
}, 8, ["loading"]);
|
|
2174
|
+
};
|
|
2175
|
+
}
|
|
2176
|
+
});
|
|
2177
|
+
//#endregion
|
|
2178
|
+
//#region src/components/img/img.vue
|
|
2179
|
+
var img_default = /* @__PURE__ */ defineComponent({
|
|
2180
|
+
inheritAttrs: false,
|
|
2181
|
+
__name: "img",
|
|
2182
|
+
props: {
|
|
2183
|
+
src: {
|
|
2184
|
+
type: String,
|
|
2185
|
+
required: true
|
|
2186
|
+
},
|
|
2187
|
+
width: {
|
|
2188
|
+
type: [Number, String],
|
|
2189
|
+
required: false
|
|
2190
|
+
},
|
|
2191
|
+
height: {
|
|
2192
|
+
type: [Number, String],
|
|
2193
|
+
required: false
|
|
2194
|
+
},
|
|
2195
|
+
aspectRatio: {
|
|
2196
|
+
type: Number,
|
|
2197
|
+
required: false
|
|
2198
|
+
},
|
|
2199
|
+
cover: {
|
|
2200
|
+
type: Boolean,
|
|
2201
|
+
required: false
|
|
2202
|
+
},
|
|
2203
|
+
eager: {
|
|
2204
|
+
type: Boolean,
|
|
2205
|
+
required: false
|
|
2206
|
+
},
|
|
2207
|
+
dataTestid: {
|
|
2208
|
+
type: String,
|
|
2209
|
+
required: false
|
|
2210
|
+
}
|
|
2211
|
+
},
|
|
2212
|
+
setup(__props) {
|
|
2213
|
+
const props = __props;
|
|
2214
|
+
return (_ctx, _cache) => {
|
|
2215
|
+
return openBlock(), createBlock(unref(VImg), {
|
|
2216
|
+
src: props.src,
|
|
2217
|
+
alt: "",
|
|
2218
|
+
width: props.width,
|
|
2219
|
+
height: props.height,
|
|
2220
|
+
"aspect-ratio": props.aspectRatio,
|
|
2221
|
+
cover: props.cover,
|
|
2222
|
+
eager: props.eager,
|
|
2223
|
+
"data-testid": props.dataTestid
|
|
2224
|
+
}, null, 8, [
|
|
2225
|
+
"src",
|
|
2226
|
+
"width",
|
|
2227
|
+
"height",
|
|
2228
|
+
"aspect-ratio",
|
|
2229
|
+
"cover",
|
|
2230
|
+
"eager",
|
|
2231
|
+
"data-testid"
|
|
2232
|
+
]);
|
|
2233
|
+
};
|
|
2234
|
+
}
|
|
2235
|
+
});
|
|
2236
|
+
//#endregion
|
|
2237
|
+
//#region src/composables/data-set/data-set.ts
|
|
2238
|
+
/**
|
|
2239
|
+
* Width, out of the grid's 12 columns, taken by each record so that
|
|
2240
|
+
* `columns` records fit side by side on a row.
|
|
2241
|
+
*/
|
|
2242
|
+
const dataSetColumnsToColumnCols = {
|
|
2243
|
+
1: "12",
|
|
2244
|
+
2: "6",
|
|
2245
|
+
3: "4",
|
|
2246
|
+
4: "3",
|
|
2247
|
+
6: "2"
|
|
2248
|
+
};
|
|
2249
|
+
/**
|
|
2250
|
+
* Space, in pixels, between two cards of the same row: the default gutter of
|
|
2251
|
+
* `URow`/`UColumn` (Vuetify's `v-row` with its default density puts a 24px
|
|
2252
|
+
* gap between its columns). `n` cards side by side take `n` card widths plus
|
|
2253
|
+
* `n - 1` gaps, so they fit in `width` pixels when
|
|
2254
|
+
* `n * (minDataSetItemWidth + gap) <= width + gap`.
|
|
2255
|
+
*/
|
|
2256
|
+
const dataSetItemGap = 24;
|
|
2257
|
+
/**
|
|
2258
|
+
* Supported numbers of records per row, from the largest to the smallest.
|
|
2259
|
+
*/
|
|
2260
|
+
const dataSetColumnsOptions = [
|
|
2261
|
+
6,
|
|
2262
|
+
4,
|
|
2263
|
+
3,
|
|
2264
|
+
2,
|
|
2265
|
+
1
|
|
2266
|
+
];
|
|
2267
|
+
/**
|
|
2268
|
+
* Number of records to place side by side: the largest supported amount, up
|
|
2269
|
+
* to `columns`, that keeps each card at least {@link minDataSetItemWidth}
|
|
2270
|
+
* pixels wide, besides the {@link dataSetItemGap} between cards, in a data set
|
|
2271
|
+
* `width` pixels wide, but never less than one.
|
|
2272
|
+
* While the width is unknown (`0`, e.g. before the first measure or during
|
|
2273
|
+
* server-side rendering), `columns` is used as is.
|
|
2274
|
+
*/
|
|
2275
|
+
function getDataSetFittingColumns(columns, width) {
|
|
2276
|
+
if (!width) return columns;
|
|
2277
|
+
const fittingColumns = Math.min(columns, Math.floor((width + dataSetItemGap) / 264));
|
|
2278
|
+
return dataSetColumnsOptions.find((option) => option <= fittingColumns) ?? 1;
|
|
2279
|
+
}
|
|
2280
|
+
/**
|
|
2281
|
+
* Reactive version of {@link getDataSetFittingColumns}.
|
|
2282
|
+
*/
|
|
2283
|
+
function useDataSetFittingColumns(columns, width) {
|
|
2284
|
+
return computed(() => getDataSetFittingColumns(toValue(columns), toValue(width)));
|
|
2285
|
+
}
|
|
2286
|
+
/**
|
|
2287
|
+
* Width, in pixels, of the given element, kept up to date with a
|
|
2288
|
+
* `ResizeObserver`. It's `0` while there's no element, e.g. before it's
|
|
2289
|
+
* mounted, and the observer is disconnected when the element changes or the
|
|
2290
|
+
* calling scope is disposed.
|
|
2291
|
+
*/
|
|
2292
|
+
function useDataSetWidth(element) {
|
|
2293
|
+
const width = ref(0);
|
|
2294
|
+
let observer;
|
|
2295
|
+
function disconnect() {
|
|
2296
|
+
observer?.disconnect();
|
|
2297
|
+
observer = void 0;
|
|
2298
|
+
}
|
|
2299
|
+
watch(() => toValue(element), (currentElement) => {
|
|
2300
|
+
disconnect();
|
|
2301
|
+
width.value = 0;
|
|
2302
|
+
if (!currentElement) return;
|
|
2303
|
+
observer = new ResizeObserver(([entry]) => {
|
|
2304
|
+
width.value = entry.contentRect.width;
|
|
2305
|
+
});
|
|
2306
|
+
observer.observe(currentElement);
|
|
2307
|
+
}, { immediate: true });
|
|
2308
|
+
onScopeDispose(disconnect);
|
|
2309
|
+
return width;
|
|
2310
|
+
}
|
|
2311
|
+
/**
|
|
2312
|
+
* Maps the number of records per row to the width of each record's grid
|
|
2313
|
+
* column.
|
|
2314
|
+
*/
|
|
2315
|
+
function useDataSetColumnCols(columns) {
|
|
2316
|
+
return computed(() => dataSetColumnsToColumnCols[toValue(columns)]);
|
|
2317
|
+
}
|
|
2318
|
+
/**
|
|
2319
|
+
* Maps the record properties considered by the search to Vuetify's filter
|
|
2320
|
+
* keys. An empty list means every property, just like an undefined one.
|
|
2321
|
+
*/
|
|
2322
|
+
function useDataSetFilterKeys(searchKeys) {
|
|
2323
|
+
return computed(() => {
|
|
2324
|
+
const keys = toValue(searchKeys);
|
|
2325
|
+
return keys?.length ? keys : void 0;
|
|
2326
|
+
});
|
|
2327
|
+
}
|
|
2328
|
+
/**
|
|
2329
|
+
* Up to this many pages, every page button is shown. Vuetify's automatic
|
|
2330
|
+
* sizing collapses 3 pages into `1 … 2 … 3` in containers narrower than
|
|
2331
|
+
* ~336px, although showing every page never takes more room than its
|
|
2332
|
+
* collapsed form (`1 … x … 5`, 5 buttons) up to this amount.
|
|
2333
|
+
*/
|
|
2334
|
+
const maxAlwaysVisiblePages = 5;
|
|
2335
|
+
/**
|
|
2336
|
+
* Number of page buttons to show for `pageCount` pages: every page up to
|
|
2337
|
+
* {@link maxAlwaysVisiblePages}, otherwise `undefined` to let Vuetify fit them
|
|
2338
|
+
* to the available width.
|
|
2339
|
+
*/
|
|
2340
|
+
function getDataSetTotalVisible(pageCount) {
|
|
2341
|
+
return pageCount <= maxAlwaysVisiblePages ? pageCount : void 0;
|
|
2342
|
+
}
|
|
2343
|
+
/**
|
|
2344
|
+
* Goes back to the first page whenever the search changes. It must run before
|
|
2345
|
+
* the new search reaches Vuetify's iterator, which would otherwise clamp the
|
|
2346
|
+
* outdated page to the last one of the filtered records.
|
|
2347
|
+
*/
|
|
2348
|
+
function useDataSetSearchPageReset(search, page) {
|
|
2349
|
+
watch(() => toValue(search), () => {
|
|
2350
|
+
page.value = 1;
|
|
2351
|
+
});
|
|
2352
|
+
}
|
|
2353
|
+
//#endregion
|
|
2354
|
+
//#region src/components/data-sets/data-set/data-set.vue
|
|
2355
|
+
var data_set_default = /* @__PURE__ */ defineComponent({
|
|
2356
|
+
inheritAttrs: false,
|
|
2357
|
+
__name: "data-set",
|
|
2358
|
+
props: /*@__PURE__*/ mergeModels({
|
|
2359
|
+
items: {
|
|
2360
|
+
type: Array,
|
|
2361
|
+
required: false
|
|
2362
|
+
},
|
|
2363
|
+
columns: {
|
|
2364
|
+
type: Number,
|
|
2365
|
+
required: false,
|
|
2366
|
+
default: 3
|
|
2367
|
+
},
|
|
2368
|
+
itemsPerPage: {
|
|
2369
|
+
type: Number,
|
|
2370
|
+
required: false,
|
|
2371
|
+
default: 10
|
|
2372
|
+
},
|
|
2373
|
+
searchable: {
|
|
2374
|
+
type: Boolean,
|
|
2375
|
+
required: false
|
|
2376
|
+
},
|
|
2377
|
+
searchKeys: {
|
|
2378
|
+
type: Array,
|
|
2379
|
+
required: false
|
|
2380
|
+
},
|
|
2381
|
+
noDataText: {
|
|
2382
|
+
type: String,
|
|
2383
|
+
required: false,
|
|
2384
|
+
default: "Nenhum registro encontrado."
|
|
2385
|
+
},
|
|
2386
|
+
loading: {
|
|
2387
|
+
type: Boolean,
|
|
2388
|
+
required: false
|
|
2389
|
+
},
|
|
2390
|
+
dataTestid: {
|
|
2391
|
+
type: String,
|
|
2392
|
+
required: false
|
|
2393
|
+
}
|
|
2394
|
+
}, {
|
|
2395
|
+
"page": {
|
|
2396
|
+
type: Number,
|
|
2397
|
+
default: 1
|
|
2398
|
+
},
|
|
2399
|
+
"pageModifiers": {},
|
|
2400
|
+
"search": {
|
|
2401
|
+
type: String,
|
|
2402
|
+
default: ""
|
|
2403
|
+
},
|
|
2404
|
+
"searchModifiers": {}
|
|
2405
|
+
}),
|
|
2406
|
+
emits: ["update:page", "update:search"],
|
|
2407
|
+
setup(__props) {
|
|
2408
|
+
const props = __props;
|
|
2409
|
+
useSlots();
|
|
2410
|
+
const page = useModel(__props, "page");
|
|
2411
|
+
const search = useModel(__props, "search");
|
|
2412
|
+
const iterator = useTemplateRef("iterator");
|
|
2413
|
+
const columnCols = useDataSetColumnCols(useDataSetFittingColumns(() => props.columns, useDataSetWidth(() => iterator.value?.$el)));
|
|
2414
|
+
const filterKeys = useDataSetFilterKeys(() => props.searchKeys);
|
|
2415
|
+
useDataSetSearchPageReset(search, page);
|
|
2416
|
+
return (_ctx, _cache) => {
|
|
2417
|
+
return openBlock(), createBlock(unref(VSkeletonLoader), {
|
|
2418
|
+
loading: props.loading,
|
|
2419
|
+
type: "card",
|
|
2420
|
+
width: "100%"
|
|
2421
|
+
}, {
|
|
2422
|
+
default: withCtx(() => [createVNode(unref(VDataIterator), {
|
|
2423
|
+
ref_key: "iterator",
|
|
2424
|
+
ref: iterator,
|
|
2425
|
+
page: page.value,
|
|
2426
|
+
"onUpdate:page": _cache[2] || (_cache[2] = ($event) => page.value = $event),
|
|
2427
|
+
items: props.items,
|
|
2428
|
+
"items-per-page": props.itemsPerPage,
|
|
2429
|
+
search: search.value,
|
|
2430
|
+
"filter-keys": unref(filterKeys),
|
|
2431
|
+
"data-testid": props.dataTestid
|
|
2432
|
+
}, {
|
|
2433
|
+
header: withCtx(() => [props.searchable ? (openBlock(), createBlock(text_field_default, {
|
|
2434
|
+
key: 0,
|
|
2435
|
+
modelValue: search.value,
|
|
2436
|
+
"onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => search.value = $event),
|
|
2437
|
+
type: "search",
|
|
2438
|
+
label: "Pesquisar"
|
|
2439
|
+
}, null, 8, ["modelValue"])) : createCommentVNode("v-if", true)]),
|
|
2440
|
+
default: withCtx(({ items: pageItems }) => [createCommentVNode(" Stretched, so the items of the same line (e.g. full-height cards) share its height "), createVNode(row_default, {
|
|
2441
|
+
list: "",
|
|
2442
|
+
"align-y": "stretch"
|
|
2443
|
+
}, {
|
|
2444
|
+
default: withCtx(() => [(openBlock(true), createElementBlock(Fragment, null, renderList(pageItems, (pageItem, index) => {
|
|
2445
|
+
return openBlock(), createBlock(column_default, {
|
|
2446
|
+
key: index,
|
|
2447
|
+
cols: unref(columnCols),
|
|
2448
|
+
"list-item": ""
|
|
2449
|
+
}, {
|
|
2450
|
+
default: withCtx(() => [renderSlot(_ctx.$slots, "default", {
|
|
2451
|
+
item: pageItem.raw,
|
|
2452
|
+
index
|
|
2453
|
+
})]),
|
|
2454
|
+
_: 2
|
|
2455
|
+
}, 1032, ["cols"]);
|
|
2456
|
+
}), 128))]),
|
|
2457
|
+
_: 2
|
|
2458
|
+
}, 1024)]),
|
|
2459
|
+
"no-data": withCtx(() => [createVNode(unref(VEmptyState), { text: props.noDataText }, null, 8, ["text"])]),
|
|
2460
|
+
footer: withCtx(({ pageCount }) => [pageCount > 1 ? (openBlock(), createBlock(unref(VPagination), {
|
|
2461
|
+
key: 0,
|
|
2462
|
+
modelValue: page.value,
|
|
2463
|
+
"onUpdate:modelValue": _cache[1] || (_cache[1] = ($event) => page.value = $event),
|
|
2464
|
+
length: pageCount,
|
|
2465
|
+
"total-visible": unref(getDataSetTotalVisible)(pageCount)
|
|
2466
|
+
}, null, 8, [
|
|
2467
|
+
"modelValue",
|
|
2468
|
+
"length",
|
|
2469
|
+
"total-visible"
|
|
2470
|
+
])) : createCommentVNode("v-if", true)]),
|
|
2471
|
+
_: 3
|
|
2472
|
+
}, 8, [
|
|
2473
|
+
"page",
|
|
2474
|
+
"items",
|
|
2475
|
+
"items-per-page",
|
|
2476
|
+
"search",
|
|
2477
|
+
"filter-keys",
|
|
2478
|
+
"data-testid"
|
|
2479
|
+
])]),
|
|
2480
|
+
_: 3
|
|
2481
|
+
}, 8, ["loading"]);
|
|
2482
|
+
};
|
|
2483
|
+
}
|
|
2484
|
+
});
|
|
2485
|
+
//#endregion
|
|
2486
|
+
//#region src/components/data-sets/data-set-item/data-set-item.vue
|
|
2487
|
+
var data_set_item_default = /* @__PURE__ */ defineComponent({
|
|
2488
|
+
inheritAttrs: false,
|
|
2489
|
+
__name: "data-set-item",
|
|
2490
|
+
props: {
|
|
2491
|
+
title: {
|
|
2492
|
+
type: String,
|
|
2493
|
+
required: false
|
|
2494
|
+
},
|
|
2495
|
+
subtitle: {
|
|
2496
|
+
type: String,
|
|
2497
|
+
required: false
|
|
2498
|
+
},
|
|
2499
|
+
variant: {
|
|
2500
|
+
type: String,
|
|
2501
|
+
required: false
|
|
2502
|
+
},
|
|
2503
|
+
actions: {
|
|
2504
|
+
type: Array,
|
|
2505
|
+
required: false
|
|
2506
|
+
},
|
|
2507
|
+
dataTestid: {
|
|
2508
|
+
type: String,
|
|
2509
|
+
required: false
|
|
2510
|
+
}
|
|
2511
|
+
},
|
|
2512
|
+
setup(__props) {
|
|
2513
|
+
const props = __props;
|
|
2514
|
+
const slots = useSlots();
|
|
2515
|
+
return (_ctx, _cache) => {
|
|
2516
|
+
return openBlock(), createBlock(section_default, {
|
|
2517
|
+
title: props.title,
|
|
2518
|
+
subtitle: props.subtitle,
|
|
2519
|
+
variant: props.variant,
|
|
2520
|
+
actions: props.actions,
|
|
2521
|
+
"data-testid": props.dataTestid,
|
|
2522
|
+
"full-height": ""
|
|
2523
|
+
}, {
|
|
2524
|
+
default: withCtx(() => [slots.default ? (openBlock(), createBlock(section_content_default, { key: 0 }, {
|
|
2525
|
+
default: withCtx(() => [renderSlot(_ctx.$slots, "default")]),
|
|
2526
|
+
_: 3
|
|
2527
|
+
})) : createCommentVNode("v-if", true)]),
|
|
2528
|
+
_: 3
|
|
2529
|
+
}, 8, [
|
|
2530
|
+
"title",
|
|
2531
|
+
"subtitle",
|
|
2532
|
+
"variant",
|
|
2533
|
+
"actions",
|
|
2534
|
+
"data-testid"
|
|
2535
|
+
]);
|
|
2536
|
+
};
|
|
2537
|
+
}
|
|
2538
|
+
});
|
|
2539
|
+
//#endregion
|
|
2540
|
+
export { autocomplete_field_default as UAutocompleteField, button_default as UButton, checkbox_default as UCheckbox, column_default as UColumn, container_default as UContainer, data_set_default as UDataSet, data_set_item_default as UDataSetItem, date_time_field_default as UDateTimeField, details_default as UDetails, dialog_default as UDialog, form_default as UForm, img_default as UImg, main_default as UMain, row_default as URow, section_default as USection, section_content_default as USectionContent, table_default as UTable, text_field_default as UTextField };
|