@nexdom/uimed-vue 2.4.2 → 2.6.0

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.
@@ -0,0 +1,5 @@
1
+ import back_to_top_vue_vue_type_script_setup_true_lang_default from "./back-to-top.vue_vue_type_script_setup_true_lang.js";
2
+ //#region src/components/main/back-to-top.vue
3
+ var back_to_top_default = back_to_top_vue_vue_type_script_setup_true_lang_default;
4
+ //#endregion
5
+ export { back_to_top_default as default };
@@ -0,0 +1,35 @@
1
+ import { icons } from "../../consts/icons.js";
2
+ import { createBlock, createCommentVNode, createElementVNode, createVNode, defineComponent, openBlock, unref, withCtx } from "vue";
3
+ import { VFab, VIcon } from "vuetify/components";
4
+ var back_to_top_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineComponent({
5
+ inheritAttrs: false,
6
+ __name: "back-to-top",
7
+ props: { active: {
8
+ type: Boolean,
9
+ required: true
10
+ } },
11
+ emits: ["click"],
12
+ setup(__props, { emit: __emit }) {
13
+ const props = __props;
14
+ const emit = __emit;
15
+ return (_ctx, _cache) => {
16
+ return openBlock(), createBlock(unref(VFab), {
17
+ active: props.active,
18
+ icon: unref(icons).backToTop,
19
+ color: "tertiary",
20
+ location: "bottom end",
21
+ app: "",
22
+ onClick: _cache[0] || (_cache[0] = ($event) => emit("click"))
23
+ }, {
24
+ default: withCtx(() => [
25
+ createVNode(unref(VIcon), { icon: unref(icons).backToTop }, null, 8, ["icon"]),
26
+ createCommentVNode(" The FAB gives its attributes to its wrapper instead of its button, so the button can't take\n an aria-label: its name is a text that only screen readers read, which no prop provides "),
27
+ _cache[1] || (_cache[1] = createElementVNode("span", { class: "d-sr-only" }, "Retornar ao topo", -1))
28
+ ]),
29
+ _: 1
30
+ }, 8, ["active", "icon"]);
31
+ };
32
+ }
33
+ });
34
+ //#endregion
35
+ export { back_to_top_vue_vue_type_script_setup_true_lang_default as default };
@@ -2,12 +2,15 @@ import app_bar_default from "../app-bar/app-bar.js";
2
2
  import { useMobileNavigation } from "../../composables/navigation/use-navigation-rail.js";
3
3
  import navigation_menu_default from "../navigation-menu/navigation-menu.js";
4
4
  import footer_default from "../footer/footer.js";
5
+ import back_to_top_default from "./back-to-top.js";
5
6
  import container_default from "../grid/container/container.js";
6
7
  import toast_default from "../dialogs/toast.js";
7
8
  import dialog_host_default from "../dialogs/dialog-host.js";
8
9
  import useVuetifyBackgroundColor from "../../composables/colors/use-vuetify-background-color.js";
9
- import { computed, createBlock, createCommentVNode, createSlots, createVNode, defineComponent, mergeModels, mergeProps, normalizeClass, normalizeProps, openBlock, ref, renderSlot, unref, useModel, useSlots, withCtx } from "vue";
10
+ import useBackToTop from "../../composables/navigation/use-back-to-top.js";
11
+ import { computed, createBlock, createCommentVNode, createSlots, createVNode, defineComponent, mergeModels, mergeProps, normalizeClass, normalizeProps, openBlock, ref, renderSlot, unref, useModel, useSlots, useTemplateRef, withCtx, withDirectives } from "vue";
10
12
  import { VApp, VMain } from "vuetify/components";
13
+ import { Scroll } from "vuetify/directives";
11
14
  var main_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineComponent({
12
15
  inheritAttrs: false,
13
16
  __name: "main",
@@ -61,6 +64,7 @@ var main_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineCompo
61
64
  const backgroundClass = useVuetifyBackgroundColor(() => props.background);
62
65
  const notificationsOpen = useModel(__props, "notificationsOpen");
63
66
  const navigationMenuOpen = ref(false);
67
+ const { visible, onScroll, backToTop } = useBackToTop(useTemplateRef("main"));
64
68
  return (_ctx, _cache) => {
65
69
  return openBlock(), createBlock(unref(VApp), {
66
70
  class: normalizeClass(unref(backgroundClass)),
@@ -82,7 +86,11 @@ var main_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineCompo
82
86
  "onUpdate:modelValue": _cache[2] || (_cache[2] = ($event) => navigationMenuOpen.value = $event),
83
87
  loading: props.loading
84
88
  }), null, 16, ["modelValue", "loading"])) : createCommentVNode("v-if", true),
85
- createVNode(unref(VMain), null, {
89
+ createCommentVNode(" Focusable, so the back-to-top button can move the focus to the start of the content "),
90
+ createVNode(unref(VMain), {
91
+ ref: "main",
92
+ tabindex: "-1"
93
+ }, {
86
94
  default: withCtx(() => [createCommentVNode(" Full height, so the page's rows and containers with `fullHeight` have a height to fill "), createVNode(container_default, { "full-height": "" }, {
87
95
  default: withCtx(() => [
88
96
  renderSlot(_ctx.$slots, "default"),
@@ -92,8 +100,13 @@ var main_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineCompo
92
100
  _: 3
93
101
  })]),
94
102
  _: 3
95
- }),
96
- props.footer?.description ? (openBlock(), createBlock(footer_default, normalizeProps(mergeProps({ key: 2 }, props.footer)), null, 16)) : createCommentVNode("v-if", true)
103
+ }, 512),
104
+ props.footer?.description ? (openBlock(), createBlock(footer_default, normalizeProps(mergeProps({ key: 2 }, props.footer)), null, 16)) : createCommentVNode("v-if", true),
105
+ createCommentVNode(" After the footer, so the layout places it above the footer "),
106
+ withDirectives(createVNode(back_to_top_default, {
107
+ active: unref(visible),
108
+ onClick: unref(backToTop)
109
+ }, null, 8, ["active", "onClick"]), [[unref(Scroll), unref(onScroll)]])
97
110
  ]),
98
111
  _: 3
99
112
  }, 8, ["class", "data-testid"]);
@@ -45,9 +45,9 @@ export type MainProps = {
45
45
  loading?: boolean;
46
46
  /**
47
47
  * Applies a color to the background of the whole app, e.g. on landing pages. Text placed
48
- * directly on the background takes the color the theme pairs with it (white or black), while
49
- * the app bar, the footer, sections and dialogs keep their own backgrounds. When omitted, the
50
- * app uses the theme's default background.
48
+ * directly on the background takes the color the theme pairs with it (white, dark green or
49
+ * black), while the app bar, the footer, sections and dialogs keep their own backgrounds. When
50
+ * omitted, the app uses the theme's default background.
51
51
  *
52
52
  * @example
53
53
  * ```vue
@@ -0,0 +1,36 @@
1
+ import { onMounted, ref, toValue } from "vue";
2
+ //#region src/composables/navigation/use-back-to-top.ts
3
+ /**
4
+ * Back-to-top button's state for `content`, the template ref of the component whose element the
5
+ * button brings into view and focuses (which must be focusable, e.g. with `tabindex="-1"`). The
6
+ * button shows once the top of the content is a screen above the viewport, instead of after the page
7
+ * scrolls a screen: in apps both are the same, but on pages with more than one `UMain` (like the
8
+ * docs) only the one scrolled past shows it.
9
+ */
10
+ function useBackToTop(content) {
11
+ const visible = ref(false);
12
+ function onScroll() {
13
+ const element = toValue(content)?.$el;
14
+ visible.value = element ? -element.getBoundingClientRect().top > globalThis.innerHeight : false;
15
+ }
16
+ function backToTop() {
17
+ const element = toValue(content)?.$el;
18
+ if (!element) return;
19
+ globalThis.scrollTo({
20
+ top: globalThis.scrollY + element.getBoundingClientRect().top,
21
+ behavior: prefersReducedMotion() ? "instant" : "smooth"
22
+ });
23
+ element.focus({ preventScroll: true });
24
+ }
25
+ onMounted(onScroll);
26
+ return {
27
+ visible,
28
+ onScroll,
29
+ backToTop
30
+ };
31
+ }
32
+ function prefersReducedMotion() {
33
+ return globalThis.matchMedia("(prefers-reduced-motion: reduce)").matches;
34
+ }
35
+ //#endregion
36
+ export { useBackToTop as default };
@@ -50,6 +50,7 @@ export declare const icons: {
50
50
  showPassword: string;
51
51
  hidePassword: string;
52
52
  close: string;
53
+ backToTop: string;
53
54
  clear: string;
54
55
  dropdown: string;
55
56
  subgroup: string;
@@ -1,4 +1,4 @@
1
- import { mdiAccount, mdiAccountGroup, mdiAccountGroupOutline, mdiAccountOutline, mdiAlertCircle, mdiBellOutline, mdiCalendar, mdiCalendarOutline, mdiChartBox, mdiChartBoxOutline, mdiCheckCircle, mdiCheckboxBlankOutline, mdiCheckboxMarked, mdiChevronDown, mdiChevronLeft, mdiChevronRight, mdiChevronUp, mdiClipboardText, mdiClipboardTextOutline, mdiClose, mdiCloseCircle, mdiCog, mdiCogOutline, mdiEye, mdiEyeOff, mdiFileDocument, mdiFileDocumentOutline, mdiFlask, mdiFlaskOutline, mdiFolder, mdiFolderOutline, mdiHelpCircleOutline, mdiHome, mdiHomeOutline, mdiHospitalBuilding, mdiInformation, mdiMagnify, mdiMenu, mdiMenuDown, mdiPill, mdiStethoscope, mdiWallet, mdiWalletOutline } from "@mdi/js";
1
+ import { mdiAccount, mdiAccountGroup, mdiAccountGroupOutline, mdiAccountOutline, mdiAlertCircle, mdiArrowUp, mdiBellOutline, mdiCalendar, mdiCalendarOutline, mdiChartBox, mdiChartBoxOutline, mdiCheckCircle, mdiCheckboxBlankOutline, mdiCheckboxMarked, mdiChevronDown, mdiChevronLeft, mdiChevronRight, mdiChevronUp, mdiClipboardText, mdiClipboardTextOutline, mdiClose, mdiCloseCircle, mdiCog, mdiCogOutline, mdiEye, mdiEyeOff, mdiFileDocument, mdiFileDocumentOutline, mdiFlask, mdiFlaskOutline, mdiFolder, mdiFolderOutline, mdiHelpCircleOutline, mdiHome, mdiHomeOutline, mdiHospitalBuilding, mdiInformation, mdiMagnify, mdiMenu, mdiMenuDown, mdiPill, mdiStethoscope, mdiWallet, mdiWalletOutline } from "@mdi/js";
2
2
  //#region src/consts/icons.ts
3
3
  /**
4
4
  * SVG path of each icon, by its name, in the order the "Ícones" guide page lists them. The paths
@@ -51,6 +51,7 @@ const icons = {
51
51
  showPassword: mdiEye,
52
52
  hidePassword: mdiEyeOff,
53
53
  close: mdiClose,
54
+ backToTop: mdiArrowUp,
54
55
  clear: mdiCloseCircle,
55
56
  dropdown: mdiMenuDown,
56
57
  subgroup: mdiMenuDown,
package/dist/index.js CHANGED
@@ -6,7 +6,7 @@ import { createVuetify } from "vuetify";
6
6
  import "vue";
7
7
  import { mdi } from "vuetify/iconsets/mdi-svg";
8
8
  //#region src/index.ts
9
- /** The library's default theme, with its colors and the opacities of secondary text and borders */
9
+ /** The library's default theme, with its colors and the opacities of the text and borders */
10
10
  const light = {
11
11
  dark: false,
12
12
  colors: {
@@ -19,6 +19,9 @@ const light = {
19
19
  warning: "#FFE596",
20
20
  error: "#D92D20",
21
21
  info: "#9ACBE5",
22
+ "on-background": "#053321",
23
+ "on-surface": "#053321",
24
+ "on-secondary": "#053321",
22
25
  "on-primary": "#FCFCFD",
23
26
  "on-tertiary": "#000000",
24
27
  "primary-text": "#074D31",
@@ -31,7 +34,8 @@ const light = {
31
34
  },
32
35
  variables: {
33
36
  "border-color": "#D0D5DD",
34
- "medium-emphasis-opacity": .7
37
+ "high-emphasis-opacity": 1,
38
+ "medium-emphasis-opacity": .72
35
39
  }
36
40
  };
37
41
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nexdom/uimed-vue",
3
- "version": "2.4.2",
3
+ "version": "2.6.0",
4
4
  "description": "A ui framework for NEXDOM applications.",
5
5
  "keywords": [
6
6
  "lib",
@@ -83,6 +83,7 @@ createApp(App).use(createUimed()).mount("#app");
83
83
  type SectionAction = NonNullable<ComponentProps<typeof USection>["actions"]>[number];
84
84
  ```
85
85
 
86
+ - `UMain` shows a "back to top" floating button on its own once the page scrolls past a screen, so don't add one to the screens.
86
87
  - Icons are passed by name (e.g. `icon="cog"`), from the list in [`references/guide/icons.md`](references/guide/icons.md).
87
88
  - The components' internal texts, such as their messages and the names read by screen readers, are in Portuguese (pt-BR).
88
89
 
@@ -6,15 +6,15 @@ Responsável por carregar o menu superior, o menu de navegação lateral, o roda
6
6
 
7
7
  ## Props
8
8
 
9
- | Prop | Tipo | Padrão | Descrição |
10
- | ---------------- | ------------------------------------------------------------------------------------------------ | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
11
- | `dataTestid` | `string` | | Aplica atributo `data-testid` para testes sobre o componente. |
12
- | `logo` | `string` | | URL utilizada para carregar a logo que será apresentada. A logo é decorativa (`alt=""`): o título do menu superior (`appBar.title`) identifica a aplicação. |
13
- | `appBar` | [`AppBar`](#appbar) | | Conjunto de propriedades para aplicar à barra superior. |
14
- | `navigationMenu` | [`NavigationMenu`](#navigationmenu) | | Conjunto de propriedades para aplicar ao menu lateral de navegação. |
15
- | `footer` | [`Footer`](#footer) | | Conjunto de propriedades para aplicar ao rodapé, fixo na parte inferior da tela e com a mesma elevação do menu superior. **O rodapé será ocultado sempre que essa prop for omitida ou o seu `description` for vazio.** |
16
- | `loading` | `boolean` | `false` | Exibe skeletons no lugar das ações do menu superior e dos itens do menu de navegação enquanto os dados são carregados. O conteúdo da página não é afetado. |
17
- | `background` | `"primary" \| "secondary" \| "tertiary" \| "positive" \| "informative" \| "caution" \| "danger"` | | Aplica uma cor ao fundo de toda a aplicação, como em landing pages. O texto colocado diretamente sobre o fundo passa a usar a cor associada a ele (branco ou preto), enquanto o menu superior, o rodapé, as sections e os diálogos mantêm os próprios fundos. **Quando omitida, a aplicação usa o fundo padrão do tema.** |
9
+ | Prop | Tipo | Padrão | Descrição |
10
+ | ---------------- | ------------------------------------------------------------------------------------------------ | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
11
+ | `dataTestid` | `string` | | Aplica atributo `data-testid` para testes sobre o componente. |
12
+ | `logo` | `string` | | URL utilizada para carregar a logo que será apresentada. A logo é decorativa (`alt=""`): o título do menu superior (`appBar.title`) identifica a aplicação. |
13
+ | `appBar` | [`AppBar`](#appbar) | | Conjunto de propriedades para aplicar à barra superior. |
14
+ | `navigationMenu` | [`NavigationMenu`](#navigationmenu) | | Conjunto de propriedades para aplicar ao menu lateral de navegação. |
15
+ | `footer` | [`Footer`](#footer) | | Conjunto de propriedades para aplicar ao rodapé, fixo na parte inferior da tela e com a mesma elevação do menu superior. **O rodapé será ocultado sempre que essa prop for omitida ou o seu `description` for vazio.** |
16
+ | `loading` | `boolean` | `false` | Exibe skeletons no lugar das ações do menu superior e dos itens do menu de navegação enquanto os dados são carregados. O conteúdo da página não é afetado. |
17
+ | `background` | `"primary" \| "secondary" \| "tertiary" \| "positive" \| "informative" \| "caution" \| "danger"` | | Aplica uma cor ao fundo de toda a aplicação, como em landing pages. O texto colocado diretamente sobre o fundo passa a usar a cor associada a ele (branco, verde-escuro ou preto), enquanto o menu superior, o rodapé, as sections e os diálogos mantêm os próprios fundos. **Quando omitida, a aplicação usa o fundo padrão do tema.** |
18
18
 
19
19
  ### `AppBar`
20
20
 
@@ -105,6 +105,10 @@ Item dentro de um [grupo](#navigationmenuparent). Tem as mesmas propriedades do
105
105
  | `dataTestid` | `string` | | Aplica atributo `data-testid` para testes sobre o rodapé. |
106
106
  | `description` | `string` | | Texto exibido no rodapé, por exemplo a versão da aplicação (`"Versão 1.4.2"`). **O rodapé será ocultado quando omitido ou vazio.** |
107
107
 
108
+ ## Retornar ao topo
109
+
110
+ O componente exibe um botão flutuante "Retornar ao topo" no canto inferior direito quando o usuário rola a página por mais de uma tela, sem props para configurá-lo. Veja [Retornar ao topo](../../guide/components/main.md#retornar-ao-topo) no guia.
111
+
108
112
  ## Eventos
109
113
 
110
114
  | Event | Retorno | Descrição |
@@ -365,7 +365,7 @@ const footer: NonNullable<MainProps["footer"]> = {
365
365
 
366
366
  A prop `background` aplica uma cor ao fundo de toda a aplicação, como em landing pages, com as mesmas opções de cor do [Botão](./button.md): `primary`, `secondary`, `tertiary`, `positive`, `informative`, `caution` e `danger`. Quando omitida, a aplicação usa o fundo padrão do tema.
367
367
 
368
- O texto colocado diretamente sobre o fundo passa a usar a cor associada a ele (branco ou preto). O menu superior, o rodapé, as [Sections](./section.md) e os diálogos mantêm os próprios fundos.
368
+ O texto colocado diretamente sobre o fundo passa a usar a cor associada a ele (branco, verde-escuro ou preto). O menu superior, o rodapé, as [Sections](./section.md) e os diálogos mantêm os próprios fundos.
369
369
 
370
370
  Cuide do contraste ao escolher a cor:
371
371
 
@@ -391,6 +391,41 @@ const appBar: NonNullable<MainProps["appBar"]> = {
391
391
  </script>
392
392
  ```
393
393
 
394
+ ## Retornar ao topo
395
+
396
+ Em páginas longas, como listagens e formulários extensos, o `UMain` exibe um botão flutuante no canto inferior direito para voltar ao início do conteúdo. Ele aparece quando o usuário rola a página por mais de uma tela e some ao voltar ao topo, sem nenhuma prop: páginas curtas nunca o exibem.
397
+
398
+ O botão fica acima do rodapé, quando exibido, e abaixo dos diálogos e dos toasts. Ao ser acionado, ele rola a página até o início do conteúdo de forma suave, ou imediata quando o usuário prefere reduzir os movimentos nas configurações do sistema, e move o foco para o início do conteúdo, para que quem navega pelo teclado continue a partir dali. Os leitores de tela o anunciam como "Retornar ao topo".
399
+
400
+ Role a demonstração abaixo para ver o botão:
401
+
402
+ ```vue
403
+ <template>
404
+ <u-main :appBar :footer>
405
+ <h2>Manual do usuário</h2>
406
+ <p v-for="step in 12" :key="step">{{ step }}. {{ manualText }}</p>
407
+ </u-main>
408
+ </template>
409
+
410
+ <script lang="ts" setup>
411
+ import type { ComponentProps } from "vue-component-type-helpers";
412
+ import { UMain } from "@nexdom/uimed-vue/components";
413
+
414
+ type MainProps = ComponentProps<typeof UMain>;
415
+
416
+ const manualText =
417
+ "Este manual descreve cada etapa do atendimento, do agendamento da consulta à emissão do relatório final, com as orientações para preencher os formulários, conferir os dados do paciente antes de salvar e resolver as pendências mais comuns. Siga as etapas na ordem em que aparecem e, em caso de dúvida, procure a equipe de suporte da sua unidade.";
418
+
419
+ const appBar: NonNullable<MainProps["appBar"]> = {
420
+ title: "Menu superior",
421
+ };
422
+
423
+ const footer: NonNullable<MainProps["footer"]> = {
424
+ description: "Versão 1.4.2",
425
+ };
426
+ </script>
427
+ ```
428
+
394
429
  ## Eventos
395
430
 
396
431
  ### Notificações
@@ -57,7 +57,7 @@ A lista começa pelos ícones de conteúdo, como `home` e `calendar`, cujos nome
57
57
 
58
58
  Em seguida vêm os ícones que os próprios componentes exibem, cujos nomes descrevem a função com que os componentes os usam:
59
59
 
60
- - Ações, como `help`, `search`, `showPassword` e `close`.
60
+ - Ações, como `help`, `search`, `showPassword`, `close` e `backToTop`.
61
61
  - Expansão de menus e grupos, como `dropdown`, `expand` e `collapse`, e navegação entre páginas, com `prev` e `next`.
62
62
  - Marcações da caixa de seleção: `checkboxOn` e `checkboxOff`.
63
63
  - Retorno ao usuário, nas cores das mensagens: `success`, `info`, `warning` e `error`.
@@ -199,6 +199,8 @@ Na v1, a cor `primary` era o azul do tema padrão. Na v2, a `primary` é um verd
199
199
  </template>
200
200
  ```
201
201
 
202
+ O texto sobre o fundo e as superfícies (cards, diálogos, menu superior) também mudou: é verde-escuro (`#053321`), não preto.
203
+
202
204
  ## Dicas de Migração
203
205
 
204
206
  1. Procure por todas as importações antigas e substitua pelos novos nomes com o prefixo `U`