@webitel/ui-datalist 1.1.32 → 1.1.33

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webitel/ui-datalist",
3
- "version": "1.1.32",
3
+ "version": "1.1.33",
4
4
  "description": "Toolkit for building data lists in webitel ui system",
5
5
  "scripts": {
6
6
  "build:types": "vue-tsc -p ./tsconfig.build.json",
@@ -1,6 +1,7 @@
1
+ import type { RegleSchema } from '@regle/schemas';
1
2
  import { refDebounced } from '@vueuse/core';
2
3
  import { type StoreDefinition, storeToRefs } from 'pinia';
3
- import { onUnmounted, watch } from 'vue';
4
+ import { onUnmounted, type Ref, watch } from 'vue';
4
5
 
5
6
  import { useCardAnyFieldEditedWatcher } from './useCardAnyFieldEditedWatcher';
6
7
  import { useCardIsNew } from './useCardIsNew';
@@ -12,9 +13,18 @@ import { useItemCardSaveText } from './useItemCardSaveText';
12
13
  export const useCardComponent = <CardEntity>({
13
14
  useCardStore,
14
15
  onLoadErrorHandler,
16
+ manualSetup = false,
15
17
  }: {
16
18
  useCardStore: StoreDefinition;
17
19
  onLoadErrorHandler?: (err: unknown) => void;
20
+ /**
21
+ * When `true` — the composable skips automatic initialization and
22
+ * `onUnmounted` reset. Use this when you need manual control over
23
+ * the card lifecycle (e.g. inside `useNestedCardComponent`).
24
+ *
25
+ * @default false
26
+ */
27
+ manualSetup?: boolean;
18
28
  }) => {
19
29
  const cardStore = useCardStore();
20
30
 
@@ -29,13 +39,9 @@ export const useCardComponent = <CardEntity>({
29
39
 
30
40
  const { initialize, saveItem, $reset } = cardStore;
31
41
 
32
- const { routeId } = useCardRouting({
33
- itemId,
34
- });
35
-
36
42
  const { modelValue, validationFields, hasValidationErrors, validate } =
37
- useCardValidation({
38
- validationSchema,
43
+ useCardValidation<CardEntity>({
44
+ validationSchema: validationSchema as Ref<RegleSchema<CardEntity>>,
39
45
  });
40
46
 
41
47
  const { isAnyFieldEdited } = useCardAnyFieldEditedWatcher({
@@ -59,11 +65,17 @@ export const useCardComponent = <CardEntity>({
59
65
  saveItem,
60
66
  });
61
67
 
62
- initialize({
63
- itemId: routeId.value,
68
+ const { routeId } = useCardRouting({
69
+ itemId,
70
+ manualSetup,
64
71
  });
65
72
 
66
- onUnmounted($reset);
73
+ if (!manualSetup) {
74
+ initialize({
75
+ itemId: routeId.value,
76
+ });
77
+ onUnmounted($reset);
78
+ }
67
79
 
68
80
  watch(error, (err) => {
69
81
  if (onLoadErrorHandler) onLoadErrorHandler(err);
@@ -3,27 +3,47 @@ import { useRoute, useRouter } from 'vue-router';
3
3
 
4
4
  import type { CardItemId } from '../types/CardStore.types';
5
5
 
6
- export const useCardRouting = ({ itemId }: { itemId: Ref<CardItemId> }) => {
6
+ /**
7
+ * Routing logic shared by top-level and nested card components.
8
+ *
9
+ * - `routeParamName` — which `route.params` key holds the item ID (default: `'id'`)
10
+ * - `parentId` — when provided, the card is treated as nested: URL is updated
11
+ * only when a newly created item receives its server-assigned ID
12
+ */
13
+ export const useCardRouting = ({
14
+ itemId,
15
+ routeParamName = 'id',
16
+ parentId,
17
+ manualSetup = false,
18
+ }: {
19
+ itemId: Ref<CardItemId>;
20
+ routeParamName?: string;
21
+ parentId?: string;
22
+ manualSetup?: boolean;
23
+ }) => {
7
24
  const router = useRouter();
8
25
  const route = useRoute();
9
26
 
10
- const routeId = computed(() => {
11
- return route.params.id;
12
- });
27
+ const routeId = computed(() => route.params[routeParamName]);
13
28
 
14
- const unwatch = watch(itemId, async (next, prev) => {
15
- if (next && !prev) {
16
- await router.replace({
17
- params: {
18
- ...route.params,
19
- id: next,
20
- },
21
- });
22
- unwatch(); // Stop watching after successful redirect "null" -> "id"
23
- }
24
- });
29
+ if (!manualSetup) {
30
+ const unwatch = watch(itemId, async (next, prev) => {
31
+ if (next && !prev) {
32
+ if (!parentId || routeId.value === 'new') {
33
+ await router.replace({
34
+ params: {
35
+ ...route.params,
36
+ [routeParamName]: next,
37
+ },
38
+ });
39
+ }
40
+ unwatch();
41
+ }
42
+ });
43
+ }
25
44
 
26
45
  return {
27
46
  routeId,
47
+ parentId,
28
48
  };
29
49
  };
@@ -0,0 +1,70 @@
1
+ import { type StoreDefinition, storeToRefs } from 'pinia';
2
+ import { watch } from 'vue';
3
+
4
+ import { useCardComponent } from './useCardComponent';
5
+ import { useCardRouting } from './useCardRouting';
6
+
7
+ /**
8
+ * Composable for nested (popup) card components.
9
+ *
10
+ * Wraps `useCardComponent` with `manualSetup: true` and delegates
11
+ * routing to `useCardRouting`. Pass `parentId` from the component —
12
+ * its presence indicates a nested card context.
13
+ *
14
+ * @example
15
+ * ```ts
16
+ * const parentId = computed(() => route.params.id ?? null);
17
+ *
18
+ * const { isNew, hasValidationErrors, save } = useNestedCardComponent({
19
+ * useCardStore: useSomeCardStore,
20
+ * routeParamName: 'conditionId',
21
+ * parentId,
22
+ * });
23
+ * ```
24
+ */
25
+ export const useNestedCardComponent = <CardEntity>({
26
+ useCardStore,
27
+ onLoadErrorHandler,
28
+ routeParamName,
29
+ parentId,
30
+ }: {
31
+ useCardStore: StoreDefinition;
32
+ onLoadErrorHandler?: (err: unknown) => void;
33
+ routeParamName: string;
34
+ parentId?: string;
35
+ }) => {
36
+ const cardSetup = useCardComponent<CardEntity>({
37
+ useCardStore,
38
+ onLoadErrorHandler,
39
+ manualSetup: true,
40
+ });
41
+
42
+ const cardStore = useCardStore();
43
+ const { itemId } = storeToRefs(cardStore);
44
+ const { initialize, $reset } = cardStore;
45
+
46
+ const { routeId } = useCardRouting({
47
+ itemId,
48
+ routeParamName,
49
+ parentId,
50
+ });
51
+
52
+ watch(
53
+ routeId,
54
+ (value) => {
55
+ if (value) {
56
+ initialize({
57
+ itemId: value === 'new' ? null : value,
58
+ parentId,
59
+ });
60
+ } else {
61
+ $reset();
62
+ }
63
+ },
64
+ {
65
+ immediate: true,
66
+ },
67
+ );
68
+
69
+ return cardSetup;
70
+ };
@@ -1,2 +1,4 @@
1
1
  export * from './composables/useCardComponent';
2
+ export * from './composables/useNestedCardComponent';
2
3
  export * from './stores/createCardStore';
4
+ export * from './types/CardValidationFields.types';
@@ -0,0 +1,5 @@
1
+ import type { RegleSchemaFieldStatus } from '@regle/schemas';
2
+
3
+ export type CardValidationFields<T> = {
4
+ [K in keyof T]: RegleSchemaFieldStatus<T[K]>;
5
+ };
@@ -1,16 +1,25 @@
1
1
  import { type StoreDefinition } from 'pinia';
2
- export declare const useCardComponent: <CardEntity>({ useCardStore, onLoadErrorHandler, }: {
2
+ import { type Ref } from 'vue';
3
+ export declare const useCardComponent: <CardEntity>({ useCardStore, onLoadErrorHandler, manualSetup, }: {
3
4
  useCardStore: StoreDefinition;
4
5
  onLoadErrorHandler?: (err: unknown) => void;
6
+ /**
7
+ * When `true` — the composable skips automatic initialization and
8
+ * `onUnmounted` reset. Use this when you need manual control over
9
+ * the card lifecycle (e.g. inside `useNestedCardComponent`).
10
+ *
11
+ * @default false
12
+ */
13
+ manualSetup?: boolean;
5
14
  }) => {
6
- modelValue: import("vue").ComputedRef<unknown>;
7
- debouncedIsLoading: Readonly<import("vue").Ref<any, any>>;
8
- originalItemInstance: import("vue").Ref<any, any> & import("vue").ComputedRef<any>;
9
- error: import("vue").Ref<any, any> & import("vue").ComputedRef<any>;
15
+ modelValue: import("vue").ComputedRef<import("@regle/core").JoinDiscriminatedUnions<import("vue").UnwrapNestedRefs<CardEntity>> | import("@regle/schemas").RegleSchemaStatus<CardEntity, unknown, true>["$value"]>;
16
+ debouncedIsLoading: Readonly<Ref<any, any>>;
17
+ originalItemInstance: Ref<any, any> & import("vue").ComputedRef<any>;
18
+ error: Ref<any, any> & import("vue").ComputedRef<any>;
10
19
  isNew: import("vue").ComputedRef<boolean>;
11
20
  saveText: import("vue").ComputedRef<any>;
12
- hasValidationErrors: import("vue").ComputedRef<boolean>;
13
- isAnyFieldEdited: import("vue").Ref<boolean, boolean>;
14
- validationFields: import("vue").ComputedRef<{} | ({} & {})>;
21
+ hasValidationErrors: import("vue").ComputedRef<boolean | import("@regle/schemas").RegleSchemaStatus<CardEntity, unknown, true>["$error"]>;
22
+ isAnyFieldEdited: Ref<boolean, boolean>;
23
+ validationFields: import("vue").ComputedRef<(import("@regle/core").HasNamedKeys<CardEntity> extends true ? { readonly [TKey in keyof import("@regle/core").JoinDiscriminatedUnions<CardEntity>]: TKey extends keyof import("@regle/core").JoinDiscriminatedUnions<CardEntity> ? import("@regle/schemas").InferRegleSchemaStatusType<NonNullable<import("@regle/core").JoinDiscriminatedUnions<CardEntity>[TKey]>, unknown> : never; } & { readonly [TKey_1 in keyof import("@regle/core").JoinDiscriminatedUnions<CardEntity> as TKey_1 extends keyof import("@regle/core").JoinDiscriminatedUnions<CardEntity> ? import("@regle/core").JoinDiscriminatedUnions<CardEntity>[TKey_1] extends NonNullable<import("@regle/core").JoinDiscriminatedUnions<CardEntity>[TKey_1]> ? TKey_1 : never : never]-?: TKey_1 extends keyof import("@regle/core").JoinDiscriminatedUnions<CardEntity> ? import("@regle/schemas").InferRegleSchemaStatusType<NonNullable<import("@regle/core").JoinDiscriminatedUnions<CardEntity>[TKey_1]>, unknown> : never; } : {}) | { [TIndex in keyof import("@regle/core").TupleToPlainObj<import("type-fest").UnionToTuple<CardEntity, import("type-fest").UnionToIntersection<CardEntity extends any ? () => CardEntity : never> extends () => (infer R) ? R : never>>]: TIndex extends `${infer TIndexInt extends number}` ? { [TKey_2 in keyof import("type-fest").UnionToTuple<CardEntity, import("type-fest").UnionToIntersection<CardEntity extends any ? () => CardEntity : never> extends () => (infer R) ? R : never>[TIndexInt] as NonNullable<import("type-fest").UnionToTuple<CardEntity, import("type-fest").UnionToIntersection<CardEntity extends any ? () => CardEntity : never> extends () => (infer R) ? R : never>[TIndexInt]>[TKey_2] extends import("type-fest").UnionToTuple<CardEntity, import("type-fest").UnionToIntersection<CardEntity extends any ? () => CardEntity : never> extends () => (infer R) ? R : never>[TIndexInt][TKey_2] ? TKey_2 : never]-?: import("@regle/schemas").InferRegleSchemaStatusType<NonNullable<import("type-fest").UnionToTuple<CardEntity, import("type-fest").UnionToIntersection<CardEntity extends any ? () => CardEntity : never> extends () => (infer R) ? R : never>[TIndexInt]>[TKey_2], unknown>; } & { [TKey_3 in keyof import("type-fest").UnionToTuple<CardEntity, import("type-fest").UnionToIntersection<CardEntity extends any ? () => CardEntity : never> extends () => (infer R) ? R : never>[TIndexInt] as NonNullable<import("type-fest").UnionToTuple<CardEntity, import("type-fest").UnionToIntersection<CardEntity extends any ? () => CardEntity : never> extends () => (infer R) ? R : never>[TIndexInt]>[TKey_3] extends import("type-fest").UnionToTuple<CardEntity, import("type-fest").UnionToIntersection<CardEntity extends any ? () => CardEntity : never> extends () => (infer R) ? R : never>[TIndexInt][TKey_3] ? never : TKey_3]?: import("@regle/schemas").InferRegleSchemaStatusType<NonNullable<import("type-fest").UnionToTuple<CardEntity, import("type-fest").UnionToIntersection<CardEntity extends any ? () => CardEntity : never> extends () => (infer R) ? R : never>[TIndexInt]>[TKey_3], unknown>; } : {}; }[keyof import("type-fest").UnionToTuple<CardEntity, import("type-fest").UnionToIntersection<CardEntity extends any ? () => CardEntity : never> extends () => (infer R) ? R : never> & `${number}`]>;
15
24
  save: () => Promise<unknown>;
16
25
  };
@@ -1,7 +1,18 @@
1
1
  import { type Ref } from 'vue';
2
2
  import type { CardItemId } from '../types/CardStore.types';
3
- export declare const useCardRouting: ({ itemId }: {
3
+ /**
4
+ * Routing logic shared by top-level and nested card components.
5
+ *
6
+ * - `routeParamName` — which `route.params` key holds the item ID (default: `'id'`)
7
+ * - `parentId` — when provided, the card is treated as nested: URL is updated
8
+ * only when a newly created item receives its server-assigned ID
9
+ */
10
+ export declare const useCardRouting: ({ itemId, routeParamName, parentId, manualSetup, }: {
4
11
  itemId: Ref<CardItemId>;
12
+ routeParamName?: string;
13
+ parentId?: string;
14
+ manualSetup?: boolean;
5
15
  }) => {
6
16
  routeId: import("vue").ComputedRef<any>;
17
+ parentId: string;
7
18
  };
@@ -0,0 +1,36 @@
1
+ import { type StoreDefinition } from 'pinia';
2
+ /**
3
+ * Composable for nested (popup) card components.
4
+ *
5
+ * Wraps `useCardComponent` with `manualSetup: true` and delegates
6
+ * routing to `useCardRouting`. Pass `parentId` from the component —
7
+ * its presence indicates a nested card context.
8
+ *
9
+ * @example
10
+ * ```ts
11
+ * const parentId = computed(() => route.params.id ?? null);
12
+ *
13
+ * const { isNew, hasValidationErrors, save } = useNestedCardComponent({
14
+ * useCardStore: useSomeCardStore,
15
+ * routeParamName: 'conditionId',
16
+ * parentId,
17
+ * });
18
+ * ```
19
+ */
20
+ export declare const useNestedCardComponent: <CardEntity>({ useCardStore, onLoadErrorHandler, routeParamName, parentId, }: {
21
+ useCardStore: StoreDefinition;
22
+ onLoadErrorHandler?: (err: unknown) => void;
23
+ routeParamName: string;
24
+ parentId?: string;
25
+ }) => {
26
+ modelValue: import("vue").ComputedRef<import("@regle/core").JoinDiscriminatedUnions<import("vue").UnwrapNestedRefs<CardEntity>> | import("@regle/schemas").RegleSchemaStatus<CardEntity, unknown, true>["$value"]>;
27
+ debouncedIsLoading: Readonly<import("vue").Ref<any, any>>;
28
+ originalItemInstance: import("vue").Ref<any, any> & import("vue").ComputedRef<any>;
29
+ error: import("vue").Ref<any, any> & import("vue").ComputedRef<any>;
30
+ isNew: import("vue").ComputedRef<boolean>;
31
+ saveText: import("vue").ComputedRef<any>;
32
+ hasValidationErrors: import("vue").ComputedRef<boolean | import("@regle/schemas").RegleSchemaStatus<CardEntity, unknown, true>["$error"]>;
33
+ isAnyFieldEdited: import("vue").Ref<boolean, boolean>;
34
+ validationFields: import("vue").ComputedRef<(import("@regle/core").HasNamedKeys<CardEntity> extends true ? { readonly [TKey in keyof import("@regle/core").JoinDiscriminatedUnions<CardEntity>]: TKey extends keyof import("@regle/core").JoinDiscriminatedUnions<CardEntity> ? import("@regle/schemas").InferRegleSchemaStatusType<NonNullable<import("@regle/core").JoinDiscriminatedUnions<CardEntity>[TKey]>, unknown> : never; } & { readonly [TKey_1 in keyof import("@regle/core").JoinDiscriminatedUnions<CardEntity> as TKey_1 extends keyof import("@regle/core").JoinDiscriminatedUnions<CardEntity> ? import("@regle/core").JoinDiscriminatedUnions<CardEntity>[TKey_1] extends NonNullable<import("@regle/core").JoinDiscriminatedUnions<CardEntity>[TKey_1]> ? TKey_1 : never : never]-?: TKey_1 extends keyof import("@regle/core").JoinDiscriminatedUnions<CardEntity> ? import("@regle/schemas").InferRegleSchemaStatusType<NonNullable<import("@regle/core").JoinDiscriminatedUnions<CardEntity>[TKey_1]>, unknown> : never; } : {}) | { [TIndex in keyof import("@regle/core").TupleToPlainObj<import("type-fest").UnionToTuple<CardEntity, import("type-fest").UnionToIntersection<CardEntity extends any ? () => CardEntity : never> extends () => (infer R) ? R : never>>]: TIndex extends `${infer TIndexInt extends number}` ? { [TKey_2 in keyof import("type-fest").UnionToTuple<CardEntity, import("type-fest").UnionToIntersection<CardEntity extends any ? () => CardEntity : never> extends () => (infer R) ? R : never>[TIndexInt] as NonNullable<import("type-fest").UnionToTuple<CardEntity, import("type-fest").UnionToIntersection<CardEntity extends any ? () => CardEntity : never> extends () => (infer R) ? R : never>[TIndexInt]>[TKey_2] extends import("type-fest").UnionToTuple<CardEntity, import("type-fest").UnionToIntersection<CardEntity extends any ? () => CardEntity : never> extends () => (infer R) ? R : never>[TIndexInt][TKey_2] ? TKey_2 : never]-?: import("@regle/schemas").InferRegleSchemaStatusType<NonNullable<import("type-fest").UnionToTuple<CardEntity, import("type-fest").UnionToIntersection<CardEntity extends any ? () => CardEntity : never> extends () => (infer R) ? R : never>[TIndexInt]>[TKey_2], unknown>; } & { [TKey_3 in keyof import("type-fest").UnionToTuple<CardEntity, import("type-fest").UnionToIntersection<CardEntity extends any ? () => CardEntity : never> extends () => (infer R) ? R : never>[TIndexInt] as NonNullable<import("type-fest").UnionToTuple<CardEntity, import("type-fest").UnionToIntersection<CardEntity extends any ? () => CardEntity : never> extends () => (infer R) ? R : never>[TIndexInt]>[TKey_3] extends import("type-fest").UnionToTuple<CardEntity, import("type-fest").UnionToIntersection<CardEntity extends any ? () => CardEntity : never> extends () => (infer R) ? R : never>[TIndexInt][TKey_3] ? never : TKey_3]?: import("@regle/schemas").InferRegleSchemaStatusType<NonNullable<import("type-fest").UnionToTuple<CardEntity, import("type-fest").UnionToIntersection<CardEntity extends any ? () => CardEntity : never> extends () => (infer R) ? R : never>[TIndexInt]>[TKey_3], unknown>; } : {}; }[keyof import("type-fest").UnionToTuple<CardEntity, import("type-fest").UnionToIntersection<CardEntity extends any ? () => CardEntity : never> extends () => (infer R) ? R : never> & `${number}`]>;
35
+ save: () => Promise<unknown>;
36
+ };
@@ -1,2 +1,4 @@
1
1
  export * from './composables/useCardComponent';
2
+ export * from './composables/useNestedCardComponent';
2
3
  export * from './stores/createCardStore';
4
+ export * from './types/CardValidationFields.types';
@@ -0,0 +1,4 @@
1
+ import type { RegleSchemaFieldStatus } from '@regle/schemas';
2
+ export type CardValidationFields<T> = {
3
+ [K in keyof T]: RegleSchemaFieldStatus<T[K]>;
4
+ };