@hjmds/design-contracts 0.8.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +208 -0
- package/dist/alert-dialog.d.ts +102 -0
- package/dist/alert-dialog.d.ts.map +1 -0
- package/dist/alert-dialog.js +136 -0
- package/dist/alert-dialog.js.map +1 -0
- package/dist/base-recipes.d.ts +184 -0
- package/dist/base-recipes.d.ts.map +1 -0
- package/dist/base-recipes.js +129 -0
- package/dist/base-recipes.js.map +1 -0
- package/dist/behaviors.d.ts +1254 -0
- package/dist/behaviors.d.ts.map +1 -0
- package/dist/behaviors.js +972 -0
- package/dist/behaviors.js.map +1 -0
- package/dist/bottom-navigation-defaults.d.ts +13 -0
- package/dist/bottom-navigation-defaults.d.ts.map +1 -0
- package/dist/bottom-navigation-defaults.js +10 -0
- package/dist/bottom-navigation-defaults.js.map +1 -0
- package/dist/bottom-navigation.d.ts +114 -0
- package/dist/bottom-navigation.d.ts.map +1 -0
- package/dist/bottom-navigation.js +223 -0
- package/dist/bottom-navigation.js.map +1 -0
- package/dist/breadcrumb.d.ts +97 -0
- package/dist/breadcrumb.d.ts.map +1 -0
- package/dist/breadcrumb.js +99 -0
- package/dist/breadcrumb.js.map +1 -0
- package/dist/calendar.d.ts +285 -0
- package/dist/calendar.d.ts.map +1 -0
- package/dist/calendar.js +297 -0
- package/dist/calendar.js.map +1 -0
- package/dist/card.d.ts +39 -0
- package/dist/card.d.ts.map +1 -0
- package/dist/card.js +50 -0
- package/dist/card.js.map +1 -0
- package/dist/carousel.d.ts +180 -0
- package/dist/carousel.d.ts.map +1 -0
- package/dist/carousel.js +172 -0
- package/dist/carousel.js.map +1 -0
- package/dist/catalog.d.ts +7158 -0
- package/dist/catalog.d.ts.map +1 -0
- package/dist/catalog.js +220 -0
- package/dist/catalog.js.map +1 -0
- package/dist/collection.d.ts +123 -0
- package/dist/collection.d.ts.map +1 -0
- package/dist/collection.js +211 -0
- package/dist/collection.js.map +1 -0
- package/dist/color-references.d.ts +46 -0
- package/dist/color-references.d.ts.map +1 -0
- package/dist/color-references.js +39 -0
- package/dist/color-references.js.map +1 -0
- package/dist/colors.d.ts +56 -0
- package/dist/colors.d.ts.map +1 -0
- package/dist/colors.js +90 -0
- package/dist/colors.js.map +1 -0
- package/dist/command-palette.d.ts +240 -0
- package/dist/command-palette.d.ts.map +1 -0
- package/dist/command-palette.js +97 -0
- package/dist/command-palette.js.map +1 -0
- package/dist/component-contracts.d.ts +137 -0
- package/dist/component-contracts.d.ts.map +1 -0
- package/dist/component-contracts.js +53 -0
- package/dist/component-contracts.js.map +1 -0
- package/dist/component-definitions.d.ts +135 -0
- package/dist/component-definitions.d.ts.map +1 -0
- package/dist/component-definitions.js +142 -0
- package/dist/component-definitions.js.map +1 -0
- package/dist/component-recipes.d.ts +3583 -0
- package/dist/component-recipes.d.ts.map +1 -0
- package/dist/component-recipes.js +1503 -0
- package/dist/component-recipes.js.map +1 -0
- package/dist/component-references.d.ts +416 -0
- package/dist/component-references.d.ts.map +1 -0
- package/dist/component-references.js +140 -0
- package/dist/component-references.js.map +1 -0
- package/dist/content-state.d.ts +104 -0
- package/dist/content-state.d.ts.map +1 -0
- package/dist/content-state.js +116 -0
- package/dist/content-state.js.map +1 -0
- package/dist/counter-badge-recipe.d.ts +80 -0
- package/dist/counter-badge-recipe.d.ts.map +1 -0
- package/dist/counter-badge-recipe.js +44 -0
- package/dist/counter-badge-recipe.js.map +1 -0
- package/dist/counter-badge.d.ts +12 -0
- package/dist/counter-badge.d.ts.map +1 -0
- package/dist/counter-badge.js +21 -0
- package/dist/counter-badge.js.map +1 -0
- package/dist/data-table.d.ts +203 -0
- package/dist/data-table.d.ts.map +1 -0
- package/dist/data-table.js +182 -0
- package/dist/data-table.js.map +1 -0
- package/dist/date-picker.d.ts +268 -0
- package/dist/date-picker.d.ts.map +1 -0
- package/dist/date-picker.js +168 -0
- package/dist/date-picker.js.map +1 -0
- package/dist/description-list.d.ts +68 -0
- package/dist/description-list.d.ts.map +1 -0
- package/dist/description-list.js +85 -0
- package/dist/description-list.js.map +1 -0
- package/dist/design-system-provider.d.ts +80 -0
- package/dist/design-system-provider.d.ts.map +1 -0
- package/dist/design-system-provider.js +147 -0
- package/dist/design-system-provider.js.map +1 -0
- package/dist/evidence.d.ts +49 -0
- package/dist/evidence.d.ts.map +1 -0
- package/dist/evidence.js +133 -0
- package/dist/evidence.js.map +1 -0
- package/dist/file-picker.d.ts +183 -0
- package/dist/file-picker.d.ts.map +1 -0
- package/dist/file-picker.js +224 -0
- package/dist/file-picker.js.map +1 -0
- package/dist/floating-action-button.d.ts +143 -0
- package/dist/floating-action-button.d.ts.map +1 -0
- package/dist/floating-action-button.js +149 -0
- package/dist/floating-action-button.js.map +1 -0
- package/dist/form.d.ts +143 -0
- package/dist/form.d.ts.map +1 -0
- package/dist/form.js +206 -0
- package/dist/form.js.map +1 -0
- package/dist/foundations.d.ts +300 -0
- package/dist/foundations.d.ts.map +1 -0
- package/dist/foundations.js +238 -0
- package/dist/foundations.js.map +1 -0
- package/dist/grid.d.ts +75 -0
- package/dist/grid.d.ts.map +1 -0
- package/dist/grid.js +133 -0
- package/dist/grid.js.map +1 -0
- package/dist/icon-button-recipe.d.ts +99 -0
- package/dist/icon-button-recipe.d.ts.map +1 -0
- package/dist/icon-button-recipe.js +53 -0
- package/dist/icon-button-recipe.js.map +1 -0
- package/dist/icon.d.ts +41 -0
- package/dist/icon.d.ts.map +1 -0
- package/dist/icon.js +147 -0
- package/dist/icon.js.map +1 -0
- package/dist/image.d.ts +82 -0
- package/dist/image.d.ts.map +1 -0
- package/dist/image.js +100 -0
- package/dist/image.js.map +1 -0
- package/dist/index.d.ts +58 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +66 -0
- package/dist/index.js.map +1 -0
- package/dist/layout.d.ts +118 -0
- package/dist/layout.d.ts.map +1 -0
- package/dist/layout.js +118 -0
- package/dist/layout.js.map +1 -0
- package/dist/link.d.ts +57 -0
- package/dist/link.d.ts.map +1 -0
- package/dist/link.js +142 -0
- package/dist/link.js.map +1 -0
- package/dist/load-more.d.ts +64 -0
- package/dist/load-more.d.ts.map +1 -0
- package/dist/load-more.js +124 -0
- package/dist/load-more.js.map +1 -0
- package/dist/mentions.d.ts +67 -0
- package/dist/mentions.d.ts.map +1 -0
- package/dist/mentions.js +107 -0
- package/dist/mentions.js.map +1 -0
- package/dist/number-field.d.ts +208 -0
- package/dist/number-field.d.ts.map +1 -0
- package/dist/number-field.js +247 -0
- package/dist/number-field.js.map +1 -0
- package/dist/otp-field.d.ts +152 -0
- package/dist/otp-field.d.ts.map +1 -0
- package/dist/otp-field.js +117 -0
- package/dist/otp-field.js.map +1 -0
- package/dist/pagination.d.ts +181 -0
- package/dist/pagination.d.ts.map +1 -0
- package/dist/pagination.js +226 -0
- package/dist/pagination.js.map +1 -0
- package/dist/password-field.d.ts +187 -0
- package/dist/password-field.d.ts.map +1 -0
- package/dist/password-field.js +120 -0
- package/dist/password-field.js.map +1 -0
- package/dist/popover.d.ts +152 -0
- package/dist/popover.d.ts.map +1 -0
- package/dist/popover.js +137 -0
- package/dist/popover.js.map +1 -0
- package/dist/progress-recipe.d.ts +43 -0
- package/dist/progress-recipe.d.ts.map +1 -0
- package/dist/progress-recipe.js +16 -0
- package/dist/progress-recipe.js.map +1 -0
- package/dist/recipes.d.ts +31 -0
- package/dist/recipes.d.ts.map +1 -0
- package/dist/recipes.js +46 -0
- package/dist/recipes.js.map +1 -0
- package/dist/responsive.d.ts +27 -0
- package/dist/responsive.d.ts.map +1 -0
- package/dist/responsive.js +66 -0
- package/dist/responsive.js.map +1 -0
- package/dist/result.d.ts +111 -0
- package/dist/result.d.ts.map +1 -0
- package/dist/result.js +97 -0
- package/dist/result.js.map +1 -0
- package/dist/selection-helpers.d.ts +16 -0
- package/dist/selection-helpers.d.ts.map +1 -0
- package/dist/selection-helpers.js +52 -0
- package/dist/selection-helpers.js.map +1 -0
- package/dist/semantic-colors.d.ts +275 -0
- package/dist/semantic-colors.d.ts.map +1 -0
- package/dist/semantic-colors.js +84 -0
- package/dist/semantic-colors.js.map +1 -0
- package/dist/sheet.d.ts +51 -0
- package/dist/sheet.d.ts.map +1 -0
- package/dist/sheet.js +69 -0
- package/dist/sheet.js.map +1 -0
- package/dist/showcase.d.ts +153 -0
- package/dist/showcase.d.ts.map +1 -0
- package/dist/showcase.js +210 -0
- package/dist/showcase.js.map +1 -0
- package/dist/side-panel.d.ts +199 -0
- package/dist/side-panel.d.ts.map +1 -0
- package/dist/side-panel.js +111 -0
- package/dist/side-panel.js.map +1 -0
- package/dist/slider.d.ts +138 -0
- package/dist/slider.d.ts.map +1 -0
- package/dist/slider.js +150 -0
- package/dist/slider.js.map +1 -0
- package/dist/splitter.d.ts +113 -0
- package/dist/splitter.d.ts.map +1 -0
- package/dist/splitter.js +99 -0
- package/dist/splitter.js.map +1 -0
- package/dist/statistic.d.ts +41 -0
- package/dist/statistic.d.ts.map +1 -0
- package/dist/statistic.js +76 -0
- package/dist/statistic.js.map +1 -0
- package/dist/steps.d.ts +196 -0
- package/dist/steps.d.ts.map +1 -0
- package/dist/steps.js +160 -0
- package/dist/steps.js.map +1 -0
- package/dist/tag.d.ts +128 -0
- package/dist/tag.d.ts.map +1 -0
- package/dist/tag.js +93 -0
- package/dist/tag.js.map +1 -0
- package/dist/timeline.d.ts +147 -0
- package/dist/timeline.d.ts.map +1 -0
- package/dist/timeline.js +127 -0
- package/dist/timeline.js.map +1 -0
- package/dist/toast.d.ts +164 -0
- package/dist/toast.d.ts.map +1 -0
- package/dist/toast.js +529 -0
- package/dist/toast.js.map +1 -0
- package/dist/tokens.d.ts +9 -0
- package/dist/tokens.d.ts.map +1 -0
- package/dist/tokens.js +9 -0
- package/dist/tokens.js.map +1 -0
- package/dist/tooltip.d.ts +44 -0
- package/dist/tooltip.d.ts.map +1 -0
- package/dist/tooltip.js +88 -0
- package/dist/tooltip.js.map +1 -0
- package/dist/tour.d.ts +218 -0
- package/dist/tour.d.ts.map +1 -0
- package/dist/tour.js +211 -0
- package/dist/tour.js.map +1 -0
- package/dist/transfer-list.d.ts +207 -0
- package/dist/transfer-list.d.ts.map +1 -0
- package/dist/transfer-list.js +193 -0
- package/dist/transfer-list.js.map +1 -0
- package/dist/tree-select.d.ts +78 -0
- package/dist/tree-select.d.ts.map +1 -0
- package/dist/tree-select.js +132 -0
- package/dist/tree-select.js.map +1 -0
- package/dist/tree.d.ts +206 -0
- package/dist/tree.d.ts.map +1 -0
- package/dist/tree.js +223 -0
- package/dist/tree.js.map +1 -0
- package/dist/upload-item.d.ts +173 -0
- package/dist/upload-item.d.ts.map +1 -0
- package/dist/upload-item.js +156 -0
- package/dist/upload-item.js.map +1 -0
- package/dist/version.d.ts +3 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +3 -0
- package/dist/version.js.map +1 -0
- package/docs/affix.md +63 -0
- package/docs/anchor.md +59 -0
- package/docs/ant-design-coverage.md +119 -0
- package/docs/app-provider.md +50 -0
- package/docs/app-rn-adoption.md +227 -0
- package/docs/architecture.md +320 -0
- package/docs/authoring-brief.md +87 -0
- package/docs/border-beam.md +66 -0
- package/docs/bottom-navigation.md +127 -0
- package/docs/breadcrumb.md +82 -0
- package/docs/calendar.md +154 -0
- package/docs/carousel.md +130 -0
- package/docs/cascader.md +93 -0
- package/docs/catalog-decision-status.md +306 -0
- package/docs/color-picker.md +72 -0
- package/docs/command-palette.md +116 -0
- package/docs/confirm-popover.md +93 -0
- package/docs/consistency-audit.md +383 -0
- package/docs/consumer-release-gate.md +90 -0
- package/docs/content-state.md +156 -0
- package/docs/context-panel.md +88 -0
- package/docs/cross-platform-core-normalization.md +118 -0
- package/docs/data-table.md +79 -0
- package/docs/date-picker.md +84 -0
- package/docs/description-list.md +75 -0
- package/docs/design-system-provider.md +139 -0
- package/docs/dropdown.md +78 -0
- package/docs/expansion-roadmap.md +285 -0
- package/docs/file-picker.md +59 -0
- package/docs/floating-action-button.md +111 -0
- package/docs/form.md +134 -0
- package/docs/generated/component-maturity.md +103 -0
- package/docs/generated/renderer-evidence.json +5597 -0
- package/docs/generated/renderer-evidence.md +132 -0
- package/docs/generated/showcase-manifest.json +3732 -0
- package/docs/icon.md +22 -0
- package/docs/identity.md +121 -0
- package/docs/image.md +84 -0
- package/docs/implementation-0.5.md +85 -0
- package/docs/layout-primitives.md +107 -0
- package/docs/layout.md +83 -0
- package/docs/library-reference-decisions.md +123 -0
- package/docs/link.md +67 -0
- package/docs/load-more.md +31 -0
- package/docs/mentions.md +82 -0
- package/docs/migration-0.2.md +108 -0
- package/docs/migration-0.3.md +72 -0
- package/docs/migration-0.5.md +82 -0
- package/docs/migration-0.6.md +197 -0
- package/docs/notification.md +54 -0
- package/docs/number-field.md +82 -0
- package/docs/otp-field.md +103 -0
- package/docs/pagination.md +139 -0
- package/docs/password-field.md +98 -0
- package/docs/popover.md +124 -0
- package/docs/promotion-candidates.md +169 -0
- package/docs/qr-code.md +69 -0
- package/docs/rating.md +58 -0
- package/docs/responsive-grid.md +90 -0
- package/docs/result.md +96 -0
- package/docs/showcase.md +97 -0
- package/docs/side-panel.md +71 -0
- package/docs/slider.md +79 -0
- package/docs/splitter.md +55 -0
- package/docs/statistic.md +16 -0
- package/docs/steps.md +115 -0
- package/docs/tag.md +57 -0
- package/docs/time-picker.md +88 -0
- package/docs/timeline.md +146 -0
- package/docs/toast.md +127 -0
- package/docs/tooltip.md +58 -0
- package/docs/tour.md +136 -0
- package/docs/transfer-list.md +94 -0
- package/docs/tree-select.md +101 -0
- package/docs/tree.md +123 -0
- package/docs/upload-item.md +68 -0
- package/docs/utility.md +53 -0
- package/docs/virtual-list.md +70 -0
- package/docs/watermark.md +58 -0
- package/package.json +402 -0
|
@@ -0,0 +1,972 @@
|
|
|
1
|
+
import { sheetBehaviorDefaults } from "./sheet.js";
|
|
2
|
+
import { loadMoreBehaviorDefaults } from "./load-more.js";
|
|
3
|
+
import { toastBehaviorDefaults } from "./toast.js";
|
|
4
|
+
import { bottomNavigationBehaviorDefaults } from "./bottom-navigation.js";
|
|
5
|
+
import { tooltipBehaviorDefaults } from "./tooltip.js";
|
|
6
|
+
/*
|
|
7
|
+
Batch 2 저작 모듈의 행동 계약. 각 컴포넌트가 자기 모듈에 spec을 두고 레지스트리는
|
|
8
|
+
경로만 모은다 — 여러 저작자가 병렬로 이 파일을 고치면 서로의 변경을 덮어쓴다
|
|
9
|
+
(`docs/authoring-brief.md`).
|
|
10
|
+
*/
|
|
11
|
+
import { breadcrumbBehaviorSpec } from "./breadcrumb.js";
|
|
12
|
+
import { calendarBehavior } from "./calendar.js";
|
|
13
|
+
import { carouselBehavior } from "./carousel.js";
|
|
14
|
+
import { commandPaletteBehaviorScenarios } from "./command-palette.js";
|
|
15
|
+
import { floatingActionButtonBehaviorScenarios } from "./floating-action-button.js";
|
|
16
|
+
import { tourBehaviorScenarios } from "./tour.js";
|
|
17
|
+
import { dataTableBehavior } from "./data-table.js";
|
|
18
|
+
import { layoutBehavior } from "./layout.js";
|
|
19
|
+
import { otpFieldBehavior } from "./otp-field.js";
|
|
20
|
+
import { passwordFieldBehavior } from "./password-field.js";
|
|
21
|
+
import { splitterBehavior } from "./splitter.js";
|
|
22
|
+
import { datePickerBehavior } from "./date-picker.js";
|
|
23
|
+
import { sidePanelBehavior } from "./side-panel.js";
|
|
24
|
+
import { filePickerBehavior } from "./file-picker.js";
|
|
25
|
+
import { paginationBehaviorScenarios } from "./pagination.js";
|
|
26
|
+
import { popoverBehaviorDefaults, popoverBehaviorScenarios } from "./popover.js";
|
|
27
|
+
import { treeBehavior } from "./tree.js";
|
|
28
|
+
import { uploadItemBehavior } from "./upload-item.js";
|
|
29
|
+
import { formBehaviorSpec } from "./form.js";
|
|
30
|
+
import { numberFieldBehavior } from "./number-field.js";
|
|
31
|
+
import { sliderBehavior } from "./slider.js";
|
|
32
|
+
import { checkboxBehaviorDefaults, } from "./selection-helpers.js";
|
|
33
|
+
export { checkboxBehaviorDefaults, getCheckboxNextState, reconcileCheckboxSelection, toggleCheckboxSelection, } from "./selection-helpers.js";
|
|
34
|
+
/** Resolves a renderer's required name while rejecting type-valid blank copy. */
|
|
35
|
+
export function resolveControlAccessibleName(label, accessibilityLabel, controlName = "Control") {
|
|
36
|
+
if (label !== undefined && (typeof label !== "string" || !label.trim())) {
|
|
37
|
+
throw new TypeError(`${controlName} label must not be empty`);
|
|
38
|
+
}
|
|
39
|
+
if (accessibilityLabel !== undefined &&
|
|
40
|
+
(typeof accessibilityLabel !== "string" || !accessibilityLabel.trim())) {
|
|
41
|
+
throw new TypeError(`${controlName} accessibilityLabel must not be empty`);
|
|
42
|
+
}
|
|
43
|
+
const resolved = accessibilityLabel?.trim() || label?.trim();
|
|
44
|
+
if (!resolved) {
|
|
45
|
+
throw new TypeError(`${controlName} needs an accessible name`);
|
|
46
|
+
}
|
|
47
|
+
return resolved;
|
|
48
|
+
}
|
|
49
|
+
export const selectionGroupBehaviorDefaults = {
|
|
50
|
+
orientation: "vertical",
|
|
51
|
+
direction: "ltr",
|
|
52
|
+
};
|
|
53
|
+
export const radioGroupBehaviorDefaults = {
|
|
54
|
+
...selectionGroupBehaviorDefaults,
|
|
55
|
+
loop: true,
|
|
56
|
+
};
|
|
57
|
+
export const selectBehaviorDefaults = {
|
|
58
|
+
disallowEmptySelection: false,
|
|
59
|
+
loop: false,
|
|
60
|
+
};
|
|
61
|
+
export const comboboxBehaviorDefaults = {
|
|
62
|
+
filtering: "local",
|
|
63
|
+
loop: false,
|
|
64
|
+
};
|
|
65
|
+
/** Throws before a renderer can expose ambiguous or unreachable selection state. */
|
|
66
|
+
export function validateSelectionItems(items) {
|
|
67
|
+
const ids = new Set();
|
|
68
|
+
for (const item of items) {
|
|
69
|
+
if (typeof item.id !== "string" || item.id.trim().length === 0) {
|
|
70
|
+
throw new TypeError("Selection item id must not be empty");
|
|
71
|
+
}
|
|
72
|
+
if (typeof item.label !== "string" || item.label.trim().length === 0) {
|
|
73
|
+
throw new TypeError(`Selection item ${item.id} label must not be empty`);
|
|
74
|
+
}
|
|
75
|
+
if (item.description !== undefined &&
|
|
76
|
+
(typeof item.description !== "string" ||
|
|
77
|
+
item.description.trim().length === 0)) {
|
|
78
|
+
throw new TypeError(`Selection item ${item.id} description must not be empty when provided`);
|
|
79
|
+
}
|
|
80
|
+
if (ids.has(item.id)) {
|
|
81
|
+
throw new TypeError(`Duplicate selection item id: ${item.id}`);
|
|
82
|
+
}
|
|
83
|
+
ids.add(item.id);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
export function validateCheckboxSelection(items, current) {
|
|
87
|
+
validateSelectionItems(items);
|
|
88
|
+
const knownIds = new Set(items.map((item) => item.id));
|
|
89
|
+
for (const selectedId of current) {
|
|
90
|
+
if (!knownIds.has(selectedId)) {
|
|
91
|
+
throw new RangeError(`Selected checkbox must exist: ${selectedId}`);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
export function resolveInitialRadioValue(items, requestedValue, required = false) {
|
|
96
|
+
validateSelectionItems(items);
|
|
97
|
+
if (requestedValue != null) {
|
|
98
|
+
if (!items.some((item) => item.id === requestedValue)) {
|
|
99
|
+
throw new RangeError(`Selected radio must exist: ${requestedValue}`);
|
|
100
|
+
}
|
|
101
|
+
return requestedValue;
|
|
102
|
+
}
|
|
103
|
+
return required ? (items.find((item) => !item.disabled)?.id ?? null) : null;
|
|
104
|
+
}
|
|
105
|
+
export function validateRadioSelection(items, current) {
|
|
106
|
+
validateSelectionItems(items);
|
|
107
|
+
if (current != null && !items.some((item) => item.id === current)) {
|
|
108
|
+
throw new RangeError(`Selected radio must exist: ${current}`);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
/** Returns the only enabled radio that may enter the Web tab order. */
|
|
112
|
+
export function resolveRadioTabStop(items, selectedValue) {
|
|
113
|
+
validateSelectionItems(items);
|
|
114
|
+
const selected = items.find((item) => item.id === selectedValue);
|
|
115
|
+
if (selected && !selected.disabled)
|
|
116
|
+
return selected.id;
|
|
117
|
+
return items.find((item) => !item.disabled)?.id;
|
|
118
|
+
}
|
|
119
|
+
/** Reconciles an uncontrolled radio when its selected item leaves the collection. */
|
|
120
|
+
export function reconcileRadioSelection(items, current, required = false) {
|
|
121
|
+
validateSelectionItems(items);
|
|
122
|
+
if (current != null && items.some((item) => item.id === current))
|
|
123
|
+
return current;
|
|
124
|
+
return required ? (items.find((item) => !item.disabled)?.id ?? null) : null;
|
|
125
|
+
}
|
|
126
|
+
export function getSelectionNavigationIntent(key, orientation, direction) {
|
|
127
|
+
if (key === "Home")
|
|
128
|
+
return "first";
|
|
129
|
+
if (key === "End")
|
|
130
|
+
return "last";
|
|
131
|
+
if (orientation === "vertical") {
|
|
132
|
+
if (key === "ArrowDown")
|
|
133
|
+
return "next";
|
|
134
|
+
if (key === "ArrowUp")
|
|
135
|
+
return "previous";
|
|
136
|
+
return undefined;
|
|
137
|
+
}
|
|
138
|
+
if (key === "ArrowRight")
|
|
139
|
+
return direction === "rtl" ? "previous" : "next";
|
|
140
|
+
if (key === "ArrowLeft")
|
|
141
|
+
return direction === "rtl" ? "next" : "previous";
|
|
142
|
+
return undefined;
|
|
143
|
+
}
|
|
144
|
+
export function getRadioNavigationTarget(items, currentId, intent, loop = true) {
|
|
145
|
+
validateSelectionItems(items);
|
|
146
|
+
const enabled = items.filter((item) => !item.disabled);
|
|
147
|
+
if (enabled.length === 0)
|
|
148
|
+
return undefined;
|
|
149
|
+
if (intent === "first")
|
|
150
|
+
return enabled[0]?.id;
|
|
151
|
+
if (intent === "last")
|
|
152
|
+
return enabled.at(-1)?.id;
|
|
153
|
+
const currentIndex = enabled.findIndex((item) => item.id === currentId);
|
|
154
|
+
if (currentIndex < 0)
|
|
155
|
+
return enabled[0]?.id;
|
|
156
|
+
const delta = intent === "next" ? 1 : -1;
|
|
157
|
+
const nextIndex = currentIndex + delta;
|
|
158
|
+
if (!loop && (nextIndex < 0 || nextIndex >= enabled.length))
|
|
159
|
+
return currentId ?? enabled[0]?.id;
|
|
160
|
+
return enabled[(nextIndex + enabled.length) % enabled.length]?.id;
|
|
161
|
+
}
|
|
162
|
+
export function getTabNavigationIntent(key, orientation, direction) {
|
|
163
|
+
if (key === "Home")
|
|
164
|
+
return "first";
|
|
165
|
+
if (key === "End")
|
|
166
|
+
return "last";
|
|
167
|
+
if (orientation === "vertical") {
|
|
168
|
+
if (key === "ArrowDown")
|
|
169
|
+
return "next";
|
|
170
|
+
if (key === "ArrowUp")
|
|
171
|
+
return "previous";
|
|
172
|
+
return undefined;
|
|
173
|
+
}
|
|
174
|
+
if (key === "ArrowRight")
|
|
175
|
+
return direction === "rtl" ? "previous" : "next";
|
|
176
|
+
if (key === "ArrowLeft")
|
|
177
|
+
return direction === "rtl" ? "next" : "previous";
|
|
178
|
+
return undefined;
|
|
179
|
+
}
|
|
180
|
+
/** Validates collection identity and resolves the only safe initial selection. */
|
|
181
|
+
export function resolveInitialTabValue(items, requestedValue) {
|
|
182
|
+
const ids = new Set();
|
|
183
|
+
for (const item of items) {
|
|
184
|
+
if (ids.has(item.id)) {
|
|
185
|
+
throw new TypeError(`Duplicate tab id: ${item.id}`);
|
|
186
|
+
}
|
|
187
|
+
ids.add(item.id);
|
|
188
|
+
}
|
|
189
|
+
if (requestedValue !== undefined) {
|
|
190
|
+
const requested = items.find((item) => item.id === requestedValue);
|
|
191
|
+
if (!requested || requested.disabled) {
|
|
192
|
+
throw new RangeError(`Selected tab must exist and be enabled: ${requestedValue}`);
|
|
193
|
+
}
|
|
194
|
+
return requestedValue;
|
|
195
|
+
}
|
|
196
|
+
return items.find((item) => !item.disabled)?.id;
|
|
197
|
+
}
|
|
198
|
+
/** Shared roving-focus math; renderers still own DOM/native focus APIs. */
|
|
199
|
+
export function getTabNavigationTarget(items, currentId, intent, loop = true) {
|
|
200
|
+
const enabled = items.filter((item) => !item.disabled);
|
|
201
|
+
if (enabled.length === 0)
|
|
202
|
+
return undefined;
|
|
203
|
+
if (intent === "first")
|
|
204
|
+
return enabled[0]?.id;
|
|
205
|
+
if (intent === "last")
|
|
206
|
+
return enabled.at(-1)?.id;
|
|
207
|
+
const currentIndex = enabled.findIndex((item) => item.id === currentId);
|
|
208
|
+
if (currentIndex < 0)
|
|
209
|
+
return enabled[0]?.id;
|
|
210
|
+
const delta = intent === "next" ? 1 : -1;
|
|
211
|
+
const nextIndex = currentIndex + delta;
|
|
212
|
+
if (!loop && (nextIndex < 0 || nextIndex >= enabled.length))
|
|
213
|
+
return currentId;
|
|
214
|
+
return enabled[(nextIndex + enabled.length) % enabled.length]?.id;
|
|
215
|
+
}
|
|
216
|
+
/** Safe behavior defaults: automatic activation is opt-in for instant panels. */
|
|
217
|
+
export const tabsBehaviorDefaults = {
|
|
218
|
+
activationMode: "manual",
|
|
219
|
+
mountPolicy: "active",
|
|
220
|
+
panelMode: "keyed",
|
|
221
|
+
orientation: "horizontal",
|
|
222
|
+
direction: "ltr",
|
|
223
|
+
loop: true,
|
|
224
|
+
};
|
|
225
|
+
/**
|
|
226
|
+
* Behavior is data, not a React implementation. Web/RN renderers can use any
|
|
227
|
+
* suitable primitive while running the same scenarios and exposing the same
|
|
228
|
+
* controlled state names.
|
|
229
|
+
*/
|
|
230
|
+
export const behaviorRegistry = {
|
|
231
|
+
link: {
|
|
232
|
+
controlled: [],
|
|
233
|
+
inputs: ["destination", "label"],
|
|
234
|
+
stateAxes: {
|
|
235
|
+
interaction: ["idle", "hover", "focusVisible", "pressed"],
|
|
236
|
+
},
|
|
237
|
+
web: {
|
|
238
|
+
roles: ["link"],
|
|
239
|
+
keyboard: ["Tab", "Enter"],
|
|
240
|
+
focus: "native",
|
|
241
|
+
},
|
|
242
|
+
native: {
|
|
243
|
+
roles: ["link"],
|
|
244
|
+
states: [],
|
|
245
|
+
actions: ["activate"],
|
|
246
|
+
},
|
|
247
|
+
scenarios: [
|
|
248
|
+
"href-is-the-destination-source-of-truth",
|
|
249
|
+
"web-renders-a-real-anchor-and-preserves-modifier-context-navigation",
|
|
250
|
+
"native-internal-destination-uses-router-link-semantics",
|
|
251
|
+
"native-external-destination-uses-platform-linking-and-reports-failure",
|
|
252
|
+
"link-never-exposes-disabled-action-or-visited-application-state",
|
|
253
|
+
"download-remains-a-separate-platform-workflow",
|
|
254
|
+
"visible-label-owns-one-accessible-name",
|
|
255
|
+
"leading-and-trailing-icons-are-decorative-semantic-icons",
|
|
256
|
+
"logical-icon-direction-follows-rtl",
|
|
257
|
+
"inline-link-has-a-persistent-non-color-cue",
|
|
258
|
+
"standalone-link-target-is-at-least-forty-four-units",
|
|
259
|
+
"destination-link-never-contains-another-interactive-descendant",
|
|
260
|
+
],
|
|
261
|
+
},
|
|
262
|
+
field: {
|
|
263
|
+
controlled: ["value", "defaultValue", "onValueChange"],
|
|
264
|
+
stateAxes: {
|
|
265
|
+
availability: ["enabled", "disabled", "readOnly"],
|
|
266
|
+
validation: ["valid", "invalid"],
|
|
267
|
+
content: ["idle", "loading", "error"],
|
|
268
|
+
},
|
|
269
|
+
web: { roles: ["textbox"], keyboard: ["Tab"], focus: "native" },
|
|
270
|
+
native: { roles: ["text"], states: ["disabled"], actions: ["focus", "setText"] },
|
|
271
|
+
scenarios: ["label-description-error-linkage", "invalid-plus-focus", "disabled-suppresses-edit"],
|
|
272
|
+
},
|
|
273
|
+
searchField: {
|
|
274
|
+
controlled: ["value", "defaultValue", "onValueChange", "onClear"],
|
|
275
|
+
stateAxes: {
|
|
276
|
+
availability: ["enabled", "disabled", "busy"],
|
|
277
|
+
value: ["empty", "filled"],
|
|
278
|
+
validation: ["valid", "invalid"],
|
|
279
|
+
content: ["idle", "loading", "error"],
|
|
280
|
+
},
|
|
281
|
+
web: { roles: ["searchbox", "button"], keyboard: ["Tab", "Enter"], focus: "native" },
|
|
282
|
+
native: { roles: ["text", "button"], states: ["disabled", "busy"], actions: ["focus", "setText", "clear"] },
|
|
283
|
+
scenarios: ["clear-has-name", "empty-hides-clear", "invalid-plus-focus", "busy-preserves-query"],
|
|
284
|
+
},
|
|
285
|
+
checkbox: {
|
|
286
|
+
controlled: ["checked", "defaultChecked", "onCheckedChange"],
|
|
287
|
+
configuration: { mixedActivation: ["check", "uncheck"] },
|
|
288
|
+
defaults: checkboxBehaviorDefaults,
|
|
289
|
+
stateAxes: {
|
|
290
|
+
availability: ["enabled", "disabled", "readOnly"],
|
|
291
|
+
value: ["checked", "mixed"],
|
|
292
|
+
validation: ["valid", "invalid"],
|
|
293
|
+
},
|
|
294
|
+
web: { roles: ["checkbox"], keyboard: ["Tab", "Space"], focus: "native" },
|
|
295
|
+
native: {
|
|
296
|
+
roles: ["checkbox"],
|
|
297
|
+
states: ["disabled", "checked"],
|
|
298
|
+
actions: ["activate"],
|
|
299
|
+
},
|
|
300
|
+
scenarios: [
|
|
301
|
+
"visible-label-is-accessible-name",
|
|
302
|
+
"mixed-is-announced-and-activates-to-default",
|
|
303
|
+
"disabled-and-read-only-suppress-change",
|
|
304
|
+
"controlled-value-never-mutates-internally",
|
|
305
|
+
"required-and-invalid-support-are-linked",
|
|
306
|
+
],
|
|
307
|
+
},
|
|
308
|
+
checkboxGroup: {
|
|
309
|
+
controlled: ["value", "defaultValue", "onValueChange"],
|
|
310
|
+
configuration: {
|
|
311
|
+
orientation: ["horizontal", "vertical"],
|
|
312
|
+
direction: ["ltr", "rtl"],
|
|
313
|
+
},
|
|
314
|
+
defaults: selectionGroupBehaviorDefaults,
|
|
315
|
+
stateAxes: {
|
|
316
|
+
availability: ["enabled", "disabled", "readOnly"],
|
|
317
|
+
value: ["checked"],
|
|
318
|
+
validation: ["valid", "invalid"],
|
|
319
|
+
},
|
|
320
|
+
web: {
|
|
321
|
+
roles: ["group", "checkbox"],
|
|
322
|
+
keyboard: ["Tab", "Space"],
|
|
323
|
+
focus: "native",
|
|
324
|
+
},
|
|
325
|
+
native: {
|
|
326
|
+
roles: ["checkbox"],
|
|
327
|
+
states: ["disabled", "checked"],
|
|
328
|
+
actions: ["activate"],
|
|
329
|
+
},
|
|
330
|
+
scenarios: [
|
|
331
|
+
"each-enabled-checkbox-is-a-tab-stop",
|
|
332
|
+
"space-toggles-only-focused-checkbox",
|
|
333
|
+
"group-label-description-and-error-are-linked",
|
|
334
|
+
"disabled-selected-item-is-retained-but-not-activated",
|
|
335
|
+
"change-emits-a-fresh-set",
|
|
336
|
+
"duplicate-and-unknown-ids-are-rejected",
|
|
337
|
+
"uncontrolled-selection-reconciles-collection-mutation",
|
|
338
|
+
"required-and-invalid-are-announced",
|
|
339
|
+
"no-nested-interactive-descendants",
|
|
340
|
+
],
|
|
341
|
+
},
|
|
342
|
+
radioGroup: {
|
|
343
|
+
controlled: ["value", "defaultValue", "onValueChange"],
|
|
344
|
+
configuration: {
|
|
345
|
+
orientation: ["horizontal", "vertical"],
|
|
346
|
+
direction: ["ltr", "rtl"],
|
|
347
|
+
loop: ["true", "false"],
|
|
348
|
+
},
|
|
349
|
+
defaults: radioGroupBehaviorDefaults,
|
|
350
|
+
stateAxes: {
|
|
351
|
+
availability: ["enabled", "disabled", "readOnly"],
|
|
352
|
+
value: ["checked", "selected"],
|
|
353
|
+
validation: ["valid", "invalid"],
|
|
354
|
+
},
|
|
355
|
+
web: {
|
|
356
|
+
roles: ["radiogroup", "radio"],
|
|
357
|
+
keyboard: [
|
|
358
|
+
"Tab",
|
|
359
|
+
"Space",
|
|
360
|
+
"ArrowUp",
|
|
361
|
+
"ArrowDown",
|
|
362
|
+
"ArrowLeft",
|
|
363
|
+
"ArrowRight",
|
|
364
|
+
"Home",
|
|
365
|
+
"End",
|
|
366
|
+
],
|
|
367
|
+
focus: "roving",
|
|
368
|
+
},
|
|
369
|
+
native: {
|
|
370
|
+
roles: ["radio"],
|
|
371
|
+
states: ["disabled", "checked"],
|
|
372
|
+
actions: ["activate"],
|
|
373
|
+
},
|
|
374
|
+
scenarios: [
|
|
375
|
+
"at-most-one-selection-and-nullable-initial-value",
|
|
376
|
+
"checked-or-first-enabled-is-the-only-tab-stop",
|
|
377
|
+
"arrow-focuses-and-selects-while-skipping-disabled",
|
|
378
|
+
"orientation-direction-and-loop-control-navigation",
|
|
379
|
+
"space-selects-focused-radio",
|
|
380
|
+
"group-label-description-and-error-are-linked",
|
|
381
|
+
"disabled-selected-item-is-retained-with-enabled-tab-stop",
|
|
382
|
+
"required-invalid-and-read-only-are-announced",
|
|
383
|
+
"controlled-value-never-mutates-internally",
|
|
384
|
+
"duplicate-and-unknown-ids-are-rejected",
|
|
385
|
+
],
|
|
386
|
+
},
|
|
387
|
+
switch: {
|
|
388
|
+
controlled: ["checked", "defaultChecked", "onCheckedChange"],
|
|
389
|
+
stateAxes: { availability: ["enabled", "disabled"], value: ["checked"] },
|
|
390
|
+
web: { roles: ["switch"], keyboard: ["Tab", "Space"], focus: "native" },
|
|
391
|
+
native: { roles: ["switch"], states: ["disabled", "checked"], actions: ["activate"] },
|
|
392
|
+
scenarios: ["row-and-control-are-one-target", "checked-announced", "disabled-suppresses-change"],
|
|
393
|
+
},
|
|
394
|
+
segmentedControl: {
|
|
395
|
+
controlled: ["value", "defaultValue", "onValueChange"],
|
|
396
|
+
stateAxes: { availability: ["enabled", "disabled"], value: ["selected"] },
|
|
397
|
+
web: { roles: ["radiogroup", "radio"], keyboard: ["Tab", "ArrowLeft", "ArrowRight", "ArrowUp", "ArrowDown", "Home", "End"], focus: "roving" },
|
|
398
|
+
native: { roles: ["radio"], states: ["disabled", "checked"], actions: ["activate"] },
|
|
399
|
+
scenarios: ["exactly-one-selected", "one-tab-stop", "arrow-selection", "selected-plus-focus"],
|
|
400
|
+
},
|
|
401
|
+
chip: {
|
|
402
|
+
controlled: ["selected", "onPress"],
|
|
403
|
+
stateAxes: {
|
|
404
|
+
availability: ["enabled", "disabled"],
|
|
405
|
+
value: ["selected"],
|
|
406
|
+
},
|
|
407
|
+
web: {
|
|
408
|
+
roles: ["button", "radio", "checkbox"],
|
|
409
|
+
keyboard: ["Tab", "Enter", "Space"],
|
|
410
|
+
focus: "native",
|
|
411
|
+
},
|
|
412
|
+
native: {
|
|
413
|
+
roles: ["button", "radio", "checkbox"],
|
|
414
|
+
states: ["disabled", "checked"],
|
|
415
|
+
actions: ["activate"],
|
|
416
|
+
},
|
|
417
|
+
scenarios: [
|
|
418
|
+
"action-never-exposes-selection",
|
|
419
|
+
"single-selection-uses-radio-checked",
|
|
420
|
+
"multiple-selection-uses-checkbox-checked",
|
|
421
|
+
"selected-plus-focus",
|
|
422
|
+
"selection-indicator-is-not-color-only",
|
|
423
|
+
"single-mode-composes-radio-group-behavior",
|
|
424
|
+
"multiple-mode-composes-checkbox-group-behavior",
|
|
425
|
+
],
|
|
426
|
+
},
|
|
427
|
+
tabs: {
|
|
428
|
+
controlled: ["value", "defaultValue", "onValueChange"],
|
|
429
|
+
configuration: {
|
|
430
|
+
activationMode: ["automatic", "manual"],
|
|
431
|
+
mountPolicy: ["active", "visited", "always"],
|
|
432
|
+
panelMode: ["keyed", "dynamic"],
|
|
433
|
+
orientation: ["horizontal", "vertical"],
|
|
434
|
+
direction: ["ltr", "rtl"],
|
|
435
|
+
loop: ["true", "false"],
|
|
436
|
+
},
|
|
437
|
+
defaults: tabsBehaviorDefaults,
|
|
438
|
+
stateAxes: { availability: ["enabled", "disabled"], value: ["selected"] },
|
|
439
|
+
web: { roles: ["tablist", "tab", "tabpanel"], keyboard: ["Tab", "Enter", "Space", "ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight", "Home", "End"], focus: "roving" },
|
|
440
|
+
native: { roles: ["tab"], states: ["disabled", "selected"], actions: ["activate"] },
|
|
441
|
+
scenarios: [
|
|
442
|
+
"tab-controls-panel",
|
|
443
|
+
"one-tab-stop",
|
|
444
|
+
"disabled-tab-skipped",
|
|
445
|
+
"selected-plus-focus",
|
|
446
|
+
"automatic-activation-only-for-instant-panels",
|
|
447
|
+
"manual-activation-keeps-focus-and-selection-distinct",
|
|
448
|
+
"active-mount-removes-inactive-panel",
|
|
449
|
+
"always-mount-makes-inactive-panels-inert",
|
|
450
|
+
"visited-mount-preserves-visited-panel-state",
|
|
451
|
+
"horizontal-arrows-do-not-consume-up-down",
|
|
452
|
+
"vertical-arrows-and-aria-orientation",
|
|
453
|
+
"web-tablist-has-accessible-name",
|
|
454
|
+
"every-tab-controls-an-existing-panel",
|
|
455
|
+
"active-panel-labelled-by-selected-tab",
|
|
456
|
+
"manual-focus-does-not-relabel-dynamic-panel",
|
|
457
|
+
"dynamic-panel-preserves-host-instance",
|
|
458
|
+
"dynamic-panel-requires-active-mount",
|
|
459
|
+
"panel-enters-tab-order-when-content-has-no-focus-target",
|
|
460
|
+
"rtl-navigation-follows-logical-direction",
|
|
461
|
+
"first-enabled-tab-is-uncontrolled-default",
|
|
462
|
+
"duplicate-and-disabled-selection-are-rejected",
|
|
463
|
+
"controlled-selection-never-mutates-internally",
|
|
464
|
+
"native-focus-does-not-select-without-activate",
|
|
465
|
+
"inactive-mounted-panels-are-hidden-and-inert",
|
|
466
|
+
"uncontrolled-selection-reconciles-collection-mutation",
|
|
467
|
+
],
|
|
468
|
+
},
|
|
469
|
+
bottomNavigation: {
|
|
470
|
+
controlled: [],
|
|
471
|
+
inputs: ["items", "selectedKey", "accessibilityLabel"],
|
|
472
|
+
events: ["onActivate", "onLongPress"],
|
|
473
|
+
configuration: {
|
|
474
|
+
direction: ["ltr", "rtl"],
|
|
475
|
+
keyboardBehavior: ["hide", "remain"],
|
|
476
|
+
},
|
|
477
|
+
defaults: bottomNavigationBehaviorDefaults,
|
|
478
|
+
stateAxes: {
|
|
479
|
+
interaction: ["idle", "hover", "focusVisible", "pressed"],
|
|
480
|
+
availability: ["enabled", "disabled"],
|
|
481
|
+
value: ["selected"],
|
|
482
|
+
},
|
|
483
|
+
web: {
|
|
484
|
+
roles: ["navigation", "list", "link"],
|
|
485
|
+
keyboard: ["Tab", "Enter"],
|
|
486
|
+
focus: "native",
|
|
487
|
+
},
|
|
488
|
+
native: {
|
|
489
|
+
roles: ["tab", "button"],
|
|
490
|
+
states: ["disabled", "selected"],
|
|
491
|
+
actions: ["activate", "longpress"],
|
|
492
|
+
},
|
|
493
|
+
scenarios: [
|
|
494
|
+
"two-to-five-stable-top-level-destinations",
|
|
495
|
+
"router-selected-key-is-read-only-input",
|
|
496
|
+
"activation-does-not-select-before-router-commit",
|
|
497
|
+
"prevented-or-failed-navigation-keeps-current-selection",
|
|
498
|
+
"reselect-is-distinct-from-navigation",
|
|
499
|
+
"navigator-preserves-each-destination-state",
|
|
500
|
+
"disabled-destination-suppresses-activation",
|
|
501
|
+
"visible-label-always-names-a-decorative-icon",
|
|
502
|
+
"selected-state-uses-icon-emphasis-and-label-weight-not-color-alone",
|
|
503
|
+
"selected-content-and-focus-indicator-remain-simultaneously-visible",
|
|
504
|
+
"centered-sibling-action-is-excluded-from-destination-collection",
|
|
505
|
+
"badge-zero-is-hidden-and-visible-count-is-bounded",
|
|
506
|
+
"badge-subtree-is-hidden-and-item-uses-one-resolved-accessibility-name",
|
|
507
|
+
"badge-update-does-not-change-focus-selection-or-live-announce",
|
|
508
|
+
"web-uses-a-labelled-navigation-landmark-and-real-links",
|
|
509
|
+
"web-current-link-uses-aria-current-page",
|
|
510
|
+
"web-preserves-modifier-click-and-does-not-use-tab-roles-or-roving-focus",
|
|
511
|
+
"native-emits-tab-press-and-respects-default-prevented-before-navigation",
|
|
512
|
+
"native-forwards-tab-long-press",
|
|
513
|
+
"native-ios-may-use-button-plus-selected-when-tab-role-is-not-reliably-supported",
|
|
514
|
+
"safe-area-padding-is-additive",
|
|
515
|
+
"software-keyboard-hides-instead-of-lifting-the-navigation",
|
|
516
|
+
"two-hundred-percent-text-wraps-without-fixed-item-height",
|
|
517
|
+
"rtl-order-and-badge-anchor-follow-logical-direction",
|
|
518
|
+
"targets-are-at-least-forty-four-units",
|
|
519
|
+
"reduced-motion-removes-transform-without-changing-state",
|
|
520
|
+
],
|
|
521
|
+
},
|
|
522
|
+
disclosureGroup: {
|
|
523
|
+
controlled: ["expandedKeys", "defaultExpandedKeys", "onExpandedChange"],
|
|
524
|
+
stateAxes: { availability: ["enabled", "disabled"], value: ["expanded"] },
|
|
525
|
+
web: { roles: ["heading", "button", "region"], keyboard: ["Tab", "Enter", "Space", "ArrowUp", "ArrowDown", "Home", "End"], focus: "native" },
|
|
526
|
+
native: { roles: ["button"], states: ["disabled", "expanded"], actions: ["activate"] },
|
|
527
|
+
scenarios: [
|
|
528
|
+
"single-and-multiple-invariants",
|
|
529
|
+
"each-enabled-trigger-is-a-tab-stop",
|
|
530
|
+
"toggle-keeps-trigger-focus",
|
|
531
|
+
"panel-removed-when-collapsed",
|
|
532
|
+
"disabled-trigger-suppresses-change",
|
|
533
|
+
"reduced-motion",
|
|
534
|
+
],
|
|
535
|
+
},
|
|
536
|
+
menu: {
|
|
537
|
+
controlled: [
|
|
538
|
+
"open",
|
|
539
|
+
"defaultOpen",
|
|
540
|
+
"onOpenChange",
|
|
541
|
+
"onAction",
|
|
542
|
+
"onActionAfterDismiss",
|
|
543
|
+
"selection",
|
|
544
|
+
"asyncState",
|
|
545
|
+
],
|
|
546
|
+
stateAxes: { availability: ["enabled", "disabled"], value: ["open", "selected"], content: ["idle", "loading", "loadingMore", "empty", "error"] },
|
|
547
|
+
web: { roles: ["menu", "menuitem", "menuitemradio", "menuitemcheckbox"], keyboard: ["Enter", "Space", "Escape", "ArrowUp", "ArrowDown", "Home", "End", "Typeahead"], focus: "restore", dismiss: ["escape", "outside", "selection"] },
|
|
548
|
+
native: { roles: ["menu", "menuitem"], states: ["disabled", "selected", "checked"], actions: ["activate"], dismiss: ["back", "outside", "selection"] },
|
|
549
|
+
scenarios: [
|
|
550
|
+
"action-and-single-close-after-selection",
|
|
551
|
+
"on-action-does-not-depend-on-controlled-close",
|
|
552
|
+
"after-dismiss-action-sequences-next-surface",
|
|
553
|
+
"multiple-selection-keeps-menu-open",
|
|
554
|
+
"disabled-item-skipped",
|
|
555
|
+
"escape-or-back-restores-trigger",
|
|
556
|
+
"danger-item-not-color-only",
|
|
557
|
+
"loading-more-preserves-items-and-selection",
|
|
558
|
+
],
|
|
559
|
+
},
|
|
560
|
+
dialog: {
|
|
561
|
+
controlled: ["open", "defaultOpen", "onOpenChange"],
|
|
562
|
+
stateAxes: { availability: ["enabled", "busy"], value: ["open"] },
|
|
563
|
+
web: { roles: ["dialog"], keyboard: ["Tab", "Escape"], focus: "trap", dismiss: ["escape", "outside"] },
|
|
564
|
+
native: { roles: ["dialog"], states: ["busy"], actions: ["dismiss"], dismiss: ["back", "outside"] },
|
|
565
|
+
scenarios: ["title-description-linkage", "focus-trap-and-restore", "modal-isolation", "single-dismiss-callback"],
|
|
566
|
+
},
|
|
567
|
+
alertDialog: {
|
|
568
|
+
controlled: ["open", "defaultOpen", "onOpenChange"],
|
|
569
|
+
stateAxes: { availability: ["enabled", "busy"], value: ["open"], content: ["idle", "loading", "error"] },
|
|
570
|
+
web: { roles: ["alertdialog"], keyboard: ["Tab", "Escape"], focus: "trap", dismiss: ["escape"] },
|
|
571
|
+
native: { roles: ["alertdialog"], states: ["busy"], actions: ["confirm", "cancel"], dismiss: ["back"] },
|
|
572
|
+
scenarios: [
|
|
573
|
+
"visible-title-and-description-are-announced",
|
|
574
|
+
"modal-isolation-and-tab-trap",
|
|
575
|
+
"confirm-mode-cancel-is-initial-focus",
|
|
576
|
+
"alert-mode-confirm-is-initial-focus",
|
|
577
|
+
"outside-attempt-is-ignored-without-callback",
|
|
578
|
+
"escape-or-back-cancels-when-idle",
|
|
579
|
+
"busy-blocks-every-dismiss-and-duplicate-confirm",
|
|
580
|
+
"confirm-action-runs-once",
|
|
581
|
+
"error-is-announced-and-dialog-stays-open",
|
|
582
|
+
"controlled-close-settles-programmatic-cancel",
|
|
583
|
+
"unmount-settles-interrupted",
|
|
584
|
+
"result-settles-once-after-exit",
|
|
585
|
+
"focus-restores-after-every-close-path",
|
|
586
|
+
"reduced-motion-still-completes-exit",
|
|
587
|
+
],
|
|
588
|
+
},
|
|
589
|
+
sheet: {
|
|
590
|
+
controlled: ["open", "defaultOpen", "onOpenChange", "dismissPolicy"],
|
|
591
|
+
defaults: sheetBehaviorDefaults,
|
|
592
|
+
stateAxes: { availability: ["enabled", "busy"], value: ["open"] },
|
|
593
|
+
web: { roles: ["dialog"], keyboard: ["Tab", "Escape"], focus: "trap", dismiss: ["escape", "outside"] },
|
|
594
|
+
native: { roles: ["dialog"], states: ["busy"], actions: ["dismiss"], dismiss: ["back", "outside"] },
|
|
595
|
+
scenarios: [
|
|
596
|
+
"focus-or-modal-isolation",
|
|
597
|
+
"scroll-lock",
|
|
598
|
+
"safe-area",
|
|
599
|
+
"single-dismiss-callback",
|
|
600
|
+
"busy-blocks-dismiss",
|
|
601
|
+
"dismiss-reason-is-reported",
|
|
602
|
+
"programmatic-owner-close-is-always-allowed",
|
|
603
|
+
"swipe-requires-enabled-policy-and-gesture-capability",
|
|
604
|
+
"successor-surface-opens-after-exit",
|
|
605
|
+
"nested-modal-surfaces-are-forbidden",
|
|
606
|
+
"reduced-motion-still-completes-dismiss",
|
|
607
|
+
],
|
|
608
|
+
},
|
|
609
|
+
select: {
|
|
610
|
+
controlled: [
|
|
611
|
+
"selectedKey",
|
|
612
|
+
"defaultSelectedKey",
|
|
613
|
+
"onSelectionChange",
|
|
614
|
+
"open",
|
|
615
|
+
"defaultOpen",
|
|
616
|
+
"onOpenChange",
|
|
617
|
+
],
|
|
618
|
+
inputs: ["asyncState", "selectedItem"],
|
|
619
|
+
configuration: {
|
|
620
|
+
disallowEmptySelection: ["true", "false"],
|
|
621
|
+
loop: ["true", "false"],
|
|
622
|
+
},
|
|
623
|
+
defaults: selectBehaviorDefaults,
|
|
624
|
+
stateAxes: {
|
|
625
|
+
availability: ["enabled", "disabled", "readOnly", "busy"],
|
|
626
|
+
value: ["empty", "selected", "open"],
|
|
627
|
+
validation: ["valid", "invalid"],
|
|
628
|
+
content: ["idle", "loading", "loadingMore", "empty", "error"],
|
|
629
|
+
},
|
|
630
|
+
web: {
|
|
631
|
+
roles: ["combobox", "listbox", "option"],
|
|
632
|
+
keyboard: [
|
|
633
|
+
"Tab",
|
|
634
|
+
"Enter",
|
|
635
|
+
"Space",
|
|
636
|
+
"Escape",
|
|
637
|
+
"ArrowUp",
|
|
638
|
+
"ArrowDown",
|
|
639
|
+
"Home",
|
|
640
|
+
"End",
|
|
641
|
+
"Typeahead",
|
|
642
|
+
],
|
|
643
|
+
focus: "activeDescendant",
|
|
644
|
+
dismiss: ["selection", "escape", "outside", "blur"],
|
|
645
|
+
},
|
|
646
|
+
native: {
|
|
647
|
+
roles: ["button", "dialog", "radio"],
|
|
648
|
+
states: ["disabled", "checked", "busy", "expanded"],
|
|
649
|
+
actions: ["activate", "dismiss"],
|
|
650
|
+
dismiss: ["selection", "back", "outside"],
|
|
651
|
+
},
|
|
652
|
+
scenarios: [
|
|
653
|
+
"visible-label-or-accessibility-label-names-trigger",
|
|
654
|
+
"collection-ids-and-text-values-are-validated",
|
|
655
|
+
"highlighted-option-is-distinct-from-committed-selection",
|
|
656
|
+
"trigger-controls-the-mounted-listbox",
|
|
657
|
+
"active-descendant-references-a-mounted-option",
|
|
658
|
+
"active-option-scrolls-into-view",
|
|
659
|
+
"disabled-options-are-skipped",
|
|
660
|
+
"escape-closes-without-commit",
|
|
661
|
+
"selection-requests-close-and-restores-trigger-focus",
|
|
662
|
+
"controlled-owner-may-defer-a-selection-close-request",
|
|
663
|
+
"removed-selection-is-reconciled",
|
|
664
|
+
"loading-more-preserves-options-and-selection",
|
|
665
|
+
"transient-async-pages-preserve-committed-key-and-copy",
|
|
666
|
+
"empty-error-and-loading-are-announced",
|
|
667
|
+
"options-have-no-nested-interactive-descendants",
|
|
668
|
+
],
|
|
669
|
+
},
|
|
670
|
+
combobox: {
|
|
671
|
+
controlled: [
|
|
672
|
+
"selectedKey",
|
|
673
|
+
"defaultSelectedKey",
|
|
674
|
+
"onSelectionChange",
|
|
675
|
+
"inputValue",
|
|
676
|
+
"defaultInputValue",
|
|
677
|
+
"onInputValueChange",
|
|
678
|
+
"open",
|
|
679
|
+
"defaultOpen",
|
|
680
|
+
"onOpenChange",
|
|
681
|
+
],
|
|
682
|
+
inputs: ["asyncState", "queryValue", "resultQuery", "selectedItem"],
|
|
683
|
+
events: ["onCommit"],
|
|
684
|
+
configuration: {
|
|
685
|
+
filtering: ["local", "external"],
|
|
686
|
+
loop: ["true", "false"],
|
|
687
|
+
},
|
|
688
|
+
defaults: comboboxBehaviorDefaults,
|
|
689
|
+
stateAxes: {
|
|
690
|
+
availability: ["enabled", "disabled", "readOnly", "busy"],
|
|
691
|
+
value: ["empty", "filled", "selected", "open"],
|
|
692
|
+
validation: ["valid", "invalid"],
|
|
693
|
+
content: ["idle", "loading", "loadingMore", "empty", "error"],
|
|
694
|
+
},
|
|
695
|
+
web: {
|
|
696
|
+
roles: ["combobox", "listbox", "option"],
|
|
697
|
+
keyboard: [
|
|
698
|
+
"Tab",
|
|
699
|
+
"Enter",
|
|
700
|
+
"Escape",
|
|
701
|
+
"ArrowUp",
|
|
702
|
+
"ArrowDown",
|
|
703
|
+
"Home",
|
|
704
|
+
"End",
|
|
705
|
+
],
|
|
706
|
+
focus: "activeDescendant",
|
|
707
|
+
dismiss: ["selection", "escape", "outside", "blur"],
|
|
708
|
+
},
|
|
709
|
+
native: {
|
|
710
|
+
roles: ["button", "text", "dialog", "radio"],
|
|
711
|
+
states: ["disabled", "checked", "busy", "expanded"],
|
|
712
|
+
actions: ["focus", "setText", "activate", "dismiss"],
|
|
713
|
+
dismiss: ["selection", "back", "outside"],
|
|
714
|
+
},
|
|
715
|
+
scenarios: [
|
|
716
|
+
"selected-key-and-input-value-are-independent",
|
|
717
|
+
"input-focus-and-active-option-are-distinct",
|
|
718
|
+
"input-controls-the-mounted-listbox",
|
|
719
|
+
"active-descendant-references-a-mounted-option",
|
|
720
|
+
"active-option-scrolls-into-view",
|
|
721
|
+
"ime-composition-does-not-prematurely-filter-or-commit",
|
|
722
|
+
"escape-restores-the-committed-label",
|
|
723
|
+
"query-edit-never-commits-a-stale-selection",
|
|
724
|
+
"external-results-do-not-implicitly-commit",
|
|
725
|
+
"committed-item-survives-transient-result-pages",
|
|
726
|
+
"stale-external-results-do-not-replace-current-query",
|
|
727
|
+
"loading-more-preserves-options-and-active-descendant",
|
|
728
|
+
"empty-error-and-loading-are-announced",
|
|
729
|
+
"custom-values-are-rejected-without-an-explicit-policy",
|
|
730
|
+
"selection-state-updates-before-commit-event-and-close-request",
|
|
731
|
+
"options-have-no-nested-interactive-descendants",
|
|
732
|
+
],
|
|
733
|
+
},
|
|
734
|
+
toast: {
|
|
735
|
+
controlled: [],
|
|
736
|
+
inputs: ["descriptor", "queueSnapshot", "visibleSnapshot"],
|
|
737
|
+
events: ["onAction", "onDismiss"],
|
|
738
|
+
configuration: {
|
|
739
|
+
priority: ["normal", "high"],
|
|
740
|
+
duplicatePolicy: ["update", "ignore"],
|
|
741
|
+
timerUpdatePolicy: ["preserve", "restart"],
|
|
742
|
+
overflowPolicy: ["discard-oldest", "discard-newest"],
|
|
743
|
+
},
|
|
744
|
+
defaults: toastBehaviorDefaults,
|
|
745
|
+
stateAxes: {
|
|
746
|
+
value: ["open"],
|
|
747
|
+
content: ["idle"],
|
|
748
|
+
},
|
|
749
|
+
web: {
|
|
750
|
+
roles: ["region", "status", "alert", "button"],
|
|
751
|
+
keyboard: ["Tab", "Enter", "Space", "Escape", "F8"],
|
|
752
|
+
focus: "native",
|
|
753
|
+
dismiss: ["timeout", "action", "close-action", "escape", "swipe", "programmatic"],
|
|
754
|
+
},
|
|
755
|
+
native: {
|
|
756
|
+
roles: ["alert", "button"],
|
|
757
|
+
states: [],
|
|
758
|
+
actions: ["announce", "activate", "dismiss"],
|
|
759
|
+
dismiss: ["timeout", "action", "close-action", "swipe", "programmatic"],
|
|
760
|
+
},
|
|
761
|
+
scenarios: [
|
|
762
|
+
"stable-id-duplicate-updates-in-place-without-reordering",
|
|
763
|
+
"bounded-queue-promotes-items-in-fifo-order",
|
|
764
|
+
"queued-time-never-consumes-auto-dismiss-duration",
|
|
765
|
+
"visible-timer-pauses-for-pointer-focus-window-and-gesture",
|
|
766
|
+
"actionable-toast-is-persistent-unless-duration-is-explicit",
|
|
767
|
+
"auto-dismiss-duration-is-never-shorter-than-five-seconds",
|
|
768
|
+
"action-and-dismiss-callbacks-run-exactly-once",
|
|
769
|
+
"programmatic-close-reports-its-own-dismiss-reason",
|
|
770
|
+
"normal-and-high-announcements-use-the-visible-copy-or-explicit-override",
|
|
771
|
+
"tone-is-always-paired-with-a-non-color-mark",
|
|
772
|
+
"web-hotkey-focuses-the-labelled-viewport-and-last-close-restores-focus",
|
|
773
|
+
"exit-completes-once-with-and-without-reduced-motion",
|
|
774
|
+
"provider-teardown-interrupts-every-session-without-leaking-a-timer",
|
|
775
|
+
],
|
|
776
|
+
},
|
|
777
|
+
loadMore: {
|
|
778
|
+
controlled: [],
|
|
779
|
+
inputs: ["state", "labels"],
|
|
780
|
+
events: ["onLoadMore"],
|
|
781
|
+
configuration: { mode: ["automatic", "manual"] },
|
|
782
|
+
defaults: loadMoreBehaviorDefaults,
|
|
783
|
+
stateAxes: {
|
|
784
|
+
availability: ["enabled", "busy"],
|
|
785
|
+
content: ["idle", "loadingMore", "error", "complete"],
|
|
786
|
+
},
|
|
787
|
+
web: {
|
|
788
|
+
roles: ["status", "alert", "button"],
|
|
789
|
+
keyboard: ["Tab", "Enter", "Space"],
|
|
790
|
+
focus: "native",
|
|
791
|
+
},
|
|
792
|
+
native: {
|
|
793
|
+
roles: ["progressbar", "alert", "button"],
|
|
794
|
+
states: ["busy", "disabled"],
|
|
795
|
+
actions: ["activate"],
|
|
796
|
+
},
|
|
797
|
+
scenarios: [
|
|
798
|
+
"existing-items-remain-mounted-in-every-footer-state",
|
|
799
|
+
"automatic-viewport-request-has-an-accessible-manual-fallback",
|
|
800
|
+
"one-request-is-in-flight-per-controller",
|
|
801
|
+
"same-request-key-is-never-issued-twice-concurrently",
|
|
802
|
+
"loading-and-complete-states-block-new-requests",
|
|
803
|
+
"error-state-retries-only-with-retry-reason",
|
|
804
|
+
"loading-status-and-error-alert-announce-once",
|
|
805
|
+
"retry-and-manual-targets-are-at-least-forty-four-units",
|
|
806
|
+
],
|
|
807
|
+
},
|
|
808
|
+
tooltip: {
|
|
809
|
+
controlled: ["open", "defaultOpen", "onOpenChange"],
|
|
810
|
+
inputs: ["content"],
|
|
811
|
+
configuration: {
|
|
812
|
+
placement: ["top", "bottom", "start", "end"],
|
|
813
|
+
align: ["start", "center", "end"],
|
|
814
|
+
},
|
|
815
|
+
defaults: tooltipBehaviorDefaults,
|
|
816
|
+
stateAxes: {
|
|
817
|
+
interaction: ["idle", "hover", "focusVisible"],
|
|
818
|
+
value: ["open"],
|
|
819
|
+
},
|
|
820
|
+
web: {
|
|
821
|
+
roles: ["tooltip"],
|
|
822
|
+
keyboard: ["Tab", "Escape"],
|
|
823
|
+
focus: "none",
|
|
824
|
+
dismiss: ["escape", "blur"],
|
|
825
|
+
},
|
|
826
|
+
native: { roles: [], states: [], actions: [] },
|
|
827
|
+
scenarios: [
|
|
828
|
+
"plain-localized-copy-never-contains-interaction",
|
|
829
|
+
"keyboard-focus-opens-immediately-and-pointer-respects-delay",
|
|
830
|
+
"recent-sibling-tooltip-uses-skip-delay",
|
|
831
|
+
"one-tooltip-is-visible-per-provider",
|
|
832
|
+
"trigger-content-hover-and-pointer-corridor-keep-open",
|
|
833
|
+
"escape-dismisses-and-suppresses-reopen-until-input-reset",
|
|
834
|
+
"blur-or-pointer-leave-closes-only-after-all-active-inputs-end",
|
|
835
|
+
"trigger-activation-closes-without-cancelling-trigger-action",
|
|
836
|
+
"trigger-keeps-focus-and-tooltip-has-no-tab-stop",
|
|
837
|
+
"existing-aria-describedby-is-preserved",
|
|
838
|
+
"touch-pointer-hover-is-ignored",
|
|
839
|
+
"controlled-close-rejection-never-exposes-two-tooltips",
|
|
840
|
+
"timer-and-global-listener-cleanup-on-unmount",
|
|
841
|
+
"reduced-motion-exit-completes-exactly-once",
|
|
842
|
+
],
|
|
843
|
+
},
|
|
844
|
+
breadcrumb: breadcrumbBehaviorSpec,
|
|
845
|
+
calendar: calendarBehavior,
|
|
846
|
+
carousel: carouselBehavior,
|
|
847
|
+
commandPalette: {
|
|
848
|
+
controlled: [
|
|
849
|
+
"open",
|
|
850
|
+
"defaultOpen",
|
|
851
|
+
"onOpenChange",
|
|
852
|
+
"inputValue",
|
|
853
|
+
"defaultInputValue",
|
|
854
|
+
"onInputValueChange",
|
|
855
|
+
],
|
|
856
|
+
inputs: ["queryValue", "resultQuery", "asyncState", "accessibilityLabel", "searchPlaceholder"],
|
|
857
|
+
events: ["onActivate", "onActivateAfterDismiss"],
|
|
858
|
+
stateAxes: { value: ["open"], content: ["idle", "loading", "loadingMore", "empty", "error"] },
|
|
859
|
+
// 저작자 명세의 dismiss 사유 "activation"은 채택하지 않았다. 같은 뜻의 "action"이
|
|
860
|
+
// 이미 유니언에 있고(Menu가 onAction으로 쓴다), 공용 어휘에 동의어를 하나 더 두면
|
|
861
|
+
// 렌더러가 둘을 구별해야 하는지 매번 물어야 한다.
|
|
862
|
+
web: { roles: ["dialog", "listbox", "option"], keyboard: ["Tab", "Enter", "Escape", "ArrowUp", "ArrowDown"], focus: "trap", dismiss: ["escape", "outside", "action"] },
|
|
863
|
+
native: { roles: [], states: [], actions: [] },
|
|
864
|
+
scenarios: [...commandPaletteBehaviorScenarios],
|
|
865
|
+
},
|
|
866
|
+
floatingActionButton: {
|
|
867
|
+
controlled: [],
|
|
868
|
+
inputs: ["label", "icon", "layoutMode", "scrollSignal", "safeAreaInset"],
|
|
869
|
+
events: ["onPress"],
|
|
870
|
+
stateAxes: { interaction: ["idle", "hover", "pressed", "focusVisible"] },
|
|
871
|
+
web: { roles: ["button"], keyboard: ["Tab", "Enter", "Space"], focus: "native" },
|
|
872
|
+
native: { roles: ["button"], states: [], actions: ["activate"] },
|
|
873
|
+
scenarios: [...floatingActionButtonBehaviorScenarios],
|
|
874
|
+
},
|
|
875
|
+
// 이 항목은 `transfer-list.ts`에서 import하지 않고 여기에 직접 쓴다. 그 모듈은
|
|
876
|
+
// 이 파일에서 **값**을(getCheckboxNextState 등) 가져오므로, 여기서 되받으면
|
|
877
|
+
// 실제 순환이 닫혀 레지스트리가 undefined를 담는다(타입만 가져오는
|
|
878
|
+
// data-table과 다른 점이다). 두 정의가 어긋나지 않는지는 테스트로 잠근다.
|
|
879
|
+
transferList: {
|
|
880
|
+
controlled: ["targetKeys", "defaultTargetKeys", "onTargetKeysChange"],
|
|
881
|
+
inputs: ["items"],
|
|
882
|
+
events: ["onMove"],
|
|
883
|
+
stateAxes: {
|
|
884
|
+
availability: ["enabled", "disabled"],
|
|
885
|
+
value: ["empty", "filled", "selected", "mixed"],
|
|
886
|
+
},
|
|
887
|
+
web: {
|
|
888
|
+
roles: ["group", "listbox", "option", "checkbox", "button"],
|
|
889
|
+
keyboard: ["Tab", "Space", "Enter", "ArrowUp", "ArrowDown", "Home", "End"],
|
|
890
|
+
focus: "roving",
|
|
891
|
+
},
|
|
892
|
+
native: {
|
|
893
|
+
roles: ["list", "checkbox", "button"],
|
|
894
|
+
states: ["disabled", "selected", "checked"],
|
|
895
|
+
actions: ["toggle", "toggleSelectAll", "moveSelection", "moveItem"],
|
|
896
|
+
},
|
|
897
|
+
scenarios: [
|
|
898
|
+
"moving-is-reachable-entirely-by-keyboard-select-with-space-then-activate-the-move-button",
|
|
899
|
+
"moving-a-single-focused-row-does-not-require-first-opening-multi-select",
|
|
900
|
+
"focus-after-a-move-lands-on-the-item-that-slid-into-the-removed-rows-position",
|
|
901
|
+
"focus-after-emptying-a-panel-falls-back-to-its-empty-state-never-lost-to-the-document",
|
|
902
|
+
"every-move-emits-which-ids-moved-so-the-product-can-announce-a-formatted-sentence",
|
|
903
|
+
"disabled-items-are-never-selectable-and-never-move",
|
|
904
|
+
"moved-items-are-cleared-from-the-origin-panels-selection-and-left-unselected-at-the-destination",
|
|
905
|
+
"select-all-in-a-panel-excludes-disabled-items-from-both-the-denominator-and-the-count",
|
|
906
|
+
"an-item-with-nothing-selected-in-its-panel-still-supports-direct-single-item-move",
|
|
907
|
+
"search-and-pagination-inside-a-panel-are-product-composition-not-this-contract",
|
|
908
|
+
],
|
|
909
|
+
},
|
|
910
|
+
dataTable: dataTableBehavior,
|
|
911
|
+
tour: {
|
|
912
|
+
controlled: ["open", "defaultOpen", "onOpenChange", "currentStepId", "defaultCurrentStepId", "onStepChange"],
|
|
913
|
+
inputs: ["steps", "labels", "anchorId"],
|
|
914
|
+
events: ["onClose"],
|
|
915
|
+
stateAxes: { value: ["open", "currentStep"] },
|
|
916
|
+
// outside 닫힘이 없다. 실수로 워크스루가 끊기지 않게 하려는 고정 규칙이라
|
|
917
|
+
// 저작자가 policy 객체조차 두지 않았고, 요약에도 그 사실을 그대로 옮긴다.
|
|
918
|
+
web: { roles: ["dialog"], keyboard: ["Tab", "Enter", "Escape", "ArrowLeft", "ArrowRight"], focus: "trap", dismiss: ["escape", "close-action", "programmatic"] },
|
|
919
|
+
native: { roles: [], states: [], actions: [] },
|
|
920
|
+
scenarios: [...tourBehaviorScenarios],
|
|
921
|
+
},
|
|
922
|
+
layout: layoutBehavior,
|
|
923
|
+
otpField: otpFieldBehavior,
|
|
924
|
+
passwordField: passwordFieldBehavior,
|
|
925
|
+
splitter: splitterBehavior,
|
|
926
|
+
datePicker: datePickerBehavior,
|
|
927
|
+
sidePanel: sidePanelBehavior,
|
|
928
|
+
filePicker: filePickerBehavior,
|
|
929
|
+
pagination: {
|
|
930
|
+
controlled: ["currentPage", "onPageChange"],
|
|
931
|
+
inputs: ["totalCount", "totalPages", "pageSize", "labels"],
|
|
932
|
+
configuration: { window: ["siblingCount", "boundaryCount"] },
|
|
933
|
+
stateAxes: {},
|
|
934
|
+
web: {
|
|
935
|
+
roles: ["navigation"],
|
|
936
|
+
keyboard: ["Tab", "Enter", "Space"],
|
|
937
|
+
focus: "native",
|
|
938
|
+
},
|
|
939
|
+
native: { roles: [], states: [], actions: [] },
|
|
940
|
+
scenarios: [...paginationBehaviorScenarios],
|
|
941
|
+
},
|
|
942
|
+
/*
|
|
943
|
+
비모달이라 `busy` 축이 없다. Sheet/AlertDialog는 진행 중 dismiss를 막지만 Popover는
|
|
944
|
+
포커스가 정당하게 밖으로 나갈 수 있어 그 축이 성립하지 않는다 — 대신 나가는 것
|
|
945
|
+
자체가 dismiss 신호이므로 `outside-focus`를 별도 reason으로 둔다.
|
|
946
|
+
*/
|
|
947
|
+
popover: {
|
|
948
|
+
controlled: ["open", "defaultOpen", "onOpenChange"],
|
|
949
|
+
defaults: popoverBehaviorDefaults,
|
|
950
|
+
stateAxes: { value: ["open"] },
|
|
951
|
+
/*
|
|
952
|
+
`trap`이 아니라 `restore`다 — Dialog·Sheet·AlertDialog는 모달이라 포커스를 가두지만
|
|
953
|
+
Popover는 비모달이라 Tab이 **정당하게 밖으로 나갈 수 있다.** 그래서 가두지 않고,
|
|
954
|
+
닫힐 때 트리거로 돌려보낸다. 같은 자리에 있는 것은 Menu다(역시 `restore`).
|
|
955
|
+
나가는 것 자체가 dismiss 신호이므로 `outside-focus`를 별도 reason으로 둔다.
|
|
956
|
+
*/
|
|
957
|
+
web: {
|
|
958
|
+
roles: ["dialog"],
|
|
959
|
+
keyboard: ["Tab", "Escape"],
|
|
960
|
+
focus: "restore",
|
|
961
|
+
dismiss: ["escape", "outside"],
|
|
962
|
+
},
|
|
963
|
+
native: { roles: [], states: [], actions: [] },
|
|
964
|
+
scenarios: [...popoverBehaviorScenarios],
|
|
965
|
+
},
|
|
966
|
+
tree: treeBehavior,
|
|
967
|
+
uploadItem: uploadItemBehavior,
|
|
968
|
+
form: formBehaviorSpec,
|
|
969
|
+
numberField: numberFieldBehavior,
|
|
970
|
+
slider: sliderBehavior,
|
|
971
|
+
};
|
|
972
|
+
//# sourceMappingURL=behaviors.js.map
|