@startupjs-ui/portal 0.1.3
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 +20 -0
- package/README.mdx +76 -0
- package/index.d.ts +11 -0
- package/index.tsx +60 -0
- package/package.json +19 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Change Log
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
|
+
|
|
6
|
+
## [0.1.3](https://github.com/startupjs/startupjs-ui/compare/v0.1.2...v0.1.3) (2025-12-29)
|
|
7
|
+
|
|
8
|
+
**Note:** Version bump only for package @startupjs-ui/portal
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
## [0.1.2](https://github.com/startupjs/startupjs-ui/compare/v0.1.1...v0.1.2) (2025-12-29)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
### Features
|
|
18
|
+
|
|
19
|
+
* add mdx and docs packages. Refactor docs to get rid of any @startupjs/ui usage and use startupjs-ui instead ([703c926](https://github.com/startupjs/startupjs-ui/commit/703c92636efb0421ffd11783f692fc892b74018f))
|
|
20
|
+
* refactor Br, Layout, Portal ([d5f4dcd](https://github.com/startupjs/startupjs-ui/commit/d5f4dcd17e834ceae95decfc1df38bda2b5a17ab))
|
package/README.mdx
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { useState } from 'react'
|
|
2
|
+
import Button from '@startupjs-ui/button'
|
|
3
|
+
import Span from '@startupjs-ui/span'
|
|
4
|
+
import Div from '@startupjs-ui/div'
|
|
5
|
+
import Portal, { _PropsJsonSchema as PortalPropsJsonSchema } from './index'
|
|
6
|
+
import { u } from 'startupjs'
|
|
7
|
+
import { Sandbox } from '@startupjs-ui/docs'
|
|
8
|
+
|
|
9
|
+
# Portal
|
|
10
|
+
|
|
11
|
+
The portal component renders its children into a new "subtree" outside of current DOM hierarchy.
|
|
12
|
+
|
|
13
|
+
```jsx
|
|
14
|
+
import { Portal } from 'startupjs-ui'
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Initialization
|
|
18
|
+
|
|
19
|
+
It is necessary to wrap the part of the application components on top of which the Portal will be displayed
|
|
20
|
+
|
|
21
|
+
```jsx
|
|
22
|
+
function Layout ({ children }) {
|
|
23
|
+
return (
|
|
24
|
+
<Portal.Provider>
|
|
25
|
+
<Layout>{children}</Layout>
|
|
26
|
+
</Portal.Provider>
|
|
27
|
+
)
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Simple example
|
|
32
|
+
|
|
33
|
+
```jsx example
|
|
34
|
+
const [visible, setVisible] = useState(false)
|
|
35
|
+
|
|
36
|
+
const contentStyle = {
|
|
37
|
+
position: 'absolute',
|
|
38
|
+
top: 0,
|
|
39
|
+
left: 0,
|
|
40
|
+
width: u(25),
|
|
41
|
+
height: u(20),
|
|
42
|
+
backgroundColor: '#444',
|
|
43
|
+
justifyContent: 'center',
|
|
44
|
+
alignItems: 'center'
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const textStyle = {
|
|
48
|
+
color: '#fff',
|
|
49
|
+
marginBottom: u(2),
|
|
50
|
+
fontSize: u(3)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return (
|
|
54
|
+
<Div>
|
|
55
|
+
<Button onPress={()=> setVisible(true)}>Open</Button>
|
|
56
|
+
{visible &&
|
|
57
|
+
<Portal>
|
|
58
|
+
<Div style={contentStyle}>
|
|
59
|
+
<Span style={textStyle}>Content</Span>
|
|
60
|
+
<Button
|
|
61
|
+
variant='flat'
|
|
62
|
+
onPress={()=> setVisible(false)}
|
|
63
|
+
>Close</Button>
|
|
64
|
+
</Div>
|
|
65
|
+
</Portal>
|
|
66
|
+
}
|
|
67
|
+
</Div>
|
|
68
|
+
)
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Sandbox
|
|
72
|
+
|
|
73
|
+
<Sandbox
|
|
74
|
+
Component={Portal}
|
|
75
|
+
propsJsonSchema={PortalPropsJsonSchema}
|
|
76
|
+
/>
|
package/index.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/* eslint-disable */
|
|
2
|
+
// DO NOT MODIFY THIS FILE - IT IS AUTOMATICALLY GENERATED ON COMMITS.
|
|
3
|
+
|
|
4
|
+
import { type ReactNode } from 'react';
|
|
5
|
+
export declare const _PropsJsonSchema: {};
|
|
6
|
+
export interface PortalProps {
|
|
7
|
+
/** Content rendered into the portal host */
|
|
8
|
+
children?: ReactNode;
|
|
9
|
+
}
|
|
10
|
+
declare const ObservedPortal: any;
|
|
11
|
+
export default ObservedPortal;
|
package/index.tsx
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { createContext, Fragment, useContext, useEffect, useId, type ReactNode } from 'react'
|
|
2
|
+
import { pug, $, observer } from 'startupjs'
|
|
3
|
+
|
|
4
|
+
const PortalContext = createContext<any>(undefined)
|
|
5
|
+
|
|
6
|
+
export const _PropsJsonSchema = {/* PortalProps */}
|
|
7
|
+
|
|
8
|
+
export interface PortalProps {
|
|
9
|
+
/** Content rendered into the portal host */
|
|
10
|
+
children?: ReactNode
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const Provider = observer(function Provider ({ children }: { children?: ReactNode }): ReactNode {
|
|
14
|
+
const $state = $({ order: [], nodes: {} })
|
|
15
|
+
return pug`
|
|
16
|
+
PortalContext.Provider(value=$state)
|
|
17
|
+
= children
|
|
18
|
+
Host($state=$state)
|
|
19
|
+
`
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
const Host = observer(function Host ({ $state }: { $state: any }): ReactNode {
|
|
23
|
+
const { order, nodes } = $state.get()
|
|
24
|
+
|
|
25
|
+
return pug`
|
|
26
|
+
each componentId in order
|
|
27
|
+
Fragment(key=componentId)
|
|
28
|
+
= nodes[componentId]?.()
|
|
29
|
+
`
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
function Portal ({ children }: PortalProps): ReactNode {
|
|
33
|
+
const componentId = useId()
|
|
34
|
+
const $state = useContext(PortalContext)
|
|
35
|
+
if (!$state) throw Error('Portal must be used within a Portal.Provider')
|
|
36
|
+
|
|
37
|
+
useEffect(() => {
|
|
38
|
+
// eslint-disable-next-line @typescript-eslint/promise-function-async
|
|
39
|
+
$state.nodes[componentId].set(() => children)
|
|
40
|
+
const { $order } = $state
|
|
41
|
+
if (!$order.get().includes(componentId)) $order.push(componentId)
|
|
42
|
+
}, [$state, componentId, children])
|
|
43
|
+
|
|
44
|
+
useEffect(() => {
|
|
45
|
+
return () => {
|
|
46
|
+
$state.nodes[componentId].del()
|
|
47
|
+
const { $order } = $state
|
|
48
|
+
const index = $order.get().indexOf(componentId)
|
|
49
|
+
$order[index].del()
|
|
50
|
+
}
|
|
51
|
+
}, [$state, componentId])
|
|
52
|
+
|
|
53
|
+
return null
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const ObservedPortal: any = observer(Portal)
|
|
57
|
+
|
|
58
|
+
ObservedPortal.Provider = Provider
|
|
59
|
+
|
|
60
|
+
export default ObservedPortal
|
package/package.json
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@startupjs-ui/portal",
|
|
3
|
+
"version": "0.1.3",
|
|
4
|
+
"publishConfig": {
|
|
5
|
+
"access": "public"
|
|
6
|
+
},
|
|
7
|
+
"main": "index.tsx",
|
|
8
|
+
"types": "index.d.ts",
|
|
9
|
+
"type": "module",
|
|
10
|
+
"dependencies": {
|
|
11
|
+
"@startupjs-ui/core": "^0.1.3"
|
|
12
|
+
},
|
|
13
|
+
"peerDependencies": {
|
|
14
|
+
"react": "*",
|
|
15
|
+
"react-native": "*",
|
|
16
|
+
"startupjs": "*"
|
|
17
|
+
},
|
|
18
|
+
"gitHead": "fd964ebc3892d3dd0a6c85438c0af619cc50c3f0"
|
|
19
|
+
}
|