@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.
- package/CHANGELOG.md +12 -0
- package/LICENSE +21 -0
- package/README.md +95 -0
- package/dist/index.cjs +305 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +180 -0
- package/dist/index.d.ts +180 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +302 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/factory.d.ts +139 -0
- package/dist/lib/factory.d.ts.map +1 -0
- package/dist/lib/responsive.d.ts +39 -0
- package/dist/lib/responsive.d.ts.map +1 -0
- package/package.json +86 -0
package/dist/index.d.cts
ADDED
|
@@ -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 };
|
package/dist/index.d.ts
ADDED
|
@@ -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
|