@liteforge/modal 0.2.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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 SchildW3rk
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,6 @@
1
+ export { createModal } from './modal.js';
2
+ export { ModalProvider } from './provider.js';
3
+ export { confirm, alert, prompt } from './presets.js';
4
+ export { injectDefaultStyles, resetStylesInjection } from './styles.js';
5
+ export type { ModalConfig, CreateModalOptions, ModalResult, ModalSize } from './types.js';
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AACtD,OAAO,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AACxE,YAAY,EAAE,WAAW,EAAE,kBAAkB,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,5 @@
1
+ export { createModal } from './modal.js';
2
+ export { ModalProvider } from './provider.js';
3
+ export { confirm, alert, prompt } from './presets.js';
4
+ export { injectDefaultStyles, resetStylesInjection } from './styles.js';
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AACtD,OAAO,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,20 @@
1
+ import { signal } from '@liteforge/core';
2
+ import type { ModalConfig, CreateModalOptions, ModalResult } from './types.js';
3
+ export interface ModalEntry {
4
+ id: symbol;
5
+ options: Required<ModalConfig>;
6
+ contentFn: () => Node;
7
+ isOpen: ReturnType<typeof signal<boolean>>;
8
+ open: () => void;
9
+ close: () => void;
10
+ toggle: () => void;
11
+ destroy: () => void;
12
+ }
13
+ export declare const modalRegistry: Set<ModalEntry>;
14
+ /**
15
+ * A signal that bumps whenever entries are added/removed from the registry.
16
+ * The provider's effect reads this so it re-runs on registry changes.
17
+ */
18
+ export declare const registryVersion: ReturnType<typeof signal<number>>;
19
+ export declare function createModal(opts: CreateModalOptions): ModalResult;
20
+ //# sourceMappingURL=modal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"modal.d.ts","sourceRoot":"","sources":["../src/modal.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AACzC,OAAO,KAAK,EAAE,WAAW,EAAE,kBAAkB,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAI/E,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,QAAQ,CAAC,WAAW,CAAC,CAAC;IAC/B,SAAS,EAAE,MAAM,IAAI,CAAC;IACtB,MAAM,EAAE,UAAU,CAAC,OAAO,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;IAC3C,IAAI,EAAE,MAAM,IAAI,CAAC;IACjB,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAwBD,eAAO,MAAM,aAAa,EAAE,GAAG,CAAC,UAAU,CAAoB,CAAC;AAE/D;;;GAGG;AACH,eAAO,MAAM,eAAe,EAAE,UAAU,CAAC,OAAO,MAAM,CAAC,MAAM,CAAC,CAAmB,CAAC;AA4BlF,wBAAgB,WAAW,CAAC,IAAI,EAAE,kBAAkB,GAAG,WAAW,CA6EjE"}
package/dist/modal.js ADDED
@@ -0,0 +1,120 @@
1
+ import { signal } from '@liteforge/core';
2
+ /**
3
+ * Global singleton key — ensures all Vite module instances share the same
4
+ * registry even when ESM module isolation creates separate module scopes
5
+ * (e.g. main.tsx and lazy-loaded page chunks in dev mode).
6
+ */
7
+ const REGISTRY_KEY = '__lfModalRegistry__';
8
+ const VERSION_KEY = '__lfModalVersion__';
9
+ const g = globalThis;
10
+ if (!g[REGISTRY_KEY]) {
11
+ g[REGISTRY_KEY] = new Set();
12
+ }
13
+ if (!g[VERSION_KEY]) {
14
+ g[VERSION_KEY] = signal(0);
15
+ }
16
+ export const modalRegistry = g[REGISTRY_KEY];
17
+ /**
18
+ * A signal that bumps whenever entries are added/removed from the registry.
19
+ * The provider's effect reads this so it re-runs on registry changes.
20
+ */
21
+ export const registryVersion = g[VERSION_KEY];
22
+ function bumpRegistry() {
23
+ registryVersion.update((v) => v + 1);
24
+ }
25
+ // ─── Shared ESC listener ─────────────────────────────────────
26
+ const ESC_KEY = '__lfModalEsc__';
27
+ const ge = globalThis;
28
+ function ensureEscListener() {
29
+ if (ge[ESC_KEY])
30
+ return;
31
+ ge[ESC_KEY] = true;
32
+ document.addEventListener('keydown', (e) => {
33
+ if (e.key !== 'Escape')
34
+ return;
35
+ for (const entry of modalRegistry) {
36
+ if (entry.isOpen() && entry.options.closeOnEsc) {
37
+ entry.close();
38
+ break;
39
+ }
40
+ }
41
+ });
42
+ }
43
+ // ─── createModal ─────────────────────────────────────────────
44
+ export function createModal(opts) {
45
+ const cfg = opts.config ?? {};
46
+ const contentFn = opts.component;
47
+ const resolvedOptions = {
48
+ title: cfg.title ?? '',
49
+ size: cfg.size ?? 'md',
50
+ closable: cfg.closable ?? true,
51
+ closeOnBackdrop: cfg.closeOnBackdrop ?? true,
52
+ closeOnEsc: cfg.closeOnEsc ?? true,
53
+ unstyled: cfg.unstyled ?? false,
54
+ onOpen: cfg.onOpen ?? (() => { }),
55
+ onClose: cfg.onClose ?? (() => { }),
56
+ };
57
+ const isOpenSignal = signal(false);
58
+ let disposed = false;
59
+ let contentNode = null;
60
+ let previousFocus = null;
61
+ const entry = {
62
+ id: Symbol(),
63
+ options: resolvedOptions,
64
+ contentFn: () => {
65
+ if (!contentNode) {
66
+ contentNode = contentFn();
67
+ }
68
+ return contentNode;
69
+ },
70
+ isOpen: isOpenSignal,
71
+ open() {
72
+ if (disposed)
73
+ return;
74
+ previousFocus = document.activeElement;
75
+ isOpenSignal.set(true);
76
+ resolvedOptions.onOpen();
77
+ },
78
+ close() {
79
+ if (disposed)
80
+ return;
81
+ isOpenSignal.set(false);
82
+ resolvedOptions.onClose();
83
+ if (previousFocus && previousFocus.focus) {
84
+ previousFocus.focus();
85
+ }
86
+ previousFocus = null;
87
+ },
88
+ toggle() {
89
+ if (disposed)
90
+ return;
91
+ if (isOpenSignal()) {
92
+ entry.close();
93
+ }
94
+ else {
95
+ entry.open();
96
+ }
97
+ },
98
+ destroy() {
99
+ disposed = true;
100
+ if (isOpenSignal()) {
101
+ entry.close();
102
+ }
103
+ modalRegistry.delete(entry);
104
+ bumpRegistry();
105
+ },
106
+ };
107
+ modalRegistry.add(entry);
108
+ bumpRegistry();
109
+ if (typeof document !== 'undefined') {
110
+ ensureEscListener();
111
+ }
112
+ return {
113
+ isOpen: isOpenSignal,
114
+ open: entry.open,
115
+ close: entry.close,
116
+ toggle: entry.toggle,
117
+ destroy: entry.destroy,
118
+ };
119
+ }
120
+ //# sourceMappingURL=modal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"modal.js","sourceRoot":"","sources":["../src/modal.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import type { ModalConfig } from './types.js';
2
+ export declare function confirm(message: string, config?: Partial<ModalConfig>): Promise<boolean>;
3
+ export declare function alert(message: string, config?: Partial<ModalConfig>): Promise<void>;
4
+ export declare function prompt(message: string, defaultValue?: string, config?: Partial<ModalConfig>): Promise<string | null>;
5
+ //# sourceMappingURL=presets.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"presets.d.ts","sourceRoot":"","sources":["../src/presets.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAI9C,wBAAgB,OAAO,CACrB,OAAO,EAAE,MAAM,EACf,MAAM,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC,GAC5B,OAAO,CAAC,OAAO,CAAC,CAsDlB;AAID,wBAAgB,KAAK,CACnB,OAAO,EAAE,MAAM,EACf,MAAM,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC,GAC5B,OAAO,CAAC,IAAI,CAAC,CAwCf;AAID,wBAAgB,MAAM,CACpB,OAAO,EAAE,MAAM,EACf,YAAY,CAAC,EAAE,MAAM,EACrB,MAAM,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC,GAC5B,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CA8DxB"}
@@ -0,0 +1,162 @@
1
+ import { createModal } from './modal.js';
2
+ // ─── confirm() ───────────────────────────────────────────────
3
+ export function confirm(message, config) {
4
+ return new Promise((resolve) => {
5
+ let resolved = false;
6
+ const modal = createModal({
7
+ config: {
8
+ title: 'Confirm',
9
+ size: 'sm',
10
+ closable: false,
11
+ closeOnBackdrop: false,
12
+ closeOnEsc: false,
13
+ ...config,
14
+ },
15
+ component: () => {
16
+ const wrapper = document.createElement('div');
17
+ const msg = document.createElement('p');
18
+ msg.style.margin = '0 0 20px';
19
+ msg.textContent = message;
20
+ wrapper.appendChild(msg);
21
+ const actions = document.createElement('div');
22
+ actions.style.cssText = 'display:flex;gap:8px;justify-content:flex-end';
23
+ const cancelBtn = document.createElement('button');
24
+ cancelBtn.textContent = 'Cancel';
25
+ cancelBtn.style.cssText = 'padding:8px 16px;border:1px solid #d1d5db;border-radius:6px;background:#fff;cursor:pointer;font-size:14px';
26
+ cancelBtn.addEventListener('click', () => {
27
+ if (!resolved) {
28
+ resolved = true;
29
+ modal.close();
30
+ resolve(false);
31
+ }
32
+ });
33
+ const okBtn = document.createElement('button');
34
+ okBtn.textContent = 'OK';
35
+ okBtn.style.cssText = 'padding:8px 16px;border:none;border-radius:6px;background:#3b82f6;color:#fff;cursor:pointer;font-size:14px';
36
+ okBtn.addEventListener('click', () => {
37
+ if (!resolved) {
38
+ resolved = true;
39
+ modal.close();
40
+ resolve(true);
41
+ }
42
+ });
43
+ actions.appendChild(cancelBtn);
44
+ actions.appendChild(okBtn);
45
+ wrapper.appendChild(actions);
46
+ return wrapper;
47
+ },
48
+ });
49
+ modal.open();
50
+ // Resolve false if closed externally
51
+ const origClose = modal.close;
52
+ modal.close = () => {
53
+ origClose();
54
+ if (!resolved) {
55
+ resolved = true;
56
+ resolve(false);
57
+ }
58
+ };
59
+ }).then((result) => result);
60
+ }
61
+ // ─── alert() ─────────────────────────────────────────────────
62
+ export function alert(message, config) {
63
+ return new Promise((resolve) => {
64
+ const modal = createModal({
65
+ config: {
66
+ title: 'Alert',
67
+ size: 'sm',
68
+ closable: false,
69
+ closeOnBackdrop: false,
70
+ closeOnEsc: false,
71
+ ...config,
72
+ },
73
+ component: () => {
74
+ const wrapper = document.createElement('div');
75
+ const msg = document.createElement('p');
76
+ msg.style.margin = '0 0 20px';
77
+ msg.textContent = message;
78
+ wrapper.appendChild(msg);
79
+ const actions = document.createElement('div');
80
+ actions.style.cssText = 'display:flex;justify-content:flex-end';
81
+ const okBtn = document.createElement('button');
82
+ okBtn.textContent = 'OK';
83
+ okBtn.style.cssText = 'padding:8px 16px;border:none;border-radius:6px;background:#3b82f6;color:#fff;cursor:pointer;font-size:14px';
84
+ okBtn.addEventListener('click', () => {
85
+ modal.close();
86
+ modal.destroy();
87
+ resolve();
88
+ });
89
+ actions.appendChild(okBtn);
90
+ wrapper.appendChild(actions);
91
+ return wrapper;
92
+ },
93
+ });
94
+ modal.open();
95
+ });
96
+ }
97
+ // ─── prompt() ────────────────────────────────────────────────
98
+ export function prompt(message, defaultValue, config) {
99
+ return new Promise((resolve) => {
100
+ let resolved = false;
101
+ const modal = createModal({
102
+ config: {
103
+ title: 'Input',
104
+ size: 'sm',
105
+ closable: false,
106
+ closeOnBackdrop: false,
107
+ closeOnEsc: false,
108
+ ...config,
109
+ },
110
+ component: () => {
111
+ const wrapper = document.createElement('div');
112
+ const msg = document.createElement('p');
113
+ msg.style.margin = '0 0 12px';
114
+ msg.textContent = message;
115
+ wrapper.appendChild(msg);
116
+ const input = document.createElement('input');
117
+ input.type = 'text';
118
+ input.value = defaultValue ?? '';
119
+ input.style.cssText = 'width:100%;padding:8px 10px;border:1px solid #d1d5db;border-radius:6px;font-size:14px;box-sizing:border-box;margin-bottom:16px';
120
+ wrapper.appendChild(input);
121
+ const actions = document.createElement('div');
122
+ actions.style.cssText = 'display:flex;gap:8px;justify-content:flex-end';
123
+ const cancelBtn = document.createElement('button');
124
+ cancelBtn.textContent = 'Cancel';
125
+ cancelBtn.style.cssText = 'padding:8px 16px;border:1px solid #d1d5db;border-radius:6px;background:#fff;cursor:pointer;font-size:14px';
126
+ cancelBtn.addEventListener('click', () => {
127
+ if (!resolved) {
128
+ resolved = true;
129
+ modal.close();
130
+ modal.destroy();
131
+ resolve(null);
132
+ }
133
+ });
134
+ const okBtn = document.createElement('button');
135
+ okBtn.textContent = 'OK';
136
+ okBtn.style.cssText = 'padding:8px 16px;border:none;border-radius:6px;background:#3b82f6;color:#fff;cursor:pointer;font-size:14px';
137
+ okBtn.addEventListener('click', () => {
138
+ if (!resolved) {
139
+ resolved = true;
140
+ modal.close();
141
+ modal.destroy();
142
+ resolve(input.value);
143
+ }
144
+ });
145
+ input.addEventListener('keydown', (e) => {
146
+ if (e.key === 'Enter' && !resolved) {
147
+ resolved = true;
148
+ modal.close();
149
+ modal.destroy();
150
+ resolve(input.value);
151
+ }
152
+ });
153
+ actions.appendChild(cancelBtn);
154
+ actions.appendChild(okBtn);
155
+ wrapper.appendChild(actions);
156
+ return wrapper;
157
+ },
158
+ });
159
+ modal.open();
160
+ });
161
+ }
162
+ //# sourceMappingURL=presets.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"presets.js","sourceRoot":"","sources":["../src/presets.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ export declare function ModalProvider(opts?: {
2
+ unstyled?: boolean;
3
+ }): Node;
4
+ //# sourceMappingURL=provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../src/provider.ts"],"names":[],"mappings":"AAwHA,wBAAgB,aAAa,CAAC,IAAI,CAAC,EAAE;IAAE,QAAQ,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,IAAI,CA+BjE"}
@@ -0,0 +1,125 @@
1
+ import { effect } from '@liteforge/core';
2
+ import { modalRegistry, registryVersion } from './modal.js';
3
+ import { injectDefaultStyles } from './styles.js';
4
+ // ─── Focus trap helpers ──────────────────────────────────────
5
+ const FOCUSABLE_SELECTOR = 'a[href], button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])';
6
+ function getFocusableElements(el) {
7
+ return Array.from(el.querySelectorAll(FOCUSABLE_SELECTOR));
8
+ }
9
+ function trapFocus(modalEl) {
10
+ return (e) => {
11
+ if (e.key !== 'Tab')
12
+ return;
13
+ const focusable = getFocusableElements(modalEl);
14
+ if (focusable.length === 0)
15
+ return;
16
+ const first = focusable[0];
17
+ const last = focusable[focusable.length - 1];
18
+ if (e.shiftKey) {
19
+ if (document.activeElement === first) {
20
+ e.preventDefault();
21
+ last.focus();
22
+ }
23
+ }
24
+ else {
25
+ if (document.activeElement === last) {
26
+ e.preventDefault();
27
+ first.focus();
28
+ }
29
+ }
30
+ };
31
+ }
32
+ // ─── Render a single modal overlay ──────────────────────────
33
+ function renderOverlay(entry, onRemove) {
34
+ const size = entry.options.size;
35
+ const overlay = document.createElement('div');
36
+ overlay.className = `lf-modal-overlay lf-modal-overlay--${size}`;
37
+ const modalEl = document.createElement('div');
38
+ modalEl.className = 'lf-modal';
39
+ modalEl.setAttribute('role', 'dialog');
40
+ modalEl.setAttribute('aria-modal', 'true');
41
+ // Header
42
+ const header = document.createElement('div');
43
+ header.className = 'lf-modal-header';
44
+ const titleEl = document.createElement('span');
45
+ titleEl.className = 'lf-modal-title';
46
+ titleEl.textContent = entry.options.title;
47
+ header.appendChild(titleEl);
48
+ if (entry.options.closable) {
49
+ const closeBtn = document.createElement('button');
50
+ closeBtn.className = 'lf-modal-close';
51
+ closeBtn.textContent = '✕';
52
+ closeBtn.setAttribute('aria-label', 'Close');
53
+ closeBtn.addEventListener('click', () => entry.close());
54
+ header.appendChild(closeBtn);
55
+ }
56
+ modalEl.appendChild(header);
57
+ // Body
58
+ const body = document.createElement('div');
59
+ body.className = 'lf-modal-body';
60
+ body.appendChild(entry.contentFn());
61
+ modalEl.appendChild(body);
62
+ overlay.appendChild(modalEl);
63
+ // Backdrop click to close
64
+ overlay.addEventListener('click', (e) => {
65
+ if (e.target === overlay && entry.options.closeOnBackdrop) {
66
+ entry.close();
67
+ }
68
+ });
69
+ // Focus trap
70
+ const focusTrapHandler = trapFocus(modalEl);
71
+ modalEl.addEventListener('keydown', focusTrapHandler);
72
+ // Animate in
73
+ requestAnimationFrame(() => {
74
+ overlay.classList.add('lf-modal-overlay--open');
75
+ // Move focus into modal
76
+ const focusable = getFocusableElements(modalEl);
77
+ if (focusable.length > 0) {
78
+ focusable[0].focus();
79
+ }
80
+ else {
81
+ modalEl.focus();
82
+ }
83
+ });
84
+ // Animate out on close
85
+ const cleanup = effect(() => {
86
+ if (!entry.isOpen()) {
87
+ overlay.classList.remove('lf-modal-overlay--open');
88
+ overlay.addEventListener('transitionend', () => {
89
+ cleanup();
90
+ onRemove();
91
+ }, { once: true });
92
+ }
93
+ });
94
+ return overlay;
95
+ }
96
+ // ─── ModalProvider ───────────────────────────────────────────
97
+ export function ModalProvider(opts) {
98
+ if (!opts?.unstyled) {
99
+ injectDefaultStyles();
100
+ }
101
+ const container = document.createElement('div');
102
+ container.className = 'lf-modal-provider';
103
+ // Track rendered overlays: entry id → overlay element
104
+ const rendered = new Map();
105
+ // Reactively sync open modals.
106
+ // Reading registryVersion() ensures effect re-runs when entries are added/removed.
107
+ effect(() => {
108
+ registryVersion(); // subscribe to registry membership changes
109
+ const openEntries = Array.from(modalRegistry).filter((e) => e.isOpen());
110
+ // Add newly opened modals
111
+ for (const entry of openEntries) {
112
+ if (!rendered.has(entry.id)) {
113
+ const overlay = renderOverlay(entry, () => {
114
+ rendered.delete(entry.id);
115
+ if (overlay.parentNode)
116
+ overlay.parentNode.removeChild(overlay);
117
+ });
118
+ rendered.set(entry.id, overlay);
119
+ container.appendChild(overlay);
120
+ }
121
+ }
122
+ });
123
+ return container;
124
+ }
125
+ //# sourceMappingURL=provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider.js","sourceRoot":"","sources":["../src/provider.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * @liteforge/modal - Default CSS Theme
3
+ *
4
+ * Minimal, clean default styles using CSS variables.
5
+ * Injected once when the first modal provider is created (unless unstyled: true).
6
+ */
7
+ /**
8
+ * Inject default styles into the document head.
9
+ * Called automatically when the first ModalProvider is created (unless unstyled: true).
10
+ */
11
+ export declare function injectDefaultStyles(): void;
12
+ /**
13
+ * Reset styles injection flag (for testing)
14
+ */
15
+ export declare function resetStylesInjection(): void;
16
+ //# sourceMappingURL=styles.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"styles.d.ts","sourceRoot":"","sources":["../src/styles.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAwIH;;;GAGG;AACH,wBAAgB,mBAAmB,IAAI,IAAI,CAU1C;AAED;;GAEG;AACH,wBAAgB,oBAAoB,IAAI,IAAI,CAM3C"}
package/dist/styles.js ADDED
@@ -0,0 +1,164 @@
1
+ /**
2
+ * @liteforge/modal - Default CSS Theme
3
+ *
4
+ * Minimal, clean default styles using CSS variables.
5
+ * Injected once when the first modal provider is created (unless unstyled: true).
6
+ */
7
+ let stylesInjected = false;
8
+ const DEFAULT_STYLES = `
9
+ /* ─── CSS Variables (Customizable) ─────────────────────────── */
10
+
11
+ :root {
12
+ --lf-modal-backdrop: rgba(0, 0, 0, 0.5);
13
+ --lf-modal-bg: #ffffff;
14
+ --lf-modal-border-radius: 10px;
15
+ --lf-modal-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
16
+ --lf-modal-header-bg: #f8fafc;
17
+ --lf-modal-header-color: #1e293b;
18
+ --lf-modal-body-color: #374151;
19
+ --lf-modal-close-color: #6b7280;
20
+ --lf-modal-z-index: 1000;
21
+ }
22
+
23
+ /* ─── Provider ─────────────────────────────────────────────── */
24
+
25
+ .lf-modal-provider {
26
+ position: fixed;
27
+ inset: 0;
28
+ pointer-events: none;
29
+ z-index: var(--lf-modal-z-index);
30
+ }
31
+
32
+ /* ─── Overlay ──────────────────────────────────────────────── */
33
+
34
+ .lf-modal-overlay {
35
+ position: fixed;
36
+ inset: 0;
37
+ background: var(--lf-modal-backdrop);
38
+ display: flex;
39
+ align-items: center;
40
+ justify-content: center;
41
+ pointer-events: all;
42
+ opacity: 0;
43
+ transition: opacity 0.2s ease;
44
+ padding: 16px;
45
+ box-sizing: border-box;
46
+ }
47
+
48
+ .lf-modal-overlay--open {
49
+ opacity: 1;
50
+ }
51
+
52
+ /* ─── Size Variants ────────────────────────────────────────── */
53
+
54
+ .lf-modal-overlay--sm .lf-modal { max-width: 400px; }
55
+ .lf-modal-overlay--md .lf-modal { max-width: 560px; }
56
+ .lf-modal-overlay--lg .lf-modal { max-width: 720px; }
57
+ .lf-modal-overlay--xl .lf-modal { max-width: 1000px; }
58
+ .lf-modal-overlay--full .lf-modal { max-width: 100vw; margin: 0; border-radius: 0; }
59
+
60
+ /* ─── Modal ────────────────────────────────────────────────── */
61
+
62
+ .lf-modal {
63
+ background: var(--lf-modal-bg);
64
+ border-radius: var(--lf-modal-border-radius);
65
+ box-shadow: var(--lf-modal-shadow);
66
+ width: 100%;
67
+ max-height: calc(100vh - 32px);
68
+ display: flex;
69
+ flex-direction: column;
70
+ transform: translateY(-8px);
71
+ transition: transform 0.2s ease;
72
+ overflow: hidden;
73
+ font-family: system-ui, -apple-system, sans-serif;
74
+ }
75
+
76
+ .lf-modal-overlay--open .lf-modal {
77
+ transform: translateY(0);
78
+ }
79
+
80
+ /* ─── Header ───────────────────────────────────────────────── */
81
+
82
+ .lf-modal-header {
83
+ display: flex;
84
+ align-items: center;
85
+ justify-content: space-between;
86
+ padding: 16px 20px;
87
+ background: var(--lf-modal-header-bg);
88
+ border-bottom: 1px solid rgba(0, 0, 0, 0.08);
89
+ flex-shrink: 0;
90
+ }
91
+
92
+ .lf-modal-title {
93
+ font-size: 16px;
94
+ font-weight: 600;
95
+ color: var(--lf-modal-header-color);
96
+ line-height: 1.4;
97
+ }
98
+
99
+ .lf-modal-close {
100
+ background: none;
101
+ border: none;
102
+ cursor: pointer;
103
+ color: var(--lf-modal-close-color);
104
+ font-size: 18px;
105
+ padding: 4px 8px;
106
+ border-radius: 4px;
107
+ line-height: 1;
108
+ transition: background-color 0.15s, color 0.15s;
109
+ flex-shrink: 0;
110
+ }
111
+
112
+ .lf-modal-close:hover {
113
+ background: rgba(0, 0, 0, 0.06);
114
+ color: var(--lf-modal-header-color);
115
+ }
116
+
117
+ /* ─── Body ─────────────────────────────────────────────────── */
118
+
119
+ .lf-modal-body {
120
+ padding: 20px;
121
+ color: var(--lf-modal-body-color);
122
+ font-size: 14px;
123
+ line-height: 1.6;
124
+ overflow-y: auto;
125
+ }
126
+
127
+ /* ─── Dark Mode Support ────────────────────────────────────── */
128
+
129
+ [data-theme="dark"] {
130
+ --lf-modal-backdrop: rgba(0, 0, 0, 0.7);
131
+ --lf-modal-bg: #1e1e2e;
132
+ --lf-modal-shadow: 0 20px 60px rgba(0, 0, 0, 0.6);
133
+ --lf-modal-header-bg: #181825;
134
+ --lf-modal-header-color: #cdd6f4;
135
+ --lf-modal-body-color: #a6adc8;
136
+ --lf-modal-close-color: #6c7086;
137
+ }
138
+ `;
139
+ /**
140
+ * Inject default styles into the document head.
141
+ * Called automatically when the first ModalProvider is created (unless unstyled: true).
142
+ */
143
+ export function injectDefaultStyles() {
144
+ if (stylesInjected)
145
+ return;
146
+ if (typeof document === 'undefined')
147
+ return; // SSR safety
148
+ const style = document.createElement('style');
149
+ style.id = 'lf-modal-styles';
150
+ style.textContent = DEFAULT_STYLES;
151
+ document.head.appendChild(style);
152
+ stylesInjected = true;
153
+ }
154
+ /**
155
+ * Reset styles injection flag (for testing)
156
+ */
157
+ export function resetStylesInjection() {
158
+ stylesInjected = false;
159
+ const existing = document.getElementById('lf-modal-styles');
160
+ if (existing) {
161
+ existing.remove();
162
+ }
163
+ }
164
+ //# sourceMappingURL=styles.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"styles.js","sourceRoot":"","sources":["../src/styles.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,IAAI,cAAc,GAAG,KAAK,CAAA;AAE1B,MAAM,cAAc,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAkItB,CAAA;AAED;;;GAGG;AACH,MAAM,UAAU,mBAAmB;IACjC,IAAI,cAAc;QAAE,OAAM;IAC1B,IAAI,OAAO,QAAQ,KAAK,WAAW;QAAE,OAAM,CAAC,aAAa;IAEzD,MAAM,KAAK,GAAG,QAAQ,CAAC,aAAa,CAAC,OAAO,CAAC,CAAA;IAC7C,KAAK,CAAC,EAAE,GAAG,iBAAiB,CAAA;IAC5B,KAAK,CAAC,WAAW,GAAG,cAAc,CAAA;IAClC,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,CAAA;IAEhC,cAAc,GAAG,IAAI,CAAA;AACvB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,oBAAoB;IAClC,cAAc,GAAG,KAAK,CAAA;IACtB,MAAM,QAAQ,GAAG,QAAQ,CAAC,cAAc,CAAC,iBAAiB,CAAC,CAAA;IAC3D,IAAI,QAAQ,EAAE,CAAC;QACb,QAAQ,CAAC,MAAM,EAAE,CAAA;IACnB,CAAC;AACH,CAAC"}
@@ -0,0 +1,26 @@
1
+ import type { Signal } from '@liteforge/core';
2
+ export type ModalSize = 'sm' | 'md' | 'lg' | 'xl' | 'full';
3
+ export interface ModalConfig {
4
+ title?: string;
5
+ size?: ModalSize;
6
+ closable?: boolean;
7
+ closeOnBackdrop?: boolean;
8
+ closeOnEsc?: boolean;
9
+ unstyled?: boolean;
10
+ onOpen?: () => void;
11
+ onClose?: () => void;
12
+ }
13
+ export interface CreateModalOptions {
14
+ config?: ModalConfig;
15
+ component: () => Node;
16
+ }
17
+ /** @deprecated Use CreateModalOptions object form instead */
18
+ export type ModalOptions = ModalConfig;
19
+ export interface ModalResult {
20
+ isOpen: Signal<boolean>;
21
+ open: () => void;
22
+ close: () => void;
23
+ toggle: () => void;
24
+ destroy: () => void;
25
+ }
26
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAE9C,MAAM,MAAM,SAAS,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,MAAM,CAAC;AAE3D,MAAM,WAAW,WAAW;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,SAAS,EAAE,MAAM,IAAI,CAAC;CACvB;AAED,6DAA6D;AAC7D,MAAM,MAAM,YAAY,GAAG,WAAW,CAAC;AAEvC,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;IACxB,IAAI,EAAE,MAAM,IAAI,CAAC;IACjB,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB"}
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
package/package.json ADDED
@@ -0,0 +1,58 @@
1
+ {
2
+ "name": "@liteforge/modal",
3
+ "version": "0.2.0",
4
+ "description": "Signal-based modal system. createModal, ModalProvider, confirm/alert/prompt presets.",
5
+ "author": "SchildW3rk <contact@schildw3rk.dev>",
6
+ "license": "MIT",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/schildw3rk/liteforge",
10
+ "directory": "packages/modal"
11
+ },
12
+ "homepage": "https://github.com/schildw3rk/liteforge#readme",
13
+ "bugs": {
14
+ "url": "https://github.com/schildw3rk/liteforge/issues"
15
+ },
16
+ "keywords": [
17
+ "liteforge",
18
+ "modal",
19
+ "dialog",
20
+ "overlay",
21
+ "signals",
22
+ "reactive"
23
+ ],
24
+ "type": "module",
25
+ "main": "./dist/index.js",
26
+ "module": "./dist/index.js",
27
+ "types": "./dist/index.d.ts",
28
+ "exports": {
29
+ ".": {
30
+ "types": "./dist/index.d.ts",
31
+ "import": "./dist/index.js"
32
+ }
33
+ },
34
+ "files": [
35
+ "dist",
36
+ "README.md",
37
+ "LICENSE"
38
+ ],
39
+ "sideEffects": false,
40
+ "engines": {
41
+ "node": ">=18"
42
+ },
43
+ "publishConfig": {
44
+ "access": "public"
45
+ },
46
+ "peerDependencies": {
47
+ "@liteforge/core": ">=0.1.0"
48
+ },
49
+ "devDependencies": {
50
+ "@liteforge/core": "0.1.0"
51
+ },
52
+ "scripts": {
53
+ "build": "tsc -p tsconfig.build.json",
54
+ "dev": "tsc -p tsconfig.build.json --watch",
55
+ "typecheck": "tsc --noEmit",
56
+ "clean": "rm -rf dist *.tsbuildinfo"
57
+ }
58
+ }