@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.
@@ -1,7 +1,8 @@
1
- import { r as useVuetifyColor, t as messages } from "./use-toast-CACuYhK_.js";
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 { VApp, VAppBar, VAppBarNavIcon, VAppBarTitle, VAvatar, VBadge, VBtn, VCard, VCardActions, VCardText, VCol, VContainer, VDivider, VForm, VIcon, VIconBtn, VImg, VList, VListGroup, VListItem, VListItemAction, VListSubheader, VMain, VMenu, VNavigationDrawer, VRow, VSkeletonLoader, VSnackbarQueue, VTable, VTextField } from "vuetify/components";
4
- import { formatDateTime, isEmail, isEmpty, isPhone, isUrl, toPeriodInterval } from "@nexdom/shared/utils";
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$2 = { class: "opacity-60" };
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), { "data-testid": props.dataTestid }, {
102
- append: withCtx(() => [
103
- showHelp.value ? (openBlock(), createBlock(unref(VBtn), mergeProps({ key: 0 }, unref(routeProps), {
104
- "data-testid": helpBtnDataTestid.value,
105
- icon: "mdi-help-circle-outline"
106
- }), null, 16, ["data-testid"])) : createCommentVNode("v-if", true),
107
- showNotifications.value ? (openBlock(), createBlock(unref(VMenu), {
108
- key: 1,
109
- modelValue: notificationsOpen.value,
110
- "onUpdate:modelValue": _cache[1] || (_cache[1] = ($event) => notificationsOpen.value = $event),
111
- "close-on-content-click": false
112
- }, {
113
- activator: withCtx(({ props }) => [createVNode(unref(VBtn), mergeProps(props, {
114
- "data-testid": notificationsBtnDataTestid.value,
115
- icon: ""
116
- }), {
117
- default: withCtx(() => [createVNode(unref(VBadge), {
118
- "model-value": hasUnreadNotifications.value,
119
- content: unreadCount.value,
120
- color: "error"
121
- }, {
122
- default: withCtx(() => [createVNode(unref(VIcon), { icon: "mdi-bell-outline" })]),
123
- _: 1
124
- }, 8, ["model-value", "content"])]),
125
- _: 1
126
- }, 16, ["data-testid"])]),
127
- default: withCtx(() => [createVNode(unref(VCard), { "data-testid": notificationsMenuDataTestid.value }, {
128
- default: withCtx(() => [props.notifications?.length ? (openBlock(), createBlock(unref(VList), { key: 0 }, {
129
- default: withCtx(() => [createVNode(unref(VListSubheader), null, {
130
- default: withCtx(() => [..._cache[2] || (_cache[2] = [createTextVNode("Notificações", -1)])]),
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
- }), (openBlock(true), createElementBlock(Fragment, null, renderList(props.notifications, (notification, index) => {
133
- return openBlock(), createBlock(unref(VListItem), {
134
- key: index,
135
- active: !notification.read,
136
- title: notification.title,
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
- })) : (openBlock(), createBlock(unref(VCardText), { key: 1 }, {
154
- default: withCtx(() => [..._cache[3] || (_cache[3] = [createTextVNode("Nenhuma notificação", -1)])]),
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, ["data-testid"])]),
159
- _: 1
160
- }, 8, ["modelValue"])) : createCommentVNode("v-if", true),
161
- showUser.value ? (openBlock(), createBlock(unref(VMenu), {
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
- prepend: withCtx(() => [createVNode(unref(VAvatar), mergeProps(userAvatarProps.value, { color: "primary" }), null, 16)]),
178
- default: withCtx(() => [createVNode(unref(VDivider)), createVNode(unref(VList), { nav: "" }, {
179
- default: withCtx(() => [(openBlock(true), createElementBlock(Fragment, null, renderList(props.user?.options, (option, index) => {
180
- return openBlock(), createElementBlock(Fragment, { key: index }, [index > 0 ? (openBlock(), createBlock(unref(VDivider), {
181
- key: 0,
182
- class: "mt-1"
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
- }, 8, [
201
- "title",
202
- "subtitle",
203
- "data-testid"
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, ["data-testid"])) : createCommentVNode("v-if", true),
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/use-rules.ts
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
- }, null, 8, [
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$1 = { class: "px-4 pt-2" };
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$1, [createVNode(text_field_default, {
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
- label: "Buscar",
470
- "data-testid": searchDataTestid.value
471
- }, null, 8, ["modelValue", "data-testid"])])]),
472
- default: withCtx(() => [createVNode(unref(VDivider)), createVNode(unref(VList), { nav: "" }, {
473
- default: withCtx(() => [(openBlock(true), createElementBlock(Fragment, null, renderList(filteredItems.value, (item, index) => {
474
- return openBlock(), createElementBlock(Fragment, { key: index }, [isParentItem(item) ? (openBlock(), createBlock(unref(VListGroup), { key: 0 }, {
475
- activator: withCtx(({ props: activatorProps }) => [createVNode(unref(VListItem), mergeProps({ ref_for: true }, activatorProps, { title: item.description }), null, 16, ["title"])]),
476
- default: withCtx(() => [(openBlock(true), createElementBlock(Fragment, null, renderList(item.items, (childItem, childIndex) => {
477
- return openBlock(), createBlock(unref(VListItem), mergeProps({ key: childIndex }, { ref_for: true }, unref(routeToProps)(childItem.route), {
478
- title: childItem.description,
479
- onClick: childItem.action
480
- }), null, 16, ["title", "onClick"]);
481
- }), 128))]),
482
- _: 2
483
- }, 1024)) : (openBlock(), createBlock(unref(VListItem), mergeProps({
484
- key: 1,
485
- title: item.description
486
- }, { ref_for: true }, unref(routeToProps)(item.route), { onClick: item.action }), null, 16, ["title", "onClick"]))], 64);
487
- }), 128))]),
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, ["modelValue", "data-testid"]);
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: { dataTestid: {
501
- type: String,
502
- required: false
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: "outlined"
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/grid/row/row.vue
704
- var row_default = /* @__PURE__ */ defineComponent({
705
- inheritAttrs: false,
706
- __name: "row",
707
- props: { dataTestid: {
708
- type: String,
709
- required: false
710
- } },
711
- setup(__props) {
712
- const props = __props;
713
- return (_ctx, _cache) => {
714
- return openBlock(), createBlock(unref(VRow), { "data-testid": props.dataTestid }, {
715
- default: withCtx(() => [renderSlot(_ctx.$slots, "default")]),
716
- _: 3
717
- }, 8, ["data-testid"]);
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/grid/column/column.vue
723
- var column_default = /* @__PURE__ */ defineComponent({
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: "column",
726
- props: {
727
- cols: {
934
+ __name: "dialog",
935
+ props: /*@__PURE__*/ mergeModels({
936
+ title: {
728
937
  type: String,
729
- required: false,
730
- default: "12"
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(VCol), {
741
- cols: "12",
742
- sm: props.cols,
743
- "data-testid": props.dataTestid
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(() => [renderSlot(_ctx.$slots, "default")]),
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, ["sm", "data-testid"]);
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/form/form.vue
753
- var form_default = /* @__PURE__ */ defineComponent({
1034
+ //#region src/components/dialogs/dialog-host.vue
1035
+ var dialog_host_default = /* @__PURE__ */ defineComponent({
754
1036
  inheritAttrs: false,
755
- __name: "form",
756
- props: {
757
- id: {
758
- type: String,
759
- required: false
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 width = computed(() => props.fullWidth ? "100%" : void 0);
857
- const height = computed(() => props.fullHeight ? "100%" : void 0);
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
- width: width.value,
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: "d-flex flex-column"
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
- "width",
894
- "height",
895
- "data-testid"
2030
+ "data-testid",
2031
+ "class"
896
2032
  ])]),
897
2033
  _: 3
898
2034
  }, 8, [
899
2035
  "loading",
900
2036
  "type",
901
- "width",
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
- export { button_default as UButton, column_default as UColumn, container_default as UContainer, form_default as UForm, 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 };
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 };