@startupjs-ui/popover 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 +127 -0
- package/index.cssx.styl +14 -0
- package/index.d.ts +36 -0
- package/index.tsx +113 -0
- package/package.json +21 -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/popover
|
|
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
|
+
* **popover:** refactor Popover component ([d43cda5](https://github.com/startupjs/startupjs-ui/commit/d43cda52d95f047bc916a7b42a388e3148513fc3))
|
package/README.mdx
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { useState } from 'react'
|
|
2
|
+
import { Sandbox } from '@startupjs-ui/docs'
|
|
3
|
+
import { faUserCircle } from '@fortawesome/free-solid-svg-icons'
|
|
4
|
+
import Popover, { _PropsJsonSchema as PopoverPropsJsonSchema } from './index'
|
|
5
|
+
import Icon from '@startupjs-ui/icon'
|
|
6
|
+
import Button from '@startupjs-ui/button'
|
|
7
|
+
import Div from '@startupjs-ui/div'
|
|
8
|
+
import Span from '@startupjs-ui/span'
|
|
9
|
+
|
|
10
|
+
# Popover
|
|
11
|
+
|
|
12
|
+
Pop-up window for displaying hidden content, linked in some way to a specific element on the page and becomes visible when you click on this.
|
|
13
|
+
|
|
14
|
+
```jsx
|
|
15
|
+
import { Popover } from 'startupjs-ui'
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Initialization
|
|
19
|
+
|
|
20
|
+
Before use you need to configure [Portal](/docs/components/Portal)
|
|
21
|
+
|
|
22
|
+
## Simple example
|
|
23
|
+
|
|
24
|
+
- `children` (ReactNode): anchor (visible part)
|
|
25
|
+
- `renderContent` (function: ReactNode): function returns hidden part
|
|
26
|
+
|
|
27
|
+
```jsx example
|
|
28
|
+
const [visible, setVisible] = useState(false)
|
|
29
|
+
|
|
30
|
+
function renderContent () {
|
|
31
|
+
return (
|
|
32
|
+
<Div style={{ padding: 10 }}>
|
|
33
|
+
<Span>Content</Span>
|
|
34
|
+
</Div>
|
|
35
|
+
)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return (
|
|
39
|
+
<Popover
|
|
40
|
+
visible={visible}
|
|
41
|
+
onChange={setVisible}
|
|
42
|
+
renderContent={renderContent}
|
|
43
|
+
>
|
|
44
|
+
<Icon icon={faUserCircle} size='xl' />
|
|
45
|
+
</Popover>
|
|
46
|
+
)
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Position
|
|
50
|
+
|
|
51
|
+
- `position` (string - 'top', 'bottom', 'left', 'right'): position relative to the visible part
|
|
52
|
+
- `attachment` (string - 'start', 'center', 'end'): optional parameter for offset
|
|
53
|
+
- `placements` (array): what positions can be used for auto-fix
|
|
54
|
+
|
|
55
|
+
```jsx example
|
|
56
|
+
const [visible, setVisible] = useState(false)
|
|
57
|
+
|
|
58
|
+
function renderContent () {
|
|
59
|
+
return (
|
|
60
|
+
<Div style={{ padding: 10 }}>
|
|
61
|
+
<Span>Content</Span>
|
|
62
|
+
</Div>
|
|
63
|
+
)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return (
|
|
67
|
+
<Popover
|
|
68
|
+
visible={visible}
|
|
69
|
+
onChange={setVisible}
|
|
70
|
+
position='top'
|
|
71
|
+
attachment='center'
|
|
72
|
+
renderContent={renderContent}
|
|
73
|
+
>
|
|
74
|
+
<Button>Open</Button>
|
|
75
|
+
</Popover>
|
|
76
|
+
)
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Stylization
|
|
80
|
+
|
|
81
|
+
- `style`: styles for the anchor wrapper
|
|
82
|
+
- `attachmentStyle`: styles for the popover container
|
|
83
|
+
- `overlayStyle`: dismiss overlay styles
|
|
84
|
+
- `arrow` (boolean): show an arrow
|
|
85
|
+
- `matchAnchorWidth` (boolean): the width of the popover is equal to the width of the anchor
|
|
86
|
+
|
|
87
|
+
```jsx example
|
|
88
|
+
const [visible, setVisible] = useState(false)
|
|
89
|
+
|
|
90
|
+
function renderContent () {
|
|
91
|
+
return (
|
|
92
|
+
<Span style={{ color: '#fff' }}>Content</Span>
|
|
93
|
+
)
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return (
|
|
97
|
+
<Popover
|
|
98
|
+
visible={visible}
|
|
99
|
+
onChange={setVisible}
|
|
100
|
+
arrow
|
|
101
|
+
matchAnchorWidth
|
|
102
|
+
attachment='center'
|
|
103
|
+
renderContent={renderContent}
|
|
104
|
+
attachmentStyle={{ backgroundColor: '#333', padding: 10 }}
|
|
105
|
+
>
|
|
106
|
+
<Button>Open</Button>
|
|
107
|
+
</Popover>
|
|
108
|
+
)
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## Extra options
|
|
112
|
+
|
|
113
|
+
- `durationOpen` (number): animation time on opening
|
|
114
|
+
- `durationClose` (number): animation time on close
|
|
115
|
+
|
|
116
|
+
## Sandbox
|
|
117
|
+
|
|
118
|
+
<Sandbox
|
|
119
|
+
Component={Popover}
|
|
120
|
+
propsJsonSchema={PopoverPropsJsonSchema}
|
|
121
|
+
props={{
|
|
122
|
+
visible: false,
|
|
123
|
+
onChange: () => {},
|
|
124
|
+
renderContent: () => <Div style={{ padding: 10 }}><Span>Content</Span></Div>,
|
|
125
|
+
children: <Span>Anchor</Span>
|
|
126
|
+
}}
|
|
127
|
+
/>
|
package/index.cssx.styl
ADDED
package/index.d.ts
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/* eslint-disable */
|
|
2
|
+
// DO NOT MODIFY THIS FILE - IT IS AUTOMATICALLY GENERATED ON COMMITS.
|
|
3
|
+
|
|
4
|
+
import { type ReactNode, type RefObject } from 'react';
|
|
5
|
+
import { type StyleProp, type ViewStyle } from 'react-native';
|
|
6
|
+
import { type AbstractPopoverProps } from '@startupjs-ui/abstract-popover';
|
|
7
|
+
import './index.cssx.styl';
|
|
8
|
+
export declare const _PropsJsonSchema: {};
|
|
9
|
+
export interface PopoverProps extends Omit<AbstractPopoverProps, 'anchorRef' | 'children' | 'style' | 'visible'> {
|
|
10
|
+
/** Ref to control popover programmatically */
|
|
11
|
+
ref?: RefObject<PopoverRef>;
|
|
12
|
+
/** Custom styles for the anchor wrapper */
|
|
13
|
+
style?: StyleProp<ViewStyle>;
|
|
14
|
+
/** Custom styles for the popover container */
|
|
15
|
+
attachmentStyle?: StyleProp<ViewStyle>;
|
|
16
|
+
/** Custom styles for the dismiss overlay */
|
|
17
|
+
overlayStyle?: StyleProp<ViewStyle>;
|
|
18
|
+
/** Controlled visibility flag */
|
|
19
|
+
visible?: boolean;
|
|
20
|
+
/** Two-way binding value controlling visibility */
|
|
21
|
+
$visible?: any;
|
|
22
|
+
/** Called when visibility should change */
|
|
23
|
+
onChange?: (visible: boolean) => void;
|
|
24
|
+
/** Anchor content */
|
|
25
|
+
children?: ReactNode;
|
|
26
|
+
/** Render function for popover content */
|
|
27
|
+
renderContent?: () => ReactNode;
|
|
28
|
+
}
|
|
29
|
+
export interface PopoverRef {
|
|
30
|
+
/** Open the popover */
|
|
31
|
+
open: () => void;
|
|
32
|
+
/** Close the popover */
|
|
33
|
+
close: () => void;
|
|
34
|
+
}
|
|
35
|
+
declare const _default: import("react").ComponentType<PopoverProps>;
|
|
36
|
+
export default _default;
|
package/index.tsx
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { useMemo, useRef, useCallback, useImperativeHandle, type ReactNode, type RefObject } from 'react'
|
|
2
|
+
import { View, TouchableWithoutFeedback, type StyleProp, type ViewStyle } from 'react-native'
|
|
3
|
+
import { pug, observer, useBind, $ } from 'startupjs'
|
|
4
|
+
import { themed } from '@startupjs-ui/core'
|
|
5
|
+
import AbstractPopover, { type AbstractPopoverProps } from '@startupjs-ui/abstract-popover'
|
|
6
|
+
import Div from '@startupjs-ui/div'
|
|
7
|
+
import './index.cssx.styl'
|
|
8
|
+
|
|
9
|
+
export const _PropsJsonSchema = {/* PopoverProps */}
|
|
10
|
+
|
|
11
|
+
export interface PopoverProps extends Omit<AbstractPopoverProps, 'anchorRef' | 'children' | 'style' | 'visible'> {
|
|
12
|
+
/** Ref to control popover programmatically */
|
|
13
|
+
ref?: RefObject<PopoverRef>
|
|
14
|
+
/** Custom styles for the anchor wrapper */
|
|
15
|
+
style?: StyleProp<ViewStyle>
|
|
16
|
+
/** Custom styles for the popover container */
|
|
17
|
+
attachmentStyle?: StyleProp<ViewStyle>
|
|
18
|
+
/** Custom styles for the dismiss overlay */
|
|
19
|
+
overlayStyle?: StyleProp<ViewStyle>
|
|
20
|
+
/** Controlled visibility flag */
|
|
21
|
+
visible?: boolean
|
|
22
|
+
/** Two-way binding value controlling visibility */
|
|
23
|
+
$visible?: any
|
|
24
|
+
/** Called when visibility should change */
|
|
25
|
+
onChange?: (visible: boolean) => void
|
|
26
|
+
/** Anchor content */
|
|
27
|
+
children?: ReactNode
|
|
28
|
+
/** Render function for popover content */
|
|
29
|
+
renderContent?: () => ReactNode
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface PopoverRef {
|
|
33
|
+
/** Open the popover */
|
|
34
|
+
open: () => void
|
|
35
|
+
/** Close the popover */
|
|
36
|
+
close: () => void
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function Popover ({
|
|
40
|
+
style,
|
|
41
|
+
attachmentStyle,
|
|
42
|
+
visible,
|
|
43
|
+
$visible,
|
|
44
|
+
children,
|
|
45
|
+
renderContent,
|
|
46
|
+
onChange,
|
|
47
|
+
renderWrapper,
|
|
48
|
+
overlayStyle,
|
|
49
|
+
ref,
|
|
50
|
+
...props
|
|
51
|
+
}: PopoverProps): ReactNode {
|
|
52
|
+
const anchorRef = useRef<any>(null)
|
|
53
|
+
|
|
54
|
+
const isUncontrolled = useMemo(() => {
|
|
55
|
+
const isUsedViaTwoWayDataBinding = typeof $visible !== 'undefined'
|
|
56
|
+
const isUsedViaState = typeof onChange === 'function'
|
|
57
|
+
return !(isUsedViaTwoWayDataBinding || isUsedViaState)
|
|
58
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
59
|
+
}, [])
|
|
60
|
+
|
|
61
|
+
const $internalVisible = $(false)
|
|
62
|
+
const $effectiveVisible = isUncontrolled ? $internalVisible : $visible
|
|
63
|
+
|
|
64
|
+
;({ visible, onChange } = useBind({ visible, $visible: $effectiveVisible, onChange }) as any)
|
|
65
|
+
|
|
66
|
+
const handleChange = useCallback((nextVisible: boolean) => {
|
|
67
|
+
if (typeof onChange === 'function') {
|
|
68
|
+
onChange(nextVisible)
|
|
69
|
+
return
|
|
70
|
+
}
|
|
71
|
+
if ($effectiveVisible) {
|
|
72
|
+
$effectiveVisible.set(nextVisible)
|
|
73
|
+
return
|
|
74
|
+
}
|
|
75
|
+
$internalVisible.set(nextVisible)
|
|
76
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
77
|
+
}, [])
|
|
78
|
+
|
|
79
|
+
useImperativeHandle(ref, () => ({
|
|
80
|
+
open: () => { handleChange(true) },
|
|
81
|
+
close: () => { handleChange(false) }
|
|
82
|
+
}), [handleChange])
|
|
83
|
+
|
|
84
|
+
const setVisibleTrue = useCallback(() => { handleChange(true) }, [handleChange])
|
|
85
|
+
const setVisibleFalse = useCallback(() => { handleChange(false) }, [handleChange])
|
|
86
|
+
|
|
87
|
+
const renderOverlayWrapper = (node: ReactNode): ReactNode => {
|
|
88
|
+
const wrappedNode = renderWrapper ? renderWrapper(node) : node
|
|
89
|
+
return pug`
|
|
90
|
+
View.root
|
|
91
|
+
TouchableWithoutFeedback(onPress=setVisibleFalse)
|
|
92
|
+
View.overlay(style=overlayStyle)
|
|
93
|
+
= wrappedNode
|
|
94
|
+
`
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return pug`
|
|
98
|
+
Div(
|
|
99
|
+
style=style
|
|
100
|
+
ref=anchorRef
|
|
101
|
+
onPress=isUncontrolled ? null : setVisibleTrue
|
|
102
|
+
)= children
|
|
103
|
+
AbstractPopover.attachment(
|
|
104
|
+
...props
|
|
105
|
+
visible=visible
|
|
106
|
+
style=[attachmentStyle]
|
|
107
|
+
anchorRef=anchorRef
|
|
108
|
+
renderWrapper=renderOverlayWrapper
|
|
109
|
+
)= renderContent && renderContent()
|
|
110
|
+
`
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export default observer(themed('Popover', Popover))
|
package/package.json
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@startupjs-ui/popover",
|
|
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/abstract-popover": "^0.1.3",
|
|
12
|
+
"@startupjs-ui/core": "^0.1.3",
|
|
13
|
+
"@startupjs-ui/div": "^0.1.3"
|
|
14
|
+
},
|
|
15
|
+
"peerDependencies": {
|
|
16
|
+
"react": "*",
|
|
17
|
+
"react-native": "*",
|
|
18
|
+
"startupjs": "*"
|
|
19
|
+
},
|
|
20
|
+
"gitHead": "fd964ebc3892d3dd0a6c85438c0af619cc50c3f0"
|
|
21
|
+
}
|