@astryxdesign/core 0.7.1 → 0.7.2-canary.07f97c6
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/dist/Button/Button.d.ts.map +1 -1
- package/dist/Button/Button.js +38 -14
- package/dist/Drawer/Drawer.d.ts +191 -0
- package/dist/Drawer/Drawer.d.ts.map +1 -0
- package/dist/Drawer/Drawer.js +382 -0
- package/dist/Drawer/DrawerHeader.d.ts +85 -0
- package/dist/Drawer/DrawerHeader.d.ts.map +1 -0
- package/dist/Drawer/DrawerHeader.js +134 -0
- package/dist/Drawer/index.d.ts +11 -0
- package/dist/Drawer/index.d.ts.map +1 -0
- package/dist/Drawer/index.js +11 -0
- package/dist/Drawer/useDrawerDialogPresence.d.ts +42 -0
- package/dist/Drawer/useDrawerDialogPresence.d.ts.map +1 -0
- package/dist/Drawer/useDrawerDialogPresence.js +236 -0
- package/dist/DropdownMenu/DropdownMenu.js +1 -1
- package/dist/DropdownMenu/DropdownMenuSubMenu.js +4 -4
- package/dist/HoverCard/useHoverCard.d.ts.map +1 -1
- package/dist/HoverCard/useHoverCard.js +10 -2
- package/dist/Layer/layerViewportInset.stylex.d.ts +6 -2
- package/dist/Layer/layerViewportInset.stylex.d.ts.map +1 -1
- package/dist/Layer/layerViewportInset.stylex.js +6 -2
- package/dist/Layer/useLayer.d.ts.map +1 -1
- package/dist/Layer/useLayer.js +13 -7
- package/dist/Layer/useLayerDismissal.d.ts +1 -1
- package/dist/Layer/useLayerDismissal.js +1 -1
- package/dist/Layout/container.stylex.d.ts +5 -5
- package/dist/Layout/container.stylex.js +4 -4
- package/dist/Markdown/plugins/frontmatter.d.ts.map +1 -1
- package/dist/Markdown/plugins/frontmatter.js +7 -3
- package/dist/MultiSelector/MultiSelector.d.ts.map +1 -1
- package/dist/MultiSelector/MultiSelector.js +22 -8
- package/dist/MultiSelector/OptionActions.a11y.chromium.spec.js +100 -2
- package/dist/MultiSelector/hooks.d.ts.map +1 -1
- package/dist/MultiSelector/hooks.js +3 -1
- package/dist/Pagination/Pagination.d.ts +8 -5
- package/dist/Pagination/Pagination.d.ts.map +1 -1
- package/dist/Pagination/Pagination.js +21 -8
- package/dist/Popover/Popover.js +2 -2
- package/dist/PowerSearch/PowerSearch.js +1 -1
- package/dist/Selector/hooks.d.ts.map +1 -1
- package/dist/Selector/hooks.js +6 -2
- package/dist/Switch/Switch.d.ts +1 -1
- package/dist/Switch/Switch.d.ts.map +1 -1
- package/dist/Switch/Switch.js +13 -1
- package/dist/TabList/TabMenu.d.ts +2 -2
- package/dist/TabList/TabMenu.d.ts.map +1 -1
- package/dist/TabList/TabMenu.js +6 -3
- package/dist/Text/useTruncation.d.ts +7 -5
- package/dist/Text/useTruncation.d.ts.map +1 -1
- package/dist/Text/useTruncation.js +16 -5
- package/dist/Tooltip/useTooltip.d.ts.map +1 -1
- package/dist/Tooltip/useTooltip.js +11 -0
- package/dist/Typeahead/BaseTypeahead.d.ts.map +1 -1
- package/dist/Typeahead/BaseTypeahead.js +26 -0
- package/dist/astryx.css +21 -10
- package/dist/hooks/useEntryAnimation.d.ts +2 -1
- package/dist/hooks/useEntryAnimation.d.ts.map +1 -1
- package/dist/hooks/useEntryAnimation.js +14 -12
- package/dist/hooks/useIsHydrating.d.ts +6 -0
- package/dist/hooks/useIsHydrating.d.ts.map +1 -0
- package/dist/hooks/useIsHydrating.js +30 -0
- package/dist/i18n/generated-locales/en.generated.d.ts.map +1 -1
- package/dist/i18n/generated-locales/en.generated.js +112 -1
- package/dist/i18n/generated-locales/pseudo.generated.d.ts.map +1 -1
- package/dist/i18n/generated-locales/pseudo.generated.js +112 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/theme/derivedVarRegistry.d.ts.map +1 -1
- package/dist/theme/derivedVarRegistry.js +0 -3
- package/dist/utils/focusOutline.stylex.d.ts +4 -0
- package/dist/utils/focusOutline.stylex.d.ts.map +1 -1
- package/dist/utils/focusOutline.stylex.js +4 -0
- package/dist/utils/sharedMutationObserver.d.ts +21 -0
- package/dist/utils/sharedMutationObserver.d.ts.map +1 -0
- package/dist/utils/sharedMutationObserver.js +69 -0
- package/locales/en.json +444 -0
- package/locales/pseudo.json +333 -0
- package/package.json +9 -4
- package/src/Button/Button.doc.mjs +2 -2
- package/src/Button/Button.test.tsx +155 -9
- package/src/Button/Button.tsx +39 -16
- package/src/Button/__tests__/Button.a11y.known-failures.ts +1 -62
- package/src/Button/__tests__/Button.a11y.states.ts +0 -10
- package/src/Drawer/Drawer.doc.mjs +472 -0
- package/src/Drawer/Drawer.spec.md +357 -0
- package/src/Drawer/Drawer.test.tsx +1300 -0
- package/src/Drawer/Drawer.tsx +613 -0
- package/src/Drawer/DrawerDirection.test.tsx +127 -0
- package/src/Drawer/DrawerHeader.doc.mjs +293 -0
- package/src/Drawer/DrawerHeader.test.tsx +102 -0
- package/src/Drawer/DrawerHeader.tsx +235 -0
- package/src/Drawer/__tests__/DrawerAudit.a11y.chromium.spec.ts +401 -0
- package/src/Drawer/__tests__/DrawerHeaderAudit.a11y.chromium.spec.ts +297 -0
- package/src/Drawer/index.ts +13 -0
- package/src/Drawer/useDrawerDialogPresence.ts +284 -0
- package/src/DropdownMenu/DropdownMenu.tsx +2 -2
- package/src/DropdownMenu/DropdownMenuSubMenu.tsx +2 -2
- package/src/HoverCard/HoverCard.test.tsx +58 -0
- package/src/HoverCard/useHoverCard.tsx +10 -2
- package/src/IconButton/IconButton.doc.mjs +2 -2
- package/src/IconButton/IconButton.test.tsx +3 -1
- package/src/Layer/layerViewportInset.source-build.test.mjs +90 -0
- package/src/Layer/layerViewportInset.stylex.ts +6 -2
- package/src/Layer/layerViewportInset.test.ts +1 -0
- package/src/Layer/useLayer.tsx +24 -13
- package/src/Layer/useLayerDismissal.ts +1 -1
- package/src/Layout/container.stylex.ts +6 -6
- package/src/List/ListItem.doc.mjs +8 -5
- package/src/Markdown/plugins/frontmatter.test.tsx +25 -0
- package/src/Markdown/plugins/frontmatter.ts +7 -3
- package/src/MultiSelector/MultiSelector.test.tsx +159 -0
- package/src/MultiSelector/MultiSelector.tsx +40 -7
- package/src/MultiSelector/OptionActions.a11y.chromium.spec.ts +112 -2
- package/src/MultiSelector/hooks.ts +3 -1
- package/src/MultiSelector/useMultiCombobox.doc.mjs +267 -0
- package/src/Pagination/Pagination.doc.mjs +7 -7
- package/src/Pagination/Pagination.spec.md +9 -9
- package/src/Pagination/Pagination.test.tsx +242 -0
- package/src/Pagination/Pagination.tsx +27 -11
- package/src/Popover/Popover.test.tsx +2 -2
- package/src/Popover/Popover.tsx +4 -4
- package/src/PowerSearch/PowerSearch.test.tsx +85 -0
- package/src/PowerSearch/PowerSearch.tsx +2 -2
- package/src/Selector/hooks.ts +6 -2
- package/src/Selector/useCombobox.doc.mjs +237 -0
- package/src/Switch/Switch.test.tsx +49 -0
- package/src/Switch/Switch.tsx +11 -0
- package/src/TabList/TabList.test.tsx +67 -0
- package/src/TabList/TabMenu.doc.mjs +4 -3
- package/src/TabList/TabMenu.tsx +7 -4
- package/src/Text/useTruncation.test.tsx +69 -0
- package/src/Text/useTruncation.ts +16 -5
- package/src/Tokenizer/Tokenizer.test.tsx +54 -1
- package/src/Tooltip/Tooltip.test.tsx +31 -0
- package/src/Tooltip/useTooltip.test.tsx +13 -0
- package/src/Tooltip/useTooltip.tsx +11 -0
- package/src/Typeahead/BaseTypeahead.tsx +26 -0
- package/src/Typeahead/Typeahead.test.tsx +260 -2
- package/src/hooks/useEntryAnimation.doc.mjs +4 -4
- package/src/hooks/useEntryAnimation.ssr.test.tsx +143 -0
- package/src/hooks/useEntryAnimation.ts +15 -16
- package/src/hooks/useIsHydrating.test.tsx +70 -0
- package/src/hooks/useIsHydrating.ts +31 -0
- package/src/i18n/InternationalizationProvider.doc.mjs +8 -0
- package/src/i18n/InternationalizationProvider.spec.md +252 -0
- package/src/i18n/__tests__/InternationalizationProvider.test.tsx +128 -0
- package/src/i18n/generated-locales/en.generated.ts +121 -0
- package/src/i18n/generated-locales/pseudo.generated.ts +121 -0
- package/src/i18n/useTranslator.test.tsx +37 -0
- package/src/index.ts +1 -0
- package/src/theme/derivedVarRegistry.test.ts +0 -3
- package/src/theme/derivedVarRegistry.ts +0 -3
- package/src/utils/focusOutline.stylex.ts +4 -0
- package/src/utils/sharedMutationObserver.test.ts +53 -0
- package/src/utils/sharedMutationObserver.ts +78 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Button.d.ts","sourceRoot":"","sources":["../../src/Button/Button.tsx"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"Button.d.ts","sourceRoot":"","sources":["../../src/Button/Button.tsx"],"names":[],"mappings":"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"}
|
package/dist/Button/Button.js
CHANGED
|
@@ -364,25 +364,35 @@ export function Button({
|
|
|
364
364
|
// the consumer is deliberately showing it.
|
|
365
365
|
const delaySpinner = isPending || isInterruptible;
|
|
366
366
|
const groupDisabled = buttonGroup?.isDisabled ?? false;
|
|
367
|
-
|
|
368
|
-
//
|
|
369
|
-
|
|
370
|
-
//
|
|
371
|
-
//
|
|
372
|
-
//
|
|
373
|
-
|
|
367
|
+
const isTrueDisabled = isDisabled || groupDisabled;
|
|
368
|
+
// Busy-only: the button can't fire again purely because an action is in
|
|
369
|
+
// flight, not because it's genuinely isDisabled/group-disabled. Per the API
|
|
370
|
+
// Conventions "Disabled vs Busy" rule, busy is visual-only (aria-busy +
|
|
371
|
+
// spinner) and must never take focusability away — the click-handler ref
|
|
372
|
+
// guard (actionInFlightRef) is what actually makes a fire-once action fire
|
|
373
|
+
// once, so the native disabled attribute adds nothing but a focus loss
|
|
374
|
+
// here. When interruptible, the loading state drives the spinner and
|
|
375
|
+
// aria-busy but not disabled at all, so clicks keep landing and can
|
|
376
|
+
// interrupt the in-flight action.
|
|
377
|
+
const isBusyOnlyDisabled = !isTrueDisabled && isLoadingState && !isInterruptible;
|
|
378
|
+
const buttonDisabled = isTrueDisabled || isBusyOnlyDisabled;
|
|
374
379
|
// isIconOnly prop is the source of truth for icon-only rendering.
|
|
375
380
|
// When false (default), label is always rendered as visible text.
|
|
376
381
|
|
|
377
382
|
const LinkComponent = useLinkComponent(as);
|
|
378
383
|
|
|
379
|
-
// Render as link when href is provided and button is not
|
|
380
|
-
// Disabled links are an accessibility anti-pattern
|
|
381
|
-
|
|
384
|
+
// Render as link when href is provided and the button is not TRULY
|
|
385
|
+
// disabled. Disabled links are an accessibility anti-pattern, so a
|
|
386
|
+
// genuinely isDisabled/group-disabled button falls back to <button>.
|
|
387
|
+
// Busy-only does NOT fall back: swapping <a> for a disabled <button>
|
|
388
|
+
// mid-action would drop focus the same way the native attribute does
|
|
389
|
+
// (credit @AKnassa, #4879), which is exactly the bug this PR fixes.
|
|
390
|
+
const renderAsLink = href != null && !isTrueDisabled;
|
|
382
391
|
|
|
383
|
-
// Use aria-disabled
|
|
384
|
-
//
|
|
385
|
-
|
|
392
|
+
// Use aria-disabled (button stays focusable) when busy-only, or when a
|
|
393
|
+
// tooltip is present so keyboard users can still reach it. A genuinely
|
|
394
|
+
// isDisabled/group-disabled button (not busy) keeps native disabled.
|
|
395
|
+
const useAriaDisabled = buttonDisabled && (isBusyOnlyDisabled || tooltip != null);
|
|
386
396
|
|
|
387
397
|
// Attach tooltip behavior via the hook rather than wrapping the button in a
|
|
388
398
|
// <Tooltip> element. The hook adds hover/focus triggers to the button itself,
|
|
@@ -398,6 +408,16 @@ export function Button({
|
|
|
398
408
|
// a re-click while pending starts a fresh action that interrupts the prior.
|
|
399
409
|
if (buttonDisabled || actionInFlightRef.current && !isInterruptible) {
|
|
400
410
|
e.preventDefault();
|
|
411
|
+
// A native `disabled` element never dispatches a click at all, so it
|
|
412
|
+
// never reaches a wrapping element's own handler either. An
|
|
413
|
+
// aria-disabled button (busy-only, or with a tooltip) is still a real,
|
|
414
|
+
// interactive element the DOM keeps dispatching clicks on —
|
|
415
|
+
// preventDefault alone only cancels the button's OWN default action
|
|
416
|
+
// (form submit, link navigation), not propagation. Without this, an
|
|
417
|
+
// unavailable Button inside a clickable row/card/backdrop still
|
|
418
|
+
// triggers that ancestor's action, which the previously native-disabled
|
|
419
|
+
// control never did.
|
|
420
|
+
e.stopPropagation();
|
|
401
421
|
return;
|
|
402
422
|
}
|
|
403
423
|
props.onClick?.(e);
|
|
@@ -431,7 +451,7 @@ export function Button({
|
|
|
431
451
|
} : null;
|
|
432
452
|
|
|
433
453
|
// Shared StyleX props for both button and link rendering
|
|
434
|
-
const sharedStylexProps = focusOutlineProps.focusVisible(styles.base, sizeStyles[size], isIconOnly && styles.iconOnly, interactionOverlayStyles.backgroundImage, buttonDisabled && styles.inactive,
|
|
454
|
+
const sharedStylexProps = focusOutlineProps.focusVisible(styles.base, sizeStyles[size], isIconOnly && styles.iconOnly, interactionOverlayStyles.backgroundImage, buttonDisabled && styles.inactive, isTrueDisabled && styles.disabled, useAriaDisabled && styles.ariaDisabled, renderAsLink && styles.link, !buttonGroup && styles.pressable, buttonGroup && (buttonGroup.orientation === 'horizontal' ? groupStyles.horizontal : groupStyles.vertical), inputGroup != null && buttonGroup == null && inputGroupStyles.buttonAddon, buttonGroup && (variant === 'primary' || variant === 'destructive') && (buttonGroup.orientation === 'horizontal' ? groupStyles.onSolidHorizontal : groupStyles.onSolidVertical),
|
|
435
455
|
// Standalone floating buttons only — a grouped button's elevation is owned
|
|
436
456
|
// by the ButtonGroup so the shared surface lifts as one unit.
|
|
437
457
|
!buttonGroup && elevationStyles[elevation], width != null && dynamicStyles.width(width),
|
|
@@ -523,7 +543,11 @@ export function Button({
|
|
|
523
543
|
...describedByProp,
|
|
524
544
|
...edgeCompAttr,
|
|
525
545
|
"aria-busy": isLoadingState || undefined,
|
|
546
|
+
"aria-disabled": useAriaDisabled || undefined,
|
|
526
547
|
onClick: handleClick,
|
|
548
|
+
...(handleKeyDown ? {
|
|
549
|
+
onKeyDown: handleKeyDown
|
|
550
|
+
} : null),
|
|
527
551
|
children: buttonContent
|
|
528
552
|
});
|
|
529
553
|
} else {
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Drawer.tsx
|
|
3
|
+
* @input Uses React, StyleX, theme tokens, the shared layer text/structure resets and content boundary, the Dialog purpose type, shared focus/dismissal/depth primitives, container padding lowering, scroll locking/dialog presence, BaseProps, merged refs/props, themeProps
|
|
4
|
+
* @output Exports Drawer component and DrawerProps
|
|
5
|
+
* @position Core implementation; consumed by index.ts, tested by Drawer.test.tsx, demonstrated in Storybook
|
|
6
|
+
*
|
|
7
|
+
* Overlay panel for inspectors and detail views — the "click a table row,
|
|
8
|
+
* see its details" pattern. Slides in from the inline start or end edge and
|
|
9
|
+
* floats above the page content: unlike a docked panel it never reflows the
|
|
10
|
+
* layout underneath, it overlays it (with or without a scrim).
|
|
11
|
+
*
|
|
12
|
+
* Inline axis only (start/end). Block-axis sheets are BottomSheet's job;
|
|
13
|
+
* a drawer is always a full-height side panel.
|
|
14
|
+
*
|
|
15
|
+
* Sizing is viewport-aware: `width` is the desktop budget, and below
|
|
16
|
+
* the mobile breakpoint it preserves a 56px reveal of the page behind, capped
|
|
17
|
+
* by the requested width (or fills the viewport with the experimental
|
|
18
|
+
* `experimental.isFullWidthOnMobile` option).
|
|
19
|
+
*
|
|
20
|
+
* Uses the native `<dialog>` element (same precedent as Dialog/MobileNav):
|
|
21
|
+
* - `showModal()` when `hasScrim` (default) — top-layer rendering, focus
|
|
22
|
+
* trapping, `::backdrop`, no z-index management.
|
|
23
|
+
* - `showPopover()` when `hasScrim={false}` — non-modal top-layer overlay;
|
|
24
|
+
* the page behind stays interactive (e.g. master-detail inspectors).
|
|
25
|
+
*
|
|
26
|
+
* Entry animation uses `@starting-style`; exit slides out before the active
|
|
27
|
+
* modal-dialog or manual-popover host releases the top layer and focus returns
|
|
28
|
+
* to the element that opened the drawer. React owns `display` for both legs
|
|
29
|
+
* rather than a discrete `display` transition, so the panel stops painting in
|
|
30
|
+
* the same commit as the host closes — see the `rendered` style for why.
|
|
31
|
+
*
|
|
32
|
+
* Sibling drawers use the shared layer dismissal stack for topmost-only Escape
|
|
33
|
+
* handling and the browser top layer's chronological paint order.
|
|
34
|
+
*
|
|
35
|
+
* Dismissal follows Dialog: `purpose` decides whether Escape and a scrim click
|
|
36
|
+
* request close, and Drawer renders no close button of its own. Compose
|
|
37
|
+
* `DrawerHeader` with `onOpenChange` for a visible close action, as with
|
|
38
|
+
* `DialogHeader`.
|
|
39
|
+
*
|
|
40
|
+
* The scrolling content area is the drawer's container, like Dialog's inner
|
|
41
|
+
* box: the `padding` prop, else the theme's `padding` on `drawer`, insets it
|
|
42
|
+
* through container tokens, defaulting to `--spacing-4` like Dialog, and the
|
|
43
|
+
* applied inset is published so a lone Section child escapes it and a Layout
|
|
44
|
+
* redistributes it to its regions. Compose `DrawerHeader` inside a `Layout`, as
|
|
45
|
+
* `DialogHeader` is composed in Dialog, so the header is not padded twice. The
|
|
46
|
+
* root dialog stays the overlay boundary (`overlayPaddingReset`).
|
|
47
|
+
*
|
|
48
|
+
* SYNC: When modified, update these files to stay in sync:
|
|
49
|
+
* - /packages/core/src/Drawer/Drawer.doc.mjs (props table, features, usage)
|
|
50
|
+
* - /packages/core/src/Drawer/Drawer.test.tsx (tests for new/changed behavior)
|
|
51
|
+
* - /packages/core/src/Drawer/Drawer.spec.md (component contract)
|
|
52
|
+
* - /packages/core/src/Drawer/index.ts (exports if types change)
|
|
53
|
+
* - /packages/cli/assets/templates/blocks/components/Drawer/ (showcase blocks)
|
|
54
|
+
* - /apps/storybook/stories/Drawer.stories.tsx (examples and visual coverage)
|
|
55
|
+
*/
|
|
56
|
+
import { type ReactNode } from 'react';
|
|
57
|
+
import type { BaseProps } from '../BaseProps';
|
|
58
|
+
import type { DialogPurpose } from '../Dialog';
|
|
59
|
+
import type { SpacingStep } from '../Layout';
|
|
60
|
+
export interface DrawerProps extends BaseProps<HTMLDialogElement> {
|
|
61
|
+
/** Ref forwarded to the root <dialog> element */
|
|
62
|
+
ref?: React.Ref<HTMLDialogElement>;
|
|
63
|
+
/**
|
|
64
|
+
* Whether the drawer is open. Fully controlled — pair with `onOpenChange`.
|
|
65
|
+
*/
|
|
66
|
+
isOpen: boolean;
|
|
67
|
+
/**
|
|
68
|
+
* Called when the drawer requests an open-state change. Escape and a scrim
|
|
69
|
+
* click call it with `false` as `purpose` allows; a `DrawerHeader` close
|
|
70
|
+
* button calls it when you pass the same callback to the header. The caller
|
|
71
|
+
* owns the open state. When sibling drawers are open, Escape only closes the
|
|
72
|
+
* top (last-opened) drawer.
|
|
73
|
+
*/
|
|
74
|
+
onOpenChange: (isOpen: boolean) => void;
|
|
75
|
+
/**
|
|
76
|
+
* Which edge the drawer slides from.
|
|
77
|
+
* - `'end'` — inline-end edge (right in LTR) — the inspector convention
|
|
78
|
+
* - `'start'` — inline-start edge (left in LTR)
|
|
79
|
+
* @default 'end'
|
|
80
|
+
*/
|
|
81
|
+
side?: 'start' | 'end';
|
|
82
|
+
/**
|
|
83
|
+
* Desktop width budget. A number is pixels; a string is any CSS length
|
|
84
|
+
* (`'50%'`, `'32rem'`). Below the mobile breakpoint (640px), this
|
|
85
|
+
* remains the maximum while the drawer preserves a 56px reveal of the page
|
|
86
|
+
* behind — see `experimental.isFullWidthOnMobile`.
|
|
87
|
+
* @default 400
|
|
88
|
+
*/
|
|
89
|
+
width?: number | string;
|
|
90
|
+
/**
|
|
91
|
+
* Experimental options, outside the stable compatibility promise: anything
|
|
92
|
+
* in this object may change or be removed in a patch release. Omit it for
|
|
93
|
+
* the stable behavior.
|
|
94
|
+
* @experimental
|
|
95
|
+
*/
|
|
96
|
+
experimental?: {
|
|
97
|
+
/**
|
|
98
|
+
* Cover the full viewport width on mobile (below 640px) instead of
|
|
99
|
+
* preserving the default 56px reveal of the page behind. The reveal makes
|
|
100
|
+
* the drawer read as an overlay rather than a navigation.
|
|
101
|
+
* @experimental
|
|
102
|
+
* @default false
|
|
103
|
+
*/
|
|
104
|
+
isFullWidthOnMobile?: boolean;
|
|
105
|
+
};
|
|
106
|
+
/**
|
|
107
|
+
* Accessible label for the drawer (required — the drawer has no
|
|
108
|
+
* built-in heading to derive a name from).
|
|
109
|
+
*/
|
|
110
|
+
label: string;
|
|
111
|
+
/**
|
|
112
|
+
* Whether to render a modal scrim behind the drawer.
|
|
113
|
+
* - `true` (default) — `showModal()`: top layer, focus trap, body scroll
|
|
114
|
+
* lock, click-outside-to-close.
|
|
115
|
+
* - `false` — `showPopover()`: non-modal top-layer overlay; the page behind
|
|
116
|
+
* stays interactive. Escape still closes through the shared layer stack.
|
|
117
|
+
* @default true
|
|
118
|
+
*/
|
|
119
|
+
hasScrim?: boolean;
|
|
120
|
+
/**
|
|
121
|
+
* Configures how the drawer enables dismissals, matching Dialog.
|
|
122
|
+
* - required: Disables Escape and scrim click (for mandatory flows); a
|
|
123
|
+
* modal required drawer is exposed as an `alertdialog`
|
|
124
|
+
* - form: Prevents scrim click, allows the Escape key
|
|
125
|
+
* - info: Allows Escape and scrim click
|
|
126
|
+
*
|
|
127
|
+
* A non-modal drawer has no scrim, so `form` and `info` behave the same.
|
|
128
|
+
* @default 'info'
|
|
129
|
+
*/
|
|
130
|
+
purpose?: DialogPurpose;
|
|
131
|
+
/**
|
|
132
|
+
* Internal padding of the drawer content using the spacing scale, matching
|
|
133
|
+
* Dialog. Accepts numeric spacing steps: 0, 0.5, 1, 1.5, 2, 3, 4, 5, 6, 8,
|
|
134
|
+
* 10. When omitted, uses the theme default for drawers (`--spacing-4`, 16px,
|
|
135
|
+
* unless the theme sets `padding` on `drawer`), as Dialog does. Pass `0` for
|
|
136
|
+
* a full-bleed content area. The content area is a container: a Section that
|
|
137
|
+
* is its only child escapes the padding, bleed children such as Table and
|
|
138
|
+
* Divider compensate against it, and a Layout picks it up for its regions.
|
|
139
|
+
*/
|
|
140
|
+
padding?: SpacingStep;
|
|
141
|
+
/**
|
|
142
|
+
* Drawer content. Rendered inside a full-height scrollable area.
|
|
143
|
+
* Focus the element with `data-autofocus` on open, if present.
|
|
144
|
+
*/
|
|
145
|
+
children: ReactNode;
|
|
146
|
+
/**
|
|
147
|
+
* Test ID for the root element.
|
|
148
|
+
*/
|
|
149
|
+
'data-testid'?: string;
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* An overlay panel for inspectors and detail views.
|
|
153
|
+
*
|
|
154
|
+
* Slides in from the logical start or end edge and floats above the page
|
|
155
|
+
* using the native `<dialog>` element: modal with a scrim by default, or a
|
|
156
|
+
* non-modal overlay with `hasScrim={false}` that leaves the page behind
|
|
157
|
+
* interactive. `width` is the desktop budget; below 640px the panel preserves
|
|
158
|
+
* a 56px page reveal without exceeding that budget (or fills the viewport
|
|
159
|
+
* with the experimental `experimental.isFullWidthOnMobile`). Escape
|
|
160
|
+
* closes the top-most open drawer; focus returns to the element that
|
|
161
|
+
* opened it.
|
|
162
|
+
*
|
|
163
|
+
* Dismissal matches Dialog: `purpose` decides whether Escape and a scrim click
|
|
164
|
+
* close the drawer, and `DrawerHeader` renders a close button when given
|
|
165
|
+
* `onOpenChange`.
|
|
166
|
+
*
|
|
167
|
+
* Like Dialog, the drawer is a container: `padding` (or a theme's `padding`
|
|
168
|
+
* on `drawer`) insets the content area, a lone Section child escapes that
|
|
169
|
+
* inset, and a Layout inside picks it up for its header, content, and footer
|
|
170
|
+
* regions. The default inset is `--spacing-4`, matching Dialog.
|
|
171
|
+
*
|
|
172
|
+
* @example
|
|
173
|
+
* ```
|
|
174
|
+
* const [selected, setSelected] = useState(null);
|
|
175
|
+
* const handleOpenChange = isOpen => !isOpen && setSelected(null);
|
|
176
|
+
* <Drawer
|
|
177
|
+
* isOpen={selected != null}
|
|
178
|
+
* onOpenChange={handleOpenChange}
|
|
179
|
+
* label={`Details: ${selected?.name}`}>
|
|
180
|
+
* <Layout
|
|
181
|
+
* header={<DrawerHeader title={selected?.name} onOpenChange={handleOpenChange} />}
|
|
182
|
+
* content={<LayoutContent><HostDetails host={selected} /></LayoutContent>}
|
|
183
|
+
* />
|
|
184
|
+
* </Drawer>
|
|
185
|
+
* ```
|
|
186
|
+
*/
|
|
187
|
+
export declare function Drawer({ isOpen, onOpenChange, side, width, experimental, label, hasScrim, purpose, padding, children, xstyle, className, style, onClick: onClickProp, onKeyDown: onKeyDownProp, ref, ...props }: DrawerProps): import("react").JSX.Element;
|
|
188
|
+
export declare namespace Drawer {
|
|
189
|
+
var displayName: string;
|
|
190
|
+
}
|
|
191
|
+
//# sourceMappingURL=Drawer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Drawer.d.ts","sourceRoot":"","sources":["../../src/Drawer/Drawer.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsDG;AAEH,OAAO,EAAgC,KAAK,SAAS,EAAC,MAAM,OAAO,CAAC;AAEpE,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAQ5C,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,WAAW,CAAC;AAe7C,OAAO,KAAK,EAAC,WAAW,EAAe,MAAM,WAAW,CAAC;AAgMzD,MAAM,WAAW,WAAY,SAAQ,SAAS,CAAC,iBAAiB,CAAC;IAC/D,iDAAiD;IACjD,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC;IAEnC;;OAEG;IACH,MAAM,EAAE,OAAO,CAAC;IAEhB;;;;;;OAMG;IACH,YAAY,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;IAExC;;;;;OAKG;IACH,IAAI,CAAC,EAAE,OAAO,GAAG,KAAK,CAAC;IAEvB;;;;;;OAMG;IACH,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAExB;;;;;OAKG;IACH,YAAY,CAAC,EAAE;QACb;;;;;;WAMG;QACH,mBAAmB,CAAC,EAAE,OAAO,CAAC;KAC/B,CAAC;IAEF;;;OAGG;IACH,KAAK,EAAE,MAAM,CAAC;IAEd;;;;;;;OAOG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB;;;;;;;;;OASG;IACH,OAAO,CAAC,EAAE,aAAa,CAAC;IAExB;;;;;;;;OAQG;IACH,OAAO,CAAC,EAAE,WAAW,CAAC;IAEtB;;;OAGG;IACH,QAAQ,EAAE,SAAS,CAAC;IAEpB;;OAEG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAMD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,wBAAgB,MAAM,CAAC,EACrB,MAAM,EACN,YAAY,EACZ,IAAY,EACZ,KAAW,EACX,YAAY,EACZ,KAAK,EACL,QAAe,EACf,OAAgB,EAChB,OAAO,EACP,QAAQ,EACR,MAAM,EACN,SAAS,EACT,KAAK,EACL,OAAO,EAAE,WAAW,EACpB,SAAS,EAAE,aAAa,EACxB,GAAG,EACH,GAAG,KAAK,EACT,EAAE,WAAW,+BA4Kb;yBA9Le,MAAM"}
|