@graphprotocol/gds-react 0.0.1 → 0.1.1
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 +21 -0
- package/README.md +11 -12
- package/dist/GDSProvider.d.ts +6 -3
- package/dist/GDSProvider.d.ts.map +1 -1
- package/dist/GDSProvider.js +14 -6
- package/dist/GDSProvider.js.map +1 -1
- package/dist/components/Address.d.ts.map +1 -1
- package/dist/components/Address.js +8 -6
- package/dist/components/Address.js.map +1 -1
- package/dist/components/Avatar.d.ts +4 -2
- package/dist/components/Avatar.d.ts.map +1 -1
- package/dist/components/Avatar.js +8 -5
- package/dist/components/Avatar.js.map +1 -1
- package/dist/components/Breadcrumbs.parts.d.ts.map +1 -1
- package/dist/components/Breadcrumbs.parts.js +2 -2
- package/dist/components/Breadcrumbs.parts.js.map +1 -1
- package/dist/components/Button.js +3 -3
- package/dist/components/Button.js.map +1 -1
- package/dist/components/Card.js +2 -2
- package/dist/components/Card.js.map +1 -1
- package/dist/components/Checkbox.parts.js +1 -1
- package/dist/components/Checkbox.parts.js.map +1 -1
- package/dist/components/CodeBlock.parts.js +1 -1
- package/dist/components/CodeBlock.parts.js.map +1 -1
- package/dist/components/CopyButton.js +1 -1
- package/dist/components/CopyButton.js.map +1 -1
- package/dist/components/Keyboard.js +1 -1
- package/dist/components/Label.d.ts.map +1 -1
- package/dist/components/Label.js +1 -1
- package/dist/components/Label.js.map +1 -1
- package/dist/components/Link.d.ts.map +1 -1
- package/dist/components/Link.js +1 -1
- package/dist/components/Link.js.map +1 -1
- package/dist/components/Menu.parts.d.ts.map +1 -1
- package/dist/components/Menu.parts.js +15 -10
- package/dist/components/Menu.parts.js.map +1 -1
- package/dist/components/Modal.parts.js +1 -1
- package/dist/components/Modal.parts.js.map +1 -1
- package/dist/components/OTCInput.js +1 -1
- package/dist/components/OTCInput.js.map +1 -1
- package/dist/components/Search.d.ts +16 -0
- package/dist/components/Search.d.ts.map +1 -0
- package/dist/components/Search.js +129 -0
- package/dist/components/Search.js.map +1 -0
- package/dist/components/Search.meta.d.ts +15 -0
- package/dist/components/Search.meta.d.ts.map +1 -0
- package/dist/components/Search.meta.js +24 -0
- package/dist/components/Search.meta.js.map +1 -0
- package/dist/components/SegmentedControl.parts.d.ts.map +1 -1
- package/dist/components/SegmentedControl.parts.js +9 -10
- package/dist/components/SegmentedControl.parts.js.map +1 -1
- package/dist/components/TabSet.parts.js +2 -2
- package/dist/components/TabSet.parts.js.map +1 -1
- package/dist/components/Tooltip.parts.d.ts.map +1 -1
- package/dist/components/Tooltip.parts.js +10 -6
- package/dist/components/Tooltip.parts.js.map +1 -1
- package/dist/components/base/ButtonOrLink.parts.d.ts.map +1 -1
- package/dist/components/base/ButtonOrLink.parts.js +23 -12
- package/dist/components/base/ButtonOrLink.parts.js.map +1 -1
- package/dist/components/base/Render.d.ts +1 -1
- package/dist/components/base/Render.d.ts.map +1 -1
- package/dist/components/base/Render.js +1 -1
- package/dist/components/base/Render.js.map +1 -1
- package/dist/components/index.d.ts +2 -0
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/index.js +2 -0
- package/dist/components/index.js.map +1 -1
- package/dist/hooks/useCSSProp.js +1 -1
- package/dist/hooks/useCSSProp.js.map +1 -1
- package/dist/hooks/useEffectWithRefDeps.js +1 -1
- package/dist/hooks/useEffectWithRefDeps.js.map +1 -1
- package/dist/hooks/useGDS.d.ts +1 -1
- package/dist/hooks/useNumberInput.js +1 -1
- package/dist/hooks/useNumberInput.js.map +1 -1
- package/dist/hooks/useStyleObserver.js +1 -1
- package/dist/hooks/useStyleObserver.js.map +1 -1
- package/dist/tailwind-plugin.d.ts.map +1 -1
- package/dist/tailwind-plugin.js +2 -0
- package/dist/tailwind-plugin.js.map +1 -1
- package/package.json +30 -61
- package/src/GDSProvider.tsx +31 -14
- package/src/components/Address.tsx +11 -6
- package/src/components/Avatar.tsx +21 -13
- package/src/components/Breadcrumbs.parts.tsx +2 -3
- package/src/components/Button.tsx +3 -3
- package/src/components/Card.tsx +2 -2
- package/src/components/Checkbox.parts.tsx +1 -1
- package/src/components/CodeBlock.parts.tsx +3 -3
- package/src/components/CopyButton.tsx +1 -1
- package/src/components/Keyboard.tsx +1 -1
- package/src/components/Label.tsx +2 -1
- package/src/components/Link.tsx +2 -1
- package/src/components/Menu.parts.tsx +20 -24
- package/src/components/Modal.parts.tsx +1 -1
- package/src/components/OTCInput.tsx +1 -1
- package/src/components/Search.meta.ts +24 -0
- package/src/components/Search.tsx +238 -0
- package/src/components/SegmentedControl.parts.tsx +10 -11
- package/src/components/TabSet.parts.tsx +2 -2
- package/src/components/Tooltip.parts.tsx +15 -4
- package/src/components/base/ButtonOrLink.parts.tsx +27 -13
- package/src/components/base/Render.tsx +1 -1
- package/src/components/index.ts +2 -0
- package/src/hooks/useCSSProp.ts +1 -1
- package/src/hooks/useEffectWithRefDeps.ts +1 -1
- package/src/hooks/useNumberInput.ts +1 -1
- package/src/hooks/useStyleObserver.ts +1 -1
- package/src/tailwind-plugin.ts +2 -0
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import { useEffect, useRef, type ComponentProps } from 'react'
|
|
4
|
+
import { useMergedRefs } from '@base-ui/utils/useMergedRefs'
|
|
5
|
+
|
|
6
|
+
import type { GDSComponentProps } from '@graphprotocol/gds-css'
|
|
7
|
+
import { MagnifyingGlassIcon, XIcon } from '@graphprotocol/gds-react/icons'
|
|
8
|
+
|
|
9
|
+
import { useControlled, useCSSPropsPolyfill, useCSSState, useGDS } from '../hooks/index.ts'
|
|
10
|
+
import { cn, getCSSPropsAttributes, splitProps } from '../utils/index.ts'
|
|
11
|
+
import { Button } from './Button.tsx'
|
|
12
|
+
import { Keyboard } from './Keyboard.js'
|
|
13
|
+
import { SearchMeta } from './Search.meta.ts'
|
|
14
|
+
|
|
15
|
+
export interface SearchProps
|
|
16
|
+
extends
|
|
17
|
+
Omit<ComponentProps<'input'>, 'disabled' | 'onChange' | 'size' | 'type'>,
|
|
18
|
+
GDSComponentProps<typeof SearchMeta> {
|
|
19
|
+
value?: string | undefined
|
|
20
|
+
defaultValue?: string | undefined
|
|
21
|
+
onChange?: ((value: string) => void) | undefined
|
|
22
|
+
/**
|
|
23
|
+
* Key that focuses the search input when pressed. Set to `false` to disable.
|
|
24
|
+
*
|
|
25
|
+
* @default '/'
|
|
26
|
+
*/
|
|
27
|
+
focusKey?: string | false | undefined
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function Search({
|
|
31
|
+
ref: passedRef,
|
|
32
|
+
size,
|
|
33
|
+
layout,
|
|
34
|
+
placeholder = 'Search...',
|
|
35
|
+
value: controlledValue,
|
|
36
|
+
defaultValue,
|
|
37
|
+
onChange,
|
|
38
|
+
focusKey = '/',
|
|
39
|
+
className,
|
|
40
|
+
style,
|
|
41
|
+
...props
|
|
42
|
+
}: SearchProps) {
|
|
43
|
+
useGDS()
|
|
44
|
+
|
|
45
|
+
const { rootProps, nestedProps } = splitProps(props)
|
|
46
|
+
|
|
47
|
+
const inputRef = useRef<HTMLInputElement>(null)
|
|
48
|
+
const inputPassedRef = useMergedRefs(inputRef, passedRef)
|
|
49
|
+
const previousActiveElementRef = useRef<HTMLElement | null>(null)
|
|
50
|
+
const [value, setValue] = useControlled(controlledValue, defaultValue ?? '', onChange)
|
|
51
|
+
|
|
52
|
+
const [stateRef, state] = useCSSState({
|
|
53
|
+
pointer: undefined,
|
|
54
|
+
focus: undefined,
|
|
55
|
+
blank: value === '',
|
|
56
|
+
open: value !== '',
|
|
57
|
+
})
|
|
58
|
+
const [cssPropsPolyfillStateRef, cssPropsPolyfillAttributes, cssProps] = useCSSPropsPolyfill(
|
|
59
|
+
SearchMeta,
|
|
60
|
+
{ size, layout },
|
|
61
|
+
{ ref: stateRef, returnPropValues: { size, layout } },
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
useEffect(() => {
|
|
65
|
+
if (!focusKey) return
|
|
66
|
+
|
|
67
|
+
function handleKeyDown(event: KeyboardEvent) {
|
|
68
|
+
if (event.key !== focusKey) return
|
|
69
|
+
|
|
70
|
+
const input = inputRef.current
|
|
71
|
+
if (!input) return
|
|
72
|
+
|
|
73
|
+
// Don't focus if already focused on an interactive element
|
|
74
|
+
const activeElement = document.activeElement
|
|
75
|
+
if (
|
|
76
|
+
activeElement instanceof HTMLInputElement ||
|
|
77
|
+
activeElement instanceof HTMLTextAreaElement ||
|
|
78
|
+
(activeElement instanceof HTMLElement && activeElement.isContentEditable)
|
|
79
|
+
) {
|
|
80
|
+
return
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Don't focus if the input has an inert/hidden ancestor
|
|
84
|
+
if (input.closest('[inert], [data-base-ui-inert], [aria-hidden="true"]')) {
|
|
85
|
+
return
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
event.preventDefault()
|
|
89
|
+
// Store the currently focused element before focusing the input
|
|
90
|
+
previousActiveElementRef.current = activeElement instanceof HTMLElement ? activeElement : null
|
|
91
|
+
input.focus()
|
|
92
|
+
input.select()
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
document.addEventListener('keydown', handleKeyDown)
|
|
96
|
+
return () => document.removeEventListener('keydown', handleKeyDown)
|
|
97
|
+
}, [focusKey])
|
|
98
|
+
|
|
99
|
+
return (
|
|
100
|
+
<div
|
|
101
|
+
ref={cssPropsPolyfillStateRef}
|
|
102
|
+
data-size={cssProps.size}
|
|
103
|
+
data-layout={cssProps.layout}
|
|
104
|
+
className={cn(
|
|
105
|
+
`gds-search root-flex flex-col u:max-w-full
|
|
106
|
+
u:hover:state-hover
|
|
107
|
+
u:active:state-active
|
|
108
|
+
u:data-[layout=compact]:data-[size=medium]:min-w-10
|
|
109
|
+
u:data-[layout=compact]:data-[size=small]:min-w-8
|
|
110
|
+
u:has-nested-not-blank/search-ref:expose-open
|
|
111
|
+
u:has-nested-blank/search-ref:expose-blank
|
|
112
|
+
u:has-nested-focus-visible/search-ref:expose-focus
|
|
113
|
+
u:has-nested-focus-visible/search-ref:expose-open
|
|
114
|
+
u:has-nested-active/search-clear-button:state-focus`,
|
|
115
|
+
className,
|
|
116
|
+
)}
|
|
117
|
+
{...state.exposedAttributes}
|
|
118
|
+
{...state.polyfillAttributes}
|
|
119
|
+
{...getCSSPropsAttributes(SearchMeta, { size, layout }, style)}
|
|
120
|
+
{...cssPropsPolyfillAttributes}
|
|
121
|
+
{...rootProps}
|
|
122
|
+
>
|
|
123
|
+
<div
|
|
124
|
+
className={`
|
|
125
|
+
flex h-(--height) grow overflow-clip text-form-text duration-300
|
|
126
|
+
@prop-size-small/search:[--height:--spacing(8)]
|
|
127
|
+
@prop-size-small/search:[--padding:--spacing(2)]
|
|
128
|
+
@prop-size-medium/search:[--height:--spacing(10)]
|
|
129
|
+
@prop-size-medium/search:[--padding:--spacing(2.5)]
|
|
130
|
+
@prop-layout-compact/search:transition-[width]
|
|
131
|
+
@prop-layout-compact/search:@state-not-open/search:w-(--height)
|
|
132
|
+
@prop-layout-compact/search:@prop-size-small/search:animate-[width-1_1ms]
|
|
133
|
+
@prop-layout-compact/search:@prop-size-medium/search:animate-[width-2_1ms]
|
|
134
|
+
`}
|
|
135
|
+
>
|
|
136
|
+
<div
|
|
137
|
+
className={`
|
|
138
|
+
h-full w-(--gds-search-input-width) grow border border-form-idle transition
|
|
139
|
+
@state-hover/search:border-form-hover
|
|
140
|
+
@state-focus/search:border-focus
|
|
141
|
+
@state-active/search:transition-none
|
|
142
|
+
@prop-size-small/search:rounded-6
|
|
143
|
+
@prop-size-medium/search:rounded-8
|
|
144
|
+
`}
|
|
145
|
+
/>
|
|
146
|
+
<input
|
|
147
|
+
ref={inputPassedRef}
|
|
148
|
+
type="search"
|
|
149
|
+
placeholder={placeholder}
|
|
150
|
+
aria-label={placeholder || 'Search'}
|
|
151
|
+
value={value}
|
|
152
|
+
onChange={(event) => setValue(event.target.value)}
|
|
153
|
+
onKeyDown={(event) => {
|
|
154
|
+
nestedProps.onKeyDown?.(event)
|
|
155
|
+
if (event.defaultPrevented) return
|
|
156
|
+
if (event.key === 'Escape' && value === '') {
|
|
157
|
+
event.preventDefault()
|
|
158
|
+
inputRef.current?.blur()
|
|
159
|
+
// Restore focus to the previous element if it still exists in the DOM
|
|
160
|
+
if (
|
|
161
|
+
previousActiveElementRef.current &&
|
|
162
|
+
document.contains(previousActiveElementRef.current)
|
|
163
|
+
) {
|
|
164
|
+
previousActiveElementRef.current.focus()
|
|
165
|
+
previousActiveElementRef.current = null
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}}
|
|
169
|
+
className={`
|
|
170
|
+
nested/search-ref absolute end-0 top-0 size-full ps-(--padding) pe-(--height) outline-0
|
|
171
|
+
@state-not-focus/search:@state-blank/search:ps-[calc(var(--height)+var(--padding))]
|
|
172
|
+
@state-focus/search:placeholder:text-transparent
|
|
173
|
+
@prop-size-small/search:text-12
|
|
174
|
+
@prop-size-medium/search:text-14
|
|
175
|
+
@prop-layout-compact/search:@state-not-open/search:w-screen
|
|
176
|
+
@prop-layout-compact/search:@state-not-open/search:opacity-0
|
|
177
|
+
`}
|
|
178
|
+
{...nestedProps}
|
|
179
|
+
/>
|
|
180
|
+
<div
|
|
181
|
+
className={`
|
|
182
|
+
pointer-events-none absolute inset-y-0 start-0 flex w-(--height) items-center justify-center
|
|
183
|
+
border-e border-form-idle transition
|
|
184
|
+
@state-hover/search:border-form-hover
|
|
185
|
+
@state-focus/search:hidden
|
|
186
|
+
@prop-layout-compact/search:@state-not-open/search:border-0
|
|
187
|
+
@prop-layout-compact/search:@state-open/search:@state-not-blank/search:hidden
|
|
188
|
+
@prop-layout-full/search:@state-not-blank/search:hidden
|
|
189
|
+
`}
|
|
190
|
+
>
|
|
191
|
+
<MagnifyingGlassIcon
|
|
192
|
+
alt=""
|
|
193
|
+
className={`
|
|
194
|
+
@prop-size-small/search:prop-size-3.5
|
|
195
|
+
@prop-size-medium/search:prop-size-4
|
|
196
|
+
`}
|
|
197
|
+
/>
|
|
198
|
+
</div>
|
|
199
|
+
<div
|
|
200
|
+
className={`
|
|
201
|
+
pointer-events-none absolute inset-y-0 end-0 grid w-(--height) place-items-center
|
|
202
|
+
*:col-span-full *:row-span-full
|
|
203
|
+
`}
|
|
204
|
+
>
|
|
205
|
+
<Button
|
|
206
|
+
variant="tertiary"
|
|
207
|
+
size="xsmall"
|
|
208
|
+
tooltip={null}
|
|
209
|
+
tabIndex={-1}
|
|
210
|
+
onClick={() => {
|
|
211
|
+
setValue('')
|
|
212
|
+
inputRef.current?.focus()
|
|
213
|
+
}}
|
|
214
|
+
className={`
|
|
215
|
+
nested/search-clear-button pointer-events-auto size-6 var-[radius=var(--radius-4)]
|
|
216
|
+
@state-blank/search:hidden
|
|
217
|
+
@prop-layout-compact/search:@state-not-open/search:hidden
|
|
218
|
+
`}
|
|
219
|
+
>
|
|
220
|
+
<XIcon alt="Clear" />
|
|
221
|
+
</Button>
|
|
222
|
+
{focusKey ? (
|
|
223
|
+
<Keyboard
|
|
224
|
+
size="large"
|
|
225
|
+
className={`
|
|
226
|
+
@state-not-blank/search:hidden
|
|
227
|
+
@state-focus/search:hidden
|
|
228
|
+
@prop-layout-compact/search:@state-not-open/search:hidden
|
|
229
|
+
`}
|
|
230
|
+
>
|
|
231
|
+
{focusKey}
|
|
232
|
+
</Keyboard>
|
|
233
|
+
) : null}
|
|
234
|
+
</div>
|
|
235
|
+
</div>
|
|
236
|
+
</div>
|
|
237
|
+
)
|
|
238
|
+
}
|
|
@@ -8,9 +8,9 @@ import {
|
|
|
8
8
|
type KeyboardEvent,
|
|
9
9
|
type MouseEvent,
|
|
10
10
|
} from 'react'
|
|
11
|
-
import { Radio } from '@base-ui
|
|
12
|
-
import { RadioGroup } from '@base-ui
|
|
13
|
-
import { useMergedRefs } from '@base-ui
|
|
11
|
+
import { Radio } from '@base-ui/react/radio'
|
|
12
|
+
import { RadioGroup } from '@base-ui/react/radio-group'
|
|
13
|
+
import { useMergedRefs } from '@base-ui/utils/useMergedRefs'
|
|
14
14
|
|
|
15
15
|
import type { GDSComponentProps } from '@graphprotocol/gds-css'
|
|
16
16
|
|
|
@@ -142,6 +142,8 @@ export function SegmentedControlOption<T extends OptionValue>({
|
|
|
142
142
|
}: SegmentedControlOptionProps<T>) {
|
|
143
143
|
useGDS()
|
|
144
144
|
|
|
145
|
+
const { rootProps, nestedProps } = splitProps(props)
|
|
146
|
+
|
|
145
147
|
const buttonRef = useRef<HTMLSpanElement>(null)
|
|
146
148
|
const buttonPassedRef = useMergedRefs(buttonRef, passedRef)
|
|
147
149
|
|
|
@@ -154,8 +156,6 @@ export function SegmentedControlOption<T extends OptionValue>({
|
|
|
154
156
|
const autoValue = useAutoValue(children)
|
|
155
157
|
const value = passedValue !== undefined ? passedValue : autoValue
|
|
156
158
|
|
|
157
|
-
const { rootProps, nestedProps } = splitProps(props)
|
|
158
|
-
|
|
159
159
|
const { onCollect, collectedContent } = useCollectedTooltip()
|
|
160
160
|
let tooltipProps: Omit<TooltipProps, 'children'> = { content: collectedContent }
|
|
161
161
|
if (tooltip !== undefined) {
|
|
@@ -190,12 +190,11 @@ export function SegmentedControlOption<T extends OptionValue>({
|
|
|
190
190
|
/**
|
|
191
191
|
* This wrapper is necessary to ensure this component returns a single element (which some
|
|
192
192
|
* Tailwind classes might assume) because `Radio.Root` renders a `<input type="radio">` as a
|
|
193
|
-
* sibling of the button (
|
|
194
|
-
*
|
|
195
|
-
*
|
|
196
|
-
*
|
|
197
|
-
*
|
|
198
|
-
* https://github.com/mui/base-ui/issues/3143).
|
|
193
|
+
* sibling of the button (actually a `<span>`). Ideally, we would make `Radio.Root` the root and
|
|
194
|
+
* it would render an internal component (e.g. `SegmentedControlOptionButton`) that would itself
|
|
195
|
+
* render a wrapper `<div>` around the button and the input (as well as calling `useCSSState`
|
|
196
|
+
* with a proper initial `checked` value, from the `render` state), but that is not possible
|
|
197
|
+
* currently (see https://github.com/mui/base-ui/issues/3143).
|
|
199
198
|
*/
|
|
200
199
|
<div
|
|
201
200
|
ref={stateRef}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use client'
|
|
2
2
|
|
|
3
3
|
import { createContext, useContext, type ComponentProps } from 'react'
|
|
4
|
-
import { Tabs } from '@base-ui
|
|
4
|
+
import { Tabs } from '@base-ui/react/tabs'
|
|
5
5
|
import flattenChildren from 'react-keyed-flatten-children'
|
|
6
6
|
|
|
7
7
|
import type { GDSComponentProps } from '@graphprotocol/gds-css'
|
|
@@ -265,7 +265,7 @@ export function TabSetPanels({
|
|
|
265
265
|
u:group-data-[activation-direction=right]/tab-set:var-[exit-translate-x=-32px]
|
|
266
266
|
u:has-nested-focus-visible/tab-set-panel:animate
|
|
267
267
|
u:has-nested-focus-visible/tab-set-panel:outline
|
|
268
|
-
u:has-nested-focus-visible/tab-set-panel:animate-outline-from-
|
|
268
|
+
u:has-nested-focus-visible/tab-set-panel:animate-outline-from-focus`,
|
|
269
269
|
transition && typeof transition === 'object' ? transition.className : undefined,
|
|
270
270
|
className,
|
|
271
271
|
)}
|
|
@@ -2,15 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
import {
|
|
4
4
|
createContext,
|
|
5
|
+
useCallback,
|
|
5
6
|
useContext,
|
|
6
7
|
useEffect,
|
|
8
|
+
useMemo,
|
|
7
9
|
useRef,
|
|
8
10
|
useState,
|
|
9
11
|
type ComponentProps,
|
|
10
12
|
type ReactElement,
|
|
11
13
|
type ReactNode,
|
|
12
14
|
} from 'react'
|
|
13
|
-
import { Tooltip } from '@base-ui
|
|
15
|
+
import { Tooltip } from '@base-ui/react/tooltip'
|
|
14
16
|
|
|
15
17
|
import { twToPx, type GDSComponentProps } from '@graphprotocol/gds-css'
|
|
16
18
|
|
|
@@ -83,9 +85,9 @@ export function TooltipRoot({
|
|
|
83
85
|
const enabled = !cssProps.disabled && !hasEnabledTooltipAncestor && Boolean(content)
|
|
84
86
|
const [open, ownSetOpen] = useControlled(controlledOpen, false, onOpenChange)
|
|
85
87
|
const nestedSetOpen = useRef<(newOpen: boolean) => void>(null)
|
|
86
|
-
const registerNestedSetOpen = (newNestedSetOpen: (newOpen: boolean) => void) => {
|
|
88
|
+
const registerNestedSetOpen = useCallback((newNestedSetOpen: (newOpen: boolean) => void) => {
|
|
87
89
|
nestedSetOpen.current = newNestedSetOpen
|
|
88
|
-
}
|
|
90
|
+
}, [])
|
|
89
91
|
const setOpen = (newOpen: boolean) => {
|
|
90
92
|
ownSetOpen(newOpen)
|
|
91
93
|
/**
|
|
@@ -112,8 +114,16 @@ export function TooltipRoot({
|
|
|
112
114
|
clearOpenTimeout()
|
|
113
115
|
}
|
|
114
116
|
|
|
117
|
+
const tooltipContextValue = useMemo(
|
|
118
|
+
() => ({
|
|
119
|
+
enabled,
|
|
120
|
+
registerNestedSetOpen,
|
|
121
|
+
}),
|
|
122
|
+
[enabled, registerNestedSetOpen],
|
|
123
|
+
)
|
|
124
|
+
|
|
115
125
|
return (
|
|
116
|
-
<TooltipContext.Provider value={
|
|
126
|
+
<TooltipContext.Provider value={tooltipContextValue}>
|
|
117
127
|
<TooltipCollector onCollect={onCollect}>
|
|
118
128
|
<Tooltip.Root
|
|
119
129
|
disabled={!enabled}
|
|
@@ -145,6 +155,7 @@ export function TooltipRoot({
|
|
|
145
155
|
side={cssProps.position}
|
|
146
156
|
sideOffset={twToPx(cssProps.gap)}
|
|
147
157
|
align={cssProps.align}
|
|
158
|
+
disableAnchorTracking
|
|
148
159
|
{...dirProps}
|
|
149
160
|
>
|
|
150
161
|
<Tooltip.Popup
|
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
createContext,
|
|
5
5
|
isValidElement,
|
|
6
6
|
useContext,
|
|
7
|
+
useMemo,
|
|
7
8
|
useRef,
|
|
8
9
|
useState,
|
|
9
10
|
type ComponentProps,
|
|
@@ -13,7 +14,7 @@ import {
|
|
|
13
14
|
type ReactElement,
|
|
14
15
|
type ReactNode,
|
|
15
16
|
} from 'react'
|
|
16
|
-
import { useMergedRefs } from '@base-ui
|
|
17
|
+
import { useMergedRefs } from '@base-ui/utils/useMergedRefs'
|
|
17
18
|
import { mergeProps } from '@react-aria/utils'
|
|
18
19
|
import { useButton } from 'react-aria'
|
|
19
20
|
|
|
@@ -337,25 +338,38 @@ export const ButtonOrLinkConfig = ({
|
|
|
337
338
|
children,
|
|
338
339
|
}: ButtonOrLinkConfigProps) => {
|
|
339
340
|
const ancestorConfig = useContext(ButtonOrLinkConfigContext)
|
|
341
|
+
|
|
340
342
|
const onClick =
|
|
341
343
|
passedOnClick && ancestorConfig?.onClick
|
|
342
|
-
? (
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
344
|
+
? (() => {
|
|
345
|
+
const ancestorOnClick = ancestorConfig.onClick
|
|
346
|
+
return (
|
|
347
|
+
event: MouseEvent<HTMLButtonElement & HTMLAnchorElement>,
|
|
348
|
+
props: InternalButtonOrLinkProps,
|
|
349
|
+
) => {
|
|
350
|
+
passedOnClick(event, props)
|
|
351
|
+
if (event.isPropagationStopped()) return
|
|
352
|
+
ancestorOnClick(event, props)
|
|
353
|
+
}
|
|
354
|
+
})()
|
|
350
355
|
: (passedOnClick ?? ancestorConfig?.onClick)
|
|
351
356
|
const transformProps =
|
|
352
357
|
passedTransformProps && ancestorConfig?.transformProps
|
|
353
|
-
? (
|
|
354
|
-
|
|
355
|
-
|
|
358
|
+
? (() => {
|
|
359
|
+
const ancestorTransformProps = ancestorConfig.transformProps
|
|
360
|
+
return (props: InternalButtonOrLinkProps) => {
|
|
361
|
+
return ancestorTransformProps(passedTransformProps(props))
|
|
362
|
+
}
|
|
363
|
+
})()
|
|
356
364
|
: (passedTransformProps ?? ancestorConfig?.transformProps)
|
|
365
|
+
|
|
366
|
+
const buttonOrLinkConfigContextValue = useMemo(() => {
|
|
367
|
+
if (!onClick && !transformProps) return null
|
|
368
|
+
return { onClick, transformProps }
|
|
369
|
+
}, [onClick, transformProps])
|
|
370
|
+
|
|
357
371
|
return (
|
|
358
|
-
<ButtonOrLinkConfigContext.Provider value={
|
|
372
|
+
<ButtonOrLinkConfigContext.Provider value={buttonOrLinkConfigContextValue}>
|
|
359
373
|
{children}
|
|
360
374
|
</ButtonOrLinkConfigContext.Provider>
|
|
361
375
|
)
|
package/src/components/index.ts
CHANGED
|
@@ -63,6 +63,8 @@ export { OTCInput, type OTCInputProps } from './OTCInput.tsx'
|
|
|
63
63
|
export { OTCInputMeta } from './OTCInput.meta.ts'
|
|
64
64
|
export { Radio, type RadioAreaProps, type RadioGroupProps, type RadioProps } from './Radio.tsx'
|
|
65
65
|
export { RadioMeta } from './Radio.meta.ts'
|
|
66
|
+
export { Search, type SearchProps } from './Search.tsx'
|
|
67
|
+
export { SearchMeta } from './Search.meta.ts'
|
|
66
68
|
export {
|
|
67
69
|
SegmentedControl,
|
|
68
70
|
type SegmentedControlOptionProps,
|
package/src/hooks/useCSSProp.ts
CHANGED
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
type Ref,
|
|
7
7
|
type RefCallback,
|
|
8
8
|
} from 'react'
|
|
9
|
-
import { useMergedRefs } from '@base-ui
|
|
9
|
+
import { useMergedRefs } from '@base-ui/utils/useMergedRefs'
|
|
10
10
|
import { useCustomCompareEffect, useCustomCompareMemo, type EffectHook } from '@react-hookz/web'
|
|
11
11
|
import { isEqual } from '@ver0/deep-equal'
|
|
12
12
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useCallback, useLayoutEffect, useRef, type Ref } from 'react'
|
|
2
|
-
import { useMergedRefs } from '@base-ui
|
|
2
|
+
import { useMergedRefs } from '@base-ui/utils/useMergedRefs'
|
|
3
3
|
import StyleObserver from 'style-observer'
|
|
4
4
|
|
|
5
5
|
import { styleScheduler } from '../utils/styleScheduler.ts'
|
package/src/tailwind-plugin.ts
CHANGED
|
@@ -31,6 +31,7 @@ import { MenuItemMeta, MenuMeta } from './components/Menu.meta.ts'
|
|
|
31
31
|
import { ModalMeta } from './components/Modal.meta.ts'
|
|
32
32
|
import { OTCInputMeta } from './components/OTCInput.meta.ts'
|
|
33
33
|
import { RadioMeta } from './components/Radio.meta.ts'
|
|
34
|
+
import { SearchMeta } from './components/Search.meta.ts'
|
|
34
35
|
import {
|
|
35
36
|
SegmentedControlMeta,
|
|
36
37
|
SegmentedControlOptionMeta,
|
|
@@ -101,6 +102,7 @@ const gdsTailwindPluginWithComponents: ReturnType<typeof createPlugin> = createP
|
|
|
101
102
|
ModalMeta,
|
|
102
103
|
OTCInputMeta,
|
|
103
104
|
RadioMeta,
|
|
105
|
+
SearchMeta,
|
|
104
106
|
SegmentedControlMeta,
|
|
105
107
|
SegmentedControlOptionMeta,
|
|
106
108
|
StatusMeta,
|