@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 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
+ }