react-modal-port 0.2.6 → 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 +47 -0
- package/LICENSE +21 -0
- package/MIGRATION.md +74 -0
- package/dist/index.cjs +220 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +113 -0
- package/dist/index.d.ts +113 -0
- package/dist/index.js +194 -0
- package/dist/index.js.map +1 -0
- package/package.json +63 -45
- package/readme.md +245 -234
- package/dist/index.mjs +0 -2
- package/dist/index.mjs.map +0 -1
- package/dist/index.modern.mjs +0 -2
- package/dist/index.modern.mjs.map +0 -1
- package/dist/index.umd.js +0 -2
- package/dist/index.umd.js.map +0 -1
- package/types/context.d.ts +0 -20
- package/types/context.d.ts.map +0 -1
- package/types/index.d.ts +0 -3
- package/types/index.d.ts.map +0 -1
- package/types/modal-port.d.ts +0 -4
- package/types/modal-port.d.ts.map +0 -1
- package/types/setupTests.d.ts +0 -1
- package/types/types.d.ts +0 -34
package/dist/index.js
ADDED
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
// src/context.tsx
|
|
4
|
+
import {
|
|
5
|
+
createContext,
|
|
6
|
+
use,
|
|
7
|
+
useCallback,
|
|
8
|
+
useMemo,
|
|
9
|
+
useReducer
|
|
10
|
+
} from "react";
|
|
11
|
+
|
|
12
|
+
// src/store.ts
|
|
13
|
+
function reducer(stack, action) {
|
|
14
|
+
switch (action.type) {
|
|
15
|
+
case "push":
|
|
16
|
+
return [...stack, action.item];
|
|
17
|
+
case "remove":
|
|
18
|
+
return stack.some((item) => item.id === action.id) ? stack.filter((item) => item.id !== action.id) : stack;
|
|
19
|
+
case "setState": {
|
|
20
|
+
const { id, update } = action;
|
|
21
|
+
if (!stack.some((item) => item.id === id)) return stack;
|
|
22
|
+
return stack.map(
|
|
23
|
+
(item) => item.id === id ? { ...item, state: typeof update === "function" ? update(item.state) : { ...update } } : item
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// src/context.tsx
|
|
30
|
+
import { jsx } from "react/jsx-runtime";
|
|
31
|
+
var ActionsContext = createContext(null);
|
|
32
|
+
var StackContext = createContext(null);
|
|
33
|
+
var ItemContext = createContext(null);
|
|
34
|
+
var nextId = 0;
|
|
35
|
+
var warned = /* @__PURE__ */ new Set();
|
|
36
|
+
var isProduction = () => {
|
|
37
|
+
try {
|
|
38
|
+
return process.env.NODE_ENV === "production";
|
|
39
|
+
} catch {
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
function warnOnce(key, message) {
|
|
44
|
+
if (isProduction() || warned.has(key)) return;
|
|
45
|
+
warned.add(key);
|
|
46
|
+
console.warn(`[react-modal-port] ${message}`);
|
|
47
|
+
}
|
|
48
|
+
function ModalProvider({ children }) {
|
|
49
|
+
const [stack, dispatch] = useReducer(reducer, []);
|
|
50
|
+
const actions = useMemo(() => {
|
|
51
|
+
const launchModal = ((render, resolvers, props = {}, options = {}) => {
|
|
52
|
+
const id = ++nextId;
|
|
53
|
+
let settled = false;
|
|
54
|
+
const wrap = (fn) => async (...args) => {
|
|
55
|
+
if (settled) return void 0;
|
|
56
|
+
settled = true;
|
|
57
|
+
try {
|
|
58
|
+
const result = await fn(...args);
|
|
59
|
+
dispatch({ type: "remove", id });
|
|
60
|
+
return result;
|
|
61
|
+
} catch (error) {
|
|
62
|
+
settled = false;
|
|
63
|
+
throw error;
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
const { onBackdropClick: legacyDismiss, ...ownResolvers } = resolvers;
|
|
67
|
+
if (legacyDismiss) {
|
|
68
|
+
warnOnce(
|
|
69
|
+
"onBackdropClick",
|
|
70
|
+
"Passing `onBackdropClick` as a resolver is deprecated. Use `launchModal(Modal, resolvers, props, { onDismiss })`."
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
const onDismiss = options.onDismiss ?? legacyDismiss;
|
|
74
|
+
for (const key of Object.keys(props)) {
|
|
75
|
+
if (key in ownResolvers) {
|
|
76
|
+
warnOnce(
|
|
77
|
+
`collision:${key}`,
|
|
78
|
+
`Prop "${key}" has the same name as a resolver and is ignored. Resolvers take precedence.`
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
dispatch({
|
|
83
|
+
type: "push",
|
|
84
|
+
item: {
|
|
85
|
+
id,
|
|
86
|
+
render,
|
|
87
|
+
props,
|
|
88
|
+
resolvers: Object.fromEntries(Object.entries(ownResolvers).map(([key, fn]) => [key, wrap(fn)])),
|
|
89
|
+
onDismiss: onDismiss ? wrap(onDismiss) : void 0,
|
|
90
|
+
state: {}
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
return {
|
|
94
|
+
id,
|
|
95
|
+
close: () => {
|
|
96
|
+
settled = true;
|
|
97
|
+
dispatch({ type: "remove", id });
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
});
|
|
101
|
+
return {
|
|
102
|
+
launchModal,
|
|
103
|
+
setState: (id, update) => dispatch({ type: "setState", id, update })
|
|
104
|
+
};
|
|
105
|
+
}, []);
|
|
106
|
+
return /* @__PURE__ */ jsx(ActionsContext, { value: actions, children: /* @__PURE__ */ jsx(StackContext, { value: stack, children }) });
|
|
107
|
+
}
|
|
108
|
+
var ModalContextProvider = ModalProvider;
|
|
109
|
+
function useRequired(context, hook) {
|
|
110
|
+
const value = use(context);
|
|
111
|
+
if (value === null) {
|
|
112
|
+
throw new Error(`${hook} must be used within a <ModalProvider>`);
|
|
113
|
+
}
|
|
114
|
+
return value;
|
|
115
|
+
}
|
|
116
|
+
function useModalItems(hook = "ModalPort") {
|
|
117
|
+
return useRequired(StackContext, hook);
|
|
118
|
+
}
|
|
119
|
+
function toEntry({ id, render, props, state }) {
|
|
120
|
+
return { id, render, props, state };
|
|
121
|
+
}
|
|
122
|
+
function useModal() {
|
|
123
|
+
return useRequired(ActionsContext, "useModal").launchModal;
|
|
124
|
+
}
|
|
125
|
+
function useModalStack() {
|
|
126
|
+
const items = useModalItems("useModalStack");
|
|
127
|
+
return useMemo(() => items.map(toEntry), [items]);
|
|
128
|
+
}
|
|
129
|
+
function useModalState() {
|
|
130
|
+
const { setState } = useRequired(ActionsContext, "useModalState");
|
|
131
|
+
const items = useModalItems("useModalState");
|
|
132
|
+
const ownId = use(ItemContext);
|
|
133
|
+
const item = ownId === null ? items.at(-1) : items.find((entry) => entry.id === ownId);
|
|
134
|
+
const id = item?.id;
|
|
135
|
+
const update = useCallback(
|
|
136
|
+
(next) => {
|
|
137
|
+
if (id !== void 0) setState(id, next);
|
|
138
|
+
},
|
|
139
|
+
[id, setState]
|
|
140
|
+
);
|
|
141
|
+
return [item ? item.state : null, update];
|
|
142
|
+
}
|
|
143
|
+
function useModalContext() {
|
|
144
|
+
const launchModal = useRequired(ActionsContext, "useModalContext").launchModal;
|
|
145
|
+
const stack = useModalStack();
|
|
146
|
+
const [, updateState] = useModalState();
|
|
147
|
+
return { stack, launchModal, updateState };
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// src/modal-port.tsx
|
|
151
|
+
import { Fragment, useEffect, useRef } from "react";
|
|
152
|
+
import { createPortal } from "react-dom";
|
|
153
|
+
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
154
|
+
var NoBackdrop = ({ children }) => /* @__PURE__ */ jsx2(Fragment, { children });
|
|
155
|
+
function ModalPort({
|
|
156
|
+
backdrop,
|
|
157
|
+
render,
|
|
158
|
+
container,
|
|
159
|
+
onModalLaunch,
|
|
160
|
+
onModalClose,
|
|
161
|
+
onStackChange
|
|
162
|
+
}) {
|
|
163
|
+
const stack = useModalItems();
|
|
164
|
+
const size = stack.length;
|
|
165
|
+
const previousSize = useRef(0);
|
|
166
|
+
useEffect(() => {
|
|
167
|
+
const previous = previousSize.current;
|
|
168
|
+
if (previous === size) return;
|
|
169
|
+
previousSize.current = size;
|
|
170
|
+
onStackChange?.(size);
|
|
171
|
+
if (previous === 0) onModalLaunch?.();
|
|
172
|
+
else if (size === 0) onModalClose?.();
|
|
173
|
+
}, [size, onModalLaunch, onModalClose, onStackChange]);
|
|
174
|
+
const top = stack.at(-1);
|
|
175
|
+
if (!top) return null;
|
|
176
|
+
const Backdrop = backdrop ?? render ?? NoBackdrop;
|
|
177
|
+
const Modal = top.render;
|
|
178
|
+
const { onDismiss } = top;
|
|
179
|
+
const onBackdropClick = onDismiss ? (event) => {
|
|
180
|
+
if (event.currentTarget === event.target) void onDismiss(event);
|
|
181
|
+
} : void 0;
|
|
182
|
+
const content = /* @__PURE__ */ jsx2(Backdrop, { onBackdropClick, modalId: top.id, stackSize: size, children: /* @__PURE__ */ jsx2(ItemContext, { value: top.id, children: /* @__PURE__ */ jsx2(Modal, { ...top.props, ...top.resolvers }) }, top.id) });
|
|
183
|
+
return container ? createPortal(content, container) : content;
|
|
184
|
+
}
|
|
185
|
+
export {
|
|
186
|
+
ModalContextProvider,
|
|
187
|
+
ModalPort,
|
|
188
|
+
ModalProvider,
|
|
189
|
+
useModal,
|
|
190
|
+
useModalContext,
|
|
191
|
+
useModalStack,
|
|
192
|
+
useModalState
|
|
193
|
+
};
|
|
194
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/context.tsx","../src/store.ts","../src/modal-port.tsx"],"sourcesContent":["import {\n createContext,\n use,\n useCallback,\n useMemo,\n useReducer,\n type ComponentType,\n type Context,\n type ReactNode,\n} from 'react';\nimport { reducer, type ModalItem, type StateUpdate } from './store';\nimport type {\n LaunchModal,\n LaunchOptions,\n ModalContextProperties,\n ModalStackEntry,\n ModalState,\n UpdateModalState,\n} from './types';\n\ntype Actions = {\n launchModal: LaunchModal;\n setState: (id: number, update: StateUpdate) => void;\n};\n\nconst ActionsContext = createContext<Actions | null>(null);\nconst StackContext = createContext<readonly ModalItem[] | null>(null);\n/** Id of the modal a component is rendered inside, if any. */\nexport const ItemContext = createContext<number | null>(null);\n\nlet nextId = 0;\nconst warned = new Set<string>();\ndeclare const process: { env: { NODE_ENV?: string } };\n// Bundlers replace the literal `process.env.NODE_ENV` but usually do not define `process`,\n// so read it directly; unbundled ESM (no `process` at all) falls back to development.\nconst isProduction = () => {\n try {\n return process.env.NODE_ENV === 'production';\n } catch {\n return false;\n }\n};\nfunction warnOnce(key: string, message: string) {\n if (isProduction() || warned.has(key)) return;\n warned.add(key);\n console.warn(`[react-modal-port] ${message}`);\n}\n\ntype AnyResolver = (...args: unknown[]) => unknown;\n\nexport function ModalProvider({ children }: { children?: ReactNode }) {\n const [stack, dispatch] = useReducer(reducer, []);\n\n const actions = useMemo<Actions>(() => {\n const launchModal = ((\n render: ComponentType<never>,\n resolvers: Record<string, AnyResolver>,\n props: Record<string, unknown> = {},\n options: LaunchOptions = {},\n ) => {\n // Created outside the reducer so StrictMode's double-invoked reducers stay pure.\n const id = ++nextId;\n let settled = false;\n\n const wrap =\n (fn: AnyResolver) =>\n async (...args: unknown[]) => {\n if (settled) return undefined;\n settled = true;\n try {\n const result = await fn(...args);\n dispatch({ type: 'remove', id });\n return result;\n } catch (error) {\n // Keep the modal open so the user can retry; let the caller handle the error.\n settled = false;\n throw error;\n }\n };\n\n const { onBackdropClick: legacyDismiss, ...ownResolvers } = resolvers;\n if (legacyDismiss) {\n warnOnce(\n 'onBackdropClick',\n 'Passing `onBackdropClick` as a resolver is deprecated. Use `launchModal(Modal, resolvers, props, { onDismiss })`.',\n );\n }\n const onDismiss = options.onDismiss ?? legacyDismiss;\n\n for (const key of Object.keys(props)) {\n if (key in ownResolvers) {\n warnOnce(\n `collision:${key}`,\n `Prop \"${key}\" has the same name as a resolver and is ignored. Resolvers take precedence.`,\n );\n }\n }\n\n dispatch({\n type: 'push',\n item: {\n id,\n render,\n props,\n resolvers: Object.fromEntries(Object.entries(ownResolvers).map(([key, fn]) => [key, wrap(fn)])),\n onDismiss: onDismiss ? wrap(onDismiss as AnyResolver) : undefined,\n state: {},\n },\n });\n\n return {\n id,\n close: () => {\n settled = true;\n dispatch({ type: 'remove', id });\n },\n };\n }) as LaunchModal;\n\n return {\n launchModal,\n setState: (id, update) => dispatch({ type: 'setState', id, update }),\n };\n }, []);\n\n return (\n <ActionsContext value={actions}>\n <StackContext value={stack}>{children}</StackContext>\n </ActionsContext>\n );\n}\n\n/** @deprecated Use `ModalProvider`. */\nexport const ModalContextProvider = ModalProvider;\n\nfunction useRequired<T>(context: Context<T | null>, hook: string): T {\n const value = use(context);\n if (value === null) {\n throw new Error(`${hook} must be used within a <ModalProvider>`);\n }\n return value;\n}\n\n/** @internal Full stack items, including wrapped resolvers. Used by `ModalPort`. */\nexport function useModalItems(hook = 'ModalPort'): readonly ModalItem[] {\n return useRequired(StackContext, hook);\n}\n\nfunction toEntry({ id, render, props, state }: ModalItem): ModalStackEntry {\n return { id, render, props, state };\n}\n\n/** Returns the `launchModal` function. Does not re-render when the stack changes. */\nexport function useModal(): LaunchModal {\n return useRequired(ActionsContext, 'useModal').launchModal;\n}\n\n/** A read-only view of the modal stack, bottom first. */\nexport function useModalStack(): readonly ModalStackEntry[] {\n const items = useModalItems('useModalStack');\n return useMemo(() => items.map(toEntry), [items]);\n}\n\n/**\n * State shared by the modal this hook is called in (or the top modal, when called\n * outside any modal). Survives while other modals are stacked on top and is\n * discarded when the modal closes. `null` when there is no such modal.\n */\nexport function useModalState<S extends ModalState = ModalState>(): [S | null, UpdateModalState<S>] {\n const { setState } = useRequired(ActionsContext, 'useModalState');\n const items = useModalItems('useModalState');\n const ownId = use(ItemContext);\n const item = ownId === null ? items.at(-1) : items.find((entry) => entry.id === ownId);\n const id = item?.id;\n\n const update = useCallback<UpdateModalState<S>>(\n (next) => {\n if (id !== undefined) setState(id, next as StateUpdate);\n },\n [id, setState],\n );\n\n return [item ? (item.state as S) : null, update];\n}\n\n/**\n * @deprecated Use `useModal`, `useModalStack` and `useModalState`. This hook re-renders\n * on every stack change.\n */\nexport function useModalContext(): ModalContextProperties {\n const launchModal = useRequired(ActionsContext, 'useModalContext').launchModal;\n const stack = useModalStack();\n const [, updateState] = useModalState();\n return { stack, launchModal, updateState };\n}\n","import type { ComponentType } from 'react';\nimport type { ModalState } from './types';\n\nexport type ModalItem = {\n readonly id: number;\n readonly render: ComponentType<never>;\n /** Resolvers, already wrapped so that they close this item. */\n readonly resolvers: Readonly<Record<string, (...args: unknown[]) => Promise<unknown>>>;\n readonly props: Readonly<Record<string, unknown>>;\n readonly onDismiss: ((...args: unknown[]) => Promise<unknown>) | undefined;\n readonly state: ModalState;\n};\n\nexport type StateUpdate = ModalState | ((prev: ModalState) => ModalState);\n\nexport type Action =\n | { type: 'push'; item: ModalItem }\n | { type: 'remove'; id: number }\n | { type: 'setState'; id: number; update: StateUpdate };\n\n/** Pure stack reducer. Ids are created by the caller, so this stays StrictMode-safe. */\nexport function reducer(stack: readonly ModalItem[], action: Action): readonly ModalItem[] {\n switch (action.type) {\n case 'push':\n return [...stack, action.item];\n case 'remove':\n return stack.some((item) => item.id === action.id)\n ? stack.filter((item) => item.id !== action.id)\n : stack;\n case 'setState': {\n const { id, update } = action;\n if (!stack.some((item) => item.id === id)) return stack;\n return stack.map((item) =>\n item.id === id\n ? { ...item, state: typeof update === 'function' ? update(item.state) : { ...update } }\n : item,\n );\n }\n }\n}\n","import { Fragment, useEffect, useRef, type ComponentType, type SyntheticEvent } from 'react';\nimport { createPortal } from 'react-dom';\nimport { ItemContext, useModalItems } from './context';\nimport type { ModalPortProps, ModalPortRenderProps } from './types';\n\nconst NoBackdrop = ({ children }: ModalPortRenderProps) => <Fragment>{children}</Fragment>;\n\n/** Renders the top modal of the stack inside `backdrop`. */\nexport function ModalPort({\n backdrop,\n render,\n container,\n onModalLaunch,\n onModalClose,\n onStackChange,\n}: ModalPortProps) {\n const stack = useModalItems();\n const size = stack.length;\n const previousSize = useRef(0);\n\n useEffect(() => {\n const previous = previousSize.current;\n if (previous === size) return;\n previousSize.current = size;\n onStackChange?.(size);\n if (previous === 0) onModalLaunch?.();\n else if (size === 0) onModalClose?.();\n }, [size, onModalLaunch, onModalClose, onStackChange]);\n\n const top = stack.at(-1);\n if (!top) return null;\n\n const Backdrop = backdrop ?? render ?? NoBackdrop;\n // Props are typed per launch; the stack stores them loosely.\n const Modal = top.render as ComponentType<Record<string, unknown>>;\n const { onDismiss } = top;\n const onBackdropClick = onDismiss\n ? (event: SyntheticEvent) => {\n // Ignore clicks that bubble up from the modal content.\n if (event.currentTarget === event.target) void onDismiss(event);\n }\n : undefined;\n\n const content = (\n <Backdrop onBackdropClick={onBackdropClick} modalId={top.id} stackSize={size}>\n <ItemContext key={top.id} value={top.id}>\n <Modal {...top.props} {...top.resolvers} />\n </ItemContext>\n </Backdrop>\n );\n\n return container ? createPortal(content, container) : content;\n}\n"],"mappings":"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","names":["jsx"]}
|
package/package.json
CHANGED
|
@@ -1,48 +1,56 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-modal-port",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Launch modals from any React component.",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Launch type-safe modals from any React component and render them in one place.",
|
|
5
5
|
"type": "module",
|
|
6
|
-
"
|
|
7
|
-
"
|
|
8
|
-
"
|
|
9
|
-
"main:umd": "dist/index.umd.js",
|
|
10
|
-
"module": "dist/index.mjs",
|
|
6
|
+
"main": "./dist/index.cjs",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
11
9
|
"exports": {
|
|
12
|
-
"
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
10
|
+
".": {
|
|
11
|
+
"import": {
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"default": "./dist/index.js"
|
|
14
|
+
},
|
|
15
|
+
"require": {
|
|
16
|
+
"types": "./dist/index.d.cts",
|
|
17
|
+
"default": "./dist/index.cjs"
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
"./package.json": "./package.json"
|
|
16
21
|
},
|
|
17
22
|
"files": [
|
|
18
23
|
"dist",
|
|
19
|
-
"
|
|
24
|
+
"CHANGELOG.md",
|
|
25
|
+
"MIGRATION.md"
|
|
20
26
|
],
|
|
27
|
+
"sideEffects": false,
|
|
28
|
+
"engines": {
|
|
29
|
+
"node": ">=18"
|
|
30
|
+
},
|
|
21
31
|
"scripts": {
|
|
22
|
-
"build": "
|
|
23
|
-
"
|
|
24
|
-
"
|
|
25
|
-
"
|
|
26
|
-
"
|
|
27
|
-
"
|
|
28
|
-
"
|
|
29
|
-
"
|
|
30
|
-
"
|
|
32
|
+
"build": "tsup",
|
|
33
|
+
"typecheck": "tsc -p tsconfig.json",
|
|
34
|
+
"lint": "eslint .",
|
|
35
|
+
"test": "vitest run",
|
|
36
|
+
"test:watch": "vitest",
|
|
37
|
+
"test:coverage": "vitest run --coverage",
|
|
38
|
+
"check:package": "publint && attw --pack . && node scripts/smoke-test.mjs",
|
|
39
|
+
"verify": "npm run lint && npm run typecheck && npm run test:coverage && npm run build && npm run check:package",
|
|
40
|
+
"prepublishOnly": "npm_config_dry_run=false npm run verify",
|
|
41
|
+
"test:react": "node scripts/test-react-versions.mjs"
|
|
31
42
|
},
|
|
32
43
|
"repository": {
|
|
33
44
|
"type": "git",
|
|
34
45
|
"url": "git+https://github.com/oliverwehn/react-modal-port.git"
|
|
35
46
|
},
|
|
36
|
-
"tags": [
|
|
37
|
-
"react",
|
|
38
|
-
"modal",
|
|
39
|
-
"dialog"
|
|
40
|
-
],
|
|
41
47
|
"keywords": [
|
|
42
48
|
"react",
|
|
43
49
|
"react-component",
|
|
44
50
|
"modal",
|
|
45
|
-
"dialog"
|
|
51
|
+
"dialog",
|
|
52
|
+
"typescript",
|
|
53
|
+
"stack"
|
|
46
54
|
],
|
|
47
55
|
"author": "Oliver Greuter-Wehn",
|
|
48
56
|
"license": "MIT",
|
|
@@ -50,25 +58,35 @@
|
|
|
50
58
|
"url": "https://github.com/oliverwehn/react-modal-port/issues"
|
|
51
59
|
},
|
|
52
60
|
"homepage": "https://github.com/oliverwehn/react-modal-port#readme",
|
|
53
|
-
"
|
|
54
|
-
"devDependencies": {
|
|
55
|
-
"react": "^19.0.0",
|
|
56
|
-
"react-dom": "^19.0.0",
|
|
61
|
+
"peerDependencies": {
|
|
57
62
|
"@types/react": "^19.0.0",
|
|
58
|
-
"
|
|
59
|
-
"
|
|
60
|
-
"microbundle": "^0.15.1",
|
|
61
|
-
"typescript": "^5.7.2",
|
|
62
|
-
"jest": "^29.7.0",
|
|
63
|
-
"jest-environment-jsdom": "^29.7.0",
|
|
64
|
-
"ts-jest": "^29.2.5",
|
|
65
|
-
"@testing-library/react": "^16.3.0",
|
|
66
|
-
"@testing-library/jest-dom": "^6.6.3",
|
|
67
|
-
"@testing-library/user-event": "^14.5.2"
|
|
63
|
+
"react": "^19.0.0",
|
|
64
|
+
"react-dom": "^19.0.0"
|
|
68
65
|
},
|
|
69
|
-
"
|
|
70
|
-
"@types/react":
|
|
71
|
-
|
|
72
|
-
|
|
66
|
+
"peerDependenciesMeta": {
|
|
67
|
+
"@types/react": {
|
|
68
|
+
"optional": true
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
"devDependencies": {
|
|
72
|
+
"@arethetypeswrong/cli": "^0.18.5",
|
|
73
|
+
"@eslint/js": "^10.0.1",
|
|
74
|
+
"@testing-library/dom": "^10.4.2",
|
|
75
|
+
"@testing-library/jest-dom": "^7.0.1",
|
|
76
|
+
"@testing-library/react": "^16.3.3",
|
|
77
|
+
"@testing-library/user-event": "^14.6.7",
|
|
78
|
+
"@types/react": "^19.3.0",
|
|
79
|
+
"@types/react-dom": "^19.3.0",
|
|
80
|
+
"@vitest/coverage-v8": "^5.0.3",
|
|
81
|
+
"eslint": "^10.11.0",
|
|
82
|
+
"eslint-plugin-react-hooks": "^7.1.1",
|
|
83
|
+
"jsdom": "^30.1.1",
|
|
84
|
+
"publint": "^0.3.25",
|
|
85
|
+
"react": "^19.3.0",
|
|
86
|
+
"react-dom": "^19.3.0",
|
|
87
|
+
"tsup": "^8.5.1",
|
|
88
|
+
"typescript": "~6.0.3",
|
|
89
|
+
"typescript-eslint": "^8.71.0",
|
|
90
|
+
"vitest": "^5.0.3"
|
|
73
91
|
}
|
|
74
92
|
}
|