@pk-design/react-tailwind 1.8.0 → 1.9.0

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 (32) hide show
  1. package/dist/cjs/components/Banner/Banner.js +1 -1
  2. package/dist/cjs/components/Banner/Banner.js.map +1 -1
  3. package/dist/cjs/components/Button/Button.js +88 -60
  4. package/dist/cjs/components/Button/Button.js.map +1 -1
  5. package/dist/cjs/components/DataTable/DataTable.js +1 -1
  6. package/dist/cjs/components/DataTable/DataTable.js.map +1 -1
  7. package/dist/cjs/components/RadioGroup/RadioGroup.js +5 -3
  8. package/dist/cjs/components/RadioGroup/RadioGroup.js.map +1 -1
  9. package/dist/cjs/components/SelectBox/SelectBox.js +25 -4
  10. package/dist/cjs/components/SelectBox/SelectBox.js.map +1 -1
  11. package/dist/cjs/components/Toast/Toast.js +1 -1
  12. package/dist/cjs/components/Toast/Toast.js.map +1 -1
  13. package/dist/es/components/Banner/Banner.js +1 -1
  14. package/dist/es/components/Banner/Banner.js.map +1 -1
  15. package/dist/es/components/Button/Button.js +89 -61
  16. package/dist/es/components/Button/Button.js.map +1 -1
  17. package/dist/es/components/DataTable/DataTable.js +1 -1
  18. package/dist/es/components/DataTable/DataTable.js.map +1 -1
  19. package/dist/es/components/RadioGroup/RadioGroup.js +5 -3
  20. package/dist/es/components/RadioGroup/RadioGroup.js.map +1 -1
  21. package/dist/es/components/SelectBox/SelectBox.js +26 -5
  22. package/dist/es/components/SelectBox/SelectBox.js.map +1 -1
  23. package/dist/es/components/Toast/Toast.js +1 -1
  24. package/dist/es/components/Toast/Toast.js.map +1 -1
  25. package/dist/react-tailwind.cjs.js +121 -70
  26. package/dist/react-tailwind.cjs.js.map +1 -1
  27. package/dist/react-tailwind.es.js +122 -71
  28. package/dist/react-tailwind.es.js.map +1 -1
  29. package/dist/types/components/Button/Button.types.d.ts +12 -6
  30. package/dist/types/components/DataTable/DataTable.types.d.ts +2 -2
  31. package/dist/types/components/SelectBox/SelectBox.types.d.ts +18 -1
  32. package/package.json +1 -1
@@ -151,59 +151,35 @@ TextContent.displayName = 'TextContent';
151
151
 
152
152
  /**
153
153
  * Tailwind CSS classes for theme + variant combinations.
154
+ *
155
+ * Only colours live here. Focus outline width/offset and disabled styling are
156
+ * applied uniformly in the component so they can be toggled in one place.
154
157
  */
155
158
  const THEMED_BTN_CLASS = {
156
159
  primary: {
157
- default: 'text-white bg-[var(--ui-primary)] hover:bg-[var(--ui-primary-hover)] focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-[var(--ui-primary-ring)] disabled:bg-[var(--ui-primary-disabled)]',
158
- outlined: 'text-[var(--ui-primary-text)] hover:text-white border border-[var(--ui-primary)] hover:bg-[var(--ui-primary)] focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-[var(--ui-primary-ring)] disabled:text-[var(--ui-primary-disabled)] disabled:border-[var(--ui-primary-disabled)]',
159
- plain: 'text-[var(--ui-primary-text)] hover:bg-blue-50/80 dark:hover:bg-blue-950/40 focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-[var(--ui-primary-ring)] disabled:text-[var(--ui-primary-disabled)]',
160
+ default: 'text-white bg-[var(--ui-primary)] hover:bg-[var(--ui-primary-hover)] focus-visible:outline-[var(--ui-primary-ring)]',
161
+ outlined: 'text-[var(--ui-primary-text)] hover:text-white border border-[var(--ui-primary)] hover:bg-[var(--ui-primary)] focus-visible:outline-[var(--ui-primary-ring)]',
162
+ plain: 'text-[var(--ui-primary-text)] hover:bg-current/10 active:bg-current/15 focus-visible:outline-[var(--ui-primary-ring)]',
160
163
  },
161
164
  danger: {
162
- default: 'text-white bg-[var(--ui-danger)] hover:bg-[var(--ui-danger-hover)] focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-[var(--ui-danger-ring)] disabled:bg-[var(--ui-danger-disabled)]',
163
- outlined: 'text-[var(--ui-danger-text)] hover:text-white border border-[var(--ui-danger)] hover:bg-[var(--ui-danger)] focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-[var(--ui-danger-ring)] disabled:text-[var(--ui-danger-disabled)] disabled:border-[var(--ui-danger-disabled)]',
164
- plain: 'text-[var(--ui-danger-text)] hover:bg-red-50/80 dark:hover:bg-red-950/40 focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-[var(--ui-danger-ring)] disabled:text-[var(--ui-danger-disabled)]',
165
+ default: 'text-white bg-[var(--ui-danger)] hover:bg-[var(--ui-danger-hover)] focus-visible:outline-[var(--ui-danger-ring)]',
166
+ outlined: 'text-[var(--ui-danger-text)] hover:text-white border border-[var(--ui-danger)] hover:bg-[var(--ui-danger)] focus-visible:outline-[var(--ui-danger-ring)]',
167
+ plain: 'text-[var(--ui-danger-text)] hover:bg-current/10 active:bg-current/15 focus-visible:outline-[var(--ui-danger-ring)]',
165
168
  },
166
169
  secondary: {
167
- default: 'text-gray-700 bg-white border border-[var(--ui-border)] hover:bg-gray-100 dark:bg-gray-800 dark:text-white dark:hover:bg-gray-700 focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-[var(--ui-focus-ring)] disabled:bg-gray-200 dark:disabled:bg-gray-700',
168
- outlined: 'text-gray-700 hover:text-white border border-[var(--ui-border)] hover:bg-gray-700 dark:text-gray-200 dark:hover:text-white dark:hover:bg-gray-600 focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-[var(--ui-focus-ring)] disabled:text-gray-400 disabled:border-[var(--ui-border-muted)]',
169
- plain: 'text-gray-700 hover:bg-gray-100 dark:text-gray-200 dark:hover:bg-gray-800 focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-[var(--ui-focus-ring)] disabled:text-gray-400',
170
+ default: 'text-gray-700 bg-white border border-[var(--ui-border)] hover:bg-gray-100 dark:bg-gray-800 dark:text-white dark:hover:bg-gray-700 focus-visible:outline-[var(--ui-focus-ring)]',
171
+ outlined: 'text-gray-700 hover:text-white border border-[var(--ui-border)] hover:bg-gray-700 dark:text-gray-200 dark:hover:text-white dark:hover:bg-gray-600 focus-visible:outline-[var(--ui-focus-ring)]',
172
+ plain: 'text-gray-700 hover:bg-current/10 active:bg-current/15 dark:text-gray-200 focus-visible:outline-[var(--ui-focus-ring)]',
170
173
  },
171
174
  success: {
172
- default: 'text-white bg-emerald-600 hover:bg-emerald-700 focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-emerald-500 disabled:bg-emerald-300 dark:disabled:bg-emerald-900',
173
- outlined: 'text-emerald-600 hover:text-white border border-emerald-600 hover:bg-emerald-600 dark:text-emerald-400 dark:border-emerald-500 focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-emerald-500 disabled:opacity-50',
174
- plain: 'text-emerald-600 hover:bg-emerald-50 dark:text-emerald-400 dark:hover:bg-emerald-950/40 focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-emerald-500 disabled:opacity-50',
175
+ default: 'text-white bg-emerald-600 hover:bg-emerald-700 focus-visible:outline-emerald-500',
176
+ outlined: 'text-emerald-700 hover:text-white border border-emerald-600 hover:bg-emerald-600 dark:text-emerald-400 dark:border-emerald-500 focus-visible:outline-emerald-500',
177
+ plain: 'text-emerald-700 hover:bg-current/10 active:bg-current/15 dark:text-emerald-400 focus-visible:outline-emerald-500',
175
178
  },
176
179
  warning: {
177
- default: 'text-white bg-amber-500 hover:bg-amber-600 focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-amber-500 disabled:bg-amber-300 dark:disabled:bg-amber-900',
178
- outlined: 'text-amber-600 hover:text-white border border-amber-500 hover:bg-amber-500 dark:text-amber-400 dark:border-amber-500 focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-amber-500 disabled:opacity-50',
179
- plain: 'text-amber-600 hover:bg-amber-50 dark:text-amber-400 dark:hover:bg-amber-950/40 focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-amber-500 disabled:opacity-50',
180
- },
181
- };
182
- const LOADER_TEXT_CLASS = {
183
- primary: {
184
- default: 'text-white',
185
- outlined: 'text-[var(--ui-primary-text)]',
186
- plain: 'text-[var(--ui-primary-text)]',
187
- },
188
- danger: {
189
- default: 'text-white',
190
- outlined: 'text-[var(--ui-danger-text)]',
191
- plain: 'text-[var(--ui-danger-text)]',
192
- },
193
- secondary: {
194
- default: 'text-gray-700 dark:text-white',
195
- outlined: 'text-gray-700 dark:text-gray-200',
196
- plain: 'text-gray-700 dark:text-gray-200',
197
- },
198
- success: {
199
- default: 'text-white',
200
- outlined: 'text-emerald-600 dark:text-emerald-400',
201
- plain: 'text-emerald-600 dark:text-emerald-400',
202
- },
203
- warning: {
204
- default: 'text-white',
205
- outlined: 'text-amber-600 dark:text-amber-400',
206
- plain: 'text-amber-600 dark:text-amber-400',
180
+ default: 'text-white bg-amber-500 hover:bg-amber-600 focus-visible:outline-amber-500',
181
+ outlined: 'text-amber-700 hover:text-white border border-amber-500 hover:bg-amber-500 dark:text-amber-400 dark:border-amber-500 focus-visible:outline-amber-500',
182
+ plain: 'text-amber-700 hover:bg-current/10 active:bg-current/15 dark:text-amber-400 focus-visible:outline-amber-500',
207
183
  },
208
184
  };
209
185
  const SIZE_CLASSES = {
@@ -223,22 +199,32 @@ const LOADER_SIZE = {
223
199
  };
224
200
  /**
225
201
  * Base shared tailwind classes.
202
+ *
203
+ * Disabled styling is keyed off both the native `disabled` attribute and
204
+ * `aria-disabled`, so non-button elements rendered via `as` look disabled too.
226
205
  */
227
206
  const BASE_BTN_CLASS = 'font-medium inline-flex items-center justify-center shrink-0 cursor-pointer select-none ' +
228
- 'disabled:cursor-not-allowed disabled:pointer-events-none disabled:opacity-75 ' +
229
- 'active:scale-[0.98] transition-all duration-150 ease-out focus:outline-none';
207
+ 'transition-[color,background-color,border-color,box-shadow,opacity,transform] duration-150 ease-out ' +
208
+ 'active:scale-[0.98] focus:outline-none ' +
209
+ 'disabled:pointer-events-none disabled:opacity-50 disabled:shadow-none ' +
210
+ 'aria-disabled:pointer-events-none aria-disabled:opacity-50 aria-disabled:shadow-none';
230
211
  const Button = React.forwardRef(({ as, type, ...props }, ref) => {
231
- var _a, _b, _c, _d;
232
212
  const { className = '', children, theme = 'primary', variant = 'default', size = 'md', leftIcon, rightIcon, fullWidth = false, loading = false, loadingText = '', rounded = false, disabled, iconOnly = false, noOutlineOnFocus = false, active, onClick, ...restProps } = props;
233
213
  const Component = as || 'button';
234
214
  const isNativeButton = Component === 'button';
215
+ // Clean invalid props when not rendering a real button
216
+ const { type: _ignoreType, disabled: _ignoreDisabled, role, tabIndex, onKeyDown, onKeyUp, ...domProps } = restProps;
217
+ const ariaLabel = domProps['aria-label'];
218
+ const ariaLabelledBy = domProps['aria-labelledby'];
235
219
  // Accessibility guard for icon-only buttons
236
- if (iconOnly && !restProps['aria-label']) {
237
- console.warn('[ui] <Button iconOnly> requires aria-label for accessibility.');
238
- }
220
+ React.useEffect(() => {
221
+ if (iconOnly && !ariaLabel && !ariaLabelledBy) {
222
+ console.warn('[ui] <Button iconOnly> requires aria-label or aria-labelledby for accessibility.');
223
+ }
224
+ }, [iconOnly, ariaLabel, ariaLabelledBy]);
239
225
  const resolvedDisabled = Boolean(disabled || loading);
240
- // Clean invalid props when not rendering a real button
241
- const { type: _ignoreType, disabled: _ignoreDisabled, ...cleanRest } = restProps;
226
+ // Links (`href`, or `to` for router Link components) keep their native semantics.
227
+ const isLink = !isNativeButton && (domProps.href != null || domProps.to != null);
242
228
  const handleClick = (e) => {
243
229
  if (resolvedDisabled) {
244
230
  e.preventDefault();
@@ -247,31 +233,73 @@ const Button = React.forwardRef(({ as, type, ...props }, ref) => {
247
233
  }
248
234
  onClick === null || onClick === void 0 ? void 0 : onClick(e);
249
235
  };
236
+ // Mirror native <button> keyboard activation for non-button elements:
237
+ // Enter activates on keydown, Space on keyup (and must not scroll the page).
238
+ const handleKeyDown = (e) => {
239
+ onKeyDown === null || onKeyDown === void 0 ? void 0 : onKeyDown(e);
240
+ if (e.defaultPrevented || e.target !== e.currentTarget)
241
+ return;
242
+ if (e.key === 'Enter') {
243
+ e.preventDefault();
244
+ e.currentTarget.click();
245
+ }
246
+ else if (e.key === ' ') {
247
+ e.preventDefault();
248
+ }
249
+ };
250
+ const handleKeyUp = (e) => {
251
+ onKeyUp === null || onKeyUp === void 0 ? void 0 : onKeyUp(e);
252
+ if (e.defaultPrevented || e.target !== e.currentTarget)
253
+ return;
254
+ if (e.key === ' ') {
255
+ e.preventDefault();
256
+ e.currentTarget.click();
257
+ }
258
+ };
250
259
  const elementProps = isNativeButton
251
260
  ? {
252
261
  type: type !== null && type !== void 0 ? type : 'button',
253
262
  disabled: resolvedDisabled,
263
+ role,
264
+ tabIndex,
254
265
  onClick: handleClick,
266
+ onKeyDown,
267
+ onKeyUp,
255
268
  }
256
- : {
257
- role: (_a = cleanRest.role) !== null && _a !== void 0 ? _a : 'button',
258
- tabIndex: resolvedDisabled ? -1 : ((_b = cleanRest.tabIndex) !== null && _b !== void 0 ? _b : 0),
259
- 'aria-disabled': resolvedDisabled ? true : undefined,
260
- onClick: handleClick,
261
- };
269
+ : isLink
270
+ ? {
271
+ role,
272
+ tabIndex: resolvedDisabled ? -1 : tabIndex,
273
+ 'aria-disabled': resolvedDisabled ? true : undefined,
274
+ onClick: handleClick,
275
+ onKeyDown,
276
+ onKeyUp,
277
+ }
278
+ : {
279
+ role: role !== null && role !== void 0 ? role : 'button',
280
+ tabIndex: resolvedDisabled ? -1 : (tabIndex !== null && tabIndex !== void 0 ? tabIndex : 0),
281
+ 'aria-disabled': resolvedDisabled ? true : undefined,
282
+ onClick: handleClick,
283
+ onKeyDown: handleKeyDown,
284
+ onKeyUp: handleKeyUp,
285
+ };
262
286
  const sizeObj = SIZE_CLASSES[size] || SIZE_CLASSES.md;
263
287
  const classes = React.useMemo(() => {
264
288
  var _a;
265
- return buildClassName(BASE_BTN_CLASS, ((_a = THEMED_BTN_CLASS[theme]) === null || _a === void 0 ? void 0 : _a[variant]) || THEMED_BTN_CLASS.primary.default, iconOnly ? sizeObj.iconOnly : sizeObj.normal, !noOutlineOnFocus && 'focus-visible:ring-2 focus-visible:ring-offset-2', rounded && 'rounded-full', fullWidth && 'w-full', variant === 'default' && 'shadow-xs hover:shadow-none disabled:shadow-none', active && 'ring-2 ring-offset-2 ring-current', className);
289
+ return buildClassName(BASE_BTN_CLASS, ((_a = THEMED_BTN_CLASS[theme]) === null || _a === void 0 ? void 0 : _a[variant]) || THEMED_BTN_CLASS.primary.default, iconOnly ? sizeObj.iconOnly : sizeObj.normal,
290
+ // An outline (not a ring) so the offset gap stays transparent on any surface/mode.
291
+ !noOutlineOnFocus &&
292
+ 'focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-solid', rounded && 'rounded-full', fullWidth && 'w-full', variant === 'default' && 'shadow-xs hover:shadow-none', active && 'ring-2 ring-current', className);
266
293
  }, [theme, variant, sizeObj, iconOnly, noOutlineOnFocus, rounded, fullWidth, active, className]);
267
- const loaderIcon = (jsxRuntime.jsx(Loader, { "data-testid": "btn-loader-icon", size: LOADER_SIZE[size] || 'xs', className: buildClassName((_c = LOADER_TEXT_CLASS[theme]) === null || _c === void 0 ? void 0 : _c[variant]) }));
294
+ // The spinner and loading text inherit the button's text colour.
295
+ const loaderIcon = (jsxRuntime.jsx(Loader, { "data-testid": "btn-loader-icon", size: LOADER_SIZE[size] || 'xs', className: "text-current" }));
268
296
  /**
269
297
  * SPECIAL CASE: iconOnly + loading → show spinner only
270
298
  */
271
299
  if (loading && iconOnly) {
272
- return (jsxRuntime.jsx(Component, { ref: ref, className: classes, "aria-busy": "true", "aria-pressed": active !== undefined ? active : undefined, ...elementProps, ...cleanRest, children: loaderIcon }));
300
+ return (jsxRuntime.jsx(Component, { ref: ref, className: classes, "aria-busy": "true", "aria-pressed": active !== undefined ? active : undefined, ...domProps, ...elementProps, children: loaderIcon }));
273
301
  }
274
- return (jsxRuntime.jsx(Component, { ref: ref, className: classes, "aria-busy": loading ? 'true' : undefined, "aria-pressed": active !== undefined ? active : undefined, ...elementProps, ...cleanRest, children: loading ? (jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-2", "aria-live": "polite", children: [loaderIcon, loadingText ? (jsxRuntime.jsx(TextContent, { className: buildClassName((_d = LOADER_TEXT_CLASS[theme]) === null || _d === void 0 ? void 0 : _d[variant]), children: loadingText })) : (children)] })) : (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [leftIcon && jsxRuntime.jsx("span", { className: "shrink-0 inline-flex items-center", children: leftIcon }), children, rightIcon && jsxRuntime.jsx("span", { className: "shrink-0 inline-flex items-center", children: rightIcon })] })) }));
302
+ return (jsxRuntime.jsx(Component, { ref: ref, className: classes, "aria-busy": loading ? 'true' : undefined, "aria-pressed": active !== undefined ? active : undefined, ...domProps, ...elementProps, children: loading ? (jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-2", "aria-live": "polite", children: [loaderIcon, loadingText ? (jsxRuntime.jsx(TextContent, { className: "text-current", children: loadingText })) : (children)] })) : (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [leftIcon && jsxRuntime.jsx("span", { className: "shrink-0 inline-flex items-center", children: leftIcon }), children, rightIcon && jsxRuntime.jsx("span", { className: "shrink-0 inline-flex items-center", children: rightIcon })] })) }));
275
303
  });
276
304
  Button.displayName = 'Button';
277
305
 
@@ -595,7 +623,7 @@ const Banner = React.forwardRef((props, ref) => {
595
623
  const { type = 'info', iconSize = 'sm', children, icon, removable = false, onRemove, className, ...restProps } = props;
596
624
  const DefaultIcon = IconMap[type];
597
625
  const iconNode = icon !== undefined ? (icon) : (jsxRuntime.jsx(DefaultIcon, { "data-testid": `banner-${type}-icon`, className: buildClassName('shrink-0', sizeMap[iconSize]) }));
598
- return (jsxRuntime.jsxs("div", { ref: ref, className: buildClassName('text-sm rounded-md flex w-full p-3 items-center gap-3 ring-1 ring-inset', TypeClassMap[type], className), "data-testid": `banner-${type}`, ...restProps, children: [iconNode, jsxRuntime.jsx("div", { className: "flex items-center w-full justify-between", children: children }), removable && (jsxRuntime.jsx(Button, { iconOnly: true, "aria-label": "Dismiss banner", size: "xs", variant: "plain", theme: "secondary", className: "hover:bg-black/10 dark:hover:bg-white/10 shrink-0", onClick: () => onRemove === null || onRemove === void 0 ? void 0 : onRemove(), "data-testid": "banner-remove-btn", children: jsxRuntime.jsx(SvgX, { className: "size-4.5", "data-testid": "banner-remove-icon" }) }))] }));
626
+ return (jsxRuntime.jsxs("div", { ref: ref, className: buildClassName('text-sm rounded-md flex w-full p-3 items-center gap-3 ring-1 ring-inset', TypeClassMap[type], className), "data-testid": `banner-${type}`, ...restProps, children: [iconNode, jsxRuntime.jsx("div", { className: "flex items-center w-full justify-between", children: children }), removable && (jsxRuntime.jsx(Button, { iconOnly: true, "aria-label": "Dismiss banner", size: "xs", variant: "plain", className: "text-current focus-visible:outline-current shrink-0", onClick: () => onRemove === null || onRemove === void 0 ? void 0 : onRemove(), "data-testid": "banner-remove-btn", children: jsxRuntime.jsx(SvgX, { className: "size-4.5", "data-testid": "banner-remove-icon" }) }))] }));
599
627
  });
600
628
  Banner.displayName = 'Banner';
601
629
 
@@ -1526,7 +1554,7 @@ function DataTable({ items, columns, sorting = {}, onSort, loading, pagination,
1526
1554
  }), isInlineMode && (jsxRuntime.jsx(TableCell, { align: "right", className: buildClassName(densityCellClass, striped && idx % 2 === 1 && 'bg-gray-50 dark:bg-gray-800/40'), onClick: (e) => e.stopPropagation(), children: jsxRuntime.jsx("div", { className: buildClassName('opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 transition-opacity duration-150 flex items-center justify-end gap-1.5', rowHoverActionClass), "data-testid": `row-hover-actions-${key}`, children: renderActionsContent(item, idx) }) })), isOverlayMode && (jsxRuntime.jsx(TableCell, { align: "right", style: { padding: 0, width: 0, minWidth: 0, maxWidth: 0 }, className: "sticky right-0 z-20 !p-0 !pr-0 !pl-0 !py-0 w-0 max-w-0 min-w-0 border-0 overflow-visible text-right", onClick: (e) => e.stopPropagation(), children: jsxRuntime.jsx("div", { className: buildClassName('absolute right-0 top-0 bottom-0 h-full opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 transition-opacity duration-150 flex items-center justify-end gap-1 px-3 z-30 pointer-events-none group-hover:pointer-events-auto whitespace-nowrap', striped && idx % 2 === 1
1527
1555
  ? 'bg-gray-100 dark:bg-gray-800'
1528
1556
  : 'bg-white group-hover:bg-gray-50 dark:bg-gray-900 dark:group-hover:bg-gray-800', rowHoverActionClass), "data-testid": `row-hover-actions-${key}`, children: renderActionsContent(item, idx) }) }))] }, key));
1529
- })) }), footerRow && jsxRuntime.jsx(TableFoot, { children: footerRow })] }) }), pagination && (jsxRuntime.jsx("div", { className: buildClassName(stickyPagination && 'sticky bottom-0 z-20 bg-white dark:bg-gray-800', paginationClass, paginationContainerClass), children: renderPagination ? (renderPagination(pagination, setPagination)) : (jsxRuntime.jsx(Pagination, { ...pagination, ...paginationProps, className: buildClassName('rounded-t-none rounded-b-lg border border-[var(--ui-border)]', stickyPagination && 'sticky bottom-0 z-20 bg-white dark:bg-gray-800', paginationProps === null || paginationProps === void 0 ? void 0 : paginationProps.className), onChange: setPagination })) }))] }));
1557
+ })) }), footerRow && jsxRuntime.jsx(TableFoot, { children: footerRow })] }) }), pagination && (jsxRuntime.jsx("div", { className: buildClassName(stickyPagination && 'sticky bottom-0 z-20', paginationContainerClass), children: renderPagination ? (renderPagination(pagination, setPagination)) : (jsxRuntime.jsx(Pagination, { ...pagination, ...paginationProps, className: buildClassName('rounded-t-none rounded-b-lg border border-[var(--ui-border)] bg-white dark:bg-gray-800', paginationClass, paginationProps === null || paginationProps === void 0 ? void 0 : paginationProps.className), onChange: setPagination })) }))] }));
1530
1558
  }
1531
1559
  DataTable.displayName = 'DataTable';
1532
1560
 
@@ -2446,6 +2474,7 @@ const COLUMN_GRID_MAP = {
2446
2474
  const RadioGroup = (props) => {
2447
2475
  const { name, variant = 'default', size = 'md', theme = 'primary', label, labelClass, labelWrapperClass, labelHint, containerClass, options, value, columns, disabled = false, row, error, showErrorMessage = true, onChange, required, 'aria-describedby': ariaDescribedBy, } = props;
2448
2476
  const groupId = React.useId();
2477
+ const groupName = name || groupId;
2449
2478
  const items = React.useMemo(() => {
2450
2479
  var _a;
2451
2480
  return (_a = options === null || options === void 0 ? void 0 : options.map((option) => typeof option === 'string'
@@ -2470,13 +2499,14 @@ const RadioGroup = (props) => {
2470
2499
  : 'flex flex-col gap-3'), children: items.map((item) => {
2471
2500
  const isSelected = value === item.value;
2472
2501
  const isItemDisabled = disabled || Boolean(item.disabled);
2502
+ const radioItemId = `${groupName}-${item.value}`;
2473
2503
  if (isCards) {
2474
- return (jsxRuntime.jsxs("label", { htmlFor: `${name}-${item.value}`, className: buildClassName('relative flex items-start gap-3 p-4 rounded-xl border transition-all cursor-pointer select-none min-w-[200px] flex-1', isSelected
2504
+ return (jsxRuntime.jsxs("label", { htmlFor: radioItemId, className: buildClassName('relative flex items-start gap-3 p-4 rounded-xl border transition-all cursor-pointer select-none min-w-[200px] flex-1', 'focus-within:ring-2 focus-within:ring-[var(--ui-primary-ring)] focus-within:border-[var(--ui-primary)]', isSelected
2475
2505
  ? 'border-[var(--ui-primary)] bg-blue-50/40 dark:bg-blue-950/30 ring-2 ring-[var(--ui-primary-ring)]/30'
2476
2506
  : 'border-[var(--ui-border)] bg-white dark:bg-gray-800 hover:border-gray-300 dark:hover:border-gray-600', isItemDisabled &&
2477
- 'opacity-50 cursor-not-allowed pointer-events-none bg-gray-50 dark:bg-gray-800/50'), children: [jsxRuntime.jsx(Radio, { name: name, id: `${name}-${item.value}`, value: item.value, "aria-label": item.label, size: size, theme: theme, checked: isSelected, disabled: isItemDisabled, onChange: onChange, containerClass: "pt-0.5" }), jsxRuntime.jsxs("div", { className: "flex-1 min-w-0", children: [jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [item.icon && (jsxRuntime.jsx("span", { className: "shrink-0 text-gray-500 dark:text-gray-400", children: item.icon })), jsxRuntime.jsx("span", { className: "text-sm font-semibold text-gray-900 dark:text-white truncate", children: item.label })] }), item.description && (jsxRuntime.jsx("p", { className: "mt-1 text-xs text-gray-500 dark:text-gray-400 font-normal leading-relaxed", children: item.description }))] })] }, item.value));
2507
+ 'opacity-50 cursor-not-allowed pointer-events-none bg-gray-50 dark:bg-gray-800/50'), children: [jsxRuntime.jsx(Radio, { name: groupName, id: radioItemId, value: item.value, "aria-label": item.label, size: size, theme: theme, checked: isSelected, disabled: isItemDisabled, onChange: onChange, containerClass: "pt-0.5" }), jsxRuntime.jsxs("div", { className: "flex-1 min-w-0", children: [jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [item.icon && (jsxRuntime.jsx("span", { className: "shrink-0 text-gray-500 dark:text-gray-400", children: item.icon })), jsxRuntime.jsx("span", { className: "text-sm font-semibold text-gray-900 dark:text-white truncate", children: item.label })] }), item.description && (jsxRuntime.jsx("p", { className: "mt-1 text-xs text-gray-500 dark:text-gray-400 font-normal leading-relaxed", children: item.description }))] })] }, item.value));
2478
2508
  }
2479
- return (jsxRuntime.jsx(Radio, { name: name, id: `${name}-${item.value}`, label: item.label, description: item.description, value: item.value, size: size, theme: theme, checked: isSelected, disabled: isItemDisabled, onChange: onChange }, item.value));
2509
+ return (jsxRuntime.jsx(Radio, { name: groupName, id: radioItemId, label: item.label, description: item.description, value: item.value, size: size, theme: theme, checked: isSelected, disabled: isItemDisabled, onChange: onChange }, item.value));
2480
2510
  }) }), showErrorMessage && error && (jsxRuntime.jsx("div", { className: "mt-1.5", children: jsxRuntime.jsx(TextContent, { error: true, small: true, id: errorId, children: error }) }))] }));
2481
2511
  };
2482
2512
  RadioGroup.displayName = 'RadioGroup';
@@ -3846,9 +3876,18 @@ const sizeClasses$1 = {
3846
3876
  },
3847
3877
  };
3848
3878
  const SelectBox = React.forwardRef((props, forwardedRef) => {
3849
- const { labelKey = 'label', valueKey = 'value', name, id = name, options = EMPTY_ARRAY, groups, selected, size = 'md', label = null, labelWrapperClass = '', labelClass = '', labelHint = null, disabled = false, containerClass = '', onChange = NOOP, placeholder, dropdownContainerClass = 'z-20', multiple = false, maxSelection, showSelectAll = false, immediate = true, showErrorMessage = true, error = null, helperText, leftGroup, renderOption, async = false, searchable = true, required = false, allowAdd = false, addNewText = 'Create', onAdd = NOOP, allowClear = false, allowFreeText = false, modalDropdown = false, noOptionsText = 'No options available', } = props;
3879
+ const { labelKey = 'label', valueKey = 'value', name, id = name, options = EMPTY_ARRAY, groups, selected: selectedProp, defaultSelected, size = 'md', label = null, labelWrapperClass = '', labelClass = '', labelHint = null, disabled = false, containerClass = '', onChange: onChangeProp = NOOP, placeholder, dropdownContainerClass = 'z-20', dropdownMinWidth, multiple = false, maxSelection, showSelectAll = false, immediate = true, showErrorMessage = true, error = null, helperText, leftGroup, renderOption, async = false, searchable = true, required = false, allowAdd = false, addNewText = 'Create', onAdd = NOOP, allowClear = false, allowFreeText = false, modalDropdown = false, noOptionsText = 'No options available', } = props;
3880
+ // Uncontrolled when `selected` is not passed: keep the selection internally.
3881
+ const isControlled = selectedProp !== undefined;
3882
+ const [internalSelected, setInternalSelected] = React.useState(defaultSelected !== null && defaultSelected !== void 0 ? defaultSelected : null);
3883
+ const selected = isControlled ? selectedProp : internalSelected;
3884
+ const onChange = React.useCallback((value) => {
3885
+ if (!isControlled)
3886
+ setInternalSelected(value);
3887
+ onChangeProp(value);
3888
+ }, [isControlled, onChangeProp]);
3850
3889
  if (props.asBottomSheet || props.mobileMode === 'sheet') {
3851
- return jsxRuntime.jsx(MobilePicker, { ...props });
3890
+ return jsxRuntime.jsx(MobilePicker, { ...props, selected: selected, onChange: onChange });
3852
3891
  }
3853
3892
  const hasError = Boolean(error);
3854
3893
  const [query, setQuery] = React.useState('');
@@ -4046,6 +4085,16 @@ const SelectBox = React.forwardRef((props, forwardedRef) => {
4046
4085
  }
4047
4086
  }, [isAllSelected, onChange, allOptions]);
4048
4087
  const hasLeftGroup = leftGroup != null && leftGroup !== undefined;
4088
+ // Reserve room for the chevron (and the clear button when shown) so long values
4089
+ // don't run underneath them.
4090
+ const showClearButton = allowClear && !multiple && !isEmpty(normalizedSelected);
4091
+ const rightPaddingClass = showClearButton
4092
+ ? 'pe-16'
4093
+ : size === 'lg'
4094
+ ? 'pe-11'
4095
+ : size === 'sm'
4096
+ ? 'pe-9'
4097
+ : 'pe-10';
4049
4098
  const hasFreeTextOption = Boolean(allowFreeText &&
4050
4099
  query.trim() &&
4051
4100
  !allOptions.some((opt) => { var _a; return ((_a = getDisplayValue(opt)) === null || _a === void 0 ? void 0 : _a.toLowerCase()) === query.trim().toLowerCase(); }));
@@ -4058,7 +4107,7 @@ const SelectBox = React.forwardRef((props, forwardedRef) => {
4058
4107
  const isOptSelected = selectedValueSet.has(optVal);
4059
4108
  return (jsxRuntime.jsx(react.ComboboxOption, { disabled: option.disabled, value: option, className: "group rounded-lg py-1.5 px-3 select-none data-[focus]:bg-gray-100 dark:data-[focus]:bg-white/10 data-disabled:opacity-50 cursor-pointer data-disabled:pointer-events-none", children: renderOption ? (renderOption(option, Boolean(isOptSelected))) : (jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-2 text-gray-900 dark:text-white group-data-[selected]:text-blue-600", children: [jsxRuntime.jsx("span", { className: "text-sm/6", children: getDisplayValue(option) }), jsxRuntime.jsx(SvgCheck, { className: "invisible size-5 dark:stroke-gray-300 group-data-[selected]:visible" })] })) }, optVal));
4060
4109
  };
4061
- return (jsxRuntime.jsxs("div", { className: buildClassName('group space-y-2', hasError && 'has-error', containerClass), ref: containerRef, children: [label && (jsxRuntime.jsxs("div", { className: buildClassName('flex items-center justify-between', labelWrapperClass), children: [jsxRuntime.jsx(Label, { className: labelClass, htmlFor: id, "aria-required": required, children: label }), labelHint && jsxRuntime.jsx(TextContent, { xsmall: true, children: labelHint })] })), jsxRuntime.jsxs(react.Combobox, { multiple: multiple, immediate: immediate, name: name, value: normalizedSelected, onChange: comboboxOnChangeWrapper, onClose: () => setQuery(''), disabled: disabled, by: (a, b) => (a && b ? getValue(a) === getValue(b) : a === b), children: [multiple ? (jsxRuntime.jsxs("div", { className: buildClassName(baseInputClass, 'flex flex-wrap gap-2 peer relative', hasLeftGroup ? (size === 'lg' ? 'ps-12' : size === 'sm' ? 'ps-8' : 'ps-10') : ''), ref: forwardedRef, children: [hasLeftGroup && (jsxRuntime.jsx("span", { className: buildClassName('absolute left-0 top-0 h-full flex items-center justify-center text-gray-400 dark:text-gray-500', currentSize.group), children: leftGroup })), isArray(normalizedSelected) &&
4110
+ return (jsxRuntime.jsxs("div", { className: buildClassName('group space-y-2', hasError && 'has-error', containerClass), ref: containerRef, children: [label && (jsxRuntime.jsxs("div", { className: buildClassName('flex items-center justify-between', labelWrapperClass), children: [jsxRuntime.jsx(Label, { className: labelClass, htmlFor: id, "aria-required": required, children: label }), labelHint && jsxRuntime.jsx(TextContent, { xsmall: true, children: labelHint })] })), jsxRuntime.jsxs(react.Combobox, { multiple: multiple, immediate: immediate, name: name, value: normalizedSelected, onChange: comboboxOnChangeWrapper, onClose: () => setQuery(''), disabled: disabled, by: (a, b) => (a && b ? getValue(a) === getValue(b) : a === b), children: [multiple ? (jsxRuntime.jsxs("div", { className: buildClassName(baseInputClass, 'flex flex-wrap gap-2 peer relative', rightPaddingClass, hasLeftGroup ? (size === 'lg' ? 'ps-12' : size === 'sm' ? 'ps-8' : 'ps-10') : ''), ref: forwardedRef, children: [hasLeftGroup && (jsxRuntime.jsx("span", { className: buildClassName('absolute left-0 top-0 h-full flex items-center justify-center text-gray-400 dark:text-gray-500', currentSize.group), children: leftGroup })), isArray(normalizedSelected) &&
4062
4111
  (normalizedSelected === null || normalizedSelected === void 0 ? void 0 : normalizedSelected.length) > 0 &&
4063
4112
  normalizedSelected.map((option, idx) => (jsxRuntime.jsx(Badge, { theme: "secondary", size: currentSize.badgeSize, removable: !disabled, onRemove: () => removeSelection(idx), children: getDisplayValue(option) }, `${getValue(option)}-${idx}`))), jsxRuntime.jsx(react.ComboboxInput, { className: "outline-none flex-1 dark:placeholder-gray-400 placeholder-gray-400 bg-transparent", "aria-label": name, value: query, autoComplete: "off", placeholder: (normalizedSelected === null || normalizedSelected === void 0 ? void 0 : normalizedSelected.length) ? '' : placeholder, onChange: (e) => {
4064
4113
  const val = e.target.value;
@@ -4098,7 +4147,9 @@ const SelectBox = React.forwardRef((props, forwardedRef) => {
4098
4147
  }
4099
4148
  }, onFocus: () => {
4100
4149
  setQuery('');
4101
- }, className: buildClassName(baseInputClass, hasLeftGroup ? (size === 'lg' ? 'ps-12' : size === 'sm' ? 'ps-8' : 'ps-10') : ''), disabled: disabled, id: id, readOnly: !searchable, ref: inputRef, "data-testid": "combobox-input" }), allowClear && !isEmpty(normalizedSelected) && (jsxRuntime.jsx(Button, { size: "xs", iconOnly: true, "aria-label": "Clear selection", theme: "secondary", variant: "plain", className: "group absolute inset-y-0 right-8 h-6 top-2", onClick: () => handleOnChangeInternal(multiple ? [] : null), disabled: disabled, "data-testid": "combobox-clear-button", noOutlineOnFocus: true, children: jsxRuntime.jsx(SvgX, { className: "size-4 stroke-gray-500 dark:stroke-gray-300" }) })), jsxRuntime.jsx(react.ComboboxButton, { className: "group absolute inset-y-0 right-0 px-2.5 flex items-center justify-center", "data-testid": "combobox-button", children: jsxRuntime.jsx(SvgChevronDown, { className: chevronIconClass }) })] })), jsxRuntime.jsxs(react.ComboboxOptions, { anchor: { to: 'bottom', gap: 5 }, as: "div", modal: modalDropdown, className: buildClassName('w-[var(--input-width)] rounded-lg border border-[var(--ui-border)] bg-white dark:bg-gray-800 p-1 shadow-lg max-h-80 overflow-y-auto z-50 [--anchor-gap:var(--spacing-1)]', '[--anchor-max-height:20rem]', 'origin-top border transition duration-200 ease-[cubic-bezier(0.4, 0.0, 0.2, 1)] data-[closed]:translate-y-[-15%] data-[closed]:opacity-0', dropdownContainerClass), transition: true, "data-testid": "combobox-options", children: [multiple && showSelectAll && allOptions.length > 0 && (jsxRuntime.jsxs("div", { className: "pb-1 mb-1 border-b border-[var(--ui-border-muted)] px-3 pt-1 flex items-center justify-between", children: [jsxRuntime.jsx("button", { type: "button", onClick: handleToggleSelectAll, className: "text-xs font-semibold text-blue-600 dark:text-blue-400 hover:underline cursor-pointer", children: isAllSelected ? 'Deselect All' : 'Select All' }), jsxRuntime.jsxs("span", { className: "text-[11px] font-medium text-gray-400", children: [Array.isArray(normalizedSelected) ? normalizedSelected.length : 0, " of", ' ', allOptions.length] })] })), optionsLoading ? (jsxRuntime.jsx(BodyText, { "data-testid": "options-loading", className: "flex items-center justify-center py-2 px-3 select-none", children: jsxRuntime.jsx(Loader, { size: "sm" }) })) : shouldShowTypeToSearch ? (jsxRuntime.jsx(BodyText, { className: "flex items-center justify-between py-2 px-3 select-none", children: "Type to search..." })) : (jsxRuntime.jsxs("div", { children: [allowFreeText &&
4150
+ }, className: buildClassName(baseInputClass, 'text-ellipsis', rightPaddingClass, hasLeftGroup ? (size === 'lg' ? 'ps-12' : size === 'sm' ? 'ps-8' : 'ps-10') : ''), disabled: disabled, id: id, readOnly: !searchable, ref: inputRef, "data-testid": "combobox-input" }), showClearButton && (jsxRuntime.jsx(Button, { size: "xs", iconOnly: true, "aria-label": "Clear selection", theme: "secondary", variant: "plain", className: "group absolute inset-y-0 right-8 h-6 top-2", onClick: () => handleOnChangeInternal(multiple ? [] : null), disabled: disabled, "data-testid": "combobox-clear-button", children: jsxRuntime.jsx(SvgX, { className: "size-4 stroke-gray-500 dark:stroke-gray-300" }) })), jsxRuntime.jsx(react.ComboboxButton, { className: "group absolute inset-y-0 right-0 px-2.5 flex items-center justify-center", "data-testid": "combobox-button", children: jsxRuntime.jsx(SvgChevronDown, { className: chevronIconClass }) })] })), jsxRuntime.jsxs(react.ComboboxOptions, { anchor: { to: 'bottom start', gap: 5, padding: 8 }, as: "div", modal: modalDropdown,
4151
+ // Matches the input width by default; min-width lets the panel grow wider than a narrow input.
4152
+ style: dropdownMinWidth != null ? { minWidth: dropdownMinWidth } : undefined, className: buildClassName('w-[var(--input-width)] rounded-lg border border-[var(--ui-border)] bg-white dark:bg-gray-800 p-1 shadow-lg max-h-80 overflow-y-auto z-50 [--anchor-gap:var(--spacing-1)]', '[--anchor-max-height:20rem]', 'origin-top border transition duration-200 ease-[cubic-bezier(0.4, 0.0, 0.2, 1)] data-[closed]:translate-y-[-15%] data-[closed]:opacity-0', dropdownContainerClass), transition: true, "data-testid": "combobox-options", children: [multiple && showSelectAll && allOptions.length > 0 && (jsxRuntime.jsxs("div", { className: "pb-1 mb-1 border-b border-[var(--ui-border-muted)] px-3 pt-1 flex items-center justify-between", children: [jsxRuntime.jsx("button", { type: "button", onClick: handleToggleSelectAll, className: "text-xs font-semibold text-blue-600 dark:text-blue-400 hover:underline cursor-pointer", children: isAllSelected ? 'Deselect All' : 'Select All' }), jsxRuntime.jsxs("span", { className: "text-[11px] font-medium text-gray-400", children: [Array.isArray(normalizedSelected) ? normalizedSelected.length : 0, " of", ' ', allOptions.length] })] })), optionsLoading ? (jsxRuntime.jsx(BodyText, { "data-testid": "options-loading", className: "flex items-center justify-center py-2 px-3 select-none", children: jsxRuntime.jsx(Loader, { size: "sm" }) })) : shouldShowTypeToSearch ? (jsxRuntime.jsx(BodyText, { className: "flex items-center justify-between py-2 px-3 select-none", children: "Type to search..." })) : (jsxRuntime.jsxs("div", { children: [allowFreeText &&
4102
4153
  query.trim() &&
4103
4154
  !allOptions.some((opt) => { var _a; return ((_a = getDisplayValue(opt)) === null || _a === void 0 ? void 0 : _a.toLowerCase()) === query.trim().toLowerCase(); }) && (jsxRuntime.jsx(react.ComboboxOption, { value: createFreeTextOption(query.trim()), className: "group flex items-center gap-2 rounded-lg py-1.5 px-3 select-none text-sm data-[focus]:bg-blue-50 dark:data-[focus]:bg-blue-950/40 text-blue-600 dark:text-blue-400 font-medium cursor-pointer w-full", "data-testid": "freetext-option", children: jsxRuntime.jsxs("span", { children: ["Use \"", query.trim(), "\""] }) }, `freetext-${query.trim()}`)), filteredGroups
4104
4155
  ? filteredGroups.map((grp, gIdx) => (jsxRuntime.jsxs("div", { children: [jsxRuntime.jsx("div", { className: "text-[11px] font-bold uppercase tracking-wider text-gray-400 dark:text-gray-500 px-3 py-1 select-none", children: grp.group }), grp.options.map(renderOptionItem)] }, gIdx)))
@@ -4568,7 +4619,7 @@ const Toast = ({ id, title, message, type, variant = 'accent', action, icon, sho
4568
4619
  const renderedIcon = icon !== null && icon !== void 0 ? icon : (variant === 'filled' ? filledIconMap[type] : iconMap[type]);
4569
4620
  return (jsxRuntime.jsx(react.Transition, { appear: true, show: true, enter: "transform transition duration-300 ease-out", enterFrom: enterFrom, enterTo: "opacity-100 translate-y-0 scale-100", leave: "transition duration-200 ease-in", leaveFrom: "opacity-100 translate-y-0 scale-100", leaveTo: leaveTo, children: jsxRuntime.jsxs("div", { role: "status", id: id.toString(), className: buildClassName('relative overflow-hidden flex items-start gap-3 rounded-xl px-4 py-3.5 min-w-[280px] max-w-md transition-all', variantStyleMap[variant][type], className), children: [jsxRuntime.jsx("div", { className: "shrink-0 mt-0.5", children: variant === 'filled' ? (renderedIcon) : (jsxRuntime.jsx(TextContent, { className: buildClassName(textColorMap[type]), children: renderedIcon })) }), jsxRuntime.jsxs("div", { className: "flex-1 flex flex-col gap-0.5", children: [title && (jsxRuntime.jsx("div", { className: buildClassName('font-semibold text-sm leading-snug', variant === 'filled' ? 'text-white' : 'text-gray-900 dark:text-gray-100'), children: title })), jsxRuntime.jsx("div", { className: buildClassName('text-sm font-medium leading-relaxed', variant === 'filled' ? 'text-white/95' : 'text-gray-700 dark:text-gray-300'), children: message }), action && (jsxRuntime.jsx("div", { className: "mt-1.5", children: jsxRuntime.jsx("button", { type: "button", onClick: action.onClick, className: buildClassName('text-xs font-semibold underline underline-offset-2 transition-opacity focus:outline-none', variant === 'filled'
4570
4621
  ? 'text-white hover:opacity-85'
4571
- : 'text-[var(--ui-primary)] hover:opacity-80'), children: action.label }) }))] }), jsxRuntime.jsx(Button, { onClick: onClose, "aria-label": "Close toast", className: buildClassName('shrink-0 mt-0.5 opacity-60 hover:opacity-100 transition', variant === 'filled' && 'text-white hover:text-white'), iconOnly: true, size: "xs", variant: "plain", theme: variant === 'filled' ? 'primary' : 'secondary', noOutlineOnFocus: true, children: jsxRuntime.jsx(SvgX, { className: "size-4" }) }), showProgressBar && duration > 0 && (jsxRuntime.jsx("div", { className: "absolute bottom-0 left-0 right-0 h-1 bg-black/10 dark:bg-white/10 overflow-hidden", children: jsxRuntime.jsx("div", { className: buildClassName('h-full transition-all duration-75 ease-linear', variant === 'filled' ? 'bg-white/70' : progressBarColorMap[type]), style: { width: `${Math.max(0, progress)}%` } }) }))] }) }));
4622
+ : 'text-[var(--ui-primary)] hover:opacity-80'), children: action.label }) }))] }), jsxRuntime.jsx(Button, { onClick: onClose, "aria-label": "Close toast", className: buildClassName('shrink-0 mt-0.5 opacity-60 hover:opacity-100 focus-visible:opacity-100 transition', variant === 'filled' && 'text-white hover:text-white focus-visible:outline-current'), iconOnly: true, size: "xs", variant: "plain", theme: variant === 'filled' ? 'primary' : 'secondary', children: jsxRuntime.jsx(SvgX, { className: "size-4" }) }), showProgressBar && duration > 0 && (jsxRuntime.jsx("div", { className: "absolute bottom-0 left-0 right-0 h-1 bg-black/10 dark:bg-white/10 overflow-hidden", children: jsxRuntime.jsx("div", { className: buildClassName('h-full transition-all duration-75 ease-linear', variant === 'filled' ? 'bg-white/70' : progressBarColorMap[type]), style: { width: `${Math.max(0, progress)}%` } }) }))] }) }));
4572
4623
  };
4573
4624
  Toast.displayName = 'Toast';
4574
4625