@graphprotocol/gds-react 0.1.1 → 0.1.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.
Files changed (58) hide show
  1. package/dist/components/Avatar.d.ts.map +1 -1
  2. package/dist/components/Avatar.js +5 -1
  3. package/dist/components/Avatar.js.map +1 -1
  4. package/dist/components/Breadcrumbs.parts.js +2 -2
  5. package/dist/components/Button.js +8 -4
  6. package/dist/components/Button.js.map +1 -1
  7. package/dist/components/Card.js +1 -1
  8. package/dist/components/Card.js.map +1 -1
  9. package/dist/components/Chip.d.ts +6 -0
  10. package/dist/components/Chip.d.ts.map +1 -0
  11. package/dist/components/Chip.js +5 -0
  12. package/dist/components/Chip.js.map +1 -0
  13. package/dist/components/Chip.meta.d.ts +17 -0
  14. package/dist/components/Chip.meta.d.ts.map +1 -0
  15. package/dist/components/Chip.meta.js +22 -0
  16. package/dist/components/Chip.meta.js.map +1 -0
  17. package/dist/components/Chip.parts.d.ts +52 -0
  18. package/dist/components/Chip.parts.d.ts.map +1 -0
  19. package/dist/components/Chip.parts.js +122 -0
  20. package/dist/components/Chip.parts.js.map +1 -0
  21. package/dist/components/DescriptionList.parts.js +1 -1
  22. package/dist/components/SegmentedControl.parts.d.ts.map +1 -1
  23. package/dist/components/SegmentedControl.parts.js +12 -23
  24. package/dist/components/SegmentedControl.parts.js.map +1 -1
  25. package/dist/components/TabSet.parts.js +1 -1
  26. package/dist/components/ToggleButton.d.ts +0 -2
  27. package/dist/components/ToggleButton.d.ts.map +1 -1
  28. package/dist/components/ToggleButton.js.map +1 -1
  29. package/dist/components/Tooltip.parts.d.ts.map +1 -1
  30. package/dist/components/Tooltip.parts.js +1 -1
  31. package/dist/components/Tooltip.parts.js.map +1 -1
  32. package/dist/components/base/ButtonOrLink.parts.d.ts +8 -5
  33. package/dist/components/base/ButtonOrLink.parts.d.ts.map +1 -1
  34. package/dist/components/base/ButtonOrLink.parts.js +19 -16
  35. package/dist/components/base/ButtonOrLink.parts.js.map +1 -1
  36. package/dist/components/index.d.ts +2 -0
  37. package/dist/components/index.d.ts.map +1 -1
  38. package/dist/components/index.js +2 -0
  39. package/dist/components/index.js.map +1 -1
  40. package/dist/tailwind-plugin.d.ts.map +1 -1
  41. package/dist/tailwind-plugin.js +3 -0
  42. package/dist/tailwind-plugin.js.map +1 -1
  43. package/package.json +7 -7
  44. package/src/components/Avatar.tsx +5 -1
  45. package/src/components/Breadcrumbs.parts.tsx +2 -2
  46. package/src/components/Button.tsx +13 -3
  47. package/src/components/Card.tsx +1 -1
  48. package/src/components/Chip.meta.ts +23 -0
  49. package/src/components/Chip.parts.tsx +329 -0
  50. package/src/components/Chip.tsx +7 -0
  51. package/src/components/DescriptionList.parts.tsx +1 -1
  52. package/src/components/SegmentedControl.parts.tsx +34 -35
  53. package/src/components/TabSet.parts.tsx +1 -1
  54. package/src/components/ToggleButton.tsx +0 -2
  55. package/src/components/Tooltip.parts.tsx +0 -1
  56. package/src/components/base/ButtonOrLink.parts.tsx +38 -21
  57. package/src/components/index.ts +2 -0
  58. package/src/tailwind-plugin.ts +3 -0
@@ -0,0 +1,329 @@
1
+ 'use client'
2
+
3
+ import { createContext, useContext, type ComponentProps, type ReactNode } from 'react'
4
+ import { Checkbox } from '@base-ui/react/checkbox'
5
+ import { CheckboxGroup } from '@base-ui/react/checkbox-group'
6
+ import { Radio } from '@base-ui/react/radio'
7
+ import { RadioGroup } from '@base-ui/react/radio-group'
8
+
9
+ import type { GDSComponentProps } from '@graphprotocol/gds-css'
10
+
11
+ import { useAutoValue, useCSSPropsPolyfill, useCSSState, useGDS } from '../hooks/index.ts'
12
+ import { cn, getCSSPropsAttributes, splitProps } from '../utils/index.ts'
13
+ import { renderAddon, type AddonValue } from './base/Addon.tsx'
14
+ import { ButtonOrLink, type ButtonOrLinkProps } from './base/ButtonOrLink.tsx'
15
+ import { ChipGroupMeta, ChipMeta } from './Chip.meta.ts'
16
+
17
+ type ExtractFn<T> = T extends (...args: infer A) => infer R ? (...args: A) => R : never
18
+
19
+ export declare namespace ChipProps {
20
+ interface BaseProps extends GDSComponentProps<typeof ChipMeta> {
21
+ /** Name used to submit the chip's value when inside a `<Chip.Group type="checkbox">` in a form. */
22
+ name?: string | undefined
23
+ /** Value used to identify this chip when inside a `<Chip.Group>`. */
24
+ value?: string | undefined
25
+ addonBefore?: AddonValue | undefined
26
+ addonAfter?: AddonValue | undefined
27
+ count?: ReactNode | undefined
28
+ }
29
+ interface ButtonProps
30
+ extends
31
+ BaseProps,
32
+ Omit<ButtonOrLinkProps.ButtonProps, 'value'>,
33
+ ButtonOrLinkProps.DisableableProps {}
34
+ interface LinkProps
35
+ extends BaseProps, ButtonOrLinkProps.LinkProps, ButtonOrLinkProps.DisableableProps {}
36
+ }
37
+
38
+ export type ChipProps = ChipProps.ButtonProps | ChipProps.LinkProps
39
+
40
+ interface ChipGroupContextValue {
41
+ type: 'checkbox' | 'radio'
42
+ }
43
+
44
+ const ChipGroupContext = createContext<ChipGroupContextValue | null>(null)
45
+
46
+ export function ChipRoot({
47
+ size,
48
+ name,
49
+ value: passedValue,
50
+ addonBefore,
51
+ addonAfter,
52
+ count,
53
+ disabled = false,
54
+ className,
55
+ style,
56
+ children,
57
+ ...props
58
+ }: ChipProps) {
59
+ useGDS()
60
+
61
+ const { rootProps, nestedProps } = splitProps(props)
62
+
63
+ const autoValue = useAutoValue(children)
64
+ const value = passedValue !== undefined ? passedValue : autoValue
65
+
66
+ const groupContext = useContext(ChipGroupContext)
67
+
68
+ const [stateRef, state] = useCSSState({
69
+ pointer: undefined,
70
+ focus: undefined,
71
+ checked: undefined,
72
+ disabled: Boolean(disabled),
73
+ })
74
+ const [cssPropsPolyfillStateRef, cssPropsPolyfillAttributes] = useCSSPropsPolyfill(
75
+ ChipMeta,
76
+ { size },
77
+ { ref: stateRef },
78
+ )
79
+
80
+ return (
81
+ <div
82
+ ref={cssPropsPolyfillStateRef}
83
+ data-type={groupContext?.type ?? 'plain'}
84
+ className={cn(
85
+ `gds-chip root-flex flex-col u:size-max u:max-w-full
86
+ u:has-nested-checked/chip-ref:expose-checked
87
+ u:has-nested-hover/chip-ref:expose-hover
88
+ u:has-nested-focus-visible/chip-ref:expose-focus
89
+ u:has-nested-disabled/chip-ref:expose-disabled
90
+ u:i:has-nested-checked/chip-ref:data-[type=radio]:state-idle`,
91
+ className,
92
+ )}
93
+ {...state.exposedAttributes}
94
+ {...state.polyfillAttributes}
95
+ {...getCSSPropsAttributes(ChipMeta, { size }, style)}
96
+ {...cssPropsPolyfillAttributes}
97
+ {...rootProps}
98
+ >
99
+ {(() => {
100
+ if (!groupContext || props.href !== undefined) {
101
+ return renderButtonOrLink({})
102
+ }
103
+
104
+ if (groupContext.type === 'checkbox') {
105
+ return (
106
+ <Checkbox.Root
107
+ name={name ?? (undefined as never)}
108
+ value={typeof value === 'string' ? value : (undefined as never)}
109
+ disabled={Boolean(disabled)}
110
+ nativeButton
111
+ render={renderButtonOrLink}
112
+ />
113
+ )
114
+ } else {
115
+ return (
116
+ <Radio.Root
117
+ value={value}
118
+ disabled={Boolean(disabled)}
119
+ nativeButton
120
+ render={renderButtonOrLink}
121
+ />
122
+ )
123
+ }
124
+
125
+ function renderButtonOrLink({
126
+ tabIndex: _tabIndex,
127
+ defaultChecked: _defaultChecked,
128
+ ...renderProps
129
+ }: Parameters<
130
+ ExtractFn<ComponentProps<typeof Checkbox.Root | typeof Radio.Root>['render']>
131
+ >[0]) {
132
+ return (
133
+ <ButtonOrLink
134
+ {...renderProps}
135
+ disabled={disabled}
136
+ className={cn(
137
+ renderProps.className,
138
+ `nested/chip-ref flex grow items-center justify-center
139
+ rounded-full border border-default text-muted transition
140
+ @state-checked/chip:border-brand-muted
141
+ @state-checked/chip:bg-brand-subtlest
142
+ @state-checked/chip:text-default
143
+ @state-hover/chip:border-strong
144
+ @state-hover/chip:text-default
145
+ @state-hover/chip:@state-checked/chip:border-brand-default
146
+ @state-hover/chip:@state-checked/chip:bg-brand-subtler
147
+ @prop-size-small/chip:h-6
148
+ @prop-size-small/chip:px-1
149
+ @prop-size-small/chip:text-12
150
+ @prop-size-medium/chip:h-8
151
+ @prop-size-medium/chip:px-1.5
152
+ @prop-size-medium/chip:text-14
153
+ @prop-size-large/chip:h-10
154
+ @prop-size-large/chip:px-2
155
+ @prop-size-large/chip:text-16
156
+ u:*:transition-opacity
157
+ u:*:@state-disabled/chip:opacity-disabled
158
+ u:*:@state-disabled/chip:grayscale
159
+ u:@prop-size-small/chip:addon-small
160
+ u:@prop-size-medium/chip:addon-medium
161
+ u:@prop-size-large/chip:addon-large
162
+ i:@state-disabled/chip:border-muted
163
+ i:@state-disabled/chip:bg-transparent
164
+ i:@state-disabled/chip:text-muted
165
+ i:@state-disabled/chip:@state-checked/chip:border-transparent
166
+ i:@state-disabled/chip:@state-checked/chip:bg-brand-subtlest`,
167
+ )}
168
+ {...nestedProps}
169
+ >
170
+ {/* Ensure rounded corners are clickable */}
171
+ <span className="absolute inset-0 not-in-clickable:hidden" />
172
+ {addonBefore ? <ChipAddon side="before">{renderAddon(addonBefore)}</ChipAddon> : null}
173
+ <span
174
+ className={`
175
+ flex items-baseline
176
+ @prop-size-small/chip:gap-0.5
177
+ @prop-size-small/chip:px-0.5
178
+ @prop-size-medium/chip:gap-1
179
+ @prop-size-medium/chip:px-1
180
+ @prop-size-large/chip:gap-1
181
+ @prop-size-large/chip:px-1
182
+ `}
183
+ >
184
+ <span className="truncate">{children}</span>
185
+ {count ? (
186
+ <span
187
+ className={`
188
+ max-w-full shrink-0 truncate text-subtle transition
189
+ @state-enabled/chip:@state-checked/chip:text-current
190
+ @state-enabled/chip:@state-hover/chip:text-current
191
+ @prop-size-small/chip:text-10
192
+ @prop-size-medium/chip:text-12
193
+ @prop-size-large/chip:text-14
194
+ `}
195
+ >
196
+ {count}
197
+ </span>
198
+ ) : null}
199
+ </span>
200
+ {addonAfter ? <ChipAddon side="after">{renderAddon(addonAfter)}</ChipAddon> : null}
201
+ </ButtonOrLink>
202
+ )
203
+ }
204
+ })()}
205
+ </div>
206
+ )
207
+ }
208
+ ChipRoot.displayName = 'Chip'
209
+
210
+ function ChipAddon({
211
+ side,
212
+ className,
213
+ children,
214
+ ...props
215
+ }: ComponentProps<'span'> & { side: 'before' | 'after' }) {
216
+ return (
217
+ <span
218
+ data-side={side}
219
+ className={cn(
220
+ `gds-addon root-flex items-center justify-center u:h-(--gds-addon-size) u:min-w-(--gds-addon-size) u:shrink-0
221
+ u:has-avatar-group:data-[side=after]:ps-0.5
222
+ u:has-tag:data-[side=after]:ps-0.5
223
+ u:has-avatar-group:data-[side=before]:pe-0.5
224
+ u:has-tag:data-[side=before]:pe-0.5`,
225
+ className,
226
+ )}
227
+ {...props}
228
+ >
229
+ {children}
230
+ </span>
231
+ )
232
+ }
233
+
234
+ export declare namespace ChipGroupProps {
235
+ interface BaseProps
236
+ extends Omit<ComponentProps<'div'>, 'onChange'>, GDSComponentProps<typeof ChipGroupMeta> {}
237
+ interface CheckboxProps extends BaseProps {
238
+ type: 'checkbox'
239
+ name?: undefined
240
+ /** Array of checked/selected chip values. */
241
+ value?: string[] | undefined
242
+ defaultValue?: string[] | undefined
243
+ onChange?: ((value: string[]) => void) | undefined
244
+ }
245
+ interface RadioProps extends BaseProps {
246
+ type: 'radio'
247
+ /** Name used to submit the checked/selected chip value when inside a form. */
248
+ name?: string | undefined
249
+ /** Checked/selected chip value. */
250
+ value?: string | undefined
251
+ defaultValue?: string | undefined
252
+ onChange?: ((value: string) => void) | undefined
253
+ }
254
+ }
255
+
256
+ export type ChipGroupProps = ChipGroupProps.CheckboxProps | ChipGroupProps.RadioProps
257
+
258
+ export function ChipGroup({
259
+ ref: passedRef,
260
+ type,
261
+ name,
262
+ value,
263
+ defaultValue,
264
+ onChange,
265
+ size,
266
+ className,
267
+ style,
268
+ children,
269
+ ...props
270
+ }: ChipGroupProps) {
271
+ useGDS()
272
+
273
+ if (props['aria-label'] === undefined && props['aria-labelledby'] === undefined) {
274
+ // oxlint-disable-next-line no-console
275
+ console.warn(
276
+ '[Chip.Group] One of `aria-label` or `aria-labelledby` should be set for accessibility',
277
+ )
278
+ }
279
+
280
+ const [cssPropsPolyfillPassedRef, cssPropsPolyfillAttributes, cssProps] = useCSSPropsPolyfill(
281
+ ChipGroupMeta,
282
+ { size },
283
+ { ref: passedRef, returnPropValues: { size } },
284
+ )
285
+
286
+ const sharedProps = {
287
+ ref: cssPropsPolyfillPassedRef,
288
+ 'data-size': cssProps.size,
289
+ className: cn(
290
+ `gds-chip-group root-flex u:flex-wrap
291
+ u:data-[size=large]:gap-2
292
+ u:data-[size=medium]:gap-1.5
293
+ u:data-[size=small]:gap-1
294
+ u:**:chip:@prop-size-small/chip-group:prop-size-small
295
+ u:**:chip:@prop-size-medium/chip-group:prop-size-medium
296
+ u:**:chip:@prop-size-large/chip-group:prop-size-large`,
297
+ className,
298
+ ),
299
+ ...getCSSPropsAttributes(ChipGroupMeta, { size }, style),
300
+ ...cssPropsPolyfillAttributes,
301
+ ...props,
302
+ }
303
+
304
+ return (
305
+ <ChipGroupContext.Provider value={{ type }}>
306
+ {type === 'checkbox' ? (
307
+ <CheckboxGroup
308
+ {...sharedProps}
309
+ {...(value !== undefined && { value })}
310
+ {...(defaultValue !== undefined && { defaultValue })}
311
+ {...(onChange !== undefined && { onValueChange: onChange })}
312
+ >
313
+ {children}
314
+ </CheckboxGroup>
315
+ ) : (
316
+ <RadioGroup
317
+ name={name ?? (undefined as never)}
318
+ {...sharedProps}
319
+ {...(value !== undefined && { value })}
320
+ {...(defaultValue !== undefined && { defaultValue })}
321
+ {...(onChange !== undefined && { onValueChange: onChange as (value: unknown) => void })}
322
+ >
323
+ {children}
324
+ </RadioGroup>
325
+ )}
326
+ </ChipGroupContext.Provider>
327
+ )
328
+ }
329
+ ChipGroup.displayName = 'Chip.Group'
@@ -0,0 +1,7 @@
1
+ import { ChipGroup, ChipRoot } from './Chip.parts.tsx'
2
+
3
+ export const Chip = Object.assign(ChipRoot, {
4
+ Group: ChipGroup,
5
+ })
6
+
7
+ export type { ChipProps, ChipGroupProps } from './Chip.parts.tsx'
@@ -189,7 +189,7 @@ export function DescriptionListItem({
189
189
  <span
190
190
  className={`
191
191
  absolute inset-y-0 flex items-center justify-center
192
- not-group-data-loading/description-list-item:hidden
192
+ group-not-data-loading/description-list-item:hidden
193
193
  @prop-orientation-horizontal/description-list:start-0
194
194
  @prop-orientation-vertical/description-list:end-0
195
195
  @prop-orientation-vertical/description-list:w-(--gds-addon-size)
@@ -53,6 +53,8 @@ export function SegmentedControlRoot<T extends OptionValue>({
53
53
  children,
54
54
  ...props
55
55
  }: SegmentedControlProps<T>) {
56
+ useGDS()
57
+
56
58
  if (props['aria-label'] === undefined && props['aria-labelledby'] === undefined) {
57
59
  // oxlint-disable-next-line no-console
58
60
  console.warn(
@@ -140,22 +142,20 @@ export function SegmentedControlOption<T extends OptionValue>({
140
142
  children,
141
143
  ...props
142
144
  }: SegmentedControlOptionProps<T>) {
143
- useGDS()
144
-
145
145
  const { rootProps, nestedProps } = splitProps(props)
146
146
 
147
147
  const buttonRef = useRef<HTMLSpanElement>(null)
148
148
  const buttonPassedRef = useMergedRefs(buttonRef, passedRef)
149
149
 
150
+ const autoValue = useAutoValue(children)
151
+ const value = passedValue !== undefined ? passedValue : autoValue
152
+
150
153
  const [stateRef, state] = useCSSState({
151
154
  pointer: undefined,
152
155
  checked: undefined,
153
156
  'is-toggle': undefined,
154
157
  })
155
158
 
156
- const autoValue = useAutoValue(children)
157
- const value = passedValue !== undefined ? passedValue : autoValue
158
-
159
159
  const { onCollect, collectedContent } = useCollectedTooltip()
160
160
  let tooltipProps: Omit<TooltipProps, 'children'> = { content: collectedContent }
161
161
  if (tooltip !== undefined) {
@@ -187,32 +187,32 @@ export function SegmentedControlOption<T extends OptionValue>({
187
187
  }
188
188
 
189
189
  return (
190
- /**
191
- * This wrapper is necessary to ensure this component returns a single element (which some
192
- * Tailwind classes might assume) because `Radio.Root` renders a `<input type="radio">` as a
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).
198
- */
199
- <div
200
- ref={stateRef}
201
- className={cn(
202
- `gds-segmented-control-option root-block
203
- state-[is-toggle=false]
204
- group-[:has([data-checked]):has(>:nth-child(2)):not(:has(>:nth-child(3)))]/segmented-control-options:state-[is-toggle]
205
- u:group-has-nested-hover/segmented-control--segmented-control-toggle:state-hover
206
- u:group-has-nested-active/segmented-control--segmented-control-toggle:state-active
207
- u:has-nested-hover/segmented-control-option-ref:state-hover
208
- u:has-nested-active/segmented-control-option-ref:state-active
209
- u:has-nested-[[data-checked]]/segmented-control-option-ref:state-checked`,
210
- className,
211
- )}
212
- {...state.polyfillAttributes}
213
- {...rootProps}
214
- >
215
- <Tooltip {...tooltipProps}>
190
+ <Tooltip {...tooltipProps}>
191
+ {/**
192
+ * This wrapper is necessary to ensure this component returns a single element (which some Tailwind
193
+ * classes might assume) because `Radio.Root` renders a `<input type="radio">` as a sibling of the
194
+ * button (actually a `<span>`). Ideally, we would make `Radio.Root` the root and it would render an
195
+ * internal component (e.g. `SegmentedControlOptionButton`) that would itself render a wrapper
196
+ * `<div>` around the button and the input (as well as calling `useCSSState` with a proper initial
197
+ * `checked` value, from the `render` state), but that is not possible currently (see
198
+ * https://github.com/mui/base-ui/issues/3143).
199
+ */}
200
+ <div
201
+ ref={stateRef}
202
+ className={cn(
203
+ `gds-segmented-control-option root-block
204
+ state-[is-toggle=false]
205
+ group-[:has([data-checked]):has(>:nth-child(2)):not(:has(>:nth-child(3)))]/segmented-control-options:state-[is-toggle]
206
+ u:group-has-nested-hover/segmented-control--segmented-control-toggle:state-hover
207
+ u:group-has-nested-active/segmented-control--segmented-control-toggle:state-active
208
+ u:has-nested-hover/segmented-control-option-ref:state-hover
209
+ u:has-nested-active/segmented-control-option-ref:state-active
210
+ u:has-nested-[[data-checked]]/segmented-control-option-ref:state-checked`,
211
+ className,
212
+ )}
213
+ {...state.polyfillAttributes}
214
+ {...rootProps}
215
+ >
216
216
  <Radio.Root
217
217
  ref={buttonPassedRef}
218
218
  value={value}
@@ -223,8 +223,7 @@ export function SegmentedControlOption<T extends OptionValue>({
223
223
  }
224
224
  }}
225
225
  className={`
226
- nested/segmented-control-option-ref block w-full cursor-pointer outline-0
227
- @state-checked/segmented-control-option:cursor-default
226
+ nested/segmented-control-option-ref block w-full outline-0
228
227
  @state-checked/segmented-control-option:[anchor-name:--gds-segmented-control-checked]
229
228
  `}
230
229
  {...nestedProps}
@@ -270,8 +269,8 @@ export function SegmentedControlOption<T extends OptionValue>({
270
269
  `}
271
270
  />
272
271
  </Radio.Root>
273
- </Tooltip>
274
- </div>
272
+ </div>
273
+ </Tooltip>
275
274
  )
276
275
  }
277
276
  SegmentedControlOption.displayName = 'SegmentedControl.Option'
@@ -118,8 +118,8 @@ export function TabSetTabs({
118
118
  className={`
119
119
  absolute inset-x-[anchor(inside)] bottom-0 h-px bg-(--border-color-brand-default) transition-[inset] duration-300
120
120
  [position-anchor:--gds-tab-set-underline]
121
- not-group-hover/tab-set-tabs:duration-0
122
121
  not-supports-[position-anchor:--foo]:hidden
122
+ group-not-hover/tab-set-tabs:duration-0
123
123
  group-has-focus-visible/tab-set-tabs:hidden
124
124
  `}
125
125
  />
@@ -17,8 +17,6 @@ export interface ToggleButtonProps
17
17
  extends
18
18
  Omit<ButtonProps.ToggleButtonProps, 'onChange' | 'variant'>,
19
19
  GDSComponentProps<typeof ToggleButtonMeta> {
20
- checked?: boolean | undefined
21
- defaultChecked?: boolean | undefined
22
20
  onChange?: ((checked: boolean) => void) | undefined
23
21
  }
24
22
 
@@ -155,7 +155,6 @@ export function TooltipRoot({
155
155
  side={cssProps.position}
156
156
  sideOffset={twToPx(cssProps.gap)}
157
157
  align={cssProps.align}
158
- disableAnchorTracking
159
158
  {...dirProps}
160
159
  >
161
160
  <Tooltip.Popup
@@ -68,19 +68,26 @@ export declare namespace InternalButtonOrLinkProps {
68
68
  linkComponent?: LinkComponent | undefined
69
69
  }
70
70
  interface ButtonProps
71
- extends BaseProps, DisableableProps, Omit<ComponentProps<'button'>, 'disabled'> {
71
+ extends
72
+ BaseProps,
73
+ DisableableProps,
74
+ Omit<ComponentProps<'button'>, 'defaultValue' | 'disabled'> {
72
75
  href?: undefined
73
76
  target?: undefined
74
77
  checked?: undefined
78
+ defaultChecked?: undefined
75
79
  }
76
- interface ToggleButtonProps extends Omit<ButtonProps, 'checked'> {
77
- /** Whether the button is in a checked/selected/pressed state. */
78
- checked?: boolean | 'indeterminate' | undefined
80
+ interface ToggleButtonProps extends Omit<ButtonProps, 'checked' | 'defaultChecked'> {
81
+ /** Whether the button is in a pressed/selected state. */
82
+ checked?: boolean | undefined
83
+ defaultChecked?: boolean | undefined
79
84
  }
80
- interface LinkProps extends BaseProps, DisableableProps, ComponentProps<'a'> {
85
+ interface LinkProps
86
+ extends BaseProps, DisableableProps, Omit<ComponentProps<'a'>, 'defaultValue'> {
81
87
  href: string
82
88
  type?: undefined
83
89
  checked?: undefined
90
+ defaultChecked?: undefined
84
91
  }
85
92
  }
86
93
 
@@ -192,11 +199,19 @@ export const ButtonOrLinkRoot = (passedProps: InternalButtonOrLinkProps) => {
192
199
  role = 'button',
193
200
  type = 'button',
194
201
  checked,
202
+ defaultChecked,
195
203
  href: _href,
196
204
  target: _target,
197
205
  ...remainingProps
198
206
  } = nonBaseProps
199
207
 
208
+ if (defaultChecked !== undefined) {
209
+ // oxlint-disable-next-line no-console
210
+ console.warn(
211
+ '[ButtonOrLink] `defaultChecked` is not supported; use a controlled `checked` prop instead, or wrap `ButtonOrLink` in a component that manages the uncontrolled state',
212
+ )
213
+ }
214
+
200
215
  const Element = inline ? SpanButtonWithContext : ButtonWithContext
201
216
 
202
217
  const state: ButtonOrLinkState = {
@@ -208,22 +223,23 @@ export const ButtonOrLinkRoot = (passedProps: InternalButtonOrLinkProps) => {
208
223
  checked,
209
224
  }
210
225
 
211
- const checkedAttribute = (() => {
212
- if (checked === undefined) {
213
- return {}
214
- }
215
- if (
216
- (role === 'option' || role === 'tab' || role === 'row' || role === 'gridcell') &&
217
- checked !== 'indeterminate'
218
- ) {
219
- return { 'aria-selected': checked }
220
- }
221
- const checkedOrMixed = checked === 'indeterminate' ? ('mixed' as const) : checked
222
- if (role === 'button') {
223
- return { 'aria-pressed': checkedOrMixed }
224
- }
225
- return { 'aria-checked': checkedOrMixed }
226
- })()
226
+ const checkedAttribute =
227
+ checked === undefined
228
+ ? {}
229
+ : ((checked: unknown) => {
230
+ if (
231
+ (role === 'option' || role === 'tab' || role === 'row' || role === 'gridcell') &&
232
+ checked !== 'indeterminate'
233
+ ) {
234
+ return { 'aria-selected': Boolean(checked) }
235
+ }
236
+ const checkedOrMixed =
237
+ checked === 'indeterminate' ? ('mixed' as const) : Boolean(checked)
238
+ if (role === 'button') {
239
+ return { 'aria-pressed': checkedOrMixed }
240
+ }
241
+ return { 'aria-checked': checkedOrMixed }
242
+ })(checked)
227
243
 
228
244
  let buttonProps: ComponentProps<typeof Element> = {
229
245
  role,
@@ -251,6 +267,7 @@ export const ButtonOrLinkRoot = (passedProps: InternalButtonOrLinkProps) => {
251
267
  rel = target === '_blank' ? 'noopener noreferrer' : undefined,
252
268
  type: _type,
253
269
  checked: _checked,
270
+ defaultChecked: _defaultChecked,
254
271
  ...remainingProps
255
272
  } = nonBaseProps
256
273
 
@@ -14,6 +14,8 @@ export { ButtonGroup, type ButtonGroupProps } from './ButtonGroup.tsx'
14
14
  export { ButtonGroupMeta } from './ButtonGroup.meta.ts'
15
15
  export { Card, type CardProps } from './Card.tsx'
16
16
  export { CardMeta } from './Card.meta.ts'
17
+ export { Chip, type ChipProps, type ChipGroupProps } from './Chip.tsx'
18
+ export { ChipMeta, ChipGroupMeta } from './Chip.meta.ts'
17
19
  export { Cluster, type ClusterProps } from './Cluster.tsx'
18
20
  export { ClusterMeta } from './Cluster.meta.ts'
19
21
  export { CodeBlock, type CodeBlockProps, type CodeBlockTabsProps } from './CodeBlock.tsx'
@@ -16,6 +16,7 @@ import { ButtonMeta } from './components/Button.meta.ts'
16
16
  import { ButtonGroupMeta } from './components/ButtonGroup.meta.ts'
17
17
  import { CardMeta } from './components/Card.meta.ts'
18
18
  import { CheckboxMeta } from './components/Checkbox.meta.ts'
19
+ import { ChipGroupMeta, ChipMeta } from './components/Chip.meta.ts'
19
20
  import { ClusterMeta } from './components/Cluster.meta.ts'
20
21
  import { CodeBlockMeta, CodeBlockTabsMeta } from './components/CodeBlock.meta.ts'
21
22
  import { CopyButtonMeta } from './components/CopyButton.meta.ts'
@@ -85,6 +86,8 @@ const gdsTailwindPluginWithComponents: ReturnType<typeof createPlugin> = createP
85
86
  CodeBlockTabsMeta,
86
87
  CheckableMeta,
87
88
  CheckboxMeta,
89
+ ChipMeta,
90
+ ChipGroupMeta,
88
91
  ClusterMeta,
89
92
  CopyButtonMeta,
90
93
  CurrencyInputMeta,