@nexdom/uimed-vue 2.0.0-beta.32 → 2.0.0-beta.34

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/AGENTS.md CHANGED
@@ -205,7 +205,7 @@ Use an existing composable (e.g. `use-toast`) as the reference, and deliver in t
205
205
  - Component layout: `src/components/<name>/<name>.vue`, `types.ts` for prop/option types, `__tests__/<name>.test.ts` for unit tests. Components that belong to a group live in the group's folder (e.g. the internal `src/components/dialogs/toast.vue`).
206
206
  - Composables live in a group folder: `src/composables/<group>/<name>.ts`, with `types.ts` and `__tests__/` in the group folder (e.g. `src/composables/dialogs/use-toast.ts`). A composable (`use-*.ts`) must depend on `vue` or `vue-router`, directly or through other modules (enforced by dependency-cruiser's `composables-use-vue` rule).
207
207
  - Library-wide configuration constants that aren't components or composables live in `src/consts/<name>.ts` (e.g. `src/consts/locale.ts`, the language set by `createUimed()` and `vueTestUtilsPluginUimed()`).
208
- - Pure helpers that don't use Vue live in `src/utils/<name>.ts`, with tests in `src/utils/__tests__/` (e.g. `src/utils/is-deep-equal.ts`).
208
+ - Pure helpers that don't use Vue live in `src/utils/<name>.ts`, with tests in `src/utils/__tests__/`. Generic helpers that any TypeScript project could use (e.g. `isDeepEqual`) belong in `@nexdom/shared` instead.
209
209
  - Public components/composables are re-exported from `src/components/index.ts` and `src/composables/index.ts`. Prop types stay internal (`types.ts` is not re-exported); consumers derive them with `ComponentProps` (see [Usage](#usage)).
210
210
  - Every publicly exported component must use the `U` prefix on its export identifier (e.g., `UButton`, `UMain`), while internal file names and component names remain unprefixed.
211
211
  - Use [JSDoc](https://jsdoc.app/about-getting-started) on every method/prop/type intended to be part of the public API — it's the primary documentation surface and supports markdown/code examples.
@@ -1,4 +1,4 @@
1
- import { t as ButtonProps } from "./types-DNT_odv7.js";
1
+ import { t as ButtonProps } from "./types-CjaJ2WAC.js";
2
2
  import { RouteLocationRaw } from "vue-router";
3
3
  //#region src/components/app-bar/types.d.ts
4
4
  /**
@@ -961,7 +961,8 @@ interface SectionAction extends ButtonProps {
961
961
  */
962
962
  label: string;
963
963
  /**
964
- * Called when the action button is clicked.
964
+ * Called when the action button is clicked. Not called while the action is `disabled` or
965
+ * `loading`.
965
966
  */
966
967
  onClick?: (event: MouseEvent) => void;
967
968
  }
@@ -1406,7 +1407,8 @@ interface DialogButtonAction extends ButtonProps {
1406
1407
  */
1407
1408
  label: string;
1408
1409
  /**
1409
- * Called when the action button is clicked. The dialog stays open.
1410
+ * Called when the action button is clicked. Not called while the action is `disabled` or
1411
+ * `loading`. The dialog stays open.
1410
1412
  */
1411
1413
  onClick?: (event: MouseEvent) => void;
1412
1414
  }
@@ -333,7 +333,11 @@ var app_bar_default = /* @__PURE__ */ defineComponent({
333
333
  class: "py-2 ml-5 mr-n3",
334
334
  cover: ""
335
335
  }, null, 8, ["src"])) : createCommentVNode("v-if", true),
336
- props.title ? (openBlock(), createBlock(unref(VAppBarTitle), { key: 2 }, {
336
+ props.title ? (openBlock(), createBlock(unref(VAppBarTitle), {
337
+ key: 2,
338
+ role: "heading",
339
+ "aria-level": "1"
340
+ }, {
337
341
  default: withCtx(() => [createTextVNode(toDisplayString(props.title), 1)]),
338
342
  _: 1
339
343
  })) : createCommentVNode("v-if", true)
@@ -818,12 +822,13 @@ var button_default = /* @__PURE__ */ defineComponent({
818
822
  const type = useButtonType(() => props.type);
819
823
  const form = useButtonForm(() => props.form);
820
824
  const widthClass = useFullWidth(() => props.fullWidth);
825
+ const isDisabled = computed(() => props.disabled || props.loading);
821
826
  function onClick(event) {
822
827
  emit("click", event);
823
828
  }
824
829
  return (_ctx, _cache) => {
825
830
  return openBlock(), createBlock(unref(VBtn), {
826
- disabled: props.disabled,
831
+ disabled: isDisabled.value,
827
832
  loading: props.loading,
828
833
  "data-testid": props.dataTestid,
829
834
  variant: unref(variant),
@@ -1080,7 +1085,6 @@ var dialog_host_default = /* @__PURE__ */ defineComponent({
1080
1085
  show();
1081
1086
  }
1082
1087
  async function select(current, action) {
1083
- if (isRunning.value) return;
1084
1088
  requests.value.shift();
1085
1089
  selected.value = action;
1086
1090
  await current.select(action?.value);
@@ -1,4 +1,4 @@
1
- import { i as FeedbackColorVariant, n as ButtonVariant, r as ColorVariant } from "./types-DNT_odv7.js";
1
+ import { i as FeedbackColorVariant, n as ButtonVariant, r as ColorVariant } from "./types-CjaJ2WAC.js";
2
2
  import { ComputedRef, MaybeRefOrGetter } from "vue";
3
3
  //#region src/composables/dialogs/types.d.ts
4
4
  interface ToastOptions {
@@ -1,5 +1,6 @@
1
1
  import { i as useDialog, o as useToast, t as openDialog } from "./use-dialog-Ck2_ZW7T.js";
2
2
  import { computed, onActivated, onDeactivated, onMounted, onUnmounted, ref, toValue, watch } from "vue";
3
+ import { isDeepEqual } from "@nexdom/shared/utils";
3
4
  import { onBeforeRouteLeave } from "vue-router";
4
5
  //#region src/composables/dialogs/use-run-or-toast.ts
5
6
  const { toast } = useToast();
@@ -115,32 +116,6 @@ function useConfirm() {
115
116
  };
116
117
  }
117
118
  //#endregion
118
- //#region src/utils/is-deep-equal.ts
119
- /**
120
- * Compares two values in depth, as a form would: key order doesn't matter, a key holding
121
- * `undefined` equals a missing key, dates are compared by their time and arrays item by item, in
122
- * order. Only plain objects are compared by their keys: other objects (e.g. `File`, `Map`, `Set`
123
- * or class instances) and the remaining values are compared with `Object.is`, so `NaN` equals
124
- * `NaN`, `0` differs from `-0`, and `null`, `""` and `undefined` differ from each other.
125
- */
126
- function isDeepEqual(a, b) {
127
- if (Object.is(a, b)) return true;
128
- if (a instanceof Date && b instanceof Date) return Object.is(a.getTime(), b.getTime());
129
- if (Array.isArray(a) && Array.isArray(b)) return a.length === b.length && a.every((item, index) => isDeepEqual(item, b[index]));
130
- if (!isPlainObject(a) || !isPlainObject(b)) return false;
131
- return [.../* @__PURE__ */ new Set([...Object.keys(a), ...Object.keys(b)])].every((key) => isDeepEqual(a[key], b[key]));
132
- }
133
- /**
134
- * Whether the value is an object literal or an object without prototype. Checks the prototype's
135
- * prototype instead of comparing it to `Object.prototype`, since objects from other realms (e.g.
136
- * iframes, or `structuredClone` in some test environments) have their own `Object.prototype`.
137
- */
138
- function isPlainObject(value) {
139
- if (value == null) return false;
140
- const prototype = Object.getPrototypeOf(value);
141
- return prototype === null || Object.getPrototypeOf(prototype) === null;
142
- }
143
- //#endregion
144
119
  //#region src/composables/navigation/use-unsaved-changes.ts
145
120
  /**
146
121
  * Calls whose page is on display with unsaved changes. The `beforeunload` listener is registered
@@ -32,8 +32,11 @@ type ButtonProps = {
32
32
  */
33
33
  disabled?: boolean;
34
34
  /**
35
- * Displays a loading indicator on the button, disabling interaction.
36
- * The button keeps its text as accessible name and is marked as busy, and
35
+ * Displays a loading indicator on the button and disables it while active, as `disabled` does:
36
+ * it can't be clicked or focused, `click` isn't emitted and its form isn't submitted, including
37
+ * by pressing `Enter` in one of the form's fields when it's the form's first submit button. It
38
+ * looks disabled, with the indicator, and loses focus if focused when loading starts, as any
39
+ * disabled button does. The button keeps its text as accessible name and is marked as busy, and
37
40
  * assistive technologies ignore the indicator.
38
41
  * @default false
39
42
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nexdom/uimed-vue",
3
- "version": "2.0.0-beta.32",
3
+ "version": "2.0.0-beta.34",
4
4
  "description": "A ui framework for NEXDOM applications.",
5
5
  "keywords": [
6
6
  "lib",
@@ -55,7 +55,7 @@
55
55
  "@commitlint/cli": "^21.2.1",
56
56
  "@commitlint/config-conventional": "^21.2.0",
57
57
  "@mdi/font": "^7.4.47",
58
- "@nexdom/shared": "^2.1.1",
58
+ "@nexdom/shared": "^2.3.0",
59
59
  "@playwright/test": "^1.62.1",
60
60
  "@sonar/scan": "^5.0.0",
61
61
  "@stryker-mutator/core": "^10.0.0",
@@ -87,7 +87,7 @@
87
87
  },
88
88
  "peerDependencies": {
89
89
  "@mdi/font": "^7.4.47",
90
- "@nexdom/shared": "^2.1.1",
90
+ "@nexdom/shared": "^2.3.0",
91
91
  "resize-observer-polyfill": "^1.5.1",
92
92
  "sass-embedded": "^1.103.1",
93
93
  "vite-plus": "^1.0.0",