@kaizen/components 2.0.0 → 2.0.2
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/alpha/README.md +28 -0
- package/alpha/package.json +5 -0
- package/dist/cjs/alpha.cjs +1 -0
- package/dist/cjs/src/Notification/InlineNotification/InlineNotification.cjs +1 -1
- package/dist/cjs/src/__alpha__/SingleSelect/SingleSelect.cjs +35 -74
- package/dist/cjs/src/__alpha__/SingleSelect/subcomponents/ComboBox/ComboBox.cjs +105 -0
- package/dist/cjs/src/__alpha__/SingleSelect/subcomponents/ComboBox/ComboBox.module.css.cjs +11 -0
- package/dist/cjs/src/__alpha__/SingleSelect/subcomponents/ComboBoxTrigger/ComboBoxTrigger.cjs +112 -0
- package/dist/cjs/src/__alpha__/SingleSelect/subcomponents/ComboBoxTrigger/ComboBoxTrigger.module.css.cjs +16 -0
- package/dist/cjs/src/__alpha__/SingleSelect/subcomponents/List/List.cjs +35 -10
- package/dist/cjs/src/__alpha__/SingleSelect/subcomponents/ListItem/ListItem.cjs +61 -8
- package/dist/cjs/src/__alpha__/SingleSelect/subcomponents/ListItem/ListItem.module.css.cjs +10 -1
- package/dist/cjs/src/__alpha__/SingleSelect/subcomponents/ListSection/ListSection.cjs +38 -9
- package/dist/cjs/src/__alpha__/SingleSelect/subcomponents/ListSection/ListSection.module.css.cjs +4 -1
- package/dist/cjs/src/__alpha__/SingleSelect/subcomponents/Popover/Popover.cjs +60 -30
- package/dist/cjs/src/__alpha__/SingleSelect/subcomponents/Popover/Popover.module.css.cjs +2 -1
- package/dist/cjs/src/__alpha__/SingleSelect/subcomponents/Popover/utils/usePopoverPositioning.cjs +2 -1
- package/dist/cjs/src/__alpha__/SingleSelect/subcomponents/Popover/utils/usePositioningStyles.cjs +4 -2
- package/dist/cjs/src/__alpha__/SingleSelect/subcomponents/Select/Select.cjs +87 -0
- package/dist/cjs/src/__alpha__/SingleSelect/subcomponents/Select/Select.module.css.cjs +11 -0
- package/dist/cjs/src/__alpha__/SingleSelect/subcomponents/SelectTrigger/SelectTrigger.cjs +52 -0
- package/dist/cjs/src/__alpha__/SingleSelect/subcomponents/SelectTrigger/SelectTrigger.module.css.cjs +13 -0
- package/dist/esm/alpha.mjs +1 -1
- package/dist/esm/src/Notification/InlineNotification/InlineNotification.mjs +1 -1
- package/dist/esm/src/__alpha__/SingleSelect/SingleSelect.mjs +39 -73
- package/dist/esm/src/__alpha__/SingleSelect/subcomponents/ComboBox/ComboBox.mjs +96 -0
- package/dist/esm/src/__alpha__/SingleSelect/subcomponents/ComboBox/ComboBox.module.css.mjs +9 -0
- package/dist/esm/src/__alpha__/SingleSelect/subcomponents/ComboBoxTrigger/ComboBoxTrigger.mjs +103 -0
- package/dist/esm/src/__alpha__/SingleSelect/subcomponents/ComboBoxTrigger/ComboBoxTrigger.module.css.mjs +14 -0
- package/dist/esm/src/__alpha__/SingleSelect/subcomponents/List/List.mjs +37 -14
- package/dist/esm/src/__alpha__/SingleSelect/subcomponents/ListItem/ListItem.mjs +63 -13
- package/dist/esm/src/__alpha__/SingleSelect/subcomponents/ListItem/ListItem.module.css.mjs +10 -1
- package/dist/esm/src/__alpha__/SingleSelect/subcomponents/ListSection/ListSection.mjs +41 -15
- package/dist/esm/src/__alpha__/SingleSelect/subcomponents/ListSection/ListSection.module.css.mjs +4 -1
- package/dist/esm/src/__alpha__/SingleSelect/subcomponents/Popover/Popover.mjs +69 -43
- package/dist/esm/src/__alpha__/SingleSelect/subcomponents/Popover/Popover.module.css.mjs +2 -1
- package/dist/esm/src/__alpha__/SingleSelect/subcomponents/Popover/utils/usePopoverPositioning.mjs +2 -1
- package/dist/esm/src/__alpha__/SingleSelect/subcomponents/Popover/utils/usePositioningStyles.mjs +4 -2
- package/dist/esm/src/__alpha__/SingleSelect/subcomponents/Select/Select.mjs +78 -0
- package/dist/esm/src/__alpha__/SingleSelect/subcomponents/Select/Select.module.css.mjs +9 -0
- package/dist/esm/src/__alpha__/SingleSelect/subcomponents/SelectTrigger/SelectTrigger.mjs +43 -0
- package/dist/esm/src/__alpha__/SingleSelect/subcomponents/SelectTrigger/SelectTrigger.module.css.mjs +11 -0
- package/dist/styles.css +443 -79
- package/dist/types/__alpha__/SingleSelect/SingleSelect.d.ts +14 -19
- package/dist/types/__alpha__/SingleSelect/_docs/mockData.d.ts +3 -0
- package/dist/types/__alpha__/SingleSelect/context/SingleSelectContext.d.ts +15 -7
- package/dist/types/__alpha__/SingleSelect/subcomponents/ComboBox/ComboBox.d.ts +2 -0
- package/dist/types/__alpha__/SingleSelect/subcomponents/ComboBox/index.d.ts +1 -0
- package/dist/types/__alpha__/SingleSelect/subcomponents/ComboBoxTrigger/ComboBoxTrigger.d.ts +2 -0
- package/dist/types/__alpha__/SingleSelect/subcomponents/ComboBoxTrigger/index.d.ts +1 -0
- package/dist/types/__alpha__/SingleSelect/subcomponents/List/List.d.ts +2 -7
- package/dist/types/__alpha__/SingleSelect/subcomponents/ListItem/ListItem.d.ts +2 -7
- package/dist/types/__alpha__/SingleSelect/subcomponents/ListSection/ListSection.d.ts +2 -9
- package/dist/types/__alpha__/SingleSelect/subcomponents/Popover/Popover.d.ts +3 -6
- package/dist/types/__alpha__/SingleSelect/subcomponents/Popover/utils/index.d.ts +1 -0
- package/dist/types/__alpha__/SingleSelect/subcomponents/Popover/utils/usePopoverPositioning.d.ts +1 -0
- package/dist/types/__alpha__/SingleSelect/subcomponents/Popover/utils/usePositioningStyles.d.ts +1 -0
- package/dist/types/__alpha__/SingleSelect/subcomponents/Select/Select.d.ts +2 -0
- package/dist/types/__alpha__/SingleSelect/subcomponents/Select/index.d.ts +1 -0
- package/dist/types/__alpha__/SingleSelect/subcomponents/SelectTrigger/SelectTrigger.d.ts +2 -0
- package/dist/types/__alpha__/SingleSelect/subcomponents/SelectTrigger/index.d.ts +1 -0
- package/dist/types/__alpha__/SingleSelect/subcomponents/index.d.ts +4 -1
- package/dist/types/__alpha__/SingleSelect/types.d.ts +68 -11
- package/locales/en.json +9 -1
- package/package.json +9 -2
- package/src/Notification/InlineNotification/InlineNotification.tsx +1 -1
- package/src/__alpha__/SingleSelect/SingleSelect.tsx +35 -88
- package/src/__alpha__/SingleSelect/_docs/SingleSelect.mdx +96 -6
- package/src/__alpha__/SingleSelect/_docs/SingleSelect.spec.stories.tsx +22 -24
- package/src/__alpha__/SingleSelect/_docs/SingleSelect.stickersheet.stories.tsx +389 -33
- package/src/__alpha__/SingleSelect/_docs/SingleSelect.stories.tsx +41 -22
- package/src/__alpha__/SingleSelect/_docs/mockData.ts +20 -14
- package/src/__alpha__/SingleSelect/context/SingleSelectContext.tsx +18 -7
- package/src/__alpha__/SingleSelect/subcomponents/ComboBox/ComboBox.module.css +35 -0
- package/src/__alpha__/SingleSelect/subcomponents/ComboBox/ComboBox.tsx +106 -0
- package/src/__alpha__/SingleSelect/subcomponents/ComboBox/index.ts +1 -0
- package/src/__alpha__/SingleSelect/subcomponents/ComboBoxTrigger/ComboBoxTrigger.module.css +130 -0
- package/src/__alpha__/SingleSelect/subcomponents/ComboBoxTrigger/ComboBoxTrigger.tsx +121 -0
- package/src/__alpha__/SingleSelect/subcomponents/ComboBoxTrigger/index.ts +1 -0
- package/src/__alpha__/SingleSelect/subcomponents/List/List.module.css +5 -0
- package/src/__alpha__/SingleSelect/subcomponents/List/List.tsx +36 -13
- package/src/__alpha__/SingleSelect/subcomponents/ListItem/ListItem.module.css +84 -3
- package/src/__alpha__/SingleSelect/subcomponents/ListItem/ListItem.tsx +67 -11
- package/src/__alpha__/SingleSelect/subcomponents/ListSection/ListSection.module.css +20 -5
- package/src/__alpha__/SingleSelect/subcomponents/ListSection/ListSection.tsx +46 -19
- package/src/__alpha__/SingleSelect/subcomponents/Popover/Popover.module.css +7 -5
- package/src/__alpha__/SingleSelect/subcomponents/Popover/Popover.tsx +90 -37
- package/src/__alpha__/SingleSelect/subcomponents/Popover/utils/index.ts +1 -0
- package/src/__alpha__/SingleSelect/subcomponents/Popover/utils/usePopoverPositioning.ts +2 -2
- package/src/__alpha__/SingleSelect/subcomponents/Popover/utils/usePositioningStyles.ts +9 -8
- package/src/__alpha__/SingleSelect/subcomponents/Select/Select.module.css +35 -0
- package/src/__alpha__/SingleSelect/subcomponents/Select/Select.tsx +84 -0
- package/src/__alpha__/SingleSelect/subcomponents/Select/index.ts +1 -0
- package/src/__alpha__/SingleSelect/subcomponents/SelectTrigger/SelectTrigger.module.css +77 -0
- package/src/__alpha__/SingleSelect/subcomponents/SelectTrigger/SelectTrigger.tsx +52 -0
- package/src/__alpha__/SingleSelect/subcomponents/SelectTrigger/index.ts +1 -0
- package/src/__alpha__/SingleSelect/subcomponents/index.ts +4 -1
- package/src/__alpha__/SingleSelect/types.ts +94 -14
- package/dist/cjs/src/__alpha__/SingleSelect/subcomponents/Trigger/Trigger.cjs +0 -57
- package/dist/cjs/src/__alpha__/SingleSelect/subcomponents/Trigger/Trigger.module.css.cjs +0 -6
- package/dist/esm/src/__alpha__/SingleSelect/subcomponents/Trigger/Trigger.mjs +0 -49
- package/dist/esm/src/__alpha__/SingleSelect/subcomponents/Trigger/Trigger.module.css.mjs +0 -4
- package/dist/types/__alpha__/SingleSelect/subcomponents/Trigger/Trigger.d.ts +0 -2
- package/dist/types/__alpha__/SingleSelect/subcomponents/Trigger/index.d.ts +0 -1
- package/src/__alpha__/SingleSelect/subcomponents/Trigger/Trigger.module.css +0 -19
- package/src/__alpha__/SingleSelect/subcomponents/Trigger/Trigger.tsx +0 -35
- package/src/__alpha__/SingleSelect/subcomponents/Trigger/index.ts +0 -1
|
@@ -1,25 +1,52 @@
|
|
|
1
|
-
import React
|
|
1
|
+
import React from 'react'
|
|
2
2
|
import classNames from 'classnames'
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
} from 'react-aria-components'
|
|
8
|
-
import { type SelectSection } from '../../types'
|
|
3
|
+
import { useListBoxSection } from 'react-aria'
|
|
4
|
+
import { Divider } from '~components/Divider'
|
|
5
|
+
import { type ListSectionProps, type SelectItem } from '../../types'
|
|
6
|
+
import { ListItem } from '../ListItem'
|
|
9
7
|
import styles from './ListSection.module.css'
|
|
10
8
|
|
|
11
|
-
export const ListSection = ({
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
9
|
+
export const ListSection = <T extends SelectItem>({
|
|
10
|
+
section,
|
|
11
|
+
state,
|
|
12
|
+
}: ListSectionProps<T>): JSX.Element => {
|
|
13
|
+
const { headingProps, itemProps, groupProps } = useListBoxSection({
|
|
14
|
+
'heading': section.rendered,
|
|
15
|
+
'aria-label': section['aria-label'],
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
const firstSectionHeader = section.key === state.collection.getFirstKey()
|
|
19
|
+
|
|
18
20
|
return (
|
|
19
|
-
<
|
|
20
|
-
<
|
|
21
|
-
{
|
|
22
|
-
|
|
21
|
+
<React.Fragment key={section.key}>
|
|
22
|
+
{!firstSectionHeader && <li role="presentation" aria-hidden />}
|
|
23
|
+
{!firstSectionHeader && <Divider variant="content" />}
|
|
24
|
+
<li
|
|
25
|
+
{...itemProps}
|
|
26
|
+
className={classNames(styles.sectionWrapper, {
|
|
27
|
+
[styles.firstSectionHeader]: firstSectionHeader,
|
|
28
|
+
})}
|
|
29
|
+
>
|
|
30
|
+
{section.rendered && (
|
|
31
|
+
<span
|
|
32
|
+
{...headingProps}
|
|
33
|
+
role="presentation"
|
|
34
|
+
aria-hidden
|
|
35
|
+
className={styles.listSectionHeader}
|
|
36
|
+
>
|
|
37
|
+
{section.rendered}
|
|
38
|
+
</span>
|
|
39
|
+
)}
|
|
40
|
+
<ul
|
|
41
|
+
key={`${section.key}-group-contents`}
|
|
42
|
+
{...groupProps}
|
|
43
|
+
className={styles.listSectionGroup}
|
|
44
|
+
>
|
|
45
|
+
{Array.from(section.childNodes).map((node) => (
|
|
46
|
+
<ListItem key={node.key} item={node} state={state} />
|
|
47
|
+
))}
|
|
48
|
+
</ul>
|
|
49
|
+
</li>
|
|
50
|
+
</React.Fragment>
|
|
23
51
|
)
|
|
24
52
|
}
|
|
25
|
-
ListSection.displayName = 'SingleSelect.ListSection'
|
|
@@ -1,17 +1,14 @@
|
|
|
1
1
|
@layer kz-components {
|
|
2
2
|
.popover {
|
|
3
3
|
position: absolute;
|
|
4
|
-
height: auto;
|
|
5
4
|
background-color: var(--color-white);
|
|
6
5
|
border-radius: var(--spacing-8);
|
|
7
6
|
padding: 0;
|
|
8
7
|
box-shadow: var(--shadow-small-box-shadow);
|
|
9
|
-
overflow: hidden auto;
|
|
10
8
|
margin: 0;
|
|
11
9
|
box-sizing: border-box;
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
width: 200px;
|
|
10
|
+
display: flex;
|
|
11
|
+
flex-direction: column;
|
|
15
12
|
|
|
16
13
|
@supports (anchor-name: --anchor) {
|
|
17
14
|
position-anchor: var(--position-anchor);
|
|
@@ -21,4 +18,9 @@
|
|
|
21
18
|
width: anchor-size(width);
|
|
22
19
|
}
|
|
23
20
|
}
|
|
21
|
+
|
|
22
|
+
.offsetSpacing {
|
|
23
|
+
margin-top: var(--spacing-4);
|
|
24
|
+
margin-bottom: var(--spacing-4);
|
|
25
|
+
}
|
|
24
26
|
}
|
|
@@ -1,54 +1,107 @@
|
|
|
1
|
-
import React, { useLayoutEffect
|
|
2
|
-
|
|
3
|
-
import {
|
|
1
|
+
import React, { useLayoutEffect } from 'react'
|
|
2
|
+
import classNames from 'classnames'
|
|
3
|
+
import { DismissButton, Overlay, usePopover } from 'react-aria'
|
|
4
4
|
import { useSingleSelectContext } from '../../context'
|
|
5
|
-
import { type PopoverProps } from '../../types'
|
|
6
|
-
import { usePositioningStyles } from './utils
|
|
5
|
+
import { type PopoverProps, type SelectItem } from '../../types'
|
|
6
|
+
import { usePositioningStyles, useSupportsAnchorPositioning } from './utils'
|
|
7
|
+
|
|
7
8
|
import styles from './Popover.module.css'
|
|
8
9
|
|
|
9
|
-
export const Popover = ({
|
|
10
|
-
|
|
10
|
+
export const Popover = <T extends SelectItem>({
|
|
11
|
+
state,
|
|
11
12
|
popoverRef,
|
|
12
|
-
racPopoverRef,
|
|
13
13
|
children,
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
clearButtonRef,
|
|
15
|
+
...restProps
|
|
16
|
+
}: PopoverProps<T>): React.ReactElement => {
|
|
17
|
+
const { anchorName } = useSingleSelectContext()
|
|
18
|
+
const manualPopoverRef = React.useRef<HTMLDivElement>(null)
|
|
16
19
|
|
|
17
|
-
const {
|
|
20
|
+
const { popoverProps } = usePopover(
|
|
21
|
+
{
|
|
22
|
+
...restProps,
|
|
23
|
+
popoverRef,
|
|
24
|
+
shouldCloseOnInteractOutside: (element) => {
|
|
25
|
+
if (clearButtonRef?.current?.contains(element)) {
|
|
26
|
+
return false
|
|
27
|
+
}
|
|
28
|
+
return true
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
state,
|
|
32
|
+
)
|
|
18
33
|
|
|
19
|
-
const
|
|
34
|
+
const supportsAnchorPositioning = useSupportsAnchorPositioning()
|
|
35
|
+
const { popoverStyle, isPositioned, updatePosition } = usePositioningStyles(
|
|
36
|
+
restProps.triggerRef as React.RefObject<HTMLElement>,
|
|
37
|
+
manualPopoverRef,
|
|
38
|
+
anchorName,
|
|
39
|
+
)
|
|
20
40
|
|
|
21
41
|
useLayoutEffect(() => {
|
|
22
|
-
|
|
23
|
-
|
|
42
|
+
if (!supportsAnchorPositioning || !state.isOpen) return
|
|
43
|
+
|
|
44
|
+
updatePosition()
|
|
24
45
|
|
|
25
|
-
|
|
46
|
+
const popover = manualPopoverRef?.current
|
|
47
|
+
|
|
48
|
+
if (popover?.showPopover) {
|
|
26
49
|
popover.showPopover()
|
|
27
|
-
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return () => {
|
|
53
|
+
if (popover?.hidePopover) {
|
|
54
|
+
popover.hidePopover()
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}, [state.isOpen, supportsAnchorPositioning, updatePosition, isPositioned])
|
|
58
|
+
|
|
59
|
+
useLayoutEffect(() => {
|
|
60
|
+
if (!supportsAnchorPositioning || state.isOpen) return
|
|
61
|
+
|
|
62
|
+
const popover = manualPopoverRef?.current
|
|
63
|
+
|
|
64
|
+
if (popover?.hidePopover) {
|
|
28
65
|
popover.hidePopover()
|
|
29
66
|
}
|
|
30
|
-
|
|
31
|
-
}, [shouldShowPopover])
|
|
67
|
+
}, [state.isOpen, supportsAnchorPositioning])
|
|
32
68
|
|
|
33
|
-
|
|
34
|
-
<
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
69
|
+
const manualPopover = (
|
|
70
|
+
<div
|
|
71
|
+
// @ts-expect-error - popover attribute is not included in current ts version, ignore type error
|
|
72
|
+
popover="manual"
|
|
73
|
+
ref={manualPopoverRef}
|
|
74
|
+
className={styles.popover}
|
|
75
|
+
style={popoverStyle}
|
|
40
76
|
>
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
popover="manual"
|
|
44
|
-
ref={popoverRef}
|
|
45
|
-
className={styles.popover}
|
|
46
|
-
style={popoverStyle}
|
|
47
|
-
>
|
|
48
|
-
{children}
|
|
49
|
-
</div>
|
|
50
|
-
</RACPopover>
|
|
77
|
+
{children}
|
|
78
|
+
</div>
|
|
51
79
|
)
|
|
52
|
-
}
|
|
53
80
|
|
|
54
|
-
|
|
81
|
+
return (
|
|
82
|
+
<>
|
|
83
|
+
{state.isOpen && (
|
|
84
|
+
<Overlay>
|
|
85
|
+
<div
|
|
86
|
+
id="popover-id"
|
|
87
|
+
{...popoverProps}
|
|
88
|
+
ref={popoverRef}
|
|
89
|
+
style={{
|
|
90
|
+
...popoverProps.style,
|
|
91
|
+
...(!supportsAnchorPositioning && {
|
|
92
|
+
width: restProps.triggerRef.current?.getBoundingClientRect().width,
|
|
93
|
+
}),
|
|
94
|
+
}}
|
|
95
|
+
className={classNames(styles.popover, {
|
|
96
|
+
[styles.offsetSpacing]: !supportsAnchorPositioning,
|
|
97
|
+
})}
|
|
98
|
+
>
|
|
99
|
+
<DismissButton onDismiss={state.close} />
|
|
100
|
+
{supportsAnchorPositioning ? manualPopover : children}
|
|
101
|
+
<DismissButton onDismiss={state.close} />
|
|
102
|
+
</div>
|
|
103
|
+
</Overlay>
|
|
104
|
+
)}
|
|
105
|
+
</>
|
|
106
|
+
)
|
|
107
|
+
}
|
|
@@ -11,7 +11,7 @@ export function usePopoverPositioning({
|
|
|
11
11
|
direction = 'ltr',
|
|
12
12
|
offset = 4,
|
|
13
13
|
preferredPlacement = 'bottom',
|
|
14
|
-
}: UsePopoverPositioningProps): Position & { isPositioned: boolean } {
|
|
14
|
+
}: UsePopoverPositioningProps): Position & { isPositioned: boolean; updatePosition: () => void } {
|
|
15
15
|
const [position, setPosition] = useState<Position>({
|
|
16
16
|
top: preferredPlacement === 'bottom' ? offset : 'auto',
|
|
17
17
|
bottom: preferredPlacement === 'top' ? offset : 'auto',
|
|
@@ -104,5 +104,5 @@ export function usePopoverPositioning({
|
|
|
104
104
|
}
|
|
105
105
|
}, [updatePosition, triggerRef])
|
|
106
106
|
|
|
107
|
-
return { ...position, isPositioned }
|
|
107
|
+
return { ...position, isPositioned, updatePosition }
|
|
108
108
|
}
|
|
@@ -42,16 +42,17 @@ export const usePositioningStyles = (
|
|
|
42
42
|
buttonRef: React.RefObject<HTMLElement>,
|
|
43
43
|
popoverRef: React.RefObject<HTMLDivElement>,
|
|
44
44
|
anchorName: string,
|
|
45
|
-
): { popoverStyle: React.CSSProperties; isPositioned: boolean } => {
|
|
45
|
+
): { popoverStyle: React.CSSProperties; isPositioned: boolean; updatePosition: () => void } => {
|
|
46
46
|
const { direction } = useLocale()
|
|
47
47
|
const hasAnchorSupport = useSupportsAnchorPositioning()
|
|
48
48
|
|
|
49
|
-
const { top, bottom, insetInlineStart, maxHeight, isPositioned } =
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
49
|
+
const { top, bottom, insetInlineStart, maxHeight, isPositioned, updatePosition } =
|
|
50
|
+
usePopoverPositioning({
|
|
51
|
+
triggerRef: buttonRef,
|
|
52
|
+
popoverRef,
|
|
53
|
+
direction,
|
|
54
|
+
preferredPlacement: 'bottom',
|
|
55
|
+
})
|
|
55
56
|
|
|
56
57
|
const positionData = useMemo(
|
|
57
58
|
() => ({
|
|
@@ -71,5 +72,5 @@ export const usePositioningStyles = (
|
|
|
71
72
|
return getAnchorPositioningStyles(anchorName, positionData)
|
|
72
73
|
}, [hasAnchorSupport, anchorName, positionData])
|
|
73
74
|
|
|
74
|
-
return { popoverStyle, isPositioned }
|
|
75
|
+
return { popoverStyle, isPositioned, updatePosition }
|
|
75
76
|
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
@layer kz-components {
|
|
2
|
+
.topLabel {
|
|
3
|
+
display: flex;
|
|
4
|
+
flex-direction: column;
|
|
5
|
+
align-items: flex-start;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
.sideLabel {
|
|
9
|
+
display: grid;
|
|
10
|
+
grid-template-columns: auto 1fr;
|
|
11
|
+
grid-template-rows: auto auto;
|
|
12
|
+
column-gap: var(--spacing-12);
|
|
13
|
+
align-items: center;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.label {
|
|
17
|
+
grid-column: 1;
|
|
18
|
+
grid-row: 1;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.labelTop {
|
|
22
|
+
margin-bottom: var(--spacing-6);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.selectTrigger {
|
|
26
|
+
grid-column: 2;
|
|
27
|
+
grid-row: 1;
|
|
28
|
+
width: 100%;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.description {
|
|
32
|
+
grid-column: 2;
|
|
33
|
+
grid-row: 2;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import React, { useId, useRef } from 'react'
|
|
2
|
+
import { useSelectState } from '@react-stately/select'
|
|
3
|
+
import classNames from 'classnames'
|
|
4
|
+
import { useSelect } from 'react-aria'
|
|
5
|
+
import { FieldMessage, Label } from '~components/index'
|
|
6
|
+
import { SingleSelectContext } from '../../context'
|
|
7
|
+
import { type SelectItem, type SelectProps } from '../../types'
|
|
8
|
+
import { List } from '../List'
|
|
9
|
+
import { Popover } from '../Popover'
|
|
10
|
+
import { SelectTrigger } from '../SelectTrigger'
|
|
11
|
+
import styles from './Select.module.css'
|
|
12
|
+
|
|
13
|
+
export const Select = <T extends SelectItem>(props: SelectProps<T>): JSX.Element => {
|
|
14
|
+
const {
|
|
15
|
+
label,
|
|
16
|
+
description,
|
|
17
|
+
labelHidden,
|
|
18
|
+
labelPosition = 'top',
|
|
19
|
+
isDisabled,
|
|
20
|
+
isReadOnly,
|
|
21
|
+
size = 'medium',
|
|
22
|
+
variant = 'primary',
|
|
23
|
+
} = props
|
|
24
|
+
|
|
25
|
+
const state = useSelectState({
|
|
26
|
+
...props,
|
|
27
|
+
items: props.items,
|
|
28
|
+
children: props.children,
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
const popoverRef = useRef<HTMLDivElement>(null)
|
|
32
|
+
const listBoxRef = useRef<HTMLUListElement>(null)
|
|
33
|
+
const triggerRef = useRef<HTMLButtonElement>(null)
|
|
34
|
+
|
|
35
|
+
const { labelProps, descriptionProps, menuProps, triggerProps, valueProps } = useSelect(
|
|
36
|
+
{
|
|
37
|
+
...props,
|
|
38
|
+
'aria-label': labelHidden ? label : undefined,
|
|
39
|
+
},
|
|
40
|
+
state,
|
|
41
|
+
triggerRef,
|
|
42
|
+
)
|
|
43
|
+
const uniqueId = useId()
|
|
44
|
+
const anchorName = `--trigger-${uniqueId}`
|
|
45
|
+
|
|
46
|
+
return (
|
|
47
|
+
<SingleSelectContext.Provider
|
|
48
|
+
value={{
|
|
49
|
+
anchorName,
|
|
50
|
+
state,
|
|
51
|
+
isComboBox: false,
|
|
52
|
+
isDisabled: isDisabled ?? false,
|
|
53
|
+
isReadOnly: isReadOnly ?? false,
|
|
54
|
+
secondary: variant === 'secondary',
|
|
55
|
+
size,
|
|
56
|
+
fieldLabel: label,
|
|
57
|
+
}}
|
|
58
|
+
>
|
|
59
|
+
<div className={labelPosition === 'top' ? styles.topLabel : styles.sideLabel}>
|
|
60
|
+
{!labelHidden && (
|
|
61
|
+
<div className={classNames(styles.label, { [styles.labelTop]: labelPosition === 'top' })}>
|
|
62
|
+
<Label {...labelProps}>{label}</Label>
|
|
63
|
+
</div>
|
|
64
|
+
)}
|
|
65
|
+
<div className={styles.selectTrigger}>
|
|
66
|
+
<SelectTrigger
|
|
67
|
+
triggerProps={triggerProps}
|
|
68
|
+
valueProps={valueProps}
|
|
69
|
+
buttonRef={triggerRef}
|
|
70
|
+
/>
|
|
71
|
+
</div>
|
|
72
|
+
{description && (
|
|
73
|
+
<div className={styles.description}>
|
|
74
|
+
<FieldMessage message={description} {...descriptionProps} />
|
|
75
|
+
</div>
|
|
76
|
+
)}
|
|
77
|
+
</div>
|
|
78
|
+
|
|
79
|
+
<Popover state={state} triggerRef={triggerRef} popoverRef={popoverRef}>
|
|
80
|
+
<List listBoxOptions={menuProps} state={state} listBoxRef={listBoxRef} />
|
|
81
|
+
</Popover>
|
|
82
|
+
</SingleSelectContext.Provider>
|
|
83
|
+
)
|
|
84
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './Select'
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
@layer kz-components {
|
|
2
|
+
.trigger {
|
|
3
|
+
anchor-name: var(--anchor-name);
|
|
4
|
+
display: flex;
|
|
5
|
+
align-items: center;
|
|
6
|
+
justify-content: space-between;
|
|
7
|
+
font-family: var(--typography-paragraph-body-font-family);
|
|
8
|
+
font-weight: var(--typography-paragraph-body-font-weight);
|
|
9
|
+
font-size: var(--typography-paragraph-body-font-size);
|
|
10
|
+
line-height: var(--typography-paragraph-body-line-height);
|
|
11
|
+
letter-spacing: var(--typography-paragraph-body-letter-spacing);
|
|
12
|
+
padding: var(--spacing-12);
|
|
13
|
+
height: var(--spacing-40);
|
|
14
|
+
min-width: var(--spacing-200);
|
|
15
|
+
width: 100%;
|
|
16
|
+
background-color: var(--color-white);
|
|
17
|
+
border-radius: var(--spacing-8);
|
|
18
|
+
border: var(--spacing-2) solid var(--color-gray-500);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.trigger:focus-visible {
|
|
22
|
+
outline-offset: var(--spacing-2);
|
|
23
|
+
outline: var(--spacing-2) solid var(--color-blue-500);
|
|
24
|
+
background-color: var(--color-white);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.trigger:hover:not(.disabled) {
|
|
28
|
+
border-color: var(--color-gray-600);
|
|
29
|
+
background-color: var(--color-gray-200);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.secondary:not(.disabled, .readOnly) {
|
|
33
|
+
border: 2px solid transparent;
|
|
34
|
+
border-bottom: var(--spacing-2) solid var(--color-gray-400);
|
|
35
|
+
border-radius: 0.4375rem 0.4375rem 0 0;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.secondary:not(.disabled, .readOnly):hover {
|
|
39
|
+
border: var(--spacing-2) solid var(--color-gray-600);
|
|
40
|
+
border-radius: 0.4375rem;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.secondary:not(.disabled, .readOnly):focus-within {
|
|
44
|
+
border: var(--spacing-2) solid var(--color-gray-500);
|
|
45
|
+
border-radius: 0.4375rem;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.disabled {
|
|
49
|
+
pointer-events: none;
|
|
50
|
+
border: var(--spacing-2) solid var(--color-gray-300);
|
|
51
|
+
background-color: var(--color-gray-100);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.disabledText {
|
|
55
|
+
color: var(--color-gray-500);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.readOnly {
|
|
59
|
+
pointer-events: none;
|
|
60
|
+
background-color: var(--color-gray-200);
|
|
61
|
+
border: var(--spacing-2) solid var(--color-gray-200);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.small {
|
|
65
|
+
height: var(--spacing-32);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.large {
|
|
69
|
+
height: var(--spacing-48);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.chevronButton {
|
|
73
|
+
background: none;
|
|
74
|
+
padding: 0;
|
|
75
|
+
display: flex;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import classNames from 'classnames'
|
|
3
|
+
import { useButton } from 'react-aria'
|
|
4
|
+
import { Icon } from '~components/Icon'
|
|
5
|
+
import { Text } from '~components/Text'
|
|
6
|
+
import { useSingleSelectContext } from '../../context'
|
|
7
|
+
import { type SelectTriggerProps } from '../../types'
|
|
8
|
+
import styles from './SelectTrigger.module.css'
|
|
9
|
+
|
|
10
|
+
const ChevronButton = (): JSX.Element => {
|
|
11
|
+
const { state } = useSingleSelectContext()
|
|
12
|
+
|
|
13
|
+
return (
|
|
14
|
+
<div className={styles.chevronButton}>
|
|
15
|
+
<Icon isPresentational name={state.isOpen ? 'keyboard_arrow_up' : 'keyboard_arrow_down'} />
|
|
16
|
+
</div>
|
|
17
|
+
)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export const SelectTrigger = ({
|
|
21
|
+
triggerProps,
|
|
22
|
+
valueProps,
|
|
23
|
+
buttonRef,
|
|
24
|
+
}: SelectTriggerProps): JSX.Element => {
|
|
25
|
+
const { state, anchorName, isDisabled, isReadOnly, secondary, size } = useSingleSelectContext()
|
|
26
|
+
const { buttonProps } = useButton(triggerProps, buttonRef)
|
|
27
|
+
|
|
28
|
+
return (
|
|
29
|
+
<button
|
|
30
|
+
{...buttonProps}
|
|
31
|
+
type="button"
|
|
32
|
+
style={{ '--anchor-name': anchorName } as React.CSSProperties}
|
|
33
|
+
className={classNames(styles.trigger, {
|
|
34
|
+
[styles.disabled]: isDisabled,
|
|
35
|
+
[styles.readOnly]: isReadOnly,
|
|
36
|
+
[styles.secondary]: secondary,
|
|
37
|
+
[styles.small]: size === 'small',
|
|
38
|
+
[styles.large]: size === 'large',
|
|
39
|
+
})}
|
|
40
|
+
ref={buttonRef}
|
|
41
|
+
>
|
|
42
|
+
<Text
|
|
43
|
+
variant={size === 'small' ? 'small' : 'body'}
|
|
44
|
+
classNameOverride={isDisabled ? styles.disabledText : undefined}
|
|
45
|
+
>
|
|
46
|
+
<span {...valueProps}>{state.selectedItem ? state.selectedItem.textValue : ''}</span>
|
|
47
|
+
</Text>
|
|
48
|
+
|
|
49
|
+
{!isReadOnly && <ChevronButton />}
|
|
50
|
+
</button>
|
|
51
|
+
)
|
|
52
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './SelectTrigger'
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
export * from './List'
|
|
2
2
|
export * from './ListSection'
|
|
3
3
|
export * from './ListItem'
|
|
4
|
-
export * from './
|
|
4
|
+
export * from './SelectTrigger'
|
|
5
|
+
export * from './ComboBoxTrigger'
|
|
5
6
|
export * from './Popover'
|
|
7
|
+
export * from './Select'
|
|
8
|
+
export * from './ComboBox'
|