@hjmds/design-contracts 1.7.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.
- package/THIRD_PARTY_NOTICES.md +58 -0
- package/dist/affix.d.ts +8 -0
- package/dist/affix.d.ts.map +1 -0
- package/dist/affix.js +7 -0
- package/dist/affix.js.map +1 -0
- package/dist/agreement.d.ts +3 -3
- package/dist/agreement.js +1 -1
- package/dist/agreement.js.map +1 -1
- package/dist/asset.d.ts +1 -1
- package/dist/asset.js +1 -1
- package/dist/asset.js.map +1 -1
- package/dist/base-recipes.d.ts +12 -12
- package/dist/base-recipes.d.ts.map +1 -1
- package/dist/base-recipes.js +15 -14
- package/dist/base-recipes.js.map +1 -1
- package/dist/behaviors.d.ts +1 -1
- package/dist/catalog.d.ts +445 -651
- package/dist/catalog.d.ts.map +1 -1
- package/dist/catalog.js +149 -101
- package/dist/catalog.js.map +1 -1
- package/dist/color-picker.d.ts +11 -0
- package/dist/color-picker.d.ts.map +1 -0
- package/dist/color-picker.js +20 -0
- package/dist/color-picker.js.map +1 -0
- package/dist/command-palette.d.ts +3 -3
- package/dist/component-contracts.d.ts +4 -4
- package/dist/component-contracts.d.ts.map +1 -1
- package/dist/component-contracts.js +5 -4
- package/dist/component-contracts.js.map +1 -1
- package/dist/component-definitions.d.ts +1 -9
- package/dist/component-definitions.d.ts.map +1 -1
- package/dist/component-definitions.js +1 -9
- package/dist/component-definitions.js.map +1 -1
- package/dist/component-recipes.d.ts +76 -83
- package/dist/component-recipes.d.ts.map +1 -1
- package/dist/component-recipes.js +29 -49
- package/dist/component-recipes.js.map +1 -1
- package/dist/component-references.d.ts +10 -25
- package/dist/component-references.d.ts.map +1 -1
- package/dist/component-references.js +5 -8
- package/dist/component-references.js.map +1 -1
- package/dist/data-table.d.ts +3 -3
- package/dist/data-table.js +1 -1
- package/dist/data-table.js.map +1 -1
- package/dist/date-picker.d.ts +2 -2
- package/dist/icon-button-recipe.d.ts +2 -2
- package/dist/icon-button-recipe.js +1 -1
- package/dist/icon-button-recipe.js.map +1 -1
- package/dist/image.d.ts +2 -2
- package/dist/image.js +2 -2
- package/dist/image.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/interaction-adapters.d.ts +53 -0
- package/dist/interaction-adapters.d.ts.map +1 -0
- package/dist/interaction-adapters.js +45 -0
- package/dist/interaction-adapters.js.map +1 -0
- package/dist/internal/thinking-orb/braid.d.ts +3 -0
- package/dist/internal/thinking-orb/braid.d.ts.map +1 -0
- package/dist/internal/thinking-orb/braid.js +47 -0
- package/dist/internal/thinking-orb/braid.js.map +1 -0
- package/dist/internal/thinking-orb/core.d.ts +60 -0
- package/dist/internal/thinking-orb/core.d.ts.map +1 -0
- package/dist/internal/thinking-orb/core.js +86 -0
- package/dist/internal/thinking-orb/core.js.map +1 -0
- package/dist/internal/thinking-orb/lattice.d.ts +5 -0
- package/dist/internal/thinking-orb/lattice.d.ts.map +1 -0
- package/dist/internal/thinking-orb/lattice.js +187 -0
- package/dist/internal/thinking-orb/lattice.js.map +1 -0
- package/dist/internal/thinking-orb/morph.d.ts +3 -0
- package/dist/internal/thinking-orb/morph.d.ts.map +1 -0
- package/dist/internal/thinking-orb/morph.js +127 -0
- package/dist/internal/thinking-orb/morph.js.map +1 -0
- package/dist/internal/thinking-orb/orbits.d.ts +3 -0
- package/dist/internal/thinking-orb/orbits.d.ts.map +1 -0
- package/dist/internal/thinking-orb/orbits.js +68 -0
- package/dist/internal/thinking-orb/orbits.js.map +1 -0
- package/dist/internal/thinking-orb/presets.d.ts +21 -0
- package/dist/internal/thinking-orb/presets.d.ts.map +1 -0
- package/dist/internal/thinking-orb/presets.js +77 -0
- package/dist/internal/thinking-orb/presets.js.map +1 -0
- package/dist/internal/thinking-orb/profiles.d.ts +8 -0
- package/dist/internal/thinking-orb/profiles.d.ts.map +1 -0
- package/dist/internal/thinking-orb/profiles.js +158 -0
- package/dist/internal/thinking-orb/profiles.js.map +1 -0
- package/dist/internal/thinking-orb/registry.d.ts +9 -0
- package/dist/internal/thinking-orb/registry.d.ts.map +1 -0
- package/dist/internal/thinking-orb/registry.js +27 -0
- package/dist/internal/thinking-orb/registry.js.map +1 -0
- package/dist/internal/thinking-orb/ribbon.d.ts +3 -0
- package/dist/internal/thinking-orb/ribbon.d.ts.map +1 -0
- package/dist/internal/thinking-orb/ribbon.js +87 -0
- package/dist/internal/thinking-orb/ribbon.js.map +1 -0
- package/dist/internal/thinking-orb/types.d.ts +15 -0
- package/dist/internal/thinking-orb/types.d.ts.map +1 -0
- package/dist/internal/thinking-orb/types.js +4 -0
- package/dist/internal/thinking-orb/types.js.map +1 -0
- package/dist/internal/thinking-orb/web.d.ts +3 -0
- package/dist/internal/thinking-orb/web.d.ts.map +1 -0
- package/dist/internal/thinking-orb/web.js +92 -0
- package/dist/internal/thinking-orb/web.js.map +1 -0
- package/dist/masonry.d.ts +17 -0
- package/dist/masonry.d.ts.map +1 -0
- package/dist/masonry.js +18 -0
- package/dist/masonry.js.map +1 -0
- package/dist/menubar.d.ts +3 -3
- package/dist/menubar.js +1 -1
- package/dist/menubar.js.map +1 -1
- package/dist/number-field.d.ts +2 -2
- package/dist/otp-field.d.ts +1 -1
- package/dist/password-field.d.ts +2 -2
- package/dist/popover.d.ts +7 -8
- package/dist/popover.d.ts.map +1 -1
- package/dist/popover.js +2 -0
- package/dist/popover.js.map +1 -1
- package/dist/qr-code-recipe.d.ts +7 -0
- package/dist/qr-code-recipe.d.ts.map +1 -0
- package/dist/qr-code-recipe.js +2 -0
- package/dist/qr-code-recipe.js.map +1 -0
- package/dist/qr-code.d.ts +16 -0
- package/dist/qr-code.d.ts.map +1 -0
- package/dist/qr-code.js +37 -0
- package/dist/qr-code.js.map +1 -0
- package/dist/semantic-colors.d.ts +1 -1
- package/dist/semantic-colors.js +1 -1
- package/dist/semantic-colors.js.map +1 -1
- package/dist/showcase.d.ts +5 -1
- package/dist/showcase.d.ts.map +1 -1
- package/dist/showcase.js +53 -12
- package/dist/showcase.js.map +1 -1
- package/dist/sidebar.d.ts +3 -3
- package/dist/sidebar.js +1 -1
- package/dist/sidebar.js.map +1 -1
- package/dist/tag.d.ts +4 -4
- package/dist/tag.js +3 -3
- package/dist/tag.js.map +1 -1
- package/dist/tags-input.d.ts +3 -3
- package/dist/tags-input.js +1 -1
- package/dist/tags-input.js.map +1 -1
- package/dist/text-formats.d.ts +2 -2
- package/dist/text-formats.js +2 -2
- package/dist/text-formats.js.map +1 -1
- package/dist/thinking-orb-recipe.d.ts +15 -0
- package/dist/thinking-orb-recipe.d.ts.map +1 -0
- package/dist/thinking-orb-recipe.js +9 -0
- package/dist/thinking-orb-recipe.js.map +1 -0
- package/dist/thinking-orb.d.ts +25 -0
- package/dist/thinking-orb.d.ts.map +1 -0
- package/dist/thinking-orb.js +40 -0
- package/dist/thinking-orb.js.map +1 -0
- package/dist/toast-liquid.d.ts +116 -0
- package/dist/toast-liquid.d.ts.map +1 -0
- package/dist/toast-liquid.js +103 -0
- package/dist/toast-liquid.js.map +1 -0
- package/dist/toast.d.ts +7 -1
- package/dist/toast.d.ts.map +1 -1
- package/dist/toast.js +5 -0
- package/dist/toast.js.map +1 -1
- package/dist/toggle-group.d.ts +2 -2
- package/dist/toggle-group.js +3 -3
- package/dist/toggle-group.js.map +1 -1
- package/dist/transfer-list.d.ts +3 -3
- package/dist/transfer-list.js +1 -1
- package/dist/transfer-list.js.map +1 -1
- package/dist/tree.d.ts +2 -2
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/version.js.map +1 -1
- package/dist/virtual-list.d.ts +13 -0
- package/dist/virtual-list.d.ts.map +1 -0
- package/dist/virtual-list.js +13 -0
- package/dist/virtual-list.js.map +1 -0
- package/dist/watermark.d.ts +15 -0
- package/dist/watermark.d.ts.map +1 -0
- package/dist/watermark.js +11 -0
- package/dist/watermark.js.map +1 -0
- package/docs/affix.md +27 -63
- package/docs/anchor.md +5 -4
- package/docs/ant-design-coverage.md +8 -12
- package/docs/architecture.md +6 -2
- package/docs/authoring-brief.md +3 -2
- package/docs/bottom-navigation.md +7 -6
- package/docs/breadcrumb.md +5 -2
- package/docs/calendar.md +6 -3
- package/docs/carousel.md +2 -2
- package/docs/cascader.md +11 -0
- package/docs/catalog-cleanup.md +7 -0
- package/docs/catalog-decision-status.md +8 -3
- package/docs/catalog-freeze.json +9 -7
- package/docs/collapsible.md +12 -0
- package/docs/color-picker.md +30 -72
- package/docs/command-palette.md +5 -3
- package/docs/confirm-popover.md +5 -0
- package/docs/consumer-policy.md +29 -12
- package/docs/context-menu.md +12 -2
- package/docs/data-table.md +11 -6
- package/docs/date-picker.md +6 -4
- package/docs/date-range.md +4 -2
- package/docs/description-list.md +8 -9
- package/docs/dialog.md +39 -0
- package/docs/expansion-roadmap.md +11 -7
- package/docs/file-picker.md +5 -3
- package/docs/form.md +16 -4
- package/docs/generated/component-maturity.md +91 -99
- package/docs/generated/renderer-evidence.json +2043 -1059
- package/docs/generated/renderer-evidence.md +156 -145
- package/docs/generated/showcase-manifest.json +476 -625
- package/docs/layout.md +8 -9
- package/docs/library-gap-analysis.md +1 -1
- package/docs/masonry.md +11 -0
- package/docs/mentions.md +14 -7
- package/docs/optional-adapters.md +126 -0
- package/docs/otp-field.md +2 -1
- package/docs/pagination.md +4 -1
- package/docs/password-field.md +2 -1
- package/docs/popover.md +9 -6
- package/docs/promotion-candidates.md +2 -1
- package/docs/qr-code.md +11 -65
- package/docs/rating.md +5 -0
- package/docs/react-native-completion.md +1 -1
- package/docs/result.md +8 -5
- package/docs/screen-chrome.md +2 -1
- package/docs/sheet.md +8 -2
- package/docs/showcase.md +10 -2
- package/docs/side-panel.md +12 -6
- package/docs/sidebar.md +3 -0
- package/docs/splitter.md +6 -6
- package/docs/stable-core.md +92 -0
- package/docs/stable-promotion.md +47 -43
- package/docs/tags-input.md +5 -2
- package/docs/theme-palette.md +27 -0
- package/docs/thinking-orb.md +124 -0
- package/docs/time-picker.md +5 -0
- package/docs/timeline.md +2 -3
- package/docs/toast.md +6 -0
- package/docs/tooltip.md +2 -1
- package/docs/tour.md +14 -8
- package/docs/transfer-list.md +24 -21
- package/docs/tree-select.md +7 -1
- package/docs/tree.md +12 -7
- package/docs/upload-item.md +7 -3
- package/docs/virtual-list.md +10 -67
- package/docs/watermark.md +26 -58
- package/package.json +54 -3
- package/docs/app-provider.md +0 -50
- package/docs/border-beam.md +0 -66
- package/docs/chart.md +0 -33
- package/docs/utility.md +0 -53
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transfer-list.js","sourceRoot":"","sources":["../src/transfer-list.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ColorReference } from \"./color-references.js\";\nimport type {\n BehaviorContract,\n CheckboxState,\n CollectionKey,\n SelectItemDescriptor,\n} from \"./behaviors.js\";\nimport {\n getCheckboxNextState,\n reconcileCheckboxSelection,\n toggleCheckboxSelection,\n} from \"./selection-helpers.js\";\nimport { collectionItemContract, focusIndicatorContract } from \"./component-contracts.js\";\nimport { validateCollection } from \"./collection.js\";\nimport { control, radius, spacing, stroke } from \"./foundations.js\";\nimport { semanticColors } from \"./semantic-colors.js\";\n\n/**\n * `docs/transfer-list.md`: two lists sharing one item set, split by whether\n * each id is in `targetKeys`. This is the same shape CheckboxGroup already\n * commits to (`ReadonlySet<Id>`, no third \"which panel\" enum to keep in\n * sync with membership) — one source of truth instead of two arrays that can\n * drift apart when an item is moved.\n */\nexport type TransferListPanel = \"source\" | \"target\";\n\nexport type TransferListDescriptor<Id extends CollectionKey = CollectionKey> = Readonly<{\n items: readonly SelectItemDescriptor<Id>[];\n targetKeys: ReadonlySet<Id>;\n}>;\n\nexport type TransferListSelection<Id extends CollectionKey = CollectionKey> = Readonly<{\n source: ReadonlySet<Id>;\n target: ReadonlySet<Id>;\n}>;\n\nfunction withPanelSelection<Id extends CollectionKey>(\n selection: TransferListSelection<Id>,\n panel: TransferListPanel,\n next: ReadonlySet<Id>,\n): TransferListSelection<Id> {\n return panel === \"source\"\n ? { source: next, target: selection.target }\n : { source: selection.source, target: next };\n}\n\nfunction assertKnownIds<Id extends CollectionKey>(\n label: string,\n ids: ReadonlySet<Id>,\n knownIds: ReadonlySet<Id>,\n): void {\n for (const id of ids) {\n if (!knownIds.has(id)) {\n throw new RangeError(`TransferList ${label} references an unknown item id: ${id}`);\n }\n }\n}\n\n/** An item already sitting entirely inside one panel (including all-in-target\n * or all-in-source) is valid — nothing here requires either panel to be\n * non-empty, and a disabled item is valid in either panel even though it can\n * never be moved by the UI. */\nexport function validateTransferListDescriptor<Id extends CollectionKey>(\n descriptor: TransferListDescriptor<Id>,\n): void {\n validateCollection({ items: descriptor.items });\n const knownIds = new Set(descriptor.items.map((item) => item.id));\n assertKnownIds(\"targetKeys\", descriptor.targetKeys, knownIds);\n}\n\nexport type TransferListPanels<Id extends CollectionKey = CollectionKey> = Readonly<{\n source: readonly SelectItemDescriptor<Id>[];\n target: readonly SelectItemDescriptor<Id>[];\n}>;\n\n/** Splits by `targetKeys` membership, preserving each item's relative order from `items`. */\nexport function resolveTransferListPanels<Id extends CollectionKey>(\n descriptor: TransferListDescriptor<Id>,\n): TransferListPanels<Id> {\n validateTransferListDescriptor(descriptor);\n const source: SelectItemDescriptor<Id>[] = [];\n const target: SelectItemDescriptor<Id>[] = [];\n for (const item of descriptor.items) {\n (descriptor.targetKeys.has(item.id) ? target : source).push(item);\n }\n return { source, target };\n}\n\nexport function validateTransferListSelection<Id extends CollectionKey>(\n descriptor: TransferListDescriptor<Id>,\n selection: TransferListSelection<Id>,\n): void {\n const panels = resolveTransferListPanels(descriptor);\n assertKnownIds(\"selection.source\", selection.source, new Set(panels.source.map((i) => i.id)));\n assertKnownIds(\"selection.target\", selection.target, new Set(panels.target.map((i) => i.id)));\n}\n\n/** Toggles one row's checkbox within its own panel; the other panel's selection is untouched. */\nexport function toggleTransferListSelection<Id extends CollectionKey>(\n descriptor: TransferListDescriptor<Id>,\n selection: TransferListSelection<Id>,\n panel: TransferListPanel,\n id: Id,\n): TransferListSelection<Id> {\n const panels = resolveTransferListPanels(descriptor);\n const next = toggleCheckboxSelection(panels[panel], selection[panel], id);\n return withPanelSelection(selection, panel, next);\n}\n\n/**\n * Same tri-state `CheckboxState` `resolveDataTableSelectAllState` derives for\n * a table header — disabled rows excluded from both the denominator and the\n * count — generalized from \"all rows\" to \"this one panel's rows\".\n */\nexport function resolveTransferListSelectAllState<Id extends CollectionKey>(\n descriptor: TransferListDescriptor<Id>,\n selection: TransferListSelection<Id>,\n panel: TransferListPanel,\n): CheckboxState {\n const items = resolveTransferListPanels(descriptor)[panel];\n const selectable = items.filter((item) => !item.disabled);\n if (selectable.length === 0) return false;\n const selectedCount = selectable.filter((item) => selection[panel].has(item.id)).length;\n if (selectedCount === 0) return false;\n return selectedCount === selectable.length ? true : \"mixed\";\n}\n\n/** Mixed-defaults-to-checked, matching `getCheckboxNextState`'s existing convention. */\nexport function toggleTransferListSelectAll<Id extends CollectionKey>(\n descriptor: TransferListDescriptor<Id>,\n selection: TransferListSelection<Id>,\n panel: TransferListPanel,\n): TransferListSelection<Id> {\n const current = resolveTransferListSelectAllState(descriptor, selection, panel);\n const checkAll = getCheckboxNextState(current);\n const items = resolveTransferListPanels(descriptor)[panel];\n const next = checkAll\n ? new Set(items.filter((item) => !item.disabled).map((item) => item.id))\n : new Set<Id>();\n return withPanelSelection(selection, panel, next);\n}\n\nexport type TransferListMoveDirection = \"toTarget\" | \"toSource\";\n\nexport type TransferListMoveResult<Id extends CollectionKey = CollectionKey> = Readonly<{\n targetKeys: ReadonlySet<Id>;\n selection: TransferListSelection<Id>;\n /** In origin-panel order — the product formats the announcement string from this. */\n movedIds: readonly Id[];\n}>;\n\n/**\n * Moves every enabled, currently-selected id out of its origin panel.\n * Disabled ids are skipped rather than rejected (a disabled row can never\n * enter a selection through `toggleTransferListSelection`, but a product\n * could hand one to `defaultSelectedKeys`, and skipping mirrors\n * `toggleTreeCheckedSelection`'s disabled guard rather than throwing on it).\n * Moved ids are cleared from the origin panel's selection and deliberately\n * left unselected in the destination panel — a move commits a value, it does\n * not also commit a new pending selection the user did not make.\n */\nexport function moveTransferListSelection<Id extends CollectionKey>(\n descriptor: TransferListDescriptor<Id>,\n selection: TransferListSelection<Id>,\n direction: TransferListMoveDirection,\n): TransferListMoveResult<Id> {\n validateTransferListSelection(descriptor, selection);\n const fromPanel: TransferListPanel = direction === \"toTarget\" ? \"source\" : \"target\";\n const fromItems = resolveTransferListPanels(descriptor)[fromPanel];\n const movedIds = fromItems\n .filter((item) => !item.disabled && selection[fromPanel].has(item.id))\n .map((item) => item.id);\n\n if (movedIds.length === 0) {\n return { targetKeys: descriptor.targetKeys, selection, movedIds: [] };\n }\n\n const movedIdSet = new Set(movedIds);\n const targetKeys =\n direction === \"toTarget\"\n ? new Set([...descriptor.targetKeys, ...movedIds])\n : new Set([...descriptor.targetKeys].filter((id) => !movedIdSet.has(id)));\n\n const nextFromSelection = new Set(\n [...selection[fromPanel]].filter((id) => !movedIdSet.has(id)),\n );\n return {\n targetKeys,\n selection: withPanelSelection(selection, fromPanel, nextFromSelection),\n movedIds,\n };\n}\n\n/**\n * Where focus lands once the moved rows are gone from a panel: the item that\n * slid into the first removed row's position, so keyboard users keep moving\n * down the list without their focus jumping to the top or vanishing. `null`\n * means the panel is now empty — the renderer falls back to the panel's\n * empty-state message or the move button, never to the document body.\n */\nexport function resolveTransferListFocusAfterMove<Id extends CollectionKey>(\n remainingPanelItems: readonly SelectItemDescriptor<Id>[],\n removedIndex: number,\n): Id | null {\n if (remainingPanelItems.length === 0) return null;\n const clamped = Math.min(Math.max(removedIndex, 0), remainingPanelItems.length - 1);\n return remainingPanelItems[clamped]!.id;\n}\n\n/** Drops selected ids that left either panel (item removed from `items` entirely). */\nexport function reconcileTransferListSelection<Id extends CollectionKey>(\n descriptor: TransferListDescriptor<Id>,\n selection: TransferListSelection<Id>,\n): TransferListSelection<Id> {\n const panels = resolveTransferListPanels(descriptor);\n const source = reconcileCheckboxSelection(panels.source, selection.source);\n const target = reconcileCheckboxSelection(panels.target, selection.target);\n if (source === selection.source && target === selection.target) return selection;\n return { source, target };\n}\n\nexport const transferListRecipe = {\n slots: [\n \"root\",\n \"panel\",\n \"panelHeader\",\n \"panelTitle\",\n \"panelCount\",\n \"list\",\n \"item\",\n \"itemCheckbox\",\n \"emptyState\",\n \"moveControls\",\n \"moveButton\",\n ] as const,\n panel: {\n background: semanticColors.surface.default,\n border: semanticColors.border.default,\n borderWidth: stroke.default,\n radius: \"md\" as const,\n },\n panelHeader: {\n minHeight: 44,\n paddingHorizontal: spacing.sm,\n title: { color: semanticColors.content.body, textVariant: \"body\" as const },\n count: { color: semanticColors.content.secondary, textVariant: \"label\" as const },\n },\n item: collectionItemContract,\n emptyState: { color: semanticColors.content.secondary, textVariant: \"label\" as const },\n moveControls: { gap: spacing.sm },\n moveButton: {\n minTarget: control.minTouchTarget,\n color: semanticColors.content.brand,\n disabledOpacity: 0.4,\n },\n states: { focus: focusIndicatorContract },\n} as const satisfies {\n slots: readonly [\n \"root\",\n \"panel\",\n \"panelHeader\",\n \"panelTitle\",\n \"panelCount\",\n \"list\",\n \"item\",\n \"itemCheckbox\",\n \"emptyState\",\n \"moveControls\",\n \"moveButton\",\n ];\n panel: { background: ColorReference; border: ColorReference; borderWidth: number; radius: keyof typeof radius };\n panelHeader: {\n minHeight: number;\n paddingHorizontal: number;\n title: { color: ColorReference; textVariant: \"body\" };\n count: { color: ColorReference; textVariant: \"label\" };\n };\n item: typeof collectionItemContract;\n emptyState: { color: ColorReference; textVariant: \"label\" };\n moveControls: { gap: number };\n moveButton: { minTarget: number; color: ColorReference; disabledOpacity: number };\n states: { focus: typeof focusIndicatorContract };\n};\n\nexport const transferListBehavior = {\n controlled: [\"targetKeys\", \"defaultTargetKeys\", \"onTargetKeysChange\"],\n inputs: [\"items\"],\n events: [\"onMove\"],\n stateAxes: {\n availability: [\"enabled\", \"disabled\"],\n value: [\"empty\", \"filled\", \"selected\", \"mixed\"],\n },\n web: {\n roles: [\"group\", \"listbox\", \"option\", \"checkbox\", \"button\"],\n keyboard: [\"Tab\", \"Space\", \"Enter\", \"ArrowUp\", \"ArrowDown\", \"Home\", \"End\"],\n focus: \"roving\",\n },\n native: {\n roles: [\"list\", \"checkbox\", \"button\"],\n states: [\"disabled\", \"selected\", \"checked\"],\n actions: [\"toggle\", \"toggleSelectAll\", \"moveSelection\", \"moveItem\"],\n },\n scenarios: [\n \"moving-is-reachable-entirely-by-keyboard-select-with-space-then-activate-the-move-button\",\n \"moving-a-single-focused-row-does-not-require-first-opening-multi-select\",\n \"focus-after-a-move-lands-on-the-item-that-slid-into-the-removed-rows-position\",\n \"focus-after-emptying-a-panel-falls-back-to-its-empty-state-never-lost-to-the-document\",\n \"every-move-emits-which-ids-moved-so-the-product-can-announce-a-formatted-sentence\",\n \"disabled-items-are-never-selectable-and-never-move\",\n \"moved-items-are-cleared-from-the-origin-panels-selection-and-left-unselected-at-the-destination\",\n \"select-all-in-a-panel-excludes-disabled-items-from-both-the-denominator-and-the-count\",\n \"an-item-with-nothing-selected-in-its-panel-still-supports-direct-single-item-move\",\n \"search-and-pagination-inside-a-panel-are-product-composition-not-this-contract\",\n ],\n} as const satisfies BehaviorContract;\n"]}
|
|
1
|
+
{"version":3,"file":"transfer-list.js","sourceRoot":"","sources":["../src/transfer-list.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ColorReference } from \"./color-references.js\";\nimport type {\n BehaviorContract,\n CheckboxState,\n CollectionKey,\n SelectItemDescriptor,\n} from \"./behaviors.js\";\nimport {\n getCheckboxNextState,\n reconcileCheckboxSelection,\n toggleCheckboxSelection,\n} from \"./selection-helpers.js\";\nimport { collectionItemContract, focusIndicatorContract } from \"./component-contracts.js\";\nimport { validateCollection } from \"./collection.js\";\nimport { control, radius, spacing, stroke } from \"./foundations.js\";\nimport { semanticColors } from \"./semantic-colors.js\";\n\n/**\n * `docs/transfer-list.md`: two lists sharing one item set, split by whether\n * each id is in `targetKeys`. This is the same shape CheckboxGroup already\n * commits to (`ReadonlySet<Id>`, no third \"which panel\" enum to keep in\n * sync with membership) — one source of truth instead of two arrays that can\n * drift apart when an item is moved.\n */\nexport type TransferListPanel = \"source\" | \"target\";\n\nexport type TransferListDescriptor<Id extends CollectionKey = CollectionKey> = Readonly<{\n items: readonly SelectItemDescriptor<Id>[];\n targetKeys: ReadonlySet<Id>;\n}>;\n\nexport type TransferListSelection<Id extends CollectionKey = CollectionKey> = Readonly<{\n source: ReadonlySet<Id>;\n target: ReadonlySet<Id>;\n}>;\n\nfunction withPanelSelection<Id extends CollectionKey>(\n selection: TransferListSelection<Id>,\n panel: TransferListPanel,\n next: ReadonlySet<Id>,\n): TransferListSelection<Id> {\n return panel === \"source\"\n ? { source: next, target: selection.target }\n : { source: selection.source, target: next };\n}\n\nfunction assertKnownIds<Id extends CollectionKey>(\n label: string,\n ids: ReadonlySet<Id>,\n knownIds: ReadonlySet<Id>,\n): void {\n for (const id of ids) {\n if (!knownIds.has(id)) {\n throw new RangeError(`TransferList ${label} references an unknown item id: ${id}`);\n }\n }\n}\n\n/** An item already sitting entirely inside one panel (including all-in-target\n * or all-in-source) is valid — nothing here requires either panel to be\n * non-empty, and a disabled item is valid in either panel even though it can\n * never be moved by the UI. */\nexport function validateTransferListDescriptor<Id extends CollectionKey>(\n descriptor: TransferListDescriptor<Id>,\n): void {\n validateCollection({ items: descriptor.items });\n const knownIds = new Set(descriptor.items.map((item) => item.id));\n assertKnownIds(\"targetKeys\", descriptor.targetKeys, knownIds);\n}\n\nexport type TransferListPanels<Id extends CollectionKey = CollectionKey> = Readonly<{\n source: readonly SelectItemDescriptor<Id>[];\n target: readonly SelectItemDescriptor<Id>[];\n}>;\n\n/** Splits by `targetKeys` membership, preserving each item's relative order from `items`. */\nexport function resolveTransferListPanels<Id extends CollectionKey>(\n descriptor: TransferListDescriptor<Id>,\n): TransferListPanels<Id> {\n validateTransferListDescriptor(descriptor);\n const source: SelectItemDescriptor<Id>[] = [];\n const target: SelectItemDescriptor<Id>[] = [];\n for (const item of descriptor.items) {\n (descriptor.targetKeys.has(item.id) ? target : source).push(item);\n }\n return { source, target };\n}\n\nexport function validateTransferListSelection<Id extends CollectionKey>(\n descriptor: TransferListDescriptor<Id>,\n selection: TransferListSelection<Id>,\n): void {\n const panels = resolveTransferListPanels(descriptor);\n assertKnownIds(\"selection.source\", selection.source, new Set(panels.source.map((i) => i.id)));\n assertKnownIds(\"selection.target\", selection.target, new Set(panels.target.map((i) => i.id)));\n}\n\n/** Toggles one row's checkbox within its own panel; the other panel's selection is untouched. */\nexport function toggleTransferListSelection<Id extends CollectionKey>(\n descriptor: TransferListDescriptor<Id>,\n selection: TransferListSelection<Id>,\n panel: TransferListPanel,\n id: Id,\n): TransferListSelection<Id> {\n const panels = resolveTransferListPanels(descriptor);\n const next = toggleCheckboxSelection(panels[panel], selection[panel], id);\n return withPanelSelection(selection, panel, next);\n}\n\n/**\n * Same tri-state `CheckboxState` `resolveDataTableSelectAllState` derives for\n * a table header — disabled rows excluded from both the denominator and the\n * count — generalized from \"all rows\" to \"this one panel's rows\".\n */\nexport function resolveTransferListSelectAllState<Id extends CollectionKey>(\n descriptor: TransferListDescriptor<Id>,\n selection: TransferListSelection<Id>,\n panel: TransferListPanel,\n): CheckboxState {\n const items = resolveTransferListPanels(descriptor)[panel];\n const selectable = items.filter((item) => !item.disabled);\n if (selectable.length === 0) return false;\n const selectedCount = selectable.filter((item) => selection[panel].has(item.id)).length;\n if (selectedCount === 0) return false;\n return selectedCount === selectable.length ? true : \"mixed\";\n}\n\n/** Mixed-defaults-to-checked, matching `getCheckboxNextState`'s existing convention. */\nexport function toggleTransferListSelectAll<Id extends CollectionKey>(\n descriptor: TransferListDescriptor<Id>,\n selection: TransferListSelection<Id>,\n panel: TransferListPanel,\n): TransferListSelection<Id> {\n const current = resolveTransferListSelectAllState(descriptor, selection, panel);\n const checkAll = getCheckboxNextState(current);\n const items = resolveTransferListPanels(descriptor)[panel];\n const next = checkAll\n ? new Set(items.filter((item) => !item.disabled).map((item) => item.id))\n : new Set<Id>();\n return withPanelSelection(selection, panel, next);\n}\n\nexport type TransferListMoveDirection = \"toTarget\" | \"toSource\";\n\nexport type TransferListMoveResult<Id extends CollectionKey = CollectionKey> = Readonly<{\n targetKeys: ReadonlySet<Id>;\n selection: TransferListSelection<Id>;\n /** In origin-panel order — the product formats the announcement string from this. */\n movedIds: readonly Id[];\n}>;\n\n/**\n * Moves every enabled, currently-selected id out of its origin panel.\n * Disabled ids are skipped rather than rejected (a disabled row can never\n * enter a selection through `toggleTransferListSelection`, but a product\n * could hand one to `defaultSelectedKeys`, and skipping mirrors\n * `toggleTreeCheckedSelection`'s disabled guard rather than throwing on it).\n * Moved ids are cleared from the origin panel's selection and deliberately\n * left unselected in the destination panel — a move commits a value, it does\n * not also commit a new pending selection the user did not make.\n */\nexport function moveTransferListSelection<Id extends CollectionKey>(\n descriptor: TransferListDescriptor<Id>,\n selection: TransferListSelection<Id>,\n direction: TransferListMoveDirection,\n): TransferListMoveResult<Id> {\n validateTransferListSelection(descriptor, selection);\n const fromPanel: TransferListPanel = direction === \"toTarget\" ? \"source\" : \"target\";\n const fromItems = resolveTransferListPanels(descriptor)[fromPanel];\n const movedIds = fromItems\n .filter((item) => !item.disabled && selection[fromPanel].has(item.id))\n .map((item) => item.id);\n\n if (movedIds.length === 0) {\n return { targetKeys: descriptor.targetKeys, selection, movedIds: [] };\n }\n\n const movedIdSet = new Set(movedIds);\n const targetKeys =\n direction === \"toTarget\"\n ? new Set([...descriptor.targetKeys, ...movedIds])\n : new Set([...descriptor.targetKeys].filter((id) => !movedIdSet.has(id)));\n\n const nextFromSelection = new Set(\n [...selection[fromPanel]].filter((id) => !movedIdSet.has(id)),\n );\n return {\n targetKeys,\n selection: withPanelSelection(selection, fromPanel, nextFromSelection),\n movedIds,\n };\n}\n\n/**\n * Where focus lands once the moved rows are gone from a panel: the item that\n * slid into the first removed row's position, so keyboard users keep moving\n * down the list without their focus jumping to the top or vanishing. `null`\n * means the panel is now empty — the renderer falls back to the panel's\n * empty-state message or the move button, never to the document body.\n */\nexport function resolveTransferListFocusAfterMove<Id extends CollectionKey>(\n remainingPanelItems: readonly SelectItemDescriptor<Id>[],\n removedIndex: number,\n): Id | null {\n if (remainingPanelItems.length === 0) return null;\n const clamped = Math.min(Math.max(removedIndex, 0), remainingPanelItems.length - 1);\n return remainingPanelItems[clamped]!.id;\n}\n\n/** Drops selected ids that left either panel (item removed from `items` entirely). */\nexport function reconcileTransferListSelection<Id extends CollectionKey>(\n descriptor: TransferListDescriptor<Id>,\n selection: TransferListSelection<Id>,\n): TransferListSelection<Id> {\n const panels = resolveTransferListPanels(descriptor);\n const source = reconcileCheckboxSelection(panels.source, selection.source);\n const target = reconcileCheckboxSelection(panels.target, selection.target);\n if (source === selection.source && target === selection.target) return selection;\n return { source, target };\n}\n\nexport const transferListRecipe = {\n slots: [\n \"root\",\n \"panel\",\n \"panelHeader\",\n \"panelTitle\",\n \"panelCount\",\n \"list\",\n \"item\",\n \"itemCheckbox\",\n \"emptyState\",\n \"moveControls\",\n \"moveButton\",\n ] as const,\n panel: {\n background: semanticColors.canvas,\n border: semanticColors.border.default,\n borderWidth: stroke.default,\n radius: \"md\" as const,\n },\n panelHeader: {\n minHeight: 44,\n paddingHorizontal: spacing.sm,\n title: { color: semanticColors.content.body, textVariant: \"body\" as const },\n count: { color: semanticColors.content.secondary, textVariant: \"label\" as const },\n },\n item: collectionItemContract,\n emptyState: { color: semanticColors.content.secondary, textVariant: \"label\" as const },\n moveControls: { gap: spacing.sm },\n moveButton: {\n minTarget: control.minTouchTarget,\n color: semanticColors.content.brand,\n disabledOpacity: 0.4,\n },\n states: { focus: focusIndicatorContract },\n} as const satisfies {\n slots: readonly [\n \"root\",\n \"panel\",\n \"panelHeader\",\n \"panelTitle\",\n \"panelCount\",\n \"list\",\n \"item\",\n \"itemCheckbox\",\n \"emptyState\",\n \"moveControls\",\n \"moveButton\",\n ];\n panel: { background: ColorReference; border: ColorReference; borderWidth: number; radius: keyof typeof radius };\n panelHeader: {\n minHeight: number;\n paddingHorizontal: number;\n title: { color: ColorReference; textVariant: \"body\" };\n count: { color: ColorReference; textVariant: \"label\" };\n };\n item: typeof collectionItemContract;\n emptyState: { color: ColorReference; textVariant: \"label\" };\n moveControls: { gap: number };\n moveButton: { minTarget: number; color: ColorReference; disabledOpacity: number };\n states: { focus: typeof focusIndicatorContract };\n};\n\nexport const transferListBehavior = {\n controlled: [\"targetKeys\", \"defaultTargetKeys\", \"onTargetKeysChange\"],\n inputs: [\"items\"],\n events: [\"onMove\"],\n stateAxes: {\n availability: [\"enabled\", \"disabled\"],\n value: [\"empty\", \"filled\", \"selected\", \"mixed\"],\n },\n web: {\n roles: [\"group\", \"listbox\", \"option\", \"checkbox\", \"button\"],\n keyboard: [\"Tab\", \"Space\", \"Enter\", \"ArrowUp\", \"ArrowDown\", \"Home\", \"End\"],\n focus: \"roving\",\n },\n native: {\n roles: [\"list\", \"checkbox\", \"button\"],\n states: [\"disabled\", \"selected\", \"checked\"],\n actions: [\"toggle\", \"toggleSelectAll\", \"moveSelection\", \"moveItem\"],\n },\n scenarios: [\n \"moving-is-reachable-entirely-by-keyboard-select-with-space-then-activate-the-move-button\",\n \"moving-a-single-focused-row-does-not-require-first-opening-multi-select\",\n \"focus-after-a-move-lands-on-the-item-that-slid-into-the-removed-rows-position\",\n \"focus-after-emptying-a-panel-falls-back-to-its-empty-state-never-lost-to-the-document\",\n \"every-move-emits-which-ids-moved-so-the-product-can-announce-a-formatted-sentence\",\n \"disabled-items-are-never-selectable-and-never-move\",\n \"moved-items-are-cleared-from-the-origin-panels-selection-and-left-unselected-at-the-destination\",\n \"select-all-in-a-panel-excludes-disabled-items-from-both-the-denominator-and-the-count\",\n \"an-item-with-nothing-selected-in-its-panel-still-supports-direct-single-item-move\",\n \"search-and-pagination-inside-a-panel-are-product-composition-not-this-contract\",\n ],\n} as const satisfies BehaviorContract;\n"]}
|
package/dist/tree.d.ts
CHANGED
|
@@ -161,7 +161,7 @@ export declare const treeRecipe: {
|
|
|
161
161
|
};
|
|
162
162
|
readonly highlightedBackground: Readonly<{
|
|
163
163
|
source: "theme";
|
|
164
|
-
key: "
|
|
164
|
+
key: "bg";
|
|
165
165
|
alpha?: number;
|
|
166
166
|
}>;
|
|
167
167
|
readonly focus: {
|
|
@@ -175,7 +175,7 @@ export declare const treeRecipe: {
|
|
|
175
175
|
};
|
|
176
176
|
readonly selectedBackground: Readonly<{
|
|
177
177
|
source: "theme";
|
|
178
|
-
key: "
|
|
178
|
+
key: "bg";
|
|
179
179
|
alpha?: number;
|
|
180
180
|
}>;
|
|
181
181
|
readonly selectedIndicator: Readonly<{
|
package/dist/version.d.ts
CHANGED
package/dist/version.js
CHANGED
package/dist/version.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,MAAM,CAAC,MAAM,mBAAmB,GAAG,OAAgB,CAAC","sourcesContent":["/** Package release shown by documentation surfaces. Kept in sync by a test. */\nexport const designSystemVersion = \"1.
|
|
1
|
+
{"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,MAAM,CAAC,MAAM,mBAAmB,GAAG,OAAgB,CAAC","sourcesContent":["/** Package release shown by documentation surfaces. Kept in sync by a test. */\nexport const designSystemVersion = \"1.9.0\" as const;\n"]}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export declare function resolveVirtualWindow(count: number, rowHeight: number, viewportHeight: number, scrollTop: number, overscan?: number): {
|
|
2
|
+
start: number;
|
|
3
|
+
end: number;
|
|
4
|
+
totalHeight: number;
|
|
5
|
+
offset: number;
|
|
6
|
+
};
|
|
7
|
+
export declare function validateListKeys(keys: readonly string[], label: string): void;
|
|
8
|
+
export declare const virtualListRecipe: {
|
|
9
|
+
readonly layout: "fixed-row-window";
|
|
10
|
+
readonly overscan: 3;
|
|
11
|
+
readonly readingOrder: "source";
|
|
12
|
+
};
|
|
13
|
+
//# sourceMappingURL=virtual-list.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"virtual-list.d.ts","sourceRoot":"","sources":["../src/virtual-list.ts"],"names":[],"mappings":"AAAA,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,SAAI;;;;;EAK7H;AACD,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,KAAK,EAAE,MAAM,QAEtE;AACD,eAAO,MAAM,iBAAiB;;;;CAA+E,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export function resolveVirtualWindow(count, rowHeight, viewportHeight, scrollTop, overscan = 3) {
|
|
2
|
+
if (!Number.isInteger(count) || count < 0 || !Number.isFinite(rowHeight) || rowHeight <= 0 || !Number.isFinite(viewportHeight) || viewportHeight <= 0 || !Number.isFinite(scrollTop) || scrollTop < 0 || !Number.isInteger(overscan) || overscan < 0)
|
|
3
|
+
throw new TypeError("Invalid VirtualList dimensions");
|
|
4
|
+
const totalHeight = count * rowHeight;
|
|
5
|
+
const offset = Math.min(scrollTop, Math.max(0, totalHeight - viewportHeight));
|
|
6
|
+
return { start: Math.max(0, Math.floor(offset / rowHeight) - overscan), end: Math.min(count, Math.ceil((offset + viewportHeight) / rowHeight) + overscan), totalHeight, offset };
|
|
7
|
+
}
|
|
8
|
+
export function validateListKeys(keys, label) {
|
|
9
|
+
if (!label.trim() || new Set(keys).size !== keys.length || keys.some(key => !key.trim()))
|
|
10
|
+
throw new TypeError("List needs a label and unique nonempty keys");
|
|
11
|
+
}
|
|
12
|
+
export const virtualListRecipe = { layout: "fixed-row-window", overscan: 3, readingOrder: "source" };
|
|
13
|
+
//# sourceMappingURL=virtual-list.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"virtual-list.js","sourceRoot":"","sources":["../src/virtual-list.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,oBAAoB,CAAC,KAAa,EAAE,SAAiB,EAAE,cAAsB,EAAE,SAAiB,EAAE,QAAQ,GAAG,CAAC;IAC5H,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,KAAK,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,SAAS,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,cAAc,CAAC,IAAI,cAAc,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,SAAS,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,QAAQ,GAAG,CAAC;QAAE,MAAM,IAAI,SAAS,CAAC,gCAAgC,CAAC,CAAC;IAC5S,MAAM,WAAW,GAAG,KAAK,GAAG,SAAS,CAAC;IACtC,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,WAAW,GAAG,cAAc,CAAC,CAAC,CAAC;IAC9E,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,SAAS,CAAC,GAAG,QAAQ,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,GAAG,cAAc,CAAC,GAAG,SAAS,CAAC,GAAG,QAAQ,CAAC,EAAE,WAAW,EAAE,MAAM,EAAE,CAAC;AACnL,CAAC;AACD,MAAM,UAAU,gBAAgB,CAAC,IAAuB,EAAE,KAAa;IACrE,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,IAAI,IAAI,GAAG,CAAC,IAAI,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;QAAE,MAAM,IAAI,SAAS,CAAC,6CAA6C,CAAC,CAAC;AAC/J,CAAC;AACD,MAAM,CAAC,MAAM,iBAAiB,GAAG,EAAE,MAAM,EAAE,kBAAkB,EAAE,QAAQ,EAAE,CAAC,EAAE,YAAY,EAAE,QAAQ,EAAW,CAAC","sourcesContent":["export function resolveVirtualWindow(count: number, rowHeight: number, viewportHeight: number, scrollTop: number, overscan = 3) {\n if (!Number.isInteger(count) || count < 0 || !Number.isFinite(rowHeight) || rowHeight <= 0 || !Number.isFinite(viewportHeight) || viewportHeight <= 0 || !Number.isFinite(scrollTop) || scrollTop < 0 || !Number.isInteger(overscan) || overscan < 0) throw new TypeError(\"Invalid VirtualList dimensions\");\n const totalHeight = count * rowHeight;\n const offset = Math.min(scrollTop, Math.max(0, totalHeight - viewportHeight));\n return { start: Math.max(0, Math.floor(offset / rowHeight) - overscan), end: Math.min(count, Math.ceil((offset + viewportHeight) / rowHeight) + overscan), totalHeight, offset };\n}\nexport function validateListKeys(keys: readonly string[], label: string) {\n if (!label.trim() || new Set(keys).size !== keys.length || keys.some(key => !key.trim())) throw new TypeError(\"List needs a label and unique nonempty keys\");\n}\nexport const virtualListRecipe = { layout: \"fixed-row-window\", overscan: 3, readingOrder: \"source\" } as const;\n"]}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export declare const watermarkRecipe: {
|
|
2
|
+
readonly tileWidth: 240;
|
|
3
|
+
readonly tileHeight: 160;
|
|
4
|
+
readonly rotate: -22;
|
|
5
|
+
readonly opacity: 0.12;
|
|
6
|
+
readonly foreground: "textSub";
|
|
7
|
+
};
|
|
8
|
+
export declare function resolveWatermark(text: string | readonly string[], width?: number, height?: number, rotate?: number, opacity?: number): {
|
|
9
|
+
lines: string[];
|
|
10
|
+
width: number;
|
|
11
|
+
height: number;
|
|
12
|
+
rotate: number;
|
|
13
|
+
opacity: number;
|
|
14
|
+
};
|
|
15
|
+
//# sourceMappingURL=watermark.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"watermark.d.ts","sourceRoot":"","sources":["../src/watermark.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,eAAe;;;;;;CAAkG,CAAC;AAC/H,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,EAAE,KAAK,GAAgC,MAAM,EAAE,MAAM,GAAiC,MAAM,EAAE,MAAM,GAA6B,MAAM,EAAE,OAAO,GAA8B,MAAM;;;;;;EAMpP"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export const watermarkRecipe = { tileWidth: 240, tileHeight: 160, rotate: -22, opacity: 0.12, foreground: "textSub" };
|
|
2
|
+
export function resolveWatermark(text, width = watermarkRecipe.tileWidth, height = watermarkRecipe.tileHeight, rotate = watermarkRecipe.rotate, opacity = watermarkRecipe.opacity) {
|
|
3
|
+
const lines = typeof text === "string" ? [text] : [...text];
|
|
4
|
+
// Bounded tiles prevent accidental invisible/huge overlays; this is decorative labeling, not tamper protection.
|
|
5
|
+
if (!lines.length || lines.length > 3 || lines.some(line => !line.trim() || line.length > 120))
|
|
6
|
+
throw new TypeError("Watermark needs one to three nonempty lines of at most 120 characters");
|
|
7
|
+
if (![width, height, rotate, opacity].every(Number.isFinite) || width < 80 || height < 60 || Math.abs(rotate) > 90 || opacity < 0 || opacity > 1)
|
|
8
|
+
throw new TypeError("Invalid Watermark geometry");
|
|
9
|
+
return { lines, width, height, rotate, opacity };
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=watermark.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"watermark.js","sourceRoot":"","sources":["../src/watermark.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,eAAe,GAAG,EAAE,SAAS,EAAE,GAAG,EAAE,UAAU,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,SAAS,EAAW,CAAC;AAC/H,MAAM,UAAU,gBAAgB,CAAC,IAAgC,EAAE,QAAQ,eAAe,CAAC,SAAmB,EAAE,SAAS,eAAe,CAAC,UAAoB,EAAE,SAAS,eAAe,CAAC,MAAgB,EAAE,UAAU,eAAe,CAAC,OAAiB;IACnP,MAAM,KAAK,GAAG,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;IAC5D,gHAAgH;IAChH,IAAI,CAAC,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,IAAI,CAAC,MAAM,GAAG,GAAG,CAAC;QAAE,MAAM,IAAI,SAAS,CAAC,uEAAuE,CAAC,CAAC;IAC7L,IAAI,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,KAAK,GAAG,EAAE,IAAI,MAAM,GAAG,EAAE,IAAI,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,EAAE,IAAI,OAAO,GAAG,CAAC,IAAI,OAAO,GAAG,CAAC;QAAE,MAAM,IAAI,SAAS,CAAC,4BAA4B,CAAC,CAAC;IACpM,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC;AACnD,CAAC","sourcesContent":["export const watermarkRecipe = { tileWidth: 240, tileHeight: 160, rotate: -22, opacity: 0.12, foreground: \"textSub\" } as const;\nexport function resolveWatermark(text: string | readonly string[], width = watermarkRecipe.tileWidth as number, height = watermarkRecipe.tileHeight as number, rotate = watermarkRecipe.rotate as number, opacity = watermarkRecipe.opacity as number) {\n const lines = typeof text === \"string\" ? [text] : [...text];\n // Bounded tiles prevent accidental invisible/huge overlays; this is decorative labeling, not tamper protection.\n if (!lines.length || lines.length > 3 || lines.some(line => !line.trim() || line.length > 120)) throw new TypeError(\"Watermark needs one to three nonempty lines of at most 120 characters\");\n if (![width, height, rotate, opacity].every(Number.isFinite) || width < 80 || height < 60 || Math.abs(rotate) > 90 || opacity < 0 || opacity > 1) throw new TypeError(\"Invalid Watermark geometry\");\n return { lines, width, height, rotate, opacity };\n}\n"]}
|
package/docs/affix.md
CHANGED
|
@@ -1,63 +1,27 @@
|
|
|
1
|
-
# Affix —
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
area")은 이미 별도 컴포넌트로 계약돼 있습니다. 둘 다 "임의 요소를 고정하는 범용
|
|
29
|
-
wrapper"를 필요로 하지 않습니다.
|
|
30
|
-
|
|
31
|
-
### 2. 임의 콘텐츠를 고정하는 범용 요구 자체가 관측되지 않는다
|
|
32
|
-
|
|
33
|
-
antd `Affix`의 핵심 사용법 — 헤더도 테이블도 아닌 **임의 콘텐츠**(플로팅 목차, 사이드
|
|
34
|
-
액션 카드 등)를 스크롤 중간에 고정 — 는 두 제품 어디에도 없습니다. 있는 모든 "고정"
|
|
35
|
-
사례는 위처럼 헤더(TopBar) 아니면 특정 컴포넌트 내부 anatomy(StatTable, BottomCTA)로
|
|
36
|
-
이미 이름이 있습니다.
|
|
37
|
-
|
|
38
|
-
### 3. 계약할 상태 축이 없다
|
|
39
|
-
|
|
40
|
-
Affix가 컴포넌트가 되려면 "Web과 Native가 각자 다른 기법으로 같은 결과를 낸다"는 공유
|
|
41
|
-
semantic이 있어야 합니다(`docs/architecture.md`의 `adaptive` 정의). 그런데 Web은 CSS
|
|
42
|
-
`position: sticky`(레이아웃 엔진이 처리, JS 상태 없음), Native는 애초에 스크롤에 따라
|
|
43
|
-
고정/해제되는 개념 자체가 드뭅니다(헤더는 기본 고정, 그 외에는 `stickyHeaderIndices`처럼
|
|
44
|
-
리스트 컴포넌트가 소유). 이는 `docs/virtual-list.md`가 항목 높이 추정을 판정한 것과 같은
|
|
45
|
-
모양입니다 — 이름도 단위도 의미도 대응하지 않는 렌더러 힌트일 뿐, 공유할 사용자 의미가
|
|
46
|
-
없습니다.
|
|
47
|
-
|
|
48
|
-
`Stack`의 판정과 같은 자리입니다: 반복되는 CSS 속성 하나를 감싸는 것만으로 제품 의미나
|
|
49
|
-
접근성 계약이 생기지 않습니다.
|
|
50
|
-
|
|
51
|
-
## 만들지 않은 것
|
|
52
|
-
|
|
53
|
-
`src/affix.ts`, `test/affix.test.ts`는 없습니다. `componentCatalog`의
|
|
54
|
-
`{ name: "Affix", category: "utility", platform: "web", status: "planned" }` 행과
|
|
55
|
-
crosswalk의 `Affix → Affix` direct 관계(`src/component-references.ts:125`)는 건드리지
|
|
56
|
-
않습니다.
|
|
57
|
-
|
|
58
|
-
## 뒤집힐 조건
|
|
59
|
-
|
|
60
|
-
1. 헤더도 테이블도 CTA도 아닌 **임의 콘텐츠**를 스크롤 중간 지점부터 고정해야 하는 실제
|
|
61
|
-
화면(예: 긴 폼 옆의 플로팅 요약 카드)이 두 제품 중 하나에 나타난다.
|
|
62
|
-
2. 그 화면에서 CSS `position: sticky`만으로 부족한 요구(예: 여러 sticky 요소의 겹침
|
|
63
|
-
순서 조정, 고정 해제 시점의 접근성 발표)가 측정된다.
|
|
1
|
+
# Affix — Web 상단 고정
|
|
2
|
+
|
|
3
|
+
2026-09-30: 사용자의 구현 요청으로 기존 수요 대기 결정을 대체한다. `position: fixed`로 복제/이동하면
|
|
4
|
+
초점과 폼 상태를 잃거나 폭을 다시 측정해야 하므로 CSS sticky로 원래 DOM과 문서 흐름을 유지한다.
|
|
5
|
+
JS는 고정 상태 관측과 화면보다 큰 콘텐츠의 해제에만 사용한다.
|
|
6
|
+
|
|
7
|
+
`@hjmds/react/affix`의 `Affix`는 `children`, `offset`(기본 0, 유한한 비음수 CSS px),
|
|
8
|
+
`disabled`, `onChange(affixed)`를 받는다. 가장 가까운 스크롤 조상의 상단에서 offset만큼 떨어져
|
|
9
|
+
고정된다. 부모의 끝에서 해제된다. 부모에 스크롤할 공간이 있어야 하며, 부모의 overflow 설정은
|
|
10
|
+
CSS sticky의 기준을 바꾼다. 부모 자체가 콘텐츠와 같은 높이면 고정 구간이 없다.
|
|
11
|
+
|
|
12
|
+
- `onChange`는 최초 상태와 이후 상태 전환에 호출한다. 렌더링마다 호출하지 않는다.
|
|
13
|
+
- 스크롤·리사이즈는 animation frame으로 모아 측정하고 unmount 시 observer/listener/frame을 해제한다.
|
|
14
|
+
- 콘텐츠가 스크롤 영역 높이에서 offset을 뺀 값보다 크면 일반 흐름으로 돌려 가려진 영역이 없게 한다.
|
|
15
|
+
- disabled/offset 변경에도 자식을 재마운트하지 않아 입력값·초점이 유지된다.
|
|
16
|
+
- 상단 고정만 지원하며 bottom 고정·portal·다중 sticky 영역 자동 충돌 조정은 제공하지 않는다.
|
|
17
|
+
- 별도 role이나 live announcement를 강제하지 않는다. 자식 의미·접근성 이름은 제품이 소유한다.
|
|
18
|
+
|
|
19
|
+
```tsx
|
|
20
|
+
<Affix offset={16} onChange={setPinned}>
|
|
21
|
+
<Button onClick={save}>{t('form.save')}</Button>
|
|
22
|
+
</Affix>
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
계약: [affix.ts](../src/affix.ts). UI: [renderer](../../react/src/affix.tsx).
|
|
26
|
+
사용 예제: [Web additions](../../../showcase/web/src/patterns/WebAdditions.stories.tsx).
|
|
27
|
+
검증: [브라우저 스크롤·초점 회귀](../../react/test/web-additions.browser.test.tsx).
|
package/docs/anchor.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# Anchor — 같은 문서 안의 목차
|
|
2
2
|
|
|
3
|
-
2026-09-16
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
2026-09-16 Web 라이브러리를 beta로 시작했다. 실제 browser keyboard·fragment 복구와 긴 문구
|
|
4
|
+
증거가 보강되어 2026-09-29 Web renderer를 stable로 승격한다. 소비 제품 채택과 보조기기 검증은
|
|
5
|
+
별도 release QA다.
|
|
6
6
|
|
|
7
7
|
[Ant Design Anchor](https://ant.design/components/anchor/)의 문서 내 링크·현재 위치·스크롤
|
|
8
8
|
영역 구분을 비교했습니다. HJM은 content-brand 글자와 얇은 논리 방향 표시선으로 위치를
|
|
@@ -56,4 +56,5 @@ Web 전용입니다. Native 라우팅·목록 위치 이동은 해당 플랫폼
|
|
|
56
56
|
|
|
57
57
|
`Patterns/Anchor`는 세 부분으로 나눈 읽기 가이드와 별도 스크롤 영역을 제공합니다.
|
|
58
58
|
브라우저 테스트는 위치 동기화·짧은 마지막 부분·offset·reduced motion·임시 focus 복원·
|
|
59
|
-
fragment 복구·나중에 삽입된
|
|
59
|
+
fragment 복구·나중에 삽입된 대상·좁은 목차의 긴 label 줄바꿈·Tab/Enter 활성화와 문서 스크롤을 검사합니다.
|
|
60
|
+
실제 제품 문서 채택·보조기기 검증은 남아 있습니다.
|
|
@@ -67,11 +67,9 @@ catalog 행 처리도 여기서 갈립니다. **흡수됨**은 행을 지우고
|
|
|
67
67
|
남깁니다 — 남겨 두면 "아직 만들 계획"으로 잘못 읽힙니다. **검증할 화면이 없음**은 행을
|
|
68
68
|
그대로 둡니다. 계약은 유효하고 언젠가 채워질 자리이기 때문입니다. **거절됨**은 행을 지울 수 없습니다 — crosswalk의 `targets`가 가리키고 있고 흡수할 다른 이름이 없기 때문입니다. 대신 `ComponentCatalogEntry.declinedReason`에 사유를 적습니다.
|
|
69
69
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
`ConfirmPopover`→Popover/AlertDialog) alias를 걸 단일 이름이 없으므로 **행을 그대로 둡니다.**
|
|
74
|
-
이 저장소는 이 답을 세 번 반복해서 냈고, 우연이 아니라 규칙입니다.
|
|
70
|
+
2026-09-30 사용자의 조합·중복 제외 요청에 따라, 구현된 조합도 독립 catalog 행에서 제거합니다.
|
|
71
|
+
단일 대상 alias나 여러 primitive를 가리키는 crosswalk로 범위를 추적하고 작동 예제는 유지합니다.
|
|
72
|
+
조합의 이름을 Planned로 예약하는 대안은 이미 해결된 기능을 미구현 수에 포함하므로 폐기합니다.
|
|
75
73
|
|
|
76
74
|
**흡수 대기**는 행과 crosswalk를 **둘 다 건드리지 않습니다.** 흡수를 지금 적용하면 아직 만들지
|
|
77
75
|
않은 해결책을 완료로 표시하게 됩니다 — `planned`이 거짓말하던 문제와 방향만 반대인 같은 문제입니다.
|
|
@@ -88,18 +86,16 @@ evidence registry로 판단합니다.
|
|
|
88
86
|
- partial maturity: decomposed target 중 일부만 stable 또는 beta
|
|
89
87
|
- planned only: 모든 target이 planned
|
|
90
88
|
|
|
91
|
-
2026-09-
|
|
92
|
-
**fully mature
|
|
93
|
-
planned only
|
|
94
|
-
|
|
95
|
-
홈과 Component Explorer는 이 수치를 분리해 표시합니다. 이 숫자는 source inventory 수가
|
|
96
|
-
아니라 HJM target의 maturity에서 계산하므로 catalog status가 바뀌면 함께 갱신합니다.
|
|
89
|
+
2026-09-30 조합 항목을 실제 primitive로 연결한 status 기반 분포는
|
|
90
|
+
**fully mature 70 / partial maturity 0 /
|
|
91
|
+
planned only 0**입니다. 이는 참조표 대상의 성숙도이며 원본 라이브러리 API 전체의 동등성을
|
|
92
|
+
보증하지 않습니다. ColorPicker·Watermark·Affix에도 Web renderer가 추가되어 Planned가 없습니다.
|
|
97
93
|
|
|
98
94
|
## lifecycle
|
|
99
95
|
|
|
100
96
|
Ant Design 6.6.1은 기존 `List`를 deprecated로 표시하고 `Listy`를 successor로 추가했습니다.
|
|
101
97
|
reference inventory는 `List.lifecycle = deprecated`, `Listy.lifecycle = new`로 보존하지만 HJM
|
|
102
|
-
`List`를 자동으로 deprecated 처리하지 않습니다. HJM은 기존 비가상 `List`와
|
|
98
|
+
`List`를 자동으로 deprecated 처리하지 않습니다. HJM은 기존 비가상 `List`와 구현된
|
|
103
99
|
`VirtualList`를 서로 다른 사용 문제로 유지합니다.
|
|
104
100
|
|
|
105
101
|
## 업데이트 규칙
|
package/docs/architecture.md
CHANGED
|
@@ -56,11 +56,15 @@ Typography recipe의 `fontWeight`·`selectedFontWeight`·`checkedFontWeight`는
|
|
|
56
56
|
|
|
57
57
|
## 지원 단계
|
|
58
58
|
|
|
59
|
-
- `stable`:
|
|
60
|
-
- `beta`:
|
|
59
|
+
- `stable`: 공개 API와 동작을 SemVer로 지원하며 해당 renderer의 필수 검증을 통과함
|
|
60
|
+
- `beta`: 공개 API·동작 또는 renderer 검증에 구체적인 미완료 항목이 있음
|
|
61
61
|
- `planned`: 범위에 포함되지만 API를 아직 안정화하지 않음
|
|
62
62
|
- `deprecated`: 새 사용을 막고 대체 경로와 제거 예정 버전을 문서화한 호환 계약
|
|
63
63
|
|
|
64
|
+
제품 채택 수·제품 배포·제품 전체 QA는 성숙도 관문이 아닙니다. 승격 기준은
|
|
65
|
+
[stable 승격 절차](stable-promotion.md) 한 곳에서 관리합니다. 2026-09-29에 서로 달랐던
|
|
66
|
+
채택 수 조건을 제거했으며 제품 검증은 소비 앱의 릴리스 책임으로 분리했습니다.
|
|
67
|
+
|
|
64
68
|
현재 전체 범위와 목표 플랫폼 분류는 `componentCatalog`가 기계 판독 가능한 형태로 제공합니다.
|
|
65
69
|
계획된 컴포넌트를 catalog에 올리는 것은 구현 완료를 의미하지 않습니다.
|
|
66
70
|
`recipeRegistry`가 실제 recipe와 catalog 이름을 타입으로 묶어 오타나 유령 계약을 막습니다.
|
package/docs/authoring-brief.md
CHANGED
|
@@ -57,8 +57,9 @@
|
|
|
57
57
|
## maturity에 대해
|
|
58
58
|
|
|
59
59
|
당신의 산출물로 컴포넌트는 **"계약+recipe 준비됨"**이 된다. catalog의 `planned → beta`
|
|
60
|
-
|
|
61
|
-
|
|
60
|
+
승격에는 실제 first-party renderer export와 실행되는 default proof가 필요하다.
|
|
61
|
+
2026-09-29 개정에서 제품 vertical slice는 승격 조건에서 분리했다. stable은
|
|
62
|
+
[승격 기준](stable-promotion.md)을 따르며 recipe만으로 구현 완료를 주장하지 않는다.
|
|
62
63
|
|
|
63
64
|
## 게이트
|
|
64
65
|
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
`BottomNavigation`은 콘텐츠 panel을 바꾸는 `Tabs`가 아니라 앱의 안정된 최상위 route를
|
|
4
4
|
이동합니다. 같은 destination 의미를 Web의 link와 React Native navigator tab으로 적응시키며,
|
|
5
|
-
route state는 제품 router 한 곳에서만 소유합니다.
|
|
6
|
-
|
|
7
|
-
`
|
|
5
|
+
route state는 제품 router 한 곳에서만 소유합니다. 각 renderer의 환경 matrix, Web route-link
|
|
6
|
+
키보드 동작, Native navigate/reselect host action과 긴 목적지 label 회귀가 연결되어 catalog
|
|
7
|
+
status는 `stable`입니다. 구체적인 router·navigator와 결합한 화면 동작은 소비 앱 QA입니다.
|
|
8
8
|
|
|
9
9
|
## Descriptor와 configuration
|
|
10
10
|
|
|
@@ -46,9 +46,8 @@ const descriptor = {
|
|
|
46
46
|
예약하며 action을 collection에 추가하지 않습니다.
|
|
47
47
|
|
|
48
48
|
Web renderer도 이름이 있는 실제 link landmark, `aria-current`, modifier click 보존,
|
|
49
|
-
keyboard viewport hide와 center-gap 배치를 first-party SSR·browser test로
|
|
50
|
-
|
|
51
|
-
debt로 남습니다.
|
|
49
|
+
keyboard viewport hide와 center-gap 배치를 first-party SSR·browser test로 검증합니다. 제품
|
|
50
|
+
router와 결합한 브라우저 릴리스 증거는 컴포넌트 API 성숙도가 아니라 소비 앱 QA에 속합니다.
|
|
52
51
|
|
|
53
52
|
## Route source of truth
|
|
54
53
|
|
|
@@ -111,6 +110,8 @@ status/live role이나 별도 accessibility label을 추가하면 같은 정보
|
|
|
111
110
|
visual label은 최대 `1.4×`까지만 커지고, 원문 전체는 item의 접근성 이름으로 유지합니다.
|
|
112
111
|
- safe-area bottom inset은 recipe의 최소 padding에 더합니다. `max(base, inset)`으로 대체하지
|
|
113
112
|
않습니다.
|
|
113
|
+
- 긴 label은 320px viewport의 Web geometry matrix와 React Native renderer matrix에서 확인합니다.
|
|
114
|
+
Web link의 전체 이름/visible label 보존과 Native accessibility name/Text 보존은 전용 interaction proof에 둡니다.
|
|
114
115
|
- 기본 keyboard behavior는 `hide`입니다. software keyboard 위로 bottom navigation을 밀어
|
|
115
116
|
올려 입력 영역을 가리지 않습니다.
|
|
116
117
|
- RTL에서는 item 순서와 badge의 inline-end anchor가 함께 뒤집힙니다. icon 자체의 mirror 여부는
|
package/docs/breadcrumb.md
CHANGED
|
@@ -78,5 +78,8 @@ Web에서는:
|
|
|
78
78
|
돌아오는 작동 예제입니다. 제품 채택이나 stable 증거로 계산하지 않습니다.
|
|
79
79
|
|
|
80
80
|
[WAI Breadcrumb](https://www.w3.org/WAI/ARIA/apg/patterns/breadcrumb/)의 landmark·조상 링크·
|
|
81
|
-
현재 위치 의미를 확인했습니다.
|
|
82
|
-
|
|
81
|
+
현재 위치 의미를 확인했습니다. Web renderer evidence는 component 자신의 긴 label이 320px
|
|
82
|
+
컨테이너 안에서 넘치지 않는지 확인하고, 실제 Tab/Shift+Tab/Enter로 조상 anchor를 따라가며
|
|
83
|
+
현재 위치가 tab stop이나 link가 아닌 `aria-current="page"` 텍스트로 남는지 확인합니다.
|
|
84
|
+
별도 브라우저 회귀는 실제 anchor URL, 장식 구분자, 320px/2배 글자·RTL 줄바꿈을 다룹니다.
|
|
85
|
+
실제 제품 라우팅·보조기기 검증은 소비 앱의 별도 범위입니다. Web renderer evidence의 필수 시나리오 누락은 0이며 Breadcrumb는 Web-only stable입니다.
|
package/docs/calendar.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Calendar
|
|
2
2
|
|
|
3
|
-
2026-09-16 · React / React Native beta
|
|
3
|
+
2026-09-16 · React / React Native renderer beta로 시작했다. 2026-09-29 두 surface의 키·host action·긴 title proof를 보강해 stable로 승격한다. 제품 채택은 별도 관측이다.
|
|
4
4
|
제품의 실제 채택·기기 검증·npm 게시를 뜻하지 않는다.
|
|
5
5
|
|
|
6
6
|
## 설계와 참조
|
|
@@ -69,7 +69,8 @@ Web의 `autoFocus`는 기본 false이며 DatePicker가 열린 격자에만 true
|
|
|
69
69
|
- 7열의 최소 touch target을 유지한다. 폭이 부족하면 격자만 가로 스크롤하고 본문은 넘치지 않는다.
|
|
70
70
|
- 셀 높이를 고정하지 않아 2배 글자나 짧은 제품 콘텐츠가 잘리지 않는다.
|
|
71
71
|
- Web: grid / row / columnheader / gridcell, 하나의 날짜 tab stop, visible focus.
|
|
72
|
-
- Native: 각 날짜는 독립 접근 가능한 button.
|
|
72
|
+
- Native: 각 날짜는 독립 접근 가능한 button. `focusDate`는 Native 접근성 초점 요청으로,
|
|
73
|
+
RN Web에서는 DOM 초점으로 전달한다. 이는 하드웨어 키보드 방향키 탐색 지원의 증거가 아니다.
|
|
73
74
|
- 단일 날짜·한 페이지 계약이다. range, 연간 view, 비그레고리력 계산 엔진은 이 컴포넌트에 없다.
|
|
74
75
|
제품이 준비한 날짜 배열의 의미를 보존하며 HJM은 날짜 형식·중복·격자 모양을 검증한다.
|
|
75
76
|
|
|
@@ -77,6 +78,8 @@ Web의 `autoFocus`는 기본 false이며 DatePicker가 열린 격자에만 true
|
|
|
77
78
|
|
|
78
79
|
Web 테스트는 비활성 날짜 focus/활성화 분리, 하루/주/Home/End, 경계에서 새 페이지의 지정 날짜로
|
|
79
80
|
focus 이동, controlled 선택 보존, 320px·2배 글자·RTL 최소 target과 본문 overflow를 검사한다.
|
|
80
|
-
Native 테스트는 개별 날짜의 접근성·비활성·선택, 명시적 월 이동, 크기와 스크롤
|
|
81
|
+
Native 테스트는 개별 날짜의 접근성·비활성·선택, 명시적 월 이동, 크기와 스크롤 경계,
|
|
82
|
+
긴 월 제목의 잘림 방지, `focusDate`의 접근성 초점 요청을 검사한다. 실제 VoiceOver/TalkBack
|
|
83
|
+
기기나 하드웨어 키보드 탐색 검증을 뜻하지 않는다.
|
|
81
84
|
DatePicker의 기존 선택·닫기·방향키 회귀와 controlled-open 읽기 전용/disabled 활성화 방지도 검사한다.
|
|
82
85
|
전체 패키지·Showcase 검증 및 브라우저 확인은 `react-native-completion.md` 실행 기록에 남긴다.
|
package/docs/carousel.md
CHANGED
|
@@ -127,8 +127,8 @@ mount policy 참고) — 새로 만든 개념이 아니라 이미 검증된 패
|
|
|
127
127
|
|
|
128
128
|
## 검증 화면
|
|
129
129
|
|
|
130
|
-
|
|
131
|
-
|
|
130
|
+
이 조사 당시 제품 채택은 미확인이었다. 후보는 야잘알 홈의 내 구단 경기 스트립이다.
|
|
131
|
+
2026-09-29부터 제품 채택은 관측으로 분리하며 [현재 승격 기준](stable-promotion.md)을 따른다.
|
|
132
132
|
|
|
133
133
|
|
|
134
134
|
## React / React Native renderer (2026-09-16)
|
package/docs/cascader.md
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
# Cascader — 별도 컴포넌트를 만들지 않는다
|
|
2
2
|
|
|
3
|
+
> 2026-09-30 정리: 구현된 조합을 미구현으로 집계하지 않도록 독립 Planned 행과 catalog ID를 제거했다.
|
|
4
|
+
> 기존 조합 예제와 공개 helper는 유지하며, 참조표는 실제 구성 컴포넌트로 연결한다.
|
|
5
|
+
> 아래 날짜별 설계 기록의 행 유지 지시는 당시 판단이며 이 결정으로 대체한다.
|
|
6
|
+
|
|
7
|
+
|
|
3
8
|
## 문제로 제기된 것
|
|
4
9
|
|
|
5
10
|
계층 데이터에서 경로 하나를 고른다(시/도 → 구 → 동). Ant Design `Cascader`와 `direct`
|
|
@@ -108,3 +113,9 @@ collection + tri-state 판정 모듈)으로 확정됐고, Tree renderer가 들
|
|
|
108
113
|
작동 예제는 Showcase `Patterns/Tree`의 Cascader 화면이다. "만들지 않는다"는 판정 자체는
|
|
109
114
|
그대로다 — 바뀐 것은 흡수하는 쪽이 컴포넌트가 아니라 조합이라는 점뿐이다.
|
|
110
115
|
|
|
116
|
+
|
|
117
|
+
## Native 조합 완성 — 2026-09-29
|
|
118
|
+
|
|
119
|
+
`showcase/native/src/Cascader.stories.tsx`는 단계별 Select로 도시→지역을 선택한다.
|
|
120
|
+
상위 항목 변경 시 하위 선택을 비워 이전 경로가 남지 않게 하고 전체 초기화를 제공한다.
|
|
121
|
+
기존 Web Tree 조합과 함께 제공하며 새 primitive나 별도 상태 계약은 만들지 않는다.
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# 제외 후보 삭제 — 2026-09-29
|
|
2
|
+
|
|
3
|
+
사용자가 도입 제외 항목을 삭제하도록 요청했다. Chart, AppProvider, BorderBeam, Utility를
|
|
4
|
+
활성 카탈로그·Planned 집계·쇼케이스에서 제거했다. 구현 계획이 없는 후보를 미래 작업처럼
|
|
5
|
+
표시하던 문제가 원인이다. 기존 dataviz 토큰, DesignSystemProvider, Toast/Dialog API는 유지한다.
|
|
6
|
+
외부 참조표에서도 App/BorderBeam/Util 후보를 제외해 지원 범위는 70개다. 이 표는 Ant Design
|
|
7
|
+
전체 73개와의 100% 구현 주장이 아니다. 이전 삭제 항목의 이력은 Git 기록으로 남긴다.
|
|
@@ -1,17 +1,22 @@
|
|
|
1
1
|
# Catalog이 "만들지 않기로 확정함"을 표현하지 못하는 문제 — 설계 제안
|
|
2
2
|
|
|
3
|
+
> 2026-09-30 후속 결정: 구현된 조합 5개는 독립 Planned 행에서 제거하고 참조표를
|
|
4
|
+
> 실제 primitive로 연결했다. 아래의 다중 대상 조합 행 유지 판단은 과거 기록이다.
|
|
5
|
+
> 현재 원칙과 집계는 [참조 범위](ant-design-coverage.md)를 따른다.
|
|
6
|
+
|
|
7
|
+
|
|
3
8
|
## 문제
|
|
4
9
|
|
|
5
10
|
`ComponentStatus`는 `"stable" | "beta" | "planned" | "deprecated"` 넷뿐이다(`src/catalog.ts`).
|
|
6
11
|
`planned`은 "아직 구현하지 않았지만 구현할 것"을 뜻해 왔다. 그런데 저작 과정에서 이 뜻이
|
|
7
12
|
거짓인 행이 실제로 쌓였다:
|
|
8
13
|
|
|
9
|
-
- `AppProvider` — 런타임(Context+훅)뿐이라 계약할 값 타입조차 남지 않는다(`docs/
|
|
14
|
+
- `AppProvider` — 런타임(Context+훅)뿐이라 계약할 값 타입조차 남지 않는다(`docs/catalog-cleanup.md`).
|
|
10
15
|
- `Utility` — antd `Util`이 가리키는 문제(토큰을 코드에서 읽는 법) 자체가 이 패키지의
|
|
11
|
-
기존 정적 export로 이미 해소돼 있다(`docs/
|
|
16
|
+
기존 정적 export로 이미 해소돼 있다(`docs/catalog-cleanup.md`).
|
|
12
17
|
- `BorderBeam` — antd에 실재하는 컴포넌트이지만(crosswalk은 정확하다, 정정: 이전 판은
|
|
13
18
|
"오염됐다"고 잘못 주장했었다), 상시 반복 장식 모션이 `docs/identity.md`와 정면으로
|
|
14
|
-
충돌해 만들지 않기로 확정했다(`docs/
|
|
19
|
+
충돌해 만들지 않기로 확정했다(`docs/catalog-cleanup.md`).
|
|
15
20
|
|
|
16
21
|
세 행 모두 **"언젠가 화면이 생기면 만든다"가 아니라 "화면이 생겨도 안 만든다"**다. 그런데
|
|
17
22
|
행을 지울 수도 없다 — `component-references.test.ts`의
|