@willbooster/react-frame-component 0.0.0-semantically-released
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.md +21 -0
- package/README.md +174 -0
- package/dist/react-frame-component.esm.js +151 -0
- package/dist/react-frame-component.esm.js.map +1 -0
- package/dist/react-frame-component.umd.js +189 -0
- package/dist/react-frame-component.umd.js.map +1 -0
- package/index.d.ts +29 -0
- package/package.json +93 -0
package/LICENSE.md
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2018 Ryan Seddon
|
|
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.
|
package/README.md
ADDED
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
# React <Frame /> component
|
|
2
|
+
|
|
3
|
+
[](https://github.com/WillBooster/react-frame-component/actions/workflows/test.yml)
|
|
4
|
+
[](https://github.com/WillBooster/react-frame-component/actions/workflows/deploy-example.yml)
|
|
5
|
+
[](https://github.com/semantic-release/semantic-release)
|
|
6
|
+
[![NPM version][npm-image]][npm-url]
|
|
7
|
+
|
|
8
|
+
This component allows you to encapsulate your entire React application or per component in an iFrame.
|
|
9
|
+
|
|
10
|
+
This is a fork of [ryanseddon/react-frame-component](https://github.com/ryanseddon/react-frame-component) maintained by [WillBooster](https://github.com/WillBooster).
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
npm install --save @willbooster/react-frame-component
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## How to use:
|
|
17
|
+
|
|
18
|
+
```js
|
|
19
|
+
import Frame from '@willbooster/react-frame-component';
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Go check out the [demo][demo-url].
|
|
23
|
+
|
|
24
|
+
```jsx
|
|
25
|
+
const Header = ({ children }) => (
|
|
26
|
+
<Frame>
|
|
27
|
+
<h1>{children}</h1>
|
|
28
|
+
</Frame>
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
ReactDOM.render(<Header>Hello</Header>, document.body);
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Or you can wrap it at the `render` call.
|
|
35
|
+
|
|
36
|
+
```jsx
|
|
37
|
+
ReactDOM.render(
|
|
38
|
+
<Frame>
|
|
39
|
+
<Header>Hello</Header>
|
|
40
|
+
</Frame>,
|
|
41
|
+
document.body
|
|
42
|
+
);
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
##### Props:
|
|
46
|
+
|
|
47
|
+
###### head
|
|
48
|
+
|
|
49
|
+
`head: PropTypes.node`
|
|
50
|
+
|
|
51
|
+
The `head` prop is a dom node that gets inserted before the children of the frame. Note that this is injected into the body of frame (see the blog post for why). This has the benefit of being able to update and works for stylesheets.
|
|
52
|
+
|
|
53
|
+
###### initialContent
|
|
54
|
+
|
|
55
|
+
`initialContent: PropTypes.string`
|
|
56
|
+
|
|
57
|
+
Defaults to `'<!DOCTYPE html><html><head></head><body><div></div></body></html>'`
|
|
58
|
+
|
|
59
|
+
The `initialContent` props is the initial html injected into frame. It is only injected once, but allows you to insert any html into the frame (e.g. a head tag, script tags, etc). Note that it does _not_ update if you change the prop. Also at least one div is required in the body of the html, which we use to render the react dom into.
|
|
60
|
+
|
|
61
|
+
###### mountTarget
|
|
62
|
+
|
|
63
|
+
`mountTarget: PropTypes.string`
|
|
64
|
+
|
|
65
|
+
The `mountTarget` props is a css selector (#target/.target) that specifies where in the `initialContent` of the iframe, children will be mounted.
|
|
66
|
+
|
|
67
|
+
```jsx
|
|
68
|
+
<Frame
|
|
69
|
+
initialContent='<!DOCTYPE html><html><head></head><body><h1>i wont be changed</h1><div id="mountHere"></div></body></html>'
|
|
70
|
+
mountTarget="#mountHere"
|
|
71
|
+
></Frame>
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
###### dangerouslyUseDocWrite
|
|
75
|
+
|
|
76
|
+
`dangerouslyUseDocWrite: PropTypes.bool`
|
|
77
|
+
|
|
78
|
+
Defaults to `false`
|
|
79
|
+
|
|
80
|
+
The frame's initial content, as defined by the `initialContent` prop, is populated via the frame's `srcdoc` attribute by default. However, this can cause issues with some libraries such as Recaptcha and Google Maps that depend on the frame's location/origin. In these cases, setting this flag will cause `Frame` to use `document.write()` to populate the initial content. This is **unperformant and unrecommended**, but allows these libraries to be used inside a `Frame` instance.
|
|
81
|
+
|
|
82
|
+
###### contentDidMount and contentDidUpdate
|
|
83
|
+
|
|
84
|
+
`contentDidMount: PropTypes.func`
|
|
85
|
+
`contentDidUpdate: PropTypes.func`
|
|
86
|
+
|
|
87
|
+
`contentDidMount` and `contentDidUpdate` are conceptually equivalent to
|
|
88
|
+
`componentDidMount` and `componentDidUpdate`, respectively. The reason these are
|
|
89
|
+
needed is because internally we call `ReactDOM.render` which starts a new set of
|
|
90
|
+
lifecycle calls. This set of lifecycle calls are sometimes triggered after the
|
|
91
|
+
lifecycle of the parent component, so these callbacks provide a hook to know
|
|
92
|
+
when the frame contents are mounted and updated.
|
|
93
|
+
|
|
94
|
+
###### ref
|
|
95
|
+
|
|
96
|
+
`ref: PropTypes.oneOfType([ PropTypes.func, PropTypes.shape({ current: PropTypes.instanceOf(Element) }) ])`
|
|
97
|
+
|
|
98
|
+
The `ref` prop provides a way to access inner iframe DOM node. To utilitize this prop use, for example, one of the React's built-in methods to create a ref: [`React.createRef()`](https://reactjs.org/docs/refs-and-the-dom.html#creating-refs) or [`React.useRef()`](https://reactjs.org/docs/hooks-reference.html#useref).
|
|
99
|
+
|
|
100
|
+
```js
|
|
101
|
+
const MyComponent = (props) => {
|
|
102
|
+
const iframeRef = React.useRef();
|
|
103
|
+
|
|
104
|
+
React.useEffect(() => {
|
|
105
|
+
// Use iframeRef for:
|
|
106
|
+
// - focus managing
|
|
107
|
+
// - triggering imperative animations
|
|
108
|
+
// - integrating with third-party DOM libraries
|
|
109
|
+
iframeRef.current.focus();
|
|
110
|
+
}, []);
|
|
111
|
+
|
|
112
|
+
return (
|
|
113
|
+
<Frame ref={iframeRef}>
|
|
114
|
+
<InnerComponent />
|
|
115
|
+
</Frame>
|
|
116
|
+
);
|
|
117
|
+
};
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
##### Accessing the iframe's window and document
|
|
121
|
+
|
|
122
|
+
The iframe's `window` and `document` may be accessed via the `FrameContextConsumer` or the `useFrame` hook.
|
|
123
|
+
|
|
124
|
+
The example with `FrameContextConsumer`:
|
|
125
|
+
|
|
126
|
+
```js
|
|
127
|
+
import Frame, { FrameContextConsumer } from '@willbooster/react-frame-component';
|
|
128
|
+
|
|
129
|
+
const MyComponent = (props, context) => (
|
|
130
|
+
<Frame>
|
|
131
|
+
<FrameContextConsumer>
|
|
132
|
+
{
|
|
133
|
+
// Callback is invoked with iframe's window and document instances
|
|
134
|
+
({ document, window }) => {
|
|
135
|
+
// Render Children
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
</FrameContextConsumer>
|
|
139
|
+
</Frame>
|
|
140
|
+
);
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
The example with `useFrame` hook:
|
|
144
|
+
|
|
145
|
+
```js
|
|
146
|
+
import Frame, { useFrame } from '@willbooster/react-frame-component';
|
|
147
|
+
|
|
148
|
+
const InnerComponent = () => {
|
|
149
|
+
// Hook returns iframe's window and document instances from Frame context
|
|
150
|
+
const { document, window } = useFrame();
|
|
151
|
+
|
|
152
|
+
return null;
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
const OuterComponent = () => (
|
|
156
|
+
<Frame>
|
|
157
|
+
<InnerComponent />
|
|
158
|
+
</Frame>
|
|
159
|
+
);
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
## More info
|
|
163
|
+
|
|
164
|
+
I wrote a [blog post][blog-url] about building this component.
|
|
165
|
+
|
|
166
|
+
## License
|
|
167
|
+
|
|
168
|
+
Copyright 2014, Ryan Seddon.
|
|
169
|
+
This content is released under the MIT license http://ryanseddon.mit-license.org
|
|
170
|
+
|
|
171
|
+
[npm-url]: https://www.npmjs.com/package/@willbooster/react-frame-component
|
|
172
|
+
[npm-image]: https://img.shields.io/npm/v/%40willbooster%2Freact-frame-component
|
|
173
|
+
[demo-url]: https://willbooster.github.io/react-frame-component/
|
|
174
|
+
[blog-url]: https://medium.com/@ryanseddon/rendering-to-iframes-in-react-d1cb92274f86
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import React, { Children, Component } from "react";
|
|
2
|
+
import ReactDOM from "react-dom";
|
|
3
|
+
import PropTypes from "prop-types";
|
|
4
|
+
import { jsx } from "react/jsx-runtime";
|
|
5
|
+
//#region src/Context.jsx
|
|
6
|
+
var doc;
|
|
7
|
+
var win;
|
|
8
|
+
if (typeof document !== "undefined") doc = document;
|
|
9
|
+
if (globalThis.window !== void 0) win = globalThis.window;
|
|
10
|
+
var FrameContext = React.createContext({
|
|
11
|
+
document: doc,
|
|
12
|
+
window: win
|
|
13
|
+
});
|
|
14
|
+
var useFrame = () => React.useContext(FrameContext);
|
|
15
|
+
var { Provider: FrameContextProvider, Consumer: FrameContextConsumer } = FrameContext;
|
|
16
|
+
//#endregion
|
|
17
|
+
//#region src/Content.jsx
|
|
18
|
+
var Content = class extends Component {
|
|
19
|
+
static propTypes = {
|
|
20
|
+
children: PropTypes.element.isRequired,
|
|
21
|
+
contentDidMount: PropTypes.func.isRequired,
|
|
22
|
+
contentDidUpdate: PropTypes.func.isRequired
|
|
23
|
+
};
|
|
24
|
+
componentDidMount() {
|
|
25
|
+
this.props.contentDidMount();
|
|
26
|
+
}
|
|
27
|
+
componentDidUpdate() {
|
|
28
|
+
this.props.contentDidUpdate();
|
|
29
|
+
}
|
|
30
|
+
render() {
|
|
31
|
+
return Children.only(this.props.children);
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
//#endregion
|
|
35
|
+
//#region src/Frame.jsx
|
|
36
|
+
var Frame = class extends Component {
|
|
37
|
+
static propTypes = {
|
|
38
|
+
style: PropTypes.object,
|
|
39
|
+
head: PropTypes.node,
|
|
40
|
+
initialContent: PropTypes.string,
|
|
41
|
+
mountTarget: PropTypes.string,
|
|
42
|
+
dangerouslyUseDocWrite: PropTypes.bool,
|
|
43
|
+
contentDidMount: PropTypes.func,
|
|
44
|
+
contentDidUpdate: PropTypes.func,
|
|
45
|
+
children: PropTypes.oneOfType([PropTypes.element, PropTypes.arrayOf(PropTypes.element)])
|
|
46
|
+
};
|
|
47
|
+
static defaultProps = {
|
|
48
|
+
style: {},
|
|
49
|
+
head: void 0,
|
|
50
|
+
children: void 0,
|
|
51
|
+
mountTarget: void 0,
|
|
52
|
+
dangerouslyUseDocWrite: false,
|
|
53
|
+
contentDidMount: () => {},
|
|
54
|
+
contentDidUpdate: () => {},
|
|
55
|
+
initialContent: "<!DOCTYPE html><html><head></head><body><div class=\"frame-root\"></div></body></html>"
|
|
56
|
+
};
|
|
57
|
+
constructor(props, context) {
|
|
58
|
+
super(props, context);
|
|
59
|
+
this._isMounted = false;
|
|
60
|
+
this.nodeRef = React.createRef();
|
|
61
|
+
this.state = { iframeLoaded: false };
|
|
62
|
+
}
|
|
63
|
+
componentDidMount() {
|
|
64
|
+
this._isMounted = true;
|
|
65
|
+
if (this.getDoc()) this.nodeRef.current.contentWindow.addEventListener("DOMContentLoaded", this.handleLoad);
|
|
66
|
+
if (this.props.dangerouslyUseDocWrite) this.handleLoad();
|
|
67
|
+
}
|
|
68
|
+
componentWillUnmount() {
|
|
69
|
+
this._isMounted = false;
|
|
70
|
+
this.nodeRef.current.removeEventListener("DOMContentLoaded", this.handleLoad);
|
|
71
|
+
}
|
|
72
|
+
getDoc() {
|
|
73
|
+
return this.nodeRef.current ? this.nodeRef.current.contentDocument : void 0;
|
|
74
|
+
}
|
|
75
|
+
getMountTarget() {
|
|
76
|
+
const doc = this.getDoc();
|
|
77
|
+
if (!doc || !doc.body) return;
|
|
78
|
+
if (this.props.mountTarget) return doc.querySelector(this.props.mountTarget);
|
|
79
|
+
return doc.body.children[0];
|
|
80
|
+
}
|
|
81
|
+
setRef = (node) => {
|
|
82
|
+
this.nodeRef.current = node;
|
|
83
|
+
const { forwardedRef } = this.props;
|
|
84
|
+
if (typeof forwardedRef === "function") forwardedRef(node);
|
|
85
|
+
else if (forwardedRef) forwardedRef.current = node;
|
|
86
|
+
};
|
|
87
|
+
handleLoad = () => {
|
|
88
|
+
clearInterval(this.loadCheck);
|
|
89
|
+
if (!this.state.iframeLoaded) this.setState({ iframeLoaded: true });
|
|
90
|
+
};
|
|
91
|
+
loadCheck = () => setInterval(() => {
|
|
92
|
+
this.handleLoad();
|
|
93
|
+
}, 500);
|
|
94
|
+
renderFrameContents() {
|
|
95
|
+
if (!this._isMounted) return;
|
|
96
|
+
const doc = this.getDoc();
|
|
97
|
+
if (!doc) return;
|
|
98
|
+
const contentDidMount = this.props.contentDidMount;
|
|
99
|
+
const contentDidUpdate = this.props.contentDidUpdate;
|
|
100
|
+
const contents = /* @__PURE__ */ jsx(Content, {
|
|
101
|
+
contentDidMount,
|
|
102
|
+
contentDidUpdate,
|
|
103
|
+
children: /* @__PURE__ */ jsx(FrameContextProvider, {
|
|
104
|
+
value: {
|
|
105
|
+
document: doc,
|
|
106
|
+
window: doc.defaultView || doc.parentView
|
|
107
|
+
},
|
|
108
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
109
|
+
className: "frame-content",
|
|
110
|
+
children: this.props.children
|
|
111
|
+
})
|
|
112
|
+
})
|
|
113
|
+
});
|
|
114
|
+
if (this.props.dangerouslyUseDocWrite && doc.body.children.length === 0) {
|
|
115
|
+
doc.open("text/html", "replace");
|
|
116
|
+
doc.write(this.props.initialContent);
|
|
117
|
+
doc.close();
|
|
118
|
+
}
|
|
119
|
+
const mountTarget = this.getMountTarget();
|
|
120
|
+
if (!mountTarget) return;
|
|
121
|
+
return [ReactDOM.createPortal(this.props.head, this.getDoc().head), ReactDOM.createPortal(contents, mountTarget)];
|
|
122
|
+
}
|
|
123
|
+
render() {
|
|
124
|
+
const props = {
|
|
125
|
+
...this.props,
|
|
126
|
+
children: void 0
|
|
127
|
+
};
|
|
128
|
+
if (!this.props.dangerouslyUseDocWrite) props.srcDoc = this.props.initialContent;
|
|
129
|
+
delete props.head;
|
|
130
|
+
delete props.initialContent;
|
|
131
|
+
delete props.mountTarget;
|
|
132
|
+
delete props.dangerouslyUseDocWrite;
|
|
133
|
+
delete props.contentDidMount;
|
|
134
|
+
delete props.contentDidUpdate;
|
|
135
|
+
delete props.forwardedRef;
|
|
136
|
+
return /* @__PURE__ */ jsx("iframe", {
|
|
137
|
+
...props,
|
|
138
|
+
ref: this.setRef,
|
|
139
|
+
onLoad: this.handleLoad,
|
|
140
|
+
children: this.state.iframeLoaded && this.renderFrameContents()
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
};
|
|
144
|
+
var Frame_default = React.forwardRef((props, ref) => /* @__PURE__ */ jsx(Frame, {
|
|
145
|
+
...props,
|
|
146
|
+
forwardedRef: ref
|
|
147
|
+
}));
|
|
148
|
+
//#endregion
|
|
149
|
+
export { FrameContext, FrameContextConsumer, Frame_default as default, useFrame };
|
|
150
|
+
|
|
151
|
+
//# sourceMappingURL=react-frame-component.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"react-frame-component.esm.js","names":[],"sources":["../src/Context.jsx","../src/Content.jsx","../src/Frame.jsx"],"sourcesContent":["import React from 'react';\n\nlet doc;\nlet win;\nif (typeof document !== 'undefined') {\n doc = document;\n}\nif (globalThis.window !== undefined) {\n win = globalThis.window;\n}\n\nexport const FrameContext = React.createContext({ document: doc, window: win });\n\nexport const useFrame = () => React.useContext(FrameContext);\n\nexport const { Provider: FrameContextProvider, Consumer: FrameContextConsumer } = FrameContext;\n","import React, { Component, Children } from 'react'; // eslint-disable-line no-unused-vars\nimport PropTypes from 'prop-types';\n\nexport default class Content extends Component {\n static propTypes = {\n children: PropTypes.element.isRequired,\n contentDidMount: PropTypes.func.isRequired,\n contentDidUpdate: PropTypes.func.isRequired,\n };\n\n componentDidMount() {\n this.props.contentDidMount();\n }\n\n componentDidUpdate() {\n this.props.contentDidUpdate();\n }\n\n render() {\n return Children.only(this.props.children);\n }\n}\n","import React, { Component } from 'react';\nimport ReactDOM from 'react-dom';\nimport PropTypes from 'prop-types';\nimport { FrameContextProvider } from './Context';\nimport Content from './Content';\n\nexport class Frame extends Component {\n // React warns when you render directly into the body since browser extensions\n // also inject into the body and can mess up React. For this reason\n // initialContent is expected to have a div inside of the body\n // element that we render react into.\n static propTypes = {\n style: PropTypes.object,\n head: PropTypes.node,\n initialContent: PropTypes.string,\n mountTarget: PropTypes.string,\n dangerouslyUseDocWrite: PropTypes.bool,\n contentDidMount: PropTypes.func,\n contentDidUpdate: PropTypes.func,\n children: PropTypes.oneOfType([PropTypes.element, PropTypes.arrayOf(PropTypes.element)]),\n };\n\n static defaultProps = {\n style: {},\n head: undefined,\n children: undefined,\n mountTarget: undefined,\n dangerouslyUseDocWrite: false,\n contentDidMount: () => {},\n contentDidUpdate: () => {},\n initialContent: '<!DOCTYPE html><html><head></head><body><div class=\"frame-root\"></div></body></html>',\n };\n\n constructor(props, context) {\n super(props, context);\n this._isMounted = false;\n this.nodeRef = React.createRef();\n this.state = { iframeLoaded: false };\n }\n\n componentDidMount() {\n this._isMounted = true;\n\n const doc = this.getDoc();\n\n if (doc) {\n this.nodeRef.current.contentWindow.addEventListener('DOMContentLoaded', this.handleLoad);\n }\n\n if (this.props.dangerouslyUseDocWrite) {\n this.handleLoad();\n }\n }\n\n componentWillUnmount() {\n this._isMounted = false;\n\n this.nodeRef.current.removeEventListener('DOMContentLoaded', this.handleLoad);\n }\n\n getDoc() {\n return this.nodeRef.current ? this.nodeRef.current.contentDocument : undefined;\n }\n\n getMountTarget() {\n const doc = this.getDoc();\n\n if (!doc || !doc.body) {\n return;\n }\n\n if (this.props.mountTarget) {\n return doc.querySelector(this.props.mountTarget);\n }\n\n return doc.body.children[0];\n }\n\n setRef = (node) => {\n this.nodeRef.current = node;\n\n const { forwardedRef } = this.props;\n if (typeof forwardedRef === 'function') {\n forwardedRef(node);\n } else if (forwardedRef) {\n forwardedRef.current = node;\n }\n };\n\n handleLoad = () => {\n clearInterval(this.loadCheck);\n // Bail update as some browsers will trigger on both DOMContentLoaded & onLoad ala firefox\n if (!this.state.iframeLoaded) {\n this.setState({ iframeLoaded: true });\n }\n };\n\n // In certain situations on a cold cache DOMContentLoaded never gets called\n // fallback to an interval to check if that's the case\n loadCheck = () =>\n setInterval(() => {\n this.handleLoad();\n }, 500);\n\n renderFrameContents() {\n if (!this._isMounted) {\n return;\n }\n\n const doc = this.getDoc();\n\n if (!doc) {\n return;\n }\n\n const contentDidMount = this.props.contentDidMount;\n const contentDidUpdate = this.props.contentDidUpdate;\n\n const win = doc.defaultView || doc.parentView;\n const contents = (\n <Content contentDidMount={contentDidMount} contentDidUpdate={contentDidUpdate}>\n <FrameContextProvider value={{ document: doc, window: win }}>\n <div className=\"frame-content\">{this.props.children}</div>\n </FrameContextProvider>\n </Content>\n );\n\n if (this.props.dangerouslyUseDocWrite && doc.body.children.length === 0) {\n doc.open('text/html', 'replace');\n doc.write(this.props.initialContent);\n doc.close();\n }\n\n const mountTarget = this.getMountTarget();\n\n if (!mountTarget) {\n return;\n }\n\n return [ReactDOM.createPortal(this.props.head, this.getDoc().head), ReactDOM.createPortal(contents, mountTarget)];\n }\n\n render() {\n const props = {\n ...this.props,\n children: undefined, // The iframe isn't ready so we drop children from props here. #12, #17\n };\n\n if (!this.props.dangerouslyUseDocWrite) {\n props.srcDoc = this.props.initialContent;\n }\n\n delete props.head;\n delete props.initialContent;\n delete props.mountTarget;\n delete props.dangerouslyUseDocWrite;\n delete props.contentDidMount;\n delete props.contentDidUpdate;\n delete props.forwardedRef;\n\n return (\n // oxlint-disable-next-line jsx-a11y/iframe-has-title -- consumers can pass `title` via the props spread\n <iframe {...props} ref={this.setRef} onLoad={this.handleLoad}>\n {this.state.iframeLoaded && this.renderFrameContents()}\n </iframe>\n );\n }\n}\n\nexport default React.forwardRef((props, ref) => <Frame {...props} forwardedRef={ref} />);\n"],"mappings":"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"}
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
(function(global, factory) {
|
|
2
|
+
typeof exports === "object" && typeof module !== "undefined" ? factory(exports, require("react"), require("react-dom"), require("prop-types"), require("react/jsx-runtime")) : typeof define === "function" && define.amd ? define([
|
|
3
|
+
"exports",
|
|
4
|
+
"react",
|
|
5
|
+
"react-dom",
|
|
6
|
+
"prop-types",
|
|
7
|
+
"react/jsx-runtime"
|
|
8
|
+
], factory) : (global = typeof globalThis !== "undefined" ? globalThis : global || self, factory(global.ReactFrameComponent = {}, global.React, global.ReactDOM, global.PropTypes, global["react/jsx-runtime"]));
|
|
9
|
+
})(this, function(exports, react, react_dom, prop_types, react_jsx_runtime) {
|
|
10
|
+
Object.defineProperties(exports, {
|
|
11
|
+
__esModule: { value: true },
|
|
12
|
+
[Symbol.toStringTag]: { value: "Module" }
|
|
13
|
+
});
|
|
14
|
+
//#region \0rolldown/runtime.js
|
|
15
|
+
var __create = Object.create;
|
|
16
|
+
var __defProp = Object.defineProperty;
|
|
17
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
18
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
19
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
20
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
21
|
+
var __copyProps = (to, from, except, desc) => {
|
|
22
|
+
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
23
|
+
key = keys[i];
|
|
24
|
+
if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
|
|
25
|
+
get: ((k) => from[k]).bind(null, key),
|
|
26
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
return to;
|
|
30
|
+
};
|
|
31
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
|
|
32
|
+
value: mod,
|
|
33
|
+
enumerable: true
|
|
34
|
+
}) : target, mod));
|
|
35
|
+
//#endregion
|
|
36
|
+
react = __toESM(react, 1);
|
|
37
|
+
react_dom = __toESM(react_dom, 1);
|
|
38
|
+
prop_types = __toESM(prop_types, 1);
|
|
39
|
+
//#region src/Context.jsx
|
|
40
|
+
var doc;
|
|
41
|
+
var win;
|
|
42
|
+
if (typeof document !== "undefined") doc = document;
|
|
43
|
+
if (globalThis.window !== void 0) win = globalThis.window;
|
|
44
|
+
var FrameContext = react.default.createContext({
|
|
45
|
+
document: doc,
|
|
46
|
+
window: win
|
|
47
|
+
});
|
|
48
|
+
var useFrame = () => react.default.useContext(FrameContext);
|
|
49
|
+
var { Provider: FrameContextProvider, Consumer: FrameContextConsumer } = FrameContext;
|
|
50
|
+
//#endregion
|
|
51
|
+
//#region src/Content.jsx
|
|
52
|
+
var Content = class extends react.Component {
|
|
53
|
+
static propTypes = {
|
|
54
|
+
children: prop_types.default.element.isRequired,
|
|
55
|
+
contentDidMount: prop_types.default.func.isRequired,
|
|
56
|
+
contentDidUpdate: prop_types.default.func.isRequired
|
|
57
|
+
};
|
|
58
|
+
componentDidMount() {
|
|
59
|
+
this.props.contentDidMount();
|
|
60
|
+
}
|
|
61
|
+
componentDidUpdate() {
|
|
62
|
+
this.props.contentDidUpdate();
|
|
63
|
+
}
|
|
64
|
+
render() {
|
|
65
|
+
return react.Children.only(this.props.children);
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
//#endregion
|
|
69
|
+
//#region src/Frame.jsx
|
|
70
|
+
var Frame = class extends react.Component {
|
|
71
|
+
static propTypes = {
|
|
72
|
+
style: prop_types.default.object,
|
|
73
|
+
head: prop_types.default.node,
|
|
74
|
+
initialContent: prop_types.default.string,
|
|
75
|
+
mountTarget: prop_types.default.string,
|
|
76
|
+
dangerouslyUseDocWrite: prop_types.default.bool,
|
|
77
|
+
contentDidMount: prop_types.default.func,
|
|
78
|
+
contentDidUpdate: prop_types.default.func,
|
|
79
|
+
children: prop_types.default.oneOfType([prop_types.default.element, prop_types.default.arrayOf(prop_types.default.element)])
|
|
80
|
+
};
|
|
81
|
+
static defaultProps = {
|
|
82
|
+
style: {},
|
|
83
|
+
head: void 0,
|
|
84
|
+
children: void 0,
|
|
85
|
+
mountTarget: void 0,
|
|
86
|
+
dangerouslyUseDocWrite: false,
|
|
87
|
+
contentDidMount: () => {},
|
|
88
|
+
contentDidUpdate: () => {},
|
|
89
|
+
initialContent: "<!DOCTYPE html><html><head></head><body><div class=\"frame-root\"></div></body></html>"
|
|
90
|
+
};
|
|
91
|
+
constructor(props, context) {
|
|
92
|
+
super(props, context);
|
|
93
|
+
this._isMounted = false;
|
|
94
|
+
this.nodeRef = react.default.createRef();
|
|
95
|
+
this.state = { iframeLoaded: false };
|
|
96
|
+
}
|
|
97
|
+
componentDidMount() {
|
|
98
|
+
this._isMounted = true;
|
|
99
|
+
if (this.getDoc()) this.nodeRef.current.contentWindow.addEventListener("DOMContentLoaded", this.handleLoad);
|
|
100
|
+
if (this.props.dangerouslyUseDocWrite) this.handleLoad();
|
|
101
|
+
}
|
|
102
|
+
componentWillUnmount() {
|
|
103
|
+
this._isMounted = false;
|
|
104
|
+
this.nodeRef.current.removeEventListener("DOMContentLoaded", this.handleLoad);
|
|
105
|
+
}
|
|
106
|
+
getDoc() {
|
|
107
|
+
return this.nodeRef.current ? this.nodeRef.current.contentDocument : void 0;
|
|
108
|
+
}
|
|
109
|
+
getMountTarget() {
|
|
110
|
+
const doc = this.getDoc();
|
|
111
|
+
if (!doc || !doc.body) return;
|
|
112
|
+
if (this.props.mountTarget) return doc.querySelector(this.props.mountTarget);
|
|
113
|
+
return doc.body.children[0];
|
|
114
|
+
}
|
|
115
|
+
setRef = (node) => {
|
|
116
|
+
this.nodeRef.current = node;
|
|
117
|
+
const { forwardedRef } = this.props;
|
|
118
|
+
if (typeof forwardedRef === "function") forwardedRef(node);
|
|
119
|
+
else if (forwardedRef) forwardedRef.current = node;
|
|
120
|
+
};
|
|
121
|
+
handleLoad = () => {
|
|
122
|
+
clearInterval(this.loadCheck);
|
|
123
|
+
if (!this.state.iframeLoaded) this.setState({ iframeLoaded: true });
|
|
124
|
+
};
|
|
125
|
+
loadCheck = () => setInterval(() => {
|
|
126
|
+
this.handleLoad();
|
|
127
|
+
}, 500);
|
|
128
|
+
renderFrameContents() {
|
|
129
|
+
if (!this._isMounted) return;
|
|
130
|
+
const doc = this.getDoc();
|
|
131
|
+
if (!doc) return;
|
|
132
|
+
const contentDidMount = this.props.contentDidMount;
|
|
133
|
+
const contentDidUpdate = this.props.contentDidUpdate;
|
|
134
|
+
const contents = /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Content, {
|
|
135
|
+
contentDidMount,
|
|
136
|
+
contentDidUpdate,
|
|
137
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(FrameContextProvider, {
|
|
138
|
+
value: {
|
|
139
|
+
document: doc,
|
|
140
|
+
window: doc.defaultView || doc.parentView
|
|
141
|
+
},
|
|
142
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
143
|
+
className: "frame-content",
|
|
144
|
+
children: this.props.children
|
|
145
|
+
})
|
|
146
|
+
})
|
|
147
|
+
});
|
|
148
|
+
if (this.props.dangerouslyUseDocWrite && doc.body.children.length === 0) {
|
|
149
|
+
doc.open("text/html", "replace");
|
|
150
|
+
doc.write(this.props.initialContent);
|
|
151
|
+
doc.close();
|
|
152
|
+
}
|
|
153
|
+
const mountTarget = this.getMountTarget();
|
|
154
|
+
if (!mountTarget) return;
|
|
155
|
+
return [react_dom.default.createPortal(this.props.head, this.getDoc().head), react_dom.default.createPortal(contents, mountTarget)];
|
|
156
|
+
}
|
|
157
|
+
render() {
|
|
158
|
+
const props = {
|
|
159
|
+
...this.props,
|
|
160
|
+
children: void 0
|
|
161
|
+
};
|
|
162
|
+
if (!this.props.dangerouslyUseDocWrite) props.srcDoc = this.props.initialContent;
|
|
163
|
+
delete props.head;
|
|
164
|
+
delete props.initialContent;
|
|
165
|
+
delete props.mountTarget;
|
|
166
|
+
delete props.dangerouslyUseDocWrite;
|
|
167
|
+
delete props.contentDidMount;
|
|
168
|
+
delete props.contentDidUpdate;
|
|
169
|
+
delete props.forwardedRef;
|
|
170
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("iframe", {
|
|
171
|
+
...props,
|
|
172
|
+
ref: this.setRef,
|
|
173
|
+
onLoad: this.handleLoad,
|
|
174
|
+
children: this.state.iframeLoaded && this.renderFrameContents()
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
};
|
|
178
|
+
var Frame_default = react.default.forwardRef((props, ref) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Frame, {
|
|
179
|
+
...props,
|
|
180
|
+
forwardedRef: ref
|
|
181
|
+
}));
|
|
182
|
+
//#endregion
|
|
183
|
+
exports.FrameContext = FrameContext;
|
|
184
|
+
exports.FrameContextConsumer = FrameContextConsumer;
|
|
185
|
+
exports.default = Frame_default;
|
|
186
|
+
exports.useFrame = useFrame;
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
//# sourceMappingURL=react-frame-component.umd.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"react-frame-component.umd.js","names":[],"sources":["../src/Context.jsx","../src/Content.jsx","../src/Frame.jsx"],"sourcesContent":["import React from 'react';\n\nlet doc;\nlet win;\nif (typeof document !== 'undefined') {\n doc = document;\n}\nif (globalThis.window !== undefined) {\n win = globalThis.window;\n}\n\nexport const FrameContext = React.createContext({ document: doc, window: win });\n\nexport const useFrame = () => React.useContext(FrameContext);\n\nexport const { Provider: FrameContextProvider, Consumer: FrameContextConsumer } = FrameContext;\n","import React, { Component, Children } from 'react'; // eslint-disable-line no-unused-vars\nimport PropTypes from 'prop-types';\n\nexport default class Content extends Component {\n static propTypes = {\n children: PropTypes.element.isRequired,\n contentDidMount: PropTypes.func.isRequired,\n contentDidUpdate: PropTypes.func.isRequired,\n };\n\n componentDidMount() {\n this.props.contentDidMount();\n }\n\n componentDidUpdate() {\n this.props.contentDidUpdate();\n }\n\n render() {\n return Children.only(this.props.children);\n }\n}\n","import React, { Component } from 'react';\nimport ReactDOM from 'react-dom';\nimport PropTypes from 'prop-types';\nimport { FrameContextProvider } from './Context';\nimport Content from './Content';\n\nexport class Frame extends Component {\n // React warns when you render directly into the body since browser extensions\n // also inject into the body and can mess up React. For this reason\n // initialContent is expected to have a div inside of the body\n // element that we render react into.\n static propTypes = {\n style: PropTypes.object,\n head: PropTypes.node,\n initialContent: PropTypes.string,\n mountTarget: PropTypes.string,\n dangerouslyUseDocWrite: PropTypes.bool,\n contentDidMount: PropTypes.func,\n contentDidUpdate: PropTypes.func,\n children: PropTypes.oneOfType([PropTypes.element, PropTypes.arrayOf(PropTypes.element)]),\n };\n\n static defaultProps = {\n style: {},\n head: undefined,\n children: undefined,\n mountTarget: undefined,\n dangerouslyUseDocWrite: false,\n contentDidMount: () => {},\n contentDidUpdate: () => {},\n initialContent: '<!DOCTYPE html><html><head></head><body><div class=\"frame-root\"></div></body></html>',\n };\n\n constructor(props, context) {\n super(props, context);\n this._isMounted = false;\n this.nodeRef = React.createRef();\n this.state = { iframeLoaded: false };\n }\n\n componentDidMount() {\n this._isMounted = true;\n\n const doc = this.getDoc();\n\n if (doc) {\n this.nodeRef.current.contentWindow.addEventListener('DOMContentLoaded', this.handleLoad);\n }\n\n if (this.props.dangerouslyUseDocWrite) {\n this.handleLoad();\n }\n }\n\n componentWillUnmount() {\n this._isMounted = false;\n\n this.nodeRef.current.removeEventListener('DOMContentLoaded', this.handleLoad);\n }\n\n getDoc() {\n return this.nodeRef.current ? this.nodeRef.current.contentDocument : undefined;\n }\n\n getMountTarget() {\n const doc = this.getDoc();\n\n if (!doc || !doc.body) {\n return;\n }\n\n if (this.props.mountTarget) {\n return doc.querySelector(this.props.mountTarget);\n }\n\n return doc.body.children[0];\n }\n\n setRef = (node) => {\n this.nodeRef.current = node;\n\n const { forwardedRef } = this.props;\n if (typeof forwardedRef === 'function') {\n forwardedRef(node);\n } else if (forwardedRef) {\n forwardedRef.current = node;\n }\n };\n\n handleLoad = () => {\n clearInterval(this.loadCheck);\n // Bail update as some browsers will trigger on both DOMContentLoaded & onLoad ala firefox\n if (!this.state.iframeLoaded) {\n this.setState({ iframeLoaded: true });\n }\n };\n\n // In certain situations on a cold cache DOMContentLoaded never gets called\n // fallback to an interval to check if that's the case\n loadCheck = () =>\n setInterval(() => {\n this.handleLoad();\n }, 500);\n\n renderFrameContents() {\n if (!this._isMounted) {\n return;\n }\n\n const doc = this.getDoc();\n\n if (!doc) {\n return;\n }\n\n const contentDidMount = this.props.contentDidMount;\n const contentDidUpdate = this.props.contentDidUpdate;\n\n const win = doc.defaultView || doc.parentView;\n const contents = (\n <Content contentDidMount={contentDidMount} contentDidUpdate={contentDidUpdate}>\n <FrameContextProvider value={{ document: doc, window: win }}>\n <div className=\"frame-content\">{this.props.children}</div>\n </FrameContextProvider>\n </Content>\n );\n\n if (this.props.dangerouslyUseDocWrite && doc.body.children.length === 0) {\n doc.open('text/html', 'replace');\n doc.write(this.props.initialContent);\n doc.close();\n }\n\n const mountTarget = this.getMountTarget();\n\n if (!mountTarget) {\n return;\n }\n\n return [ReactDOM.createPortal(this.props.head, this.getDoc().head), ReactDOM.createPortal(contents, mountTarget)];\n }\n\n render() {\n const props = {\n ...this.props,\n children: undefined, // The iframe isn't ready so we drop children from props here. #12, #17\n };\n\n if (!this.props.dangerouslyUseDocWrite) {\n props.srcDoc = this.props.initialContent;\n }\n\n delete props.head;\n delete props.initialContent;\n delete props.mountTarget;\n delete props.dangerouslyUseDocWrite;\n delete props.contentDidMount;\n delete props.contentDidUpdate;\n delete props.forwardedRef;\n\n return (\n // oxlint-disable-next-line jsx-a11y/iframe-has-title -- consumers can pass `title` via the props spread\n <iframe {...props} ref={this.setRef} onLoad={this.handleLoad}>\n {this.state.iframeLoaded && this.renderFrameContents()}\n </iframe>\n );\n }\n}\n\nexport default React.forwardRef((props, ref) => <Frame {...props} forwardedRef={ref} />);\n"],"mappings":"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"}
|
package/index.d.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
|
|
3
|
+
export interface FrameComponentProps
|
|
4
|
+
extends React.IframeHTMLAttributes<HTMLIFrameElement>,
|
|
5
|
+
React.RefAttributes<HTMLIFrameElement> {
|
|
6
|
+
head?: React.ReactNode | undefined;
|
|
7
|
+
mountTarget?: string | undefined;
|
|
8
|
+
initialContent?: string | undefined;
|
|
9
|
+
contentDidMount?: (() => void) | undefined;
|
|
10
|
+
contentDidUpdate?: (() => void) | undefined;
|
|
11
|
+
dangerouslyUseDocWrite?: boolean | undefined;
|
|
12
|
+
children: React.ReactNode;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
declare const FrameComponent: React.ForwardRefExoticComponent<FrameComponentProps>;
|
|
16
|
+
export default FrameComponent;
|
|
17
|
+
|
|
18
|
+
export interface FrameContextProps {
|
|
19
|
+
document?: Document;
|
|
20
|
+
window?: Window;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export declare const FrameContext: React.Context<FrameContextProps>;
|
|
24
|
+
|
|
25
|
+
export declare const FrameContextProvider: React.Provider<FrameContextProps>;
|
|
26
|
+
|
|
27
|
+
export declare const FrameContextConsumer: React.Consumer<FrameContextProps>;
|
|
28
|
+
|
|
29
|
+
export declare function useFrame(): FrameContextProps;
|
package/package.json
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@willbooster/react-frame-component",
|
|
3
|
+
"version": "0.0.0-semantically-released",
|
|
4
|
+
"description": "React component to wrap your application or component in an iFrame for encapsulation purposes",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"React",
|
|
7
|
+
"component",
|
|
8
|
+
"iFrame",
|
|
9
|
+
"browser"
|
|
10
|
+
],
|
|
11
|
+
"homepage": "https://github.com/WillBooster/react-frame-component#readme",
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/WillBooster/react-frame-component/issues"
|
|
14
|
+
},
|
|
15
|
+
"repository": {
|
|
16
|
+
"type": "git",
|
|
17
|
+
"url": "git+https://github.com/WillBooster/react-frame-component.git"
|
|
18
|
+
},
|
|
19
|
+
"license": "MIT",
|
|
20
|
+
"author": "WillBooster Inc.",
|
|
21
|
+
"contributors": [
|
|
22
|
+
"Chris Trevino <darthtrevino@gmail.com>"
|
|
23
|
+
],
|
|
24
|
+
"type": "module",
|
|
25
|
+
"exports": {
|
|
26
|
+
".": {
|
|
27
|
+
"types": "./index.d.ts",
|
|
28
|
+
"import": "./dist/react-frame-component.esm.js",
|
|
29
|
+
"require": "./dist/react-frame-component.umd.js"
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
"main": "dist/react-frame-component.umd.js",
|
|
33
|
+
"module": "dist/react-frame-component.esm.js",
|
|
34
|
+
"types": "index.d.ts",
|
|
35
|
+
"files": [
|
|
36
|
+
"dist",
|
|
37
|
+
"index.d.ts"
|
|
38
|
+
],
|
|
39
|
+
"scripts": {
|
|
40
|
+
"build": "vite build",
|
|
41
|
+
"build:example": "vite build --config vite.example.config.js",
|
|
42
|
+
"clean": "rimraf dist",
|
|
43
|
+
"cleanup": "yarn format && yarn lint-fix",
|
|
44
|
+
"format": "sort-package-json && yarn format-code",
|
|
45
|
+
"format-code": "oxfmt --write --no-error-on-unmatched-pattern . '!**/package.json'",
|
|
46
|
+
"lint": "oxlint --no-error-on-unmatched-pattern .",
|
|
47
|
+
"lint-fix": "yarn lint --fix",
|
|
48
|
+
"prepare": "lefthook install || true",
|
|
49
|
+
"serve": "vite --root example",
|
|
50
|
+
"start": "npm run serve",
|
|
51
|
+
"test": "vitest run",
|
|
52
|
+
"test:watch": "vitest",
|
|
53
|
+
"test/ci-setup": "playwright install --with-deps chromium firefox",
|
|
54
|
+
"verify": "wb verify",
|
|
55
|
+
"verify-full": "wb verify --full"
|
|
56
|
+
},
|
|
57
|
+
"devDependencies": {
|
|
58
|
+
"@playwright/test": "^1.58.2",
|
|
59
|
+
"@testing-library/dom": "^10.4.1",
|
|
60
|
+
"@testing-library/react": "^16.3.2",
|
|
61
|
+
"@tsconfig/node-lts": "24.0.0",
|
|
62
|
+
"@tsconfig/node-ts": "23.6.4",
|
|
63
|
+
"@types/react": "^18",
|
|
64
|
+
"@vitejs/plugin-react": "^5.1.4",
|
|
65
|
+
"@vitest/browser": "^4.0.18",
|
|
66
|
+
"@vitest/browser-playwright": "^4.0.18",
|
|
67
|
+
"@willbooster/oxfmt-config": "1.2.2",
|
|
68
|
+
"@willbooster/oxlint-config": "1.4.8",
|
|
69
|
+
"@willbooster/wb": "13.22.19",
|
|
70
|
+
"conventional-changelog-conventionalcommits": "^9.3.1",
|
|
71
|
+
"lefthook": "2.1.9",
|
|
72
|
+
"oxfmt": "0.57.0",
|
|
73
|
+
"oxlint": "1.72.0",
|
|
74
|
+
"oxlint-tsgolint": "0.24.0",
|
|
75
|
+
"prop-types": "^15.8.1",
|
|
76
|
+
"react": "^18.2.0",
|
|
77
|
+
"react-dom": "^18.2.0",
|
|
78
|
+
"rimraf": "^5.0.5",
|
|
79
|
+
"semantic-release": "^25.0.3",
|
|
80
|
+
"sort-package-json": "4.0.0",
|
|
81
|
+
"vite": "8.1.0",
|
|
82
|
+
"vitest": "^4.0.18"
|
|
83
|
+
},
|
|
84
|
+
"peerDependencies": {
|
|
85
|
+
"prop-types": "^15.8.1 || ^16.0.0 || ^17.0.0 || ^18.0.0",
|
|
86
|
+
"react": ">= 16.8 || ^17.0.0 || ^18.0.0 || ^19.0.0",
|
|
87
|
+
"react-dom": ">= 16.8 || ^17.0.0 || ^18.0.0 || ^19.0.0"
|
|
88
|
+
},
|
|
89
|
+
"packageManager": "yarn@4.17.0",
|
|
90
|
+
"publishConfig": {
|
|
91
|
+
"access": "public"
|
|
92
|
+
}
|
|
93
|
+
}
|