@zxkit/surface 1.0.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,180 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import React$1 from 'react';
3
+ import { FieldValues, UseFormProps, UseFormReturn } from 'react-hook-form';
4
+
5
+ interface CreatePushModalOptions<T> {
6
+ modals: {
7
+ [key in keyof T]: {
8
+ Wrapper: React$1.ComponentType<{
9
+ open?: boolean;
10
+ onOpenChange?: (open: boolean) => void;
11
+ children?: React$1.ReactNode;
12
+ defaultOpen?: boolean;
13
+ }>;
14
+ Component: React$1.ComponentType<T[key]>;
15
+ } | React$1.ComponentType<T[key]>;
16
+ };
17
+ }
18
+ declare function createPushModal<T>({ modals }: CreatePushModalOptions<T>): {
19
+ ModalProvider: () => react_jsx_runtime.JSX.Element;
20
+ pushModal: <T_1 extends keyof T, B extends (({ [key in keyof T]: React$1.ComponentType<T[key]> | {
21
+ Wrapper: React$1.ComponentType<{
22
+ open?: boolean;
23
+ onOpenChange?: (open: boolean) => void;
24
+ children?: React$1.ReactNode;
25
+ defaultOpen?: boolean;
26
+ }>;
27
+ Component: React$1.ComponentType<T[key]>;
28
+ }; }[T_1] extends infer T_4 ? T_4 extends { [key in keyof T]: React$1.ComponentType<T[key]> | {
29
+ Wrapper: React$1.ComponentType<{
30
+ open?: boolean;
31
+ onOpenChange?: (open: boolean) => void;
32
+ children?: React$1.ReactNode;
33
+ defaultOpen?: boolean;
34
+ }>;
35
+ Component: React$1.ComponentType<T[key]>;
36
+ }; }[T_1] ? T_4 extends React$1.ComponentType<infer P> | React$1.Component<infer P, {}, any> | {
37
+ Component: React$1.ComponentType<infer P>;
38
+ } ? P : never : never : never) extends infer T_3 ? { [K in keyof T_3]: T_3[K]; } : never) & Record<never, never>>(name: T_1, ...args: (keyof ({ [K_1 in keyof B]: B[K_1]; } & Record<never, never> extends Record<string | number | symbol, unknown> ? { [K_1 in keyof B]: B[K_1]; } & Record<never, never> : never) extends never ? never : { [K_1 in keyof B]: B[K_1]; } & Record<never, never> extends Record<string | number | symbol, unknown> ? { [K_1 in keyof B]: B[K_1]; } & Record<never, never> : never) extends never ? [] : [props: B]) => void;
39
+ popModal: (name?: keyof T) => void;
40
+ popAllModals: () => void;
41
+ replaceWithModal: <T_1 extends keyof T, B extends { [key in keyof T]: React$1.ComponentType<T[key]> | {
42
+ Wrapper: React$1.ComponentType<{
43
+ open?: boolean;
44
+ onOpenChange?: (open: boolean) => void;
45
+ children?: React$1.ReactNode;
46
+ defaultOpen?: boolean;
47
+ }>;
48
+ Component: React$1.ComponentType<T[key]>;
49
+ }; }[T_1] extends infer T_2 ? T_2 extends { [key in keyof T]: React$1.ComponentType<T[key]> | {
50
+ Wrapper: React$1.ComponentType<{
51
+ open?: boolean;
52
+ onOpenChange?: (open: boolean) => void;
53
+ children?: React$1.ReactNode;
54
+ defaultOpen?: boolean;
55
+ }>;
56
+ Component: React$1.ComponentType<T[key]>;
57
+ }; }[T_1] ? T_2 extends React$1.ComponentType<infer P> | React$1.Component<infer P, {}, any> | {
58
+ Component: React$1.ComponentType<infer P>;
59
+ } ? P : never : never : never>(name: T_1, ...args: (keyof ({ [K in keyof B]: B[K]; } & Record<never, never> extends Record<string | number | symbol, unknown> ? { [K in keyof B]: B[K]; } & Record<never, never> : never) extends never ? never : { [K in keyof B]: B[K]; } & Record<never, never> extends Record<string | number | symbol, unknown> ? { [K in keyof B]: B[K]; } & Record<never, never> : never) extends never ? [] : [props: B]) => void;
60
+ onPushModal: <T_1 extends keyof T>(name: T_1 | "*", callback: (open: boolean, props: { [key in keyof T]: React$1.ComponentType<T[key]> | {
61
+ Wrapper: React$1.ComponentType<{
62
+ open?: boolean;
63
+ onOpenChange?: (open: boolean) => void;
64
+ children?: React$1.ReactNode;
65
+ defaultOpen?: boolean;
66
+ }>;
67
+ Component: React$1.ComponentType<T[key]>;
68
+ }; }[T_1] extends infer T_2 ? T_2 extends { [key in keyof T]: React$1.ComponentType<T[key]> | {
69
+ Wrapper: React$1.ComponentType<{
70
+ open?: boolean;
71
+ onOpenChange?: (open: boolean) => void;
72
+ children?: React$1.ReactNode;
73
+ defaultOpen?: boolean;
74
+ }>;
75
+ Component: React$1.ComponentType<T[key]>;
76
+ }; }[T_1] ? T_2 extends React$1.ComponentType<infer P> | React$1.Component<infer P, {}, any> | {
77
+ Component: React$1.ComponentType<infer P>;
78
+ } ? P : never : never : never, name?: T_1 | undefined) => void) => () => void;
79
+ onCloseModal: <T_1 extends keyof T>(name: T_1 | "*", callback: (props: { [key in keyof T]: React$1.ComponentType<T[key]> | {
80
+ Wrapper: React$1.ComponentType<{
81
+ open?: boolean;
82
+ onOpenChange?: (open: boolean) => void;
83
+ children?: React$1.ReactNode;
84
+ defaultOpen?: boolean;
85
+ }>;
86
+ Component: React$1.ComponentType<T[key]>;
87
+ }; }[T_1] extends infer T_2 ? T_2 extends { [key in keyof T]: React$1.ComponentType<T[key]> | {
88
+ Wrapper: React$1.ComponentType<{
89
+ open?: boolean;
90
+ onOpenChange?: (open: boolean) => void;
91
+ children?: React$1.ReactNode;
92
+ defaultOpen?: boolean;
93
+ }>;
94
+ Component: React$1.ComponentType<T[key]>;
95
+ }; }[T_1] ? T_2 extends React$1.ComponentType<infer P> | React$1.Component<infer P, {}, any> | {
96
+ Component: React$1.ComponentType<infer P>;
97
+ } ? P : never : never : never, name?: T_1 | undefined) => void, options?: {
98
+ delay?: number;
99
+ }) => () => void;
100
+ useOnPushModal: <T_1 extends keyof T>(name: T_1 | "*", callback: (open: boolean, props: { [key in keyof T]: React$1.ComponentType<T[key]> | {
101
+ Wrapper: React$1.ComponentType<{
102
+ open?: boolean;
103
+ onOpenChange?: (open: boolean) => void;
104
+ children?: React$1.ReactNode;
105
+ defaultOpen?: boolean;
106
+ }>;
107
+ Component: React$1.ComponentType<T[key]>;
108
+ }; }[T_1] extends infer T_2 ? T_2 extends { [key in keyof T]: React$1.ComponentType<T[key]> | {
109
+ Wrapper: React$1.ComponentType<{
110
+ open?: boolean;
111
+ onOpenChange?: (open: boolean) => void;
112
+ children?: React$1.ReactNode;
113
+ defaultOpen?: boolean;
114
+ }>;
115
+ Component: React$1.ComponentType<T[key]>;
116
+ }; }[T_1] ? T_2 extends React$1.ComponentType<infer P> | React$1.Component<infer P, {}, any> | {
117
+ Component: React$1.ComponentType<infer P>;
118
+ } ? P : never : never : never, name?: T_1 | undefined) => void) => void;
119
+ useOnCloseModal: <T_1 extends keyof T>(name: T_1 | "*", callback: (props: { [key in keyof T]: React$1.ComponentType<T[key]> | {
120
+ Wrapper: React$1.ComponentType<{
121
+ open?: boolean;
122
+ onOpenChange?: (open: boolean) => void;
123
+ children?: React$1.ReactNode;
124
+ defaultOpen?: boolean;
125
+ }>;
126
+ Component: React$1.ComponentType<T[key]>;
127
+ }; }[T_1] extends infer T_2 ? T_2 extends { [key in keyof T]: React$1.ComponentType<T[key]> | {
128
+ Wrapper: React$1.ComponentType<{
129
+ open?: boolean;
130
+ onOpenChange?: (open: boolean) => void;
131
+ children?: React$1.ReactNode;
132
+ defaultOpen?: boolean;
133
+ }>;
134
+ Component: React$1.ComponentType<T[key]>;
135
+ }; }[T_1] ? T_2 extends React$1.ComponentType<infer P> | React$1.Component<infer P, {}, any> | {
136
+ Component: React$1.ComponentType<infer P>;
137
+ } ? P : never : never : never, name?: T_1 | undefined) => void, options?: {
138
+ delay?: number;
139
+ }) => void;
140
+ };
141
+
142
+ interface WrapperProps {
143
+ open?: boolean;
144
+ onOpenChange?: (open: boolean) => void;
145
+ children?: React.ReactNode;
146
+ defaultOpen?: boolean;
147
+ modal?: boolean;
148
+ }
149
+ interface ContentProps {
150
+ children?: React.ReactNode;
151
+ className?: string;
152
+ onAnimationEnd?: (...args: unknown[]) => void;
153
+ onOpenAutoFocus?: (event: Event) => void;
154
+ onCloseAutoFocus?: (event: Event) => void;
155
+ onEscapeKeyDown?: (event: KeyboardEvent) => void;
156
+ onPointerDownOutside?: (event: Event) => void;
157
+ onInteractOutside?: (event: Event) => void;
158
+ [key: string]: unknown;
159
+ }
160
+ type Options = {
161
+ mobile: {
162
+ Wrapper: React.ComponentType<WrapperProps>;
163
+ Content: React.ComponentType<ContentProps>;
164
+ };
165
+ desktop: {
166
+ Wrapper: React.ComponentType<WrapperProps>;
167
+ Content: React.ComponentType<ContentProps>;
168
+ };
169
+ breakpoint?: number;
170
+ };
171
+ interface ResponsiveWrapperReturn {
172
+ Wrapper: React.ComponentType<WrapperProps>;
173
+ Content: React.ComponentType<ContentProps>;
174
+ usePreservedState: <T>(key: string, initialValue: T) => [T, React.Dispatch<React.SetStateAction<T>>];
175
+ usePreservedForm: <T extends FieldValues>(key: string, options: UseFormProps<T>) => UseFormReturn<T>;
176
+ }
177
+ declare function createResponsiveWrapper({ mobile, desktop, breakpoint, }: Options): ResponsiveWrapperReturn;
178
+
179
+ export { createPushModal, createResponsiveWrapper };
180
+ export type { ContentProps, ResponsiveWrapperReturn, WrapperProps };
@@ -0,0 +1,180 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import React$1 from 'react';
3
+ import { FieldValues, UseFormProps, UseFormReturn } from 'react-hook-form';
4
+
5
+ interface CreatePushModalOptions<T> {
6
+ modals: {
7
+ [key in keyof T]: {
8
+ Wrapper: React$1.ComponentType<{
9
+ open?: boolean;
10
+ onOpenChange?: (open: boolean) => void;
11
+ children?: React$1.ReactNode;
12
+ defaultOpen?: boolean;
13
+ }>;
14
+ Component: React$1.ComponentType<T[key]>;
15
+ } | React$1.ComponentType<T[key]>;
16
+ };
17
+ }
18
+ declare function createPushModal<T>({ modals }: CreatePushModalOptions<T>): {
19
+ ModalProvider: () => react_jsx_runtime.JSX.Element;
20
+ pushModal: <T_1 extends keyof T, B extends (({ [key in keyof T]: React$1.ComponentType<T[key]> | {
21
+ Wrapper: React$1.ComponentType<{
22
+ open?: boolean;
23
+ onOpenChange?: (open: boolean) => void;
24
+ children?: React$1.ReactNode;
25
+ defaultOpen?: boolean;
26
+ }>;
27
+ Component: React$1.ComponentType<T[key]>;
28
+ }; }[T_1] extends infer T_4 ? T_4 extends { [key in keyof T]: React$1.ComponentType<T[key]> | {
29
+ Wrapper: React$1.ComponentType<{
30
+ open?: boolean;
31
+ onOpenChange?: (open: boolean) => void;
32
+ children?: React$1.ReactNode;
33
+ defaultOpen?: boolean;
34
+ }>;
35
+ Component: React$1.ComponentType<T[key]>;
36
+ }; }[T_1] ? T_4 extends React$1.ComponentType<infer P> | React$1.Component<infer P, {}, any> | {
37
+ Component: React$1.ComponentType<infer P>;
38
+ } ? P : never : never : never) extends infer T_3 ? { [K in keyof T_3]: T_3[K]; } : never) & Record<never, never>>(name: T_1, ...args: (keyof ({ [K_1 in keyof B]: B[K_1]; } & Record<never, never> extends Record<string | number | symbol, unknown> ? { [K_1 in keyof B]: B[K_1]; } & Record<never, never> : never) extends never ? never : { [K_1 in keyof B]: B[K_1]; } & Record<never, never> extends Record<string | number | symbol, unknown> ? { [K_1 in keyof B]: B[K_1]; } & Record<never, never> : never) extends never ? [] : [props: B]) => void;
39
+ popModal: (name?: keyof T) => void;
40
+ popAllModals: () => void;
41
+ replaceWithModal: <T_1 extends keyof T, B extends { [key in keyof T]: React$1.ComponentType<T[key]> | {
42
+ Wrapper: React$1.ComponentType<{
43
+ open?: boolean;
44
+ onOpenChange?: (open: boolean) => void;
45
+ children?: React$1.ReactNode;
46
+ defaultOpen?: boolean;
47
+ }>;
48
+ Component: React$1.ComponentType<T[key]>;
49
+ }; }[T_1] extends infer T_2 ? T_2 extends { [key in keyof T]: React$1.ComponentType<T[key]> | {
50
+ Wrapper: React$1.ComponentType<{
51
+ open?: boolean;
52
+ onOpenChange?: (open: boolean) => void;
53
+ children?: React$1.ReactNode;
54
+ defaultOpen?: boolean;
55
+ }>;
56
+ Component: React$1.ComponentType<T[key]>;
57
+ }; }[T_1] ? T_2 extends React$1.ComponentType<infer P> | React$1.Component<infer P, {}, any> | {
58
+ Component: React$1.ComponentType<infer P>;
59
+ } ? P : never : never : never>(name: T_1, ...args: (keyof ({ [K in keyof B]: B[K]; } & Record<never, never> extends Record<string | number | symbol, unknown> ? { [K in keyof B]: B[K]; } & Record<never, never> : never) extends never ? never : { [K in keyof B]: B[K]; } & Record<never, never> extends Record<string | number | symbol, unknown> ? { [K in keyof B]: B[K]; } & Record<never, never> : never) extends never ? [] : [props: B]) => void;
60
+ onPushModal: <T_1 extends keyof T>(name: T_1 | "*", callback: (open: boolean, props: { [key in keyof T]: React$1.ComponentType<T[key]> | {
61
+ Wrapper: React$1.ComponentType<{
62
+ open?: boolean;
63
+ onOpenChange?: (open: boolean) => void;
64
+ children?: React$1.ReactNode;
65
+ defaultOpen?: boolean;
66
+ }>;
67
+ Component: React$1.ComponentType<T[key]>;
68
+ }; }[T_1] extends infer T_2 ? T_2 extends { [key in keyof T]: React$1.ComponentType<T[key]> | {
69
+ Wrapper: React$1.ComponentType<{
70
+ open?: boolean;
71
+ onOpenChange?: (open: boolean) => void;
72
+ children?: React$1.ReactNode;
73
+ defaultOpen?: boolean;
74
+ }>;
75
+ Component: React$1.ComponentType<T[key]>;
76
+ }; }[T_1] ? T_2 extends React$1.ComponentType<infer P> | React$1.Component<infer P, {}, any> | {
77
+ Component: React$1.ComponentType<infer P>;
78
+ } ? P : never : never : never, name?: T_1 | undefined) => void) => () => void;
79
+ onCloseModal: <T_1 extends keyof T>(name: T_1 | "*", callback: (props: { [key in keyof T]: React$1.ComponentType<T[key]> | {
80
+ Wrapper: React$1.ComponentType<{
81
+ open?: boolean;
82
+ onOpenChange?: (open: boolean) => void;
83
+ children?: React$1.ReactNode;
84
+ defaultOpen?: boolean;
85
+ }>;
86
+ Component: React$1.ComponentType<T[key]>;
87
+ }; }[T_1] extends infer T_2 ? T_2 extends { [key in keyof T]: React$1.ComponentType<T[key]> | {
88
+ Wrapper: React$1.ComponentType<{
89
+ open?: boolean;
90
+ onOpenChange?: (open: boolean) => void;
91
+ children?: React$1.ReactNode;
92
+ defaultOpen?: boolean;
93
+ }>;
94
+ Component: React$1.ComponentType<T[key]>;
95
+ }; }[T_1] ? T_2 extends React$1.ComponentType<infer P> | React$1.Component<infer P, {}, any> | {
96
+ Component: React$1.ComponentType<infer P>;
97
+ } ? P : never : never : never, name?: T_1 | undefined) => void, options?: {
98
+ delay?: number;
99
+ }) => () => void;
100
+ useOnPushModal: <T_1 extends keyof T>(name: T_1 | "*", callback: (open: boolean, props: { [key in keyof T]: React$1.ComponentType<T[key]> | {
101
+ Wrapper: React$1.ComponentType<{
102
+ open?: boolean;
103
+ onOpenChange?: (open: boolean) => void;
104
+ children?: React$1.ReactNode;
105
+ defaultOpen?: boolean;
106
+ }>;
107
+ Component: React$1.ComponentType<T[key]>;
108
+ }; }[T_1] extends infer T_2 ? T_2 extends { [key in keyof T]: React$1.ComponentType<T[key]> | {
109
+ Wrapper: React$1.ComponentType<{
110
+ open?: boolean;
111
+ onOpenChange?: (open: boolean) => void;
112
+ children?: React$1.ReactNode;
113
+ defaultOpen?: boolean;
114
+ }>;
115
+ Component: React$1.ComponentType<T[key]>;
116
+ }; }[T_1] ? T_2 extends React$1.ComponentType<infer P> | React$1.Component<infer P, {}, any> | {
117
+ Component: React$1.ComponentType<infer P>;
118
+ } ? P : never : never : never, name?: T_1 | undefined) => void) => void;
119
+ useOnCloseModal: <T_1 extends keyof T>(name: T_1 | "*", callback: (props: { [key in keyof T]: React$1.ComponentType<T[key]> | {
120
+ Wrapper: React$1.ComponentType<{
121
+ open?: boolean;
122
+ onOpenChange?: (open: boolean) => void;
123
+ children?: React$1.ReactNode;
124
+ defaultOpen?: boolean;
125
+ }>;
126
+ Component: React$1.ComponentType<T[key]>;
127
+ }; }[T_1] extends infer T_2 ? T_2 extends { [key in keyof T]: React$1.ComponentType<T[key]> | {
128
+ Wrapper: React$1.ComponentType<{
129
+ open?: boolean;
130
+ onOpenChange?: (open: boolean) => void;
131
+ children?: React$1.ReactNode;
132
+ defaultOpen?: boolean;
133
+ }>;
134
+ Component: React$1.ComponentType<T[key]>;
135
+ }; }[T_1] ? T_2 extends React$1.ComponentType<infer P> | React$1.Component<infer P, {}, any> | {
136
+ Component: React$1.ComponentType<infer P>;
137
+ } ? P : never : never : never, name?: T_1 | undefined) => void, options?: {
138
+ delay?: number;
139
+ }) => void;
140
+ };
141
+
142
+ interface WrapperProps {
143
+ open?: boolean;
144
+ onOpenChange?: (open: boolean) => void;
145
+ children?: React.ReactNode;
146
+ defaultOpen?: boolean;
147
+ modal?: boolean;
148
+ }
149
+ interface ContentProps {
150
+ children?: React.ReactNode;
151
+ className?: string;
152
+ onAnimationEnd?: (...args: unknown[]) => void;
153
+ onOpenAutoFocus?: (event: Event) => void;
154
+ onCloseAutoFocus?: (event: Event) => void;
155
+ onEscapeKeyDown?: (event: KeyboardEvent) => void;
156
+ onPointerDownOutside?: (event: Event) => void;
157
+ onInteractOutside?: (event: Event) => void;
158
+ [key: string]: unknown;
159
+ }
160
+ type Options = {
161
+ mobile: {
162
+ Wrapper: React.ComponentType<WrapperProps>;
163
+ Content: React.ComponentType<ContentProps>;
164
+ };
165
+ desktop: {
166
+ Wrapper: React.ComponentType<WrapperProps>;
167
+ Content: React.ComponentType<ContentProps>;
168
+ };
169
+ breakpoint?: number;
170
+ };
171
+ interface ResponsiveWrapperReturn {
172
+ Wrapper: React.ComponentType<WrapperProps>;
173
+ Content: React.ComponentType<ContentProps>;
174
+ usePreservedState: <T>(key: string, initialValue: T) => [T, React.Dispatch<React.SetStateAction<T>>];
175
+ usePreservedForm: <T extends FieldValues>(key: string, options: UseFormProps<T>) => UseFormReturn<T>;
176
+ }
177
+ declare function createResponsiveWrapper({ mobile, desktop, breakpoint, }: Options): ResponsiveWrapperReturn;
178
+
179
+ export { createPushModal, createResponsiveWrapper };
180
+ export type { ContentProps, ResponsiveWrapperReturn, WrapperProps };
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAA;AAC7B,cAAc,kBAAkB,CAAA"}
package/dist/index.js ADDED
@@ -0,0 +1,302 @@
1
+ 'use client';
2
+ import { jsx, Fragment } from 'react/jsx-runtime';
3
+ import { useEffect, useState, Suspense, createContext, useContext, useRef, useSyncExternalStore } from 'react';
4
+ import { Dialog } from 'radix-ui';
5
+ import { useForm } from 'react-hook-form';
6
+
7
+ function mitt(n){return {all:n=n||new Map,on:function(t,e){var i=n.get(t);i?i.push(e):n.set(t,[e]);},off:function(t,e){var i=n.get(t);i&&(e?i.splice(i.indexOf(e)>>>0,1):n.set(t,[]));},emit:function(t,e){var i=n.get(t);i&&i.slice().map(function(n){n(e);}),(i=n.get("*"))&&i.slice().map(function(n){n(t,e);});}}}
8
+
9
+ function createPushModal({ modals }) {
10
+ const filterGarbage = (item) => {
11
+ if (item.open || !item.closedAt) {
12
+ return true;
13
+ }
14
+ return Date.now() - item.closedAt < 300;
15
+ };
16
+ const emitter = mitt();
17
+ function ModalProvider() {
18
+ const [state, setState] = useState([]);
19
+ // Remove closed modals from state after their exit animation completes
20
+ useEffect(() => {
21
+ const hasClosedModals = state.some((item) => typeof item.closedAt === 'number');
22
+ if (!hasClosedModals)
23
+ return;
24
+ const timer = setTimeout(() => {
25
+ setState((p) => p.filter(filterGarbage));
26
+ }, 350);
27
+ return () => {
28
+ clearTimeout(timer);
29
+ };
30
+ }, [state]);
31
+ useEffect(() => {
32
+ const pushHandler = ({ name, props }) => {
33
+ emitter.emit('change', { name, open: true, props });
34
+ setState((p) => [
35
+ ...p,
36
+ {
37
+ key: Math.random().toString(),
38
+ name,
39
+ props,
40
+ open: true,
41
+ },
42
+ ].filter(filterGarbage));
43
+ };
44
+ const replaceHandler = ({ name, props }) => {
45
+ setState((p) => {
46
+ // find last item to replace
47
+ const last = p.findLast((item) => item.open);
48
+ if (last) {
49
+ // if found emit close event
50
+ emitter.emit('change', { name: last.name, open: false, props: last.props });
51
+ }
52
+ emitter.emit('change', { name, open: true, props });
53
+ return [
54
+ // 1) close last item 2) filter garbage 3) add new item
55
+ ...p
56
+ .map((item) => {
57
+ if (item.key === last?.key) {
58
+ return { ...item, open: false, closedAt: Date.now() };
59
+ }
60
+ return item;
61
+ })
62
+ .filter(filterGarbage),
63
+ {
64
+ key: Math.random().toString(),
65
+ name,
66
+ props,
67
+ open: true,
68
+ },
69
+ ];
70
+ });
71
+ };
72
+ const popHandler = ({ name }) => {
73
+ setState((items) => {
74
+ // Find last open item index
75
+ const index = name === undefined
76
+ ? // Pick last open item if no name is provided
77
+ items.findLastIndex((item) => item.open)
78
+ : items.findLastIndex((item) => item.name === name && item.open);
79
+ const match = items[index];
80
+ if (match) {
81
+ emitter.emit('change', {
82
+ name: match.name,
83
+ open: false,
84
+ props: match.props,
85
+ });
86
+ }
87
+ return items.map((item) => match?.key !== item.key ? item : { ...item, open: false, closedAt: Date.now() });
88
+ });
89
+ };
90
+ const popAllHandler = () => {
91
+ setState((items) => {
92
+ items.forEach((item) => {
93
+ if (item.open) {
94
+ emitter.emit('change', { name: item.name, open: false, props: item.props });
95
+ }
96
+ });
97
+ return items.map((item) => item.open ? { ...item, open: false, closedAt: Date.now() } : item);
98
+ });
99
+ };
100
+ emitter.on('push', pushHandler);
101
+ emitter.on('replace', replaceHandler);
102
+ emitter.on('pop', popHandler);
103
+ emitter.on('popAll', popAllHandler);
104
+ return () => {
105
+ emitter.off('push', pushHandler);
106
+ emitter.off('replace', replaceHandler);
107
+ emitter.off('pop', popHandler);
108
+ emitter.off('popAll', popAllHandler);
109
+ };
110
+ }, []);
111
+ return (jsx(Fragment, { children: state.map((item) => {
112
+ const modal = modals[item.name];
113
+ const Component = ('Component' in modal ? modal.Component : modal);
114
+ const Root = 'Wrapper' in modal ? modal.Wrapper : Dialog.Root;
115
+ return (jsx(Root, { open: item.open, onOpenChange: (isOpen) => {
116
+ if (!isOpen) {
117
+ popModal(item.name);
118
+ }
119
+ }, children: jsx(Suspense, { children: jsx(Component, { ...item.props }) }) }, item.key));
120
+ }) }));
121
+ }
122
+ const pushModal = (name, ...args) => {
123
+ const [props] = args;
124
+ return emitter.emit('push', {
125
+ name,
126
+ props: props ?? {},
127
+ });
128
+ };
129
+ const popModal = (name) => emitter.emit('pop', {
130
+ name,
131
+ });
132
+ const replaceWithModal = (name, ...args) => {
133
+ const [props] = args;
134
+ emitter.emit('replace', {
135
+ name,
136
+ props: props ?? {},
137
+ });
138
+ };
139
+ const popAllModals = () => emitter.emit('popAll');
140
+ const onPushModal = (name, callback) => {
141
+ const fn = (payload) => {
142
+ if (payload.name === name) {
143
+ callback(payload.open, payload.props, payload.name);
144
+ }
145
+ else if (name === '*') {
146
+ callback(payload.open, payload.props, payload.name);
147
+ }
148
+ };
149
+ emitter.on('change', fn);
150
+ return () => emitter.off('change', fn);
151
+ };
152
+ const onCloseModal = (name, callback, options) => {
153
+ const delay = options?.delay ?? 0;
154
+ const fn = (payload) => {
155
+ if (!payload.open) {
156
+ if (payload.name === name) {
157
+ if (delay > 0) {
158
+ setTimeout(() => {
159
+ callback(payload.props, payload.name);
160
+ }, delay);
161
+ }
162
+ else {
163
+ callback(payload.props, payload.name);
164
+ }
165
+ }
166
+ else if (name === '*') {
167
+ if (delay > 0) {
168
+ setTimeout(() => {
169
+ callback(payload.props, payload.name);
170
+ }, delay);
171
+ }
172
+ else {
173
+ callback(payload.props, payload.name);
174
+ }
175
+ }
176
+ }
177
+ };
178
+ emitter.on('change', fn);
179
+ return () => emitter.off('change', fn);
180
+ };
181
+ return {
182
+ ModalProvider,
183
+ pushModal,
184
+ popModal,
185
+ popAllModals,
186
+ replaceWithModal,
187
+ onPushModal,
188
+ onCloseModal,
189
+ useOnPushModal: (name, callback) => {
190
+ useEffect(() => {
191
+ return onPushModal(name, callback);
192
+ }, [name, callback]);
193
+ },
194
+ useOnCloseModal: (name, callback, options) => {
195
+ useEffect(() => {
196
+ return onCloseModal(name, callback, options);
197
+ }, [name, callback, options]);
198
+ },
199
+ };
200
+ }
201
+
202
+ function createResponsiveWrapper({ mobile, desktop, breakpoint = 640, }) {
203
+ // Create a context to share the isMobile state between Wrapper and Content
204
+ const ResponsiveContext = createContext(undefined);
205
+ const mediaQuery = `(max-width: ${breakpoint}px)`;
206
+ let mql = null;
207
+ function getMql() {
208
+ if (!mql)
209
+ mql = window.matchMedia(mediaQuery);
210
+ return mql;
211
+ }
212
+ function subscribe(callback) {
213
+ const m = getMql();
214
+ m.addEventListener('change', callback);
215
+ return () => m.removeEventListener('change', callback);
216
+ }
217
+ function getSnapshot() {
218
+ return getMql().matches;
219
+ }
220
+ function useIsMobile() {
221
+ return useSyncExternalStore(subscribe, getSnapshot,
222
+ // server snapshot is always false (desktop) to match initial client render and avoid hydration mismatch
223
+ () => false);
224
+ }
225
+ const StateStoreContext = createContext(new Map());
226
+ function Wrapper(props) {
227
+ const isMobile = useIsMobile();
228
+ const stateStore = useRef(new Map()).current;
229
+ const WrapperComponent = isMobile ? mobile.Wrapper : desktop.Wrapper;
230
+ // Clear the preserved state store when the dialog/drawer closes
231
+ useEffect(() => {
232
+ if (props.open === false) {
233
+ stateStore.clear();
234
+ }
235
+ }, [props.open, stateStore]);
236
+ return (jsx(StateStoreContext.Provider, { value: stateStore, children: jsx(ResponsiveContext.Provider, { value: isMobile, children: jsx(WrapperComponent, { ...props }) }) }));
237
+ }
238
+ function Content(props) {
239
+ const contextIsMobile = useContext(ResponsiveContext);
240
+ if (contextIsMobile === undefined) {
241
+ throw new Error('Content must be used within a Wrapper component');
242
+ }
243
+ const ContentComponent = contextIsMobile ? mobile.Content : desktop.Content;
244
+ return jsx(ContentComponent, { ...props });
245
+ }
246
+ // Hook to preserve state across unmounts. State is stored in the StateStoreContext and keyed by the provided key.
247
+ function usePreservedState(key, initialValue) {
248
+ const store = useContext(StateStoreContext);
249
+ const [state, setState] = useState(() => {
250
+ // if the store already has a value for this key, use it.
251
+ // Otherwise, use the provided initial value
252
+ if (store.has(key))
253
+ return store.get(key);
254
+ return initialValue;
255
+ });
256
+ useEffect(() => {
257
+ store.set(key, state);
258
+ }, [store, key, state]);
259
+ return [state, setState];
260
+ }
261
+ // Hook to create a react-hook-form form with preserved state. Form state is stored in the StateStoreContext and keyed by the provided key.
262
+ function usePreservedForm(key, options) {
263
+ const store = useContext(StateStoreContext);
264
+ const hasStoredValues = store.has(key);
265
+ const form = useForm({
266
+ ...options,
267
+ // Use stored values as initial defaultValues so data is visible immediately (no flash)
268
+ defaultValues: (hasStoredValues ? store.get(key) : options.defaultValues),
269
+ });
270
+ // When restoring from store, the stored values ARE the defaultValues,
271
+ // so isDirty is false. Fix this by re-establishing the original defaults
272
+ // as the baseline, then restoring the stored values with keepDefaultValues.
273
+ const didRestore = useRef(hasStoredValues);
274
+ useEffect(() => {
275
+ if (didRestore.current) {
276
+ didRestore.current = false;
277
+ const currentValues = form.getValues();
278
+ // Set internal defaults back to the originals
279
+ form.reset(options.defaultValues);
280
+ // Restore stored values, keeping original defaults as the isDirty baseline
281
+ form.reset(currentValues, { keepDefaultValues: true });
282
+ }
283
+ // eslint-disable-next-line react-hooks/exhaustive-deps
284
+ }, []);
285
+ useEffect(() => {
286
+ const subscription = form.watch((values) => {
287
+ store.set(key, values);
288
+ });
289
+ return () => subscription.unsubscribe();
290
+ }, [form, store, key]);
291
+ return form;
292
+ }
293
+ return {
294
+ Wrapper,
295
+ Content,
296
+ usePreservedState,
297
+ usePreservedForm,
298
+ };
299
+ }
300
+
301
+ export { createPushModal, createResponsiveWrapper };
302
+ //# sourceMappingURL=index.js.map