nuance-ui 0.1.53 → 0.1.54

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/dist/module.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "compatibility": {
5
5
  "nuxt": "^4.0.0"
6
6
  },
7
- "version": "0.1.53",
7
+ "version": "0.1.54",
8
8
  "builder": {
9
9
  "@nuxt/module-builder": "1.0.2",
10
10
  "unbuild": "3.6.1"
package/dist/module.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { defineNuxtModule, createResolver, addComponentsDir, addImportsDir } from '@nuxt/kit';
1
+ import { defineNuxtModule, createResolver, addComponentsDir, addImportsDir, addPlugin } from '@nuxt/kit';
2
2
  import { defu } from 'defu';
3
3
 
4
4
  const defaultConfig = {
@@ -32,12 +32,12 @@ const module$1 = defineNuxtModule({
32
32
  defaults: defaultConfig,
33
33
  setup(options, nuxt) {
34
34
  const { resolve } = createResolver(import.meta.url);
35
- nuxt.options.alias["@nui"] = resolve("./runtime");
36
35
  nuxt.options.alias["@nui/composals"] = resolve("./runtime/composals");
37
36
  nuxt.options.alias["@nui/components"] = resolve("./runtime/components");
38
37
  nuxt.options.alias["@nui/utils"] = resolve("./runtime/utils");
39
38
  nuxt.options.alias["@nui/helpers"] = resolve("./runtime/helpers");
40
39
  nuxt.options.alias["@nui/types"] = resolve("./runtime/types");
40
+ nuxt.options.alias["@nui/modals"] = resolve("./runtime/plugins/modals");
41
41
  nuxt.options.appConfig.nui = defu(nuxt.options.appConfig.nui || {}, defaultConfig);
42
42
  nuxt.options.postcss = nuxt.options.postcss || {};
43
43
  nuxt.options.postcss.plugins = nuxt.options.postcss.plugins || {};
@@ -70,6 +70,10 @@ const module$1 = defineNuxtModule({
70
70
  addImportsDir(resolve("./runtime/composals"));
71
71
  addImportsDir(resolve("./runtime/helpers"));
72
72
  }
73
+ addPlugin({
74
+ src: resolve("./runtime/plugins/modals/plugin.client.ts"),
75
+ mode: "client"
76
+ });
73
77
  nuxt.options.css.push(resolve("./runtime/styles/global.css"));
74
78
  }
75
79
  });
@@ -25,15 +25,15 @@ type __VLS_Slots = {} & {
25
25
  default?: (props: typeof __VLS_8) => any;
26
26
  };
27
27
  declare const __VLS_base: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
28
- clear: () => any;
29
28
  select: (args_0: number) => any;
29
+ clear: () => any;
30
30
  close: (args_0: import("./types/index.js").ComboboxDropdownEventSource) => any;
31
31
  submit: (args_0: string, args_1: import("./types/index.js").ComboboxItem) => any;
32
32
  open: (args_0: import("./types/index.js").ComboboxDropdownEventSource) => any;
33
33
  "update:open": (value: boolean) => any;
34
34
  }, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
35
- onClear?: (() => any) | undefined;
36
35
  onSelect?: ((args_0: number) => any) | undefined;
36
+ onClear?: (() => any) | undefined;
37
37
  onClose?: ((args_0: import("./types/index.js").ComboboxDropdownEventSource) => any) | undefined;
38
38
  onSubmit?: ((args_0: string, args_1: import("./types/index.js").ComboboxItem) => any) | undefined;
39
39
  onOpen?: ((args_0: import("./types/index.js").ComboboxDropdownEventSource) => any) | undefined;
@@ -25,15 +25,15 @@ type __VLS_Slots = {} & {
25
25
  default?: (props: typeof __VLS_8) => any;
26
26
  };
27
27
  declare const __VLS_base: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
28
- clear: () => any;
29
28
  select: (args_0: number) => any;
29
+ clear: () => any;
30
30
  close: (args_0: import("./types/index.js").ComboboxDropdownEventSource) => any;
31
31
  submit: (args_0: string, args_1: import("./types/index.js").ComboboxItem) => any;
32
32
  open: (args_0: import("./types/index.js").ComboboxDropdownEventSource) => any;
33
33
  "update:open": (value: boolean) => any;
34
34
  }, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
35
- onClear?: (() => any) | undefined;
36
35
  onSelect?: ((args_0: number) => any) | undefined;
36
+ onClear?: (() => any) | undefined;
37
37
  onClose?: ((args_0: import("./types/index.js").ComboboxDropdownEventSource) => any) | undefined;
38
38
  onSubmit?: ((args_0: string, args_1: import("./types/index.js").ComboboxItem) => any) | undefined;
39
39
  onOpen?: ((args_0: import("./types/index.js").ComboboxDropdownEventSource) => any) | undefined;
@@ -1,4 +1,4 @@
1
- import { $modals } from "@nui/composals";
1
+ import { $modals } from "../../../plugins/modals/index.js";
2
2
  import ConfirmModal from "./confirm-modal.vue";
3
3
  export const openConfirmModal = $modals.create(
4
4
  "confirm",
@@ -1,5 +1,5 @@
1
1
  <script setup>
2
- import { $modals } from "@nui/composals";
2
+ import { $modals } from "../../plugins/modals";
3
3
  </script>
4
4
 
5
5
  <template>
@@ -24,8 +24,8 @@ declare const __VLS_export: <Value extends string = string, Ext extends Combobox
24
24
  modelValue?: ComboboxItem<Value, Ext> | null;
25
25
  search?: string;
26
26
  }) & {
27
- onClear?: (() => any) | undefined;
28
27
  onSelect?: ((args_0: number) => any) | undefined;
28
+ onClear?: (() => any) | undefined;
29
29
  onClose?: ((args_0: import("..").ComboboxDropdownEventSource) => any) | undefined;
30
30
  onSubmit?: ((args_0: string, args_1: ComboboxItem) => any) | undefined;
31
31
  "onUpdate:modelValue"?: ((value: ComboboxItem<Value, Ext> | null) => any) | undefined;
@@ -48,7 +48,7 @@ declare const __VLS_export: <Value extends string = string, Ext extends Combobox
48
48
  } & {
49
49
  rightSection?: (props: {}) => any;
50
50
  };
51
- emit: (((evt: "clear") => void) & ((evt: "select", args_0: number) => void) & ((evt: "close", args_0: import("..").ComboboxDropdownEventSource) => void) & ((evt: "submit", args_0: string, args_1: ComboboxItem) => void) & ((evt: "open", args_0: import("..").ComboboxDropdownEventSource) => void)) & (((event: "update:modelValue", value: ComboboxItem<Value, Ext> | null) => void) & ((event: "update:search", value: string) => void) & ((event: "update:open", value: boolean) => void));
51
+ emit: (((evt: "select", args_0: number) => void) & ((evt: "clear") => void) & ((evt: "close", args_0: import("..").ComboboxDropdownEventSource) => void) & ((evt: "submit", args_0: string, args_1: ComboboxItem) => void) & ((evt: "open", args_0: import("..").ComboboxDropdownEventSource) => void)) & (((event: "update:modelValue", value: ComboboxItem<Value, Ext> | null) => void) & ((event: "update:search", value: string) => void) & ((event: "update:open", value: boolean) => void));
52
52
  }>) => import("vue").VNode & {
53
53
  __ctx?: Awaited<typeof __VLS_setup>;
54
54
  };
@@ -24,8 +24,8 @@ declare const __VLS_export: <Value extends string = string, Ext extends Combobox
24
24
  modelValue?: ComboboxItem<Value, Ext> | null;
25
25
  search?: string;
26
26
  }) & {
27
- onClear?: (() => any) | undefined;
28
27
  onSelect?: ((args_0: number) => any) | undefined;
28
+ onClear?: (() => any) | undefined;
29
29
  onClose?: ((args_0: import("..").ComboboxDropdownEventSource) => any) | undefined;
30
30
  onSubmit?: ((args_0: string, args_1: ComboboxItem) => any) | undefined;
31
31
  "onUpdate:modelValue"?: ((value: ComboboxItem<Value, Ext> | null) => any) | undefined;
@@ -48,7 +48,7 @@ declare const __VLS_export: <Value extends string = string, Ext extends Combobox
48
48
  } & {
49
49
  rightSection?: (props: {}) => any;
50
50
  };
51
- emit: (((evt: "clear") => void) & ((evt: "select", args_0: number) => void) & ((evt: "close", args_0: import("..").ComboboxDropdownEventSource) => void) & ((evt: "submit", args_0: string, args_1: ComboboxItem) => void) & ((evt: "open", args_0: import("..").ComboboxDropdownEventSource) => void)) & (((event: "update:modelValue", value: ComboboxItem<Value, Ext> | null) => void) & ((event: "update:search", value: string) => void) & ((event: "update:open", value: boolean) => void));
51
+ emit: (((evt: "select", args_0: number) => void) & ((evt: "clear") => void) & ((evt: "close", args_0: import("..").ComboboxDropdownEventSource) => void) & ((evt: "submit", args_0: string, args_1: ComboboxItem) => void) & ((evt: "open", args_0: import("..").ComboboxDropdownEventSource) => void)) & (((event: "update:modelValue", value: ComboboxItem<Value, Ext> | null) => void) & ((event: "update:search", value: string) => void) & ((event: "update:open", value: boolean) => void));
52
52
  }>) => import("vue").VNode & {
53
53
  __ctx?: Awaited<typeof __VLS_setup>;
54
54
  };
@@ -1,5 +1,5 @@
1
1
  export * from './use-active-link.js';
2
2
  export * from './use-date-config.js';
3
- export * from './use-modal/index.js';
3
+ export * from './use-modal.js';
4
4
  export * from './use-style-resolver.js';
5
5
  export * from './use-theme.js';
@@ -1,5 +1,5 @@
1
1
  export * from "./use-active-link.js";
2
2
  export * from "./use-date-config.js";
3
- export * from "./use-modal/index.js";
3
+ export * from "./use-modal.js";
4
4
  export * from "./use-style-resolver.js";
5
5
  export * from "./use-theme.js";
@@ -21,8 +21,8 @@ id: string): {
21
21
  *
22
22
  * Setting to `true` reopens the modal, setting to `false` calls `reject`
23
23
  */
24
- opened: import("vue").WritableComputedRef<boolean, boolean>;
24
+ opened: import("vue").WritableComputedRef<any, boolean>;
25
25
  /** closes the modal and resolves the promise */
26
- resolve: (reason: Resolve) => void;
27
- reject: () => void;
26
+ resolve: (reason: Resolve) => any;
27
+ reject: () => any;
28
28
  };
@@ -1,10 +1,11 @@
1
+ import { useNuxtApp } from "#app";
1
2
  import { computed } from "vue";
2
- import { $modals } from "./modal-manager.js";
3
3
  export function useModal(id) {
4
- const state = computed(() => $modals.state(id));
4
+ const manager = useNuxtApp().$modals;
5
+ const state = computed(() => manager.state(id));
5
6
  const opened = computed({
6
7
  get: () => state.value?.opened,
7
- set: (opened2) => opened2 ? $modals.show(id, state.value.props) : $modals.reject(id, "cancel")
8
+ set: (opened2) => opened2 ? manager.show(id, state.value.props) : manager.reject(id, "cancel")
8
9
  });
9
10
  if (!state)
10
11
  throw new Error(`Modal ${id} is not exist`);
@@ -16,7 +17,7 @@ export function useModal(id) {
16
17
  */
17
18
  opened,
18
19
  /** closes the modal and resolves the promise */
19
- resolve: (reason) => $modals.resolve(id, reason),
20
- reject: () => $modals.reject(id)
20
+ resolve: (reason) => manager.resolve(id, reason),
21
+ reject: () => manager.reject(id)
21
22
  };
22
23
  }
@@ -0,0 +1 @@
1
+ export { $modals } from './plugin.client.js';
@@ -0,0 +1 @@
1
+ export { $modals } from "./plugin.client.js";
@@ -17,7 +17,7 @@ export interface ModalState<Props extends object = object, Resolve = unknown, Re
17
17
  reject: (reason?: Reject) => void;
18
18
  }
19
19
  /**
20
- * Singleton modal manager.
20
+ * Modal manager.
21
21
  *
22
22
  * Maintains a component registry and a reactive map of active modals.
23
23
  * Opening a modal returns a `Promise` that resolves via `hide`
@@ -31,9 +31,6 @@ export interface ModalState<Props extends object = object, Resolve = unknown, Re
31
31
  */
32
32
  export declare class ModalManager {
33
33
  #private;
34
- private constructor();
35
- /** Returns the singleton instance (creates on first access) */
36
- static get instance(): ModalManager;
37
34
  /** Reactive map of all active modals. Used by `ModalProvider` for rendering */
38
35
  get modals(): import("vue").Reactive<Map<string, ModalState<object, unknown, unknown>>>;
39
36
  /**
@@ -79,5 +76,3 @@ export declare class ModalManager {
79
76
  */
80
77
  state<Props extends object = object, Resolve = unknown, Reject = unknown>(id: string): ModalState<Props, Resolve, Reject>;
81
78
  }
82
- /** Global {@link ModalManager} instance for use throughout the application */
83
- export declare const $modals: ModalManager;
@@ -1,23 +1,14 @@
1
1
  import { markRaw, reactive } from "vue";
2
2
  export class ModalManager {
3
- static #instance = null;
4
3
  /** Reactive map of active modals */
5
4
  #modals = reactive(/* @__PURE__ */ new Map());
6
5
  /** Eagerly registered components (id → Component) */
7
6
  #registered = /* @__PURE__ */ new Map();
8
7
  /** Lazily registered loaders (id → loader) */
9
8
  #lazy = /* @__PURE__ */ new Map();
10
- constructor() {
11
- }
12
- /** Returns the singleton instance (creates on first access) */
13
- static get instance() {
14
- if (!ModalManager.#instance)
15
- ModalManager.#instance = new ModalManager();
16
- return ModalManager.#instance;
17
- }
18
9
  /** Reactive map of all active modals. Used by `ModalProvider` for rendering */
19
10
  get modals() {
20
- return ModalManager.instance.#modals;
11
+ return this.#modals;
21
12
  }
22
13
  // ── Facade ──
23
14
  /**
@@ -114,4 +105,3 @@ export class ModalManager {
114
105
  modal.reject?.(reason);
115
106
  }
116
107
  }
117
- export const $modals = ModalManager.instance;
@@ -0,0 +1,8 @@
1
+ import { ModalManager } from './modal-manager.js';
2
+ export declare const $modals: ModalManager;
3
+ declare const _default: import("#app").Plugin<{
4
+ modals: ModalManager;
5
+ }> & import("#app").ObjectPlugin<{
6
+ modals: ModalManager;
7
+ }>;
8
+ export default _default;
@@ -0,0 +1,10 @@
1
+ import { defineNuxtPlugin } from "#imports";
2
+ import { ModalManager } from "./modal-manager.js";
3
+ export const $modals = new ModalManager();
4
+ export default defineNuxtPlugin(() => {
5
+ return {
6
+ provide: {
7
+ modals: $modals
8
+ }
9
+ };
10
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nuance-ui",
3
- "version": "0.1.53",
3
+ "version": "0.1.54",
4
4
  "description": "A UI Library for Modern Web Apps, powered by Vue.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -1,302 +0,0 @@
1
- # Modal System
2
-
3
- Система управления модальными окнами на основе промисов. Позволяет открывать модалки императивно из любого места приложения и получать результат через `await`.
4
-
5
- ## Архитектура
6
-
7
- ```
8
- ModalManager (singleton) — хранит состояния всех модалок, управляет жизненным циклом
9
- ├─ create() / createLazy() — регистрирует компонент модалки и возвращает функцию-открывашку
10
- ├─ show() / hide() / reject() — императивное управление
11
- └─ state() — реактивное состояние для использования внутри компонента
12
-
13
- useModal(id) — composable для компонента модалки (opened + resolve)
14
-
15
- ModalProvider — рендерит все активные модалки в DOM
16
- ```
17
-
18
- ## Быстрый старт
19
-
20
- ### 1. Регистрация модалки
21
-
22
- ```ts
23
- // src/runtime/components/modals/_my-modal/index.ts
24
- import { $modals } from '@nui/composals'
25
-
26
- import MyModal from './my-modal.vue'
27
-
28
-
29
- export const openMyModal = $modals.create<MyModalProps, string>(
30
- 'my-modal',
31
- MyModal,
32
- )
33
- ```
34
-
35
- ### 2. Компонент модалки
36
-
37
- ```vue
38
- <!-- my-modal.vue -->
39
- <script setup lang="ts">
40
- import { useModal } from '@nui/composals'
41
-
42
-
43
- defineProps<{ message: string }>()
44
-
45
- const { opened, resolve } = useModal('my-modal')
46
- </script>
47
-
48
- <template>
49
- <ModalRoot v-model:open='opened'>
50
- <p>{{ message }}</p>
51
- <button @click="resolve('ok')">
52
- OK
53
- </button>
54
- </ModalRoot>
55
- </template>
56
- ```
57
-
58
- ### 3. Вызов из любого места
59
-
60
- ```ts
61
- const result = await openMyModal({ message: 'Hello!' })
62
- // result: 'ok'
63
- ```
64
-
65
- ---
66
-
67
- ## API
68
-
69
- ### `ModalManager`
70
-
71
- > Файл: `modal-manager.ts`
72
-
73
- Singleton-класс, управляющий реестром и жизненным циклом модальных окон. Экспортируется как `$modals`.
74
-
75
- ```ts
76
- import { $modals } from '@nui/composals'
77
- ```
78
-
79
- #### `create<TProps, TResult>(id, component)`
80
-
81
- Регистрирует компонент модалки и возвращает типизированную функцию для её открытия.
82
-
83
- ```ts
84
- const openModal = $modals.create<{ name: string }, boolean>(
85
- 'greeting',
86
- GreetingModal,
87
- )
88
-
89
- const confirmed = await openModal({ name: 'World' })
90
- ```
91
-
92
- - **id** — уникальный строковый идентификатор модалки
93
- - **component** — Vue-компонент
94
- - **Возвращает** — `(props?) => Promise<TResult>`
95
-
96
- #### `createLazy<TProps, TResult>(id, loader)`
97
-
98
- Аналогичен `create`, но компонент загружается лениво при первом открытии.
99
-
100
- ```ts
101
- const openHeavyModal = $modals.createLazy<HeavyProps, void>(
102
- 'heavy',
103
- () => import('./heavy-modal.vue'),
104
- )
105
- ```
106
-
107
- #### `show<T>(id, props?)`
108
-
109
- Открывает ранее зарегистрированную модалку по `id`. Возвращает `Promise<T>`.
110
-
111
- #### `hide(id, result?)`
112
-
113
- Закрывает модалку, резолвит промис переданным `result`.
114
-
115
- #### `reject(id, reason?)`
116
-
117
- Закрывает модалку, реджектит промис переданным `reason`.
118
-
119
- #### `state<Props, Resolve, Reject>(id)`
120
-
121
- Возвращает `ComputedRef<ModalState>` — реактивное состояние модалки. Используется внутри компонента модалки через `useModal`.
122
-
123
- #### `modals` (getter)
124
-
125
- `ShallowRef<Map<string, ModalState>>` — реактивная карта всех активных модалок. Используется в `ModalProvider` для рендеринга.
126
-
127
- #### Интерфейс `ModalState`
128
-
129
- ```ts
130
- interface ModalState<Props, Resolve, Reject> {
131
- id: string
132
- component: Component
133
- props: Props
134
- opened: boolean
135
- resolve: (value?: Resolve) => void
136
- reject: (reason?: Reject) => void
137
- }
138
- ```
139
-
140
- ---
141
-
142
- ### `useModal(id)`
143
-
144
- > Файл: `use-modal.ts`
145
-
146
- Composable для использования **внутри** компонента модалки. Связывает компонент с `ModalManager` по `id`.
147
-
148
- ```ts
149
- const { opened, resolve } = useModal<MyProps, ResultType>('my-modal')
150
- ```
151
-
152
- #### Возвращает
153
-
154
- | Поле | Тип | Описание |
155
- |------|-----|----------|
156
- | `opened` | `WritableComputedRef<boolean>` | Двусторонний binding для открытия/закрытия. При установке в `false` вызывает `reject`. |
157
- | `resolve` | `(reason: Resolve) => void` | Закрывает модалку и резолвит промис переданным значением. |
158
-
159
- #### Типизация
160
-
161
- ```ts
162
- function useModal<
163
- Props extends Record<string, unknown>,
164
- Resolve = unknown,
165
- Reject = unknown,
166
- >(id: string): { opened: WritableComputedRef<boolean>, resolve: (reason: Resolve) => void }
167
- ```
168
-
169
- > **Важно:** `id` должен совпадать с тем, что передан в `$modals.create()`.
170
-
171
- ---
172
-
173
- ### `ModalProvider`
174
-
175
- > Файл: `modal-provider.vue`
176
-
177
- Компонент-контейнер, который рендерит все активные модалки. Должен быть размещён один раз в корне приложения (обычно в `app.vue` или layout).
178
-
179
- ```vue
180
- <template>
181
- <NuxtPage />
182
- <ModalProvider />
183
- </template>
184
- ```
185
-
186
- Внутри итерирует `$modals.modals` и рендерит каждую модалку через `<component :is="..." v-bind="props" />`.
187
-
188
- ---
189
-
190
- ## Встроенные модалки
191
-
192
- ### `ConfirmModal`
193
-
194
- > Файл: `_confirm-modal/confirm-modal.vue`
195
-
196
- Модалка подтверждения с кнопками «Confirm» / «Cancel». Зарегистрирована с `id = 'confirm'`.
197
-
198
- #### Props (`ConfirmModalProps`)
199
-
200
- | Prop | Тип | По умолчанию | Описание |
201
- |------|-----|-------------|----------|
202
- | `title` | `string` | — | Заголовок модалки (обязательный) |
203
- | `body` | `string` | — | Текст описания |
204
- | `labels` | `{ confirm: string, cancel: string }` | `{ confirm: 'Confirm', cancel: 'Cancel' }` | Тексты кнопок |
205
- | `variant` | `'default' \| 'danger'` | `'default'` | При `'danger'` кнопка подтверждения становится красной |
206
- | `onCancel` | `() => void` | — | Колбэк при отмене |
207
- | `onConfirm` | `() => MaybePromise<void>` | — | Колбэк при подтверждении (поддерживает async) |
208
- | `cancelProps` | `Partial<ButtonProps>` | — | Дополнительные props для кнопки отмены |
209
- | `confirmProps` | `Partial<ButtonProps>` | — | Дополнительные props для кнопки подтверждения |
210
-
211
- Также принимает все props от `ModalRootProps` (например `size`).
212
-
213
- #### Использование
214
-
215
- ```ts
216
- import { openConfirmModal } from '@nui/components'
217
-
218
- // Простое подтверждение
219
- const confirmed = await openConfirmModal({
220
- title: 'Удалить запись?',
221
- body: 'Это действие нельзя отменить.',
222
- variant: 'danger',
223
- labels: { confirm: 'Удалить', cancel: 'Отмена' },
224
- })
225
-
226
- if (confirmed) {
227
- // пользователь подтвердил
228
- }
229
- ```
230
-
231
- #### Результат
232
-
233
- - **Resolve** → `true` — пользователь нажал «Confirm»
234
- - **Reject** → промис реджектится — пользователь нажал «Cancel» или закрыл модалку
235
-
236
- > **Совет:** оборачивайте вызов в `try/catch`, чтобы обработать отмену:
237
- > ```ts
238
- > try {
239
- > const confirmed = await openConfirmModal({ title: '...' })
240
- > }
241
- > catch {
242
- > // пользователь отменил
243
- > }
244
- > ```
245
-
246
- ---
247
-
248
- ## Паттерны
249
-
250
- ### Wizard (пошаговые модалки)
251
-
252
- Можно вызывать `openConfirmModal` последовательно для реализации пошагового сценария:
253
-
254
- ```ts
255
- const steps = [
256
- { title: 'Шаг 1', body: 'Начать?' },
257
- { title: 'Шаг 2', body: 'Продолжить?' },
258
- { title: 'Шаг 3', body: 'Завершить?', variant: 'danger' },
259
- ]
260
-
261
- let current = 0
262
- while (current < steps.length) {
263
- try {
264
- const confirmed = await openConfirmModal(steps[current])
265
- confirmed ? current++ : current--
266
- }
267
- catch {
268
- break // отмена
269
- }
270
- }
271
- ```
272
-
273
- ### Создание кастомной модалки
274
-
275
- 1. Создайте компонент в `src/runtime/components/modals/_my-modal/`
276
- 2. Внутри компонента используйте `useModal(id)` для получения `opened` и `resolve`
277
- 3. В `index.ts` зарегистрируйте через `$modals.create()` и экспортируйте функцию-открывашку
278
- 4. Реэкспортируйте из `src/runtime/components/modals/index.ts`
279
-
280
- ### Lazy-модалки
281
-
282
- Для тяжёлых модалок используйте `createLazy`, чтобы компонент загружался только при первом открытии:
283
-
284
- ```ts
285
- export const openHeavyModal = $modals.createLazy<HeavyProps, void>(
286
- 'heavy',
287
- () => import('./heavy-modal.vue'),
288
- )
289
- ```
290
-
291
- ### Асинхронный onConfirm
292
-
293
- `ConfirmModal` поддерживает асинхронный `onConfirm` — кнопка показывает loading-состояние до завершения:
294
-
295
- ```ts
296
- await openConfirmModal({
297
- title: 'Сохранить?',
298
- onConfirm: async () => {
299
- await api.save(data)
300
- },
301
- })
302
- ```
@@ -1,2 +0,0 @@
1
- export { $modals } from './modal-manager.js';
2
- export * from './use-modal.js';
@@ -1,2 +0,0 @@
1
- export { $modals } from "./modal-manager.js";
2
- export * from "./use-modal.js";