@hjmds/design-contracts 1.6.0 → 1.8.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/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 +417 -561
- package/dist/catalog.d.ts.map +1 -1
- package/dist/catalog.js +138 -90
- package/dist/catalog.js.map +1 -1
- 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 -4
- package/dist/component-definitions.d.ts.map +1 -1
- package/dist/component-definitions.js +1 -4
- 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 +0 -15
- package/dist/component-references.d.ts.map +1 -1
- package/dist/component-references.js +0 -3
- 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/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 +51 -13
- 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 +100 -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/docs/anchor.md +5 -4
- package/docs/ant-design-coverage.md +2 -2
- 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 +6 -0
- package/docs/catalog-cleanup.md +7 -0
- package/docs/catalog-decision-status.md +3 -3
- package/docs/catalog-freeze.json +9 -7
- package/docs/collapsible.md +12 -0
- package/docs/command-palette.md +5 -3
- 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 +88 -91
- package/docs/generated/renderer-evidence.json +1848 -1023
- package/docs/generated/renderer-evidence.md +153 -145
- package/docs/generated/showcase-manifest.json +431 -497
- 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 +106 -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/react-native-completion.md +1 -1
- package/docs/result.md +8 -5
- package/docs/screen-chrome.md +2 -1
- package/docs/sheet.md +16 -3
- 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 +72 -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/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 +2 -1
- package/docs/tree.md +12 -7
- package/docs/upload-item.md +7 -3
- package/docs/virtual-list.md +10 -67
- package/package.json +30 -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
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# Third-party notices
|
|
2
|
+
|
|
3
|
+
Liquid Toast geometry and motion are adapted from rit3zh/expo-dynamic-notifications
|
|
4
|
+
(https://github.com/rit3zh/expo-dynamic-notifications), commit
|
|
5
|
+
5de059a5cbefbe28c14efbe785166665a7c70bc5. Original files: src/core/build-notification-geometry.ts,
|
|
6
|
+
src/logic/neck-profile.ts, src/conf/springs.ts, src/constants/notification.consts.ts,
|
|
7
|
+
src/components/dynamic-notifications/gooey.tsx. HJM changes: measured accessible content,
|
|
8
|
+
optional renderer boundary, hardware/capsule positioning and the existing Toast lifecycle.
|
|
9
|
+
|
|
10
|
+
The MIT License (MIT)
|
|
11
|
+
|
|
12
|
+
Copyright (c) 2015-present 650 Industries, Inc. (aka Expo)
|
|
13
|
+
|
|
14
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
15
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
16
|
+
in the Software without restriction, including without limitation the rights
|
|
17
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
18
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
19
|
+
furnished to do so, subject to the following conditions:
|
|
20
|
+
|
|
21
|
+
The above copyright notice and this permission notice shall be included in all
|
|
22
|
+
copies or substantial portions of the Software.
|
|
23
|
+
|
|
24
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
25
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
26
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
27
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
28
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
29
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
30
|
+
SOFTWARE.
|
|
31
|
+
|
|
32
|
+
## Thinking Orbs
|
|
33
|
+
|
|
34
|
+
Source: https://github.com/Jakubantalik/thinking-orbs/tree/de85557ca220332586d070d8788c0e1d6e877a0d
|
|
35
|
+
|
|
36
|
+
Geometry and presets adapted; DOM painters removed from the shared engine, lifecycle and semantic color integration rewritten for HJM.
|
|
37
|
+
|
|
38
|
+
MIT License
|
|
39
|
+
|
|
40
|
+
Copyright (c) 2026 Jakub Antalik
|
|
41
|
+
|
|
42
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
43
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
44
|
+
in the Software without restriction, including without limitation the rights
|
|
45
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
46
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
47
|
+
furnished to do so, subject to the following conditions:
|
|
48
|
+
|
|
49
|
+
The above copyright notice and this permission notice shall be included in all
|
|
50
|
+
copies or substantial portions of the Software.
|
|
51
|
+
|
|
52
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
53
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
54
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
55
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
56
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
57
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
58
|
+
SOFTWARE.
|
package/dist/agreement.d.ts
CHANGED
|
@@ -68,7 +68,7 @@ export declare const agreementRecipe: {
|
|
|
68
68
|
readonly paddingVertical: 12;
|
|
69
69
|
readonly background: Readonly<{
|
|
70
70
|
source: "theme";
|
|
71
|
-
key: "
|
|
71
|
+
key: "bg";
|
|
72
72
|
alpha?: number;
|
|
73
73
|
}>;
|
|
74
74
|
readonly radius: "md";
|
|
@@ -102,7 +102,7 @@ export declare const agreementRecipe: {
|
|
|
102
102
|
};
|
|
103
103
|
readonly highlightedBackground: Readonly<{
|
|
104
104
|
source: "theme";
|
|
105
|
-
key: "
|
|
105
|
+
key: "bg";
|
|
106
106
|
alpha?: number;
|
|
107
107
|
}>;
|
|
108
108
|
readonly focus: {
|
|
@@ -116,7 +116,7 @@ export declare const agreementRecipe: {
|
|
|
116
116
|
};
|
|
117
117
|
readonly selectedBackground: Readonly<{
|
|
118
118
|
source: "theme";
|
|
119
|
-
key: "
|
|
119
|
+
key: "bg";
|
|
120
120
|
alpha?: number;
|
|
121
121
|
}>;
|
|
122
122
|
readonly selectedIndicator: Readonly<{
|
package/dist/agreement.js
CHANGED
|
@@ -90,7 +90,7 @@ export const agreementRecipe = {
|
|
|
90
90
|
gap: spacing.sm,
|
|
91
91
|
paddingHorizontal: spacing.md,
|
|
92
92
|
paddingVertical: spacing.sm,
|
|
93
|
-
background: semanticColors.
|
|
93
|
+
background: semanticColors.canvas,
|
|
94
94
|
radius: "md",
|
|
95
95
|
textVariant: "bodyLarge",
|
|
96
96
|
color: semanticColors.content.primary,
|
package/dist/agreement.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agreement.js","sourceRoot":"","sources":["../src/agreement.ts"],"names":[],"mappings":"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","sourcesContent":["import type { BehaviorContract } from \"./behaviors.js\";\nimport type { ColorReference } from \"./color-references.js\";\nimport { collectionItemContract, focusIndicatorContract } from \"./component-contracts.js\";\nimport { control, spacing } from \"./foundations.js\";\nimport { semanticColors } from \"./semantic-colors.js\";\nimport {\n reconcileCheckboxSelection,\n toggleCheckboxSelection,\n type CheckboxSelectionItem,\n type CheckboxState,\n} from \"./selection-helpers.js\";\n\n/**\n * 가입·결제 앞에 서는 \"약관 동의\" 묶음이다. CheckboxGroup으로 매번 조립하던 것을\n * 계약으로 올리는 이유는 세 가지가 **체크박스 목록이 아니라 법적 절차**이기 때문이다.\n *\n * 1. 필수/선택이 제출 가능 여부를 결정한다 — CheckboxGroup은 그 판정을 갖지 않는다.\n * 2. 전체 동의는 자식의 합이지 별도 항목이 아니다(DataTable 머리글·TreeSelect 부모와\n * 같은 파생 관계). 저장되는 것은 개별 항목뿐이다.\n * 3. 각 항목은 \"읽을 수 있어야\" 한다 — 상세 보기 경로가 없는 동의는 동의가 아니다.\n * 그래서 `detail`은 renderer가 장식으로 넣는 화살표가 아니라 계약된 행동이다.\n *\n * 문구·링크 주소·법적 유효성은 제품이 소유한다. 이 계약은 판정과 배치만 갖는다.\n */\nexport type AgreementItemDescriptor<Id extends string = string> =\n CheckboxSelectionItem<Id> &\n Readonly<{\n /** 필수 항목은 하나라도 비면 제출을 막는다. 기본값은 선택(false). */\n required?: boolean;\n /**\n * 전문을 여는 경로. 제품이 링크(`href`)로 열지 시트로 열지는 renderer 밖의\n * 결정이라 여기서는 \"열 수 있다\"는 사실만 계약한다.\n */\n detail?: Readonly<{ label: string; href?: string }>;\n }>;\n\nexport type AgreementDescriptor<Id extends string = string> = Readonly<{\n /** 묶음 전체의 접근성 이름. \"약관 동의\"처럼 제품이 현지화한다. */\n accessibilityLabel: string;\n /** 전체 동의 행의 라벨. 필수이므로 renderer가 임의 문구를 만들지 않는다. */\n allLabel: string;\n items: readonly AgreementItemDescriptor<Id>[];\n}>;\n\nfunction assertNonEmpty(value: string, field: string): void {\n if (typeof value !== \"string\" || value.trim().length === 0) {\n throw new TypeError(`Agreement ${field} must not be empty`);\n }\n}\n\nexport function validateAgreementDescriptor<Id extends string>(\n descriptor: AgreementDescriptor<Id>,\n): void {\n assertNonEmpty(descriptor.accessibilityLabel, \"accessibilityLabel\");\n assertNonEmpty(descriptor.allLabel, \"allLabel\");\n if (!Array.isArray(descriptor.items) || descriptor.items.length === 0) {\n throw new RangeError(\"Agreement must contain at least one item\");\n }\n const ids = new Set<Id>();\n for (const item of descriptor.items) {\n assertNonEmpty(item.id, \"item id\");\n assertNonEmpty(item.label, \"item label\");\n if (ids.has(item.id)) throw new TypeError(`Duplicate Agreement item id: ${item.id}`);\n ids.add(item.id);\n if (item.detail !== undefined) {\n assertNonEmpty(item.detail.label, `item ${item.id} detail label`);\n }\n if (item.required === true && item.disabled === true) {\n /*\n 비활성 필수 항목은 사용자가 영원히 제출할 수 없는 화면을 만든다. 조용히\n 허용하면 \"버튼이 왜 안 눌리는지\" 알 수 없는 상태가 되므로 여기서 막는다.\n */\n throw new TypeError(\n `Agreement item ${item.id} cannot be both required and disabled`,\n );\n }\n }\n}\n\nexport type AgreementState<Id extends string = string> = Readonly<{\n /** 전체 동의 행이 그릴 tri-state. 개별 항목의 합에서만 나온다. */\n all: CheckboxState;\n /** 필수 항목이 모두 체크됐는가 — 제품의 제출 버튼이 읽는 값. */\n satisfied: boolean;\n /** 아직 체크되지 않은 필수 항목. 제품이 \"무엇이 남았는지\" 문장을 만든다. */\n missingRequiredIds: readonly Id[];\n}>;\n\n/**\n * 비활성 항목은 분모에서 뺀다 — 사용자가 바꿀 수 없는 것을 \"덜 동의했다\"고 셀 수\n * 없기 때문이다(`resolveDataTableSelectAllState`·`resolveTreeCheckedStates`와 같은 규칙).\n * 필수 항목은 비활성일 수 없으므로(위 validate) `satisfied` 판정에는 이 예외가 없다.\n */\nexport function resolveAgreementState<Id extends string>(\n descriptor: AgreementDescriptor<Id>,\n checkedIds: ReadonlySet<Id>,\n): AgreementState<Id> {\n validateAgreementDescriptor(descriptor);\n const selectable = descriptor.items.filter((item) => !item.disabled);\n const checkedCount = selectable.filter((item) => checkedIds.has(item.id)).length;\n const all: CheckboxState = selectable.length === 0 || checkedCount === 0\n ? false\n : checkedCount === selectable.length\n ? true\n : \"mixed\";\n const missingRequiredIds = descriptor.items\n .filter((item) => item.required === true && !checkedIds.has(item.id))\n .map((item) => item.id);\n return { all, satisfied: missingRequiredIds.length === 0, missingRequiredIds };\n}\n\n/** 개별 항목 토글. 비활성 항목 보호는 공용 helper가 이미 갖고 있다. */\nexport function toggleAgreementItem<Id extends string>(\n descriptor: AgreementDescriptor<Id>,\n checkedIds: ReadonlySet<Id>,\n id: Id,\n): ReadonlySet<Id> {\n validateAgreementDescriptor(descriptor);\n return toggleCheckboxSelection(descriptor.items, checkedIds, id);\n}\n\n/**\n * 전체 동의는 \"모두 체크됨\"의 반대로 간다 — mixed에서 누르면 채운다(공용\n * `getCheckboxNextState`의 기본값과 같은 관습). 비활성 항목의 현재 상태는 건드리지\n * 않는다: 그 값은 사용자가 만든 것이 아니라 제품이 고정한 것이다.\n */\nexport function toggleAgreementAll<Id extends string>(\n descriptor: AgreementDescriptor<Id>,\n checkedIds: ReadonlySet<Id>,\n): ReadonlySet<Id> {\n const { all } = resolveAgreementState(descriptor, checkedIds);\n const next = new Set(checkedIds);\n for (const item of descriptor.items) {\n if (item.disabled) continue;\n if (all === true) next.delete(item.id);\n else next.add(item.id);\n }\n return next;\n}\n\n/** 목록에서 사라진 항목의 동의는 남기지 않는다. */\nexport function reconcileAgreementSelection<Id extends string>(\n descriptor: AgreementDescriptor<Id>,\n checkedIds: ReadonlySet<Id>,\n): ReadonlySet<Id> {\n validateAgreementDescriptor(descriptor);\n return reconcileCheckboxSelection(descriptor.items, checkedIds);\n}\n\n/**\n * 전체 동의 행은 개별 행보다 시각적으로 무겁다 — 목록의 제목 역할을 하기 때문이다.\n * 나머지는 `collectionItemContract`를 그대로 쓴다(Menu·Tree·ListRow와 같은 행 chrome).\n */\nexport const agreementRecipe = {\n slots: [\"root\", \"all\", \"list\", \"item\", \"label\", \"detail\"] as const,\n all: {\n minHeight: control.minTouchTarget,\n gap: spacing.sm,\n paddingHorizontal: spacing.md,\n paddingVertical: spacing.sm,\n background: semanticColors.surface.sunken,\n radius: \"md\" as const,\n textVariant: \"bodyLarge\" as const,\n color: semanticColors.content.primary,\n },\n item: collectionItemContract,\n detail: {\n color: semanticColors.content.secondary,\n textVariant: \"label\" as const,\n minHeight: control.minTouchTarget,\n },\n required: { color: semanticColors.content.brand, textVariant: \"label\" as const },\n gap: spacing.xs,\n states: { focus: focusIndicatorContract },\n} as const satisfies {\n slots: readonly [\"root\", \"all\", \"list\", \"item\", \"label\", \"detail\"];\n all: {\n minHeight: number;\n gap: number;\n paddingHorizontal: number;\n paddingVertical: number;\n background: ColorReference;\n radius: \"md\";\n textVariant: \"bodyLarge\";\n color: ColorReference;\n };\n item: typeof collectionItemContract;\n detail: { color: ColorReference; textVariant: \"label\"; minHeight: number };\n required: { color: ColorReference; textVariant: \"label\" };\n gap: number;\n states: { focus: typeof focusIndicatorContract };\n};\n\nexport const agreementBehavior = {\n controlled: [\"checkedIds\", \"defaultCheckedIds\", \"onCheckedIdsChange\"],\n inputs: [\"items\", \"allLabel\", \"accessibilityLabel\"],\n events: [\"onDetail\"],\n stateAxes: {\n availability: [\"enabled\", \"disabled\"],\n value: [\"unchecked\", \"checked\", \"mixed\"],\n },\n web: {\n roles: [\"group\", \"checkbox\", \"link\", \"button\"],\n keyboard: [\"Tab\", \"Space\", \"Enter\"],\n focus: \"native\",\n },\n native: {\n roles: [\"checkbox\", \"link\", \"button\"],\n states: [\"checked\", \"disabled\"],\n actions: [\"toggle\", \"toggleAll\", \"openDetail\"],\n },\n scenarios: [\n \"all-agree-is-derived-from-the-items-never-stored-as-its-own-value\",\n \"checking-all-checks-every-enabled-item-and-leaves-disabled-ones-untouched\",\n \"required-items-alone-decide-whether-the-product-may-submit\",\n \"a-required-item-can-never-be-disabled-the-descriptor-is-rejected\",\n \"every-item-may-open-its-full-text-and-that-control-is-a-separate-tab-stop\",\n \"the-detail-control-never-toggles-the-agreement-it-only-opens-the-text\",\n \"optional-items-never-block-submission-and-are-announced-as-optional\",\n \"removing-an-item-drops-its-consent-instead-of-keeping-an-orphan-id\",\n ],\n} as const satisfies BehaviorContract;\n"]}
|
|
1
|
+
{"version":3,"file":"agreement.js","sourceRoot":"","sources":["../src/agreement.ts"],"names":[],"mappings":"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","sourcesContent":["import type { BehaviorContract } from \"./behaviors.js\";\nimport type { ColorReference } from \"./color-references.js\";\nimport { collectionItemContract, focusIndicatorContract } from \"./component-contracts.js\";\nimport { control, spacing } from \"./foundations.js\";\nimport { semanticColors } from \"./semantic-colors.js\";\nimport {\n reconcileCheckboxSelection,\n toggleCheckboxSelection,\n type CheckboxSelectionItem,\n type CheckboxState,\n} from \"./selection-helpers.js\";\n\n/**\n * 가입·결제 앞에 서는 \"약관 동의\" 묶음이다. CheckboxGroup으로 매번 조립하던 것을\n * 계약으로 올리는 이유는 세 가지가 **체크박스 목록이 아니라 법적 절차**이기 때문이다.\n *\n * 1. 필수/선택이 제출 가능 여부를 결정한다 — CheckboxGroup은 그 판정을 갖지 않는다.\n * 2. 전체 동의는 자식의 합이지 별도 항목이 아니다(DataTable 머리글·TreeSelect 부모와\n * 같은 파생 관계). 저장되는 것은 개별 항목뿐이다.\n * 3. 각 항목은 \"읽을 수 있어야\" 한다 — 상세 보기 경로가 없는 동의는 동의가 아니다.\n * 그래서 `detail`은 renderer가 장식으로 넣는 화살표가 아니라 계약된 행동이다.\n *\n * 문구·링크 주소·법적 유효성은 제품이 소유한다. 이 계약은 판정과 배치만 갖는다.\n */\nexport type AgreementItemDescriptor<Id extends string = string> =\n CheckboxSelectionItem<Id> &\n Readonly<{\n /** 필수 항목은 하나라도 비면 제출을 막는다. 기본값은 선택(false). */\n required?: boolean;\n /**\n * 전문을 여는 경로. 제품이 링크(`href`)로 열지 시트로 열지는 renderer 밖의\n * 결정이라 여기서는 \"열 수 있다\"는 사실만 계약한다.\n */\n detail?: Readonly<{ label: string; href?: string }>;\n }>;\n\nexport type AgreementDescriptor<Id extends string = string> = Readonly<{\n /** 묶음 전체의 접근성 이름. \"약관 동의\"처럼 제품이 현지화한다. */\n accessibilityLabel: string;\n /** 전체 동의 행의 라벨. 필수이므로 renderer가 임의 문구를 만들지 않는다. */\n allLabel: string;\n items: readonly AgreementItemDescriptor<Id>[];\n}>;\n\nfunction assertNonEmpty(value: string, field: string): void {\n if (typeof value !== \"string\" || value.trim().length === 0) {\n throw new TypeError(`Agreement ${field} must not be empty`);\n }\n}\n\nexport function validateAgreementDescriptor<Id extends string>(\n descriptor: AgreementDescriptor<Id>,\n): void {\n assertNonEmpty(descriptor.accessibilityLabel, \"accessibilityLabel\");\n assertNonEmpty(descriptor.allLabel, \"allLabel\");\n if (!Array.isArray(descriptor.items) || descriptor.items.length === 0) {\n throw new RangeError(\"Agreement must contain at least one item\");\n }\n const ids = new Set<Id>();\n for (const item of descriptor.items) {\n assertNonEmpty(item.id, \"item id\");\n assertNonEmpty(item.label, \"item label\");\n if (ids.has(item.id)) throw new TypeError(`Duplicate Agreement item id: ${item.id}`);\n ids.add(item.id);\n if (item.detail !== undefined) {\n assertNonEmpty(item.detail.label, `item ${item.id} detail label`);\n }\n if (item.required === true && item.disabled === true) {\n /*\n 비활성 필수 항목은 사용자가 영원히 제출할 수 없는 화면을 만든다. 조용히\n 허용하면 \"버튼이 왜 안 눌리는지\" 알 수 없는 상태가 되므로 여기서 막는다.\n */\n throw new TypeError(\n `Agreement item ${item.id} cannot be both required and disabled`,\n );\n }\n }\n}\n\nexport type AgreementState<Id extends string = string> = Readonly<{\n /** 전체 동의 행이 그릴 tri-state. 개별 항목의 합에서만 나온다. */\n all: CheckboxState;\n /** 필수 항목이 모두 체크됐는가 — 제품의 제출 버튼이 읽는 값. */\n satisfied: boolean;\n /** 아직 체크되지 않은 필수 항목. 제품이 \"무엇이 남았는지\" 문장을 만든다. */\n missingRequiredIds: readonly Id[];\n}>;\n\n/**\n * 비활성 항목은 분모에서 뺀다 — 사용자가 바꿀 수 없는 것을 \"덜 동의했다\"고 셀 수\n * 없기 때문이다(`resolveDataTableSelectAllState`·`resolveTreeCheckedStates`와 같은 규칙).\n * 필수 항목은 비활성일 수 없으므로(위 validate) `satisfied` 판정에는 이 예외가 없다.\n */\nexport function resolveAgreementState<Id extends string>(\n descriptor: AgreementDescriptor<Id>,\n checkedIds: ReadonlySet<Id>,\n): AgreementState<Id> {\n validateAgreementDescriptor(descriptor);\n const selectable = descriptor.items.filter((item) => !item.disabled);\n const checkedCount = selectable.filter((item) => checkedIds.has(item.id)).length;\n const all: CheckboxState = selectable.length === 0 || checkedCount === 0\n ? false\n : checkedCount === selectable.length\n ? true\n : \"mixed\";\n const missingRequiredIds = descriptor.items\n .filter((item) => item.required === true && !checkedIds.has(item.id))\n .map((item) => item.id);\n return { all, satisfied: missingRequiredIds.length === 0, missingRequiredIds };\n}\n\n/** 개별 항목 토글. 비활성 항목 보호는 공용 helper가 이미 갖고 있다. */\nexport function toggleAgreementItem<Id extends string>(\n descriptor: AgreementDescriptor<Id>,\n checkedIds: ReadonlySet<Id>,\n id: Id,\n): ReadonlySet<Id> {\n validateAgreementDescriptor(descriptor);\n return toggleCheckboxSelection(descriptor.items, checkedIds, id);\n}\n\n/**\n * 전체 동의는 \"모두 체크됨\"의 반대로 간다 — mixed에서 누르면 채운다(공용\n * `getCheckboxNextState`의 기본값과 같은 관습). 비활성 항목의 현재 상태는 건드리지\n * 않는다: 그 값은 사용자가 만든 것이 아니라 제품이 고정한 것이다.\n */\nexport function toggleAgreementAll<Id extends string>(\n descriptor: AgreementDescriptor<Id>,\n checkedIds: ReadonlySet<Id>,\n): ReadonlySet<Id> {\n const { all } = resolveAgreementState(descriptor, checkedIds);\n const next = new Set(checkedIds);\n for (const item of descriptor.items) {\n if (item.disabled) continue;\n if (all === true) next.delete(item.id);\n else next.add(item.id);\n }\n return next;\n}\n\n/** 목록에서 사라진 항목의 동의는 남기지 않는다. */\nexport function reconcileAgreementSelection<Id extends string>(\n descriptor: AgreementDescriptor<Id>,\n checkedIds: ReadonlySet<Id>,\n): ReadonlySet<Id> {\n validateAgreementDescriptor(descriptor);\n return reconcileCheckboxSelection(descriptor.items, checkedIds);\n}\n\n/**\n * 전체 동의 행은 개별 행보다 시각적으로 무겁다 — 목록의 제목 역할을 하기 때문이다.\n * 나머지는 `collectionItemContract`를 그대로 쓴다(Menu·Tree·ListRow와 같은 행 chrome).\n */\nexport const agreementRecipe = {\n slots: [\"root\", \"all\", \"list\", \"item\", \"label\", \"detail\"] as const,\n all: {\n minHeight: control.minTouchTarget,\n gap: spacing.sm,\n paddingHorizontal: spacing.md,\n paddingVertical: spacing.sm,\n background: semanticColors.canvas,\n radius: \"md\" as const,\n textVariant: \"bodyLarge\" as const,\n color: semanticColors.content.primary,\n },\n item: collectionItemContract,\n detail: {\n color: semanticColors.content.secondary,\n textVariant: \"label\" as const,\n minHeight: control.minTouchTarget,\n },\n required: { color: semanticColors.content.brand, textVariant: \"label\" as const },\n gap: spacing.xs,\n states: { focus: focusIndicatorContract },\n} as const satisfies {\n slots: readonly [\"root\", \"all\", \"list\", \"item\", \"label\", \"detail\"];\n all: {\n minHeight: number;\n gap: number;\n paddingHorizontal: number;\n paddingVertical: number;\n background: ColorReference;\n radius: \"md\";\n textVariant: \"bodyLarge\";\n color: ColorReference;\n };\n item: typeof collectionItemContract;\n detail: { color: ColorReference; textVariant: \"label\"; minHeight: number };\n required: { color: ColorReference; textVariant: \"label\" };\n gap: number;\n states: { focus: typeof focusIndicatorContract };\n};\n\nexport const agreementBehavior = {\n controlled: [\"checkedIds\", \"defaultCheckedIds\", \"onCheckedIdsChange\"],\n inputs: [\"items\", \"allLabel\", \"accessibilityLabel\"],\n events: [\"onDetail\"],\n stateAxes: {\n availability: [\"enabled\", \"disabled\"],\n value: [\"unchecked\", \"checked\", \"mixed\"],\n },\n web: {\n roles: [\"group\", \"checkbox\", \"link\", \"button\"],\n keyboard: [\"Tab\", \"Space\", \"Enter\"],\n focus: \"native\",\n },\n native: {\n roles: [\"checkbox\", \"link\", \"button\"],\n states: [\"checked\", \"disabled\"],\n actions: [\"toggle\", \"toggleAll\", \"openDetail\"],\n },\n scenarios: [\n \"all-agree-is-derived-from-the-items-never-stored-as-its-own-value\",\n \"checking-all-checks-every-enabled-item-and-leaves-disabled-ones-untouched\",\n \"required-items-alone-decide-whether-the-product-may-submit\",\n \"a-required-item-can-never-be-disabled-the-descriptor-is-rejected\",\n \"every-item-may-open-its-full-text-and-that-control-is-a-separate-tab-stop\",\n \"the-detail-control-never-toggles-the-agreement-it-only-opens-the-text\",\n \"optional-items-never-block-submission-and-are-announced-as-optional\",\n \"removing-an-item-drops-its-consent-instead-of-keeping-an-orphan-id\",\n ],\n} as const satisfies BehaviorContract;\n"]}
|
package/dist/asset.d.ts
CHANGED
package/dist/asset.js
CHANGED
|
@@ -30,7 +30,7 @@ export const assetRecipe = {
|
|
|
30
30
|
// 정사각은 모서리 0이다 — radius 토큰에 0이 없는 이유는 "모서리 없음"이 토큰이 아니라
|
|
31
31
|
// 값의 부재이기 때문이다.
|
|
32
32
|
shapes: { square: 0, rounded: radius.md, circle: radius.full },
|
|
33
|
-
background: semanticColors.
|
|
33
|
+
background: semanticColors.canvas,
|
|
34
34
|
border: semanticColors.border.default,
|
|
35
35
|
/** 묶음으로 겹칠 때의 비율. Avatar와 같은 값을 쓴다 — 한 줄에 섞여 나오기 때문이다. */
|
|
36
36
|
overlapRatio: 0.3,
|
package/dist/asset.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"asset.js","sourceRoot":"","sources":["../src/asset.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AA8BtD,MAAM,UAAU,uBAAuB,CAAC,UAA2B;IACjE,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QACjD,MAAM,IAAI,SAAS,CAAC,2BAA2B,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC5E,CAAC;IACD,MAAM,UAAU,GAAG,UAAU,CAAC,UAAU,IAAI,KAAK,CAAC;IAClD,MAAM,KAAK,GAAG,UAAU,CAAC,kBAAkB,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IAC1D,IAAI,CAAC,UAAU,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACtC,MAAM,IAAI,SAAS,CAAC,oDAAoD,CAAC,CAAC;IAC5E,CAAC;IACD,IAAI,UAAU,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACnC,mDAAmD;QACnD,MAAM,IAAI,SAAS,CAAC,wDAAwD,CAAC,CAAC;IAChF,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,kBAAkB,CAAC,IAAoB,EAAE,aAAsB;IAC7E,OAAO,CAAC,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,OAAO,CAAC,IAAI,CAAC,aAAa,CAAC;AACnE,CAAC;AAED,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB,KAAK,EAAE,CAAC,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,OAAO,CAAU;IAChE,KAAK,EAAE,CAAC,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,CAAU;IACpD,QAAQ,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,SAAS,EAAE;IAC9C,KAAK,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE;IACxD,wDAAwD;IACxD,gBAAgB;IAChB,MAAM,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,IAAI,EAAE;IAC9D,UAAU,EAAE,cAAc,CAAC,
|
|
1
|
+
{"version":3,"file":"asset.js","sourceRoot":"","sources":["../src/asset.ts"],"names":[],"mappings":"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","sourcesContent":["import type { BehaviorContract } from \"./behaviors.js\";\nimport { radius, spacing } from \"./foundations.js\";\nimport { semanticColors } from \"./semantic-colors.js\";\n\n/**\n * 아이콘·이미지·Lottie·비디오를 **같은 액자**에 넣는 자리.\n *\n * Icon·Image·Avatar가 이미 있는데 왜 또 두는가: 세 컴포넌트는 각자 다른 모양 규칙을 갖고\n * 있고(아이콘은 정사각, Avatar는 원, Image는 비율), 화면에서 이들이 **같은 줄에 섞여**\n * 나올 때 크기와 모서리가 어긋난다. Diairy의 `LottieArt`·`AnimalArt`가 그 어긋남을\n * 제품 안에서 다시 맞추고 있었다. Asset은 그 액자 규칙만 갖고, **무엇을 그릴지는 슬롯으로\n * 받는다** — Lottie와 비디오 재생기를 이 패키지가 의존하지 않기 위해서다.\n *\n * 그래서 이 계약에 재생 상태(play/pause/seek)가 없다. 재생기는 제품 것이고, 여기서\n * 정하는 것은 액자·크기·겹침·보조 표식뿐이다.\n */\nexport type AssetMediaKind = \"icon\" | \"image\" | \"lottie\" | \"video\";\nexport type AssetShape = \"square\" | \"rounded\" | \"circle\";\nexport type AssetSize = \"small\" | \"medium\" | \"large\" | \"xlarge\";\n\nexport type AssetDescriptor = Readonly<{\n kind: AssetMediaKind;\n size?: AssetSize;\n shape?: AssetShape;\n /**\n * 장식이면 `true`. 장식이 아닌데 이름이 없으면 거절한다 — 움직이는 그림일수록\n * \"무엇을 뜻하는지\"가 화면에 없으면 보조기기에서 사라진다.\n */\n decorative?: boolean;\n accessibilityLabel?: string;\n}>;\n\nexport function validateAssetDescriptor(descriptor: AssetDescriptor): void {\n if (!assetRecipe.kinds.includes(descriptor.kind)) {\n throw new TypeError(`Unsupported Asset kind: ${String(descriptor.kind)}`);\n }\n const decorative = descriptor.decorative ?? false;\n const label = descriptor.accessibilityLabel?.trim() ?? \"\";\n if (!decorative && label.length === 0) {\n throw new TypeError(\"A meaningful Asset must provide accessibilityLabel\");\n }\n if (decorative && label.length > 0) {\n // 둘 다 주면 어느 쪽이 참인지 화면이 모른다. 조용히 무시하면 이름을 지운 줄 모른다.\n throw new TypeError(\"A decorative Asset must not provide accessibilityLabel\");\n }\n}\n\n/**\n * 움직이는 자산은 `reducedMotion`에서 **첫 프레임(또는 포스터)로 정지**한다. 숨기지\n * 않는 이유: 그 자리에 그림이 있다는 사실 자체가 화면의 뜻인 경우가 많다(에어리의 동물).\n * 정지 화면을 제품이 주지 못하면 재생을 멈추기만 한다.\n */\nexport function shouldAnimateAsset(kind: AssetMediaKind, reducedMotion: boolean): boolean {\n return (kind === \"lottie\" || kind === \"video\") && !reducedMotion;\n}\n\nexport const assetRecipe = {\n slots: [\"root\", \"frame\", \"media\", \"accessory\", \"group\"] as const,\n kinds: [\"icon\", \"image\", \"lottie\", \"video\"] as const,\n defaults: { size: \"medium\", shape: \"rounded\" },\n sizes: { small: 32, medium: 48, large: 72, xlarge: 120 },\n // 정사각은 모서리 0이다 — radius 토큰에 0이 없는 이유는 \"모서리 없음\"이 토큰이 아니라\n // 값의 부재이기 때문이다.\n shapes: { square: 0, rounded: radius.md, circle: radius.full },\n background: semanticColors.canvas,\n border: semanticColors.border.default,\n /** 묶음으로 겹칠 때의 비율. Avatar와 같은 값을 쓴다 — 한 줄에 섞여 나오기 때문이다. */\n overlapRatio: 0.3,\n /** 보조 표식(재생 아이콘·상태 점)은 액자 **바깥 모서리**에 붙어 매체를 가리지 않는다. */\n accessory: { offset: spacing.xxs, gap: spacing.xxs },\n} as const;\n\nexport const assetBehavior = {\n /** 상태가 없다 — 액자는 값을 갖지 않고 슬롯만 받는다. */\n controlled: [],\n inputs: [\"kind\", \"size\", \"shape\", \"decorative\", \"accessibilityLabel\"],\n configuration: {\n kind: [\"icon\", \"image\", \"lottie\", \"video\"],\n shape: [\"square\", \"rounded\", \"circle\"],\n size: [\"small\", \"medium\", \"large\", \"xlarge\"],\n },\n stateAxes: { availability: [\"enabled\"] },\n web: { roles: [\"img\", \"presentation\"], keyboard: [], focus: \"none\" },\n native: { roles: [\"image\"], states: [], actions: [] },\n scenarios: [\n \"one-frame-rule-covers-icon-image-lottie-and-video-so-a-mixed-row-lines-up\",\n \"the-package-never-depends-on-a-player-the-media-arrives-as-a-slot\",\n \"a-meaningful-asset-without-a-name-is-rejected-instead-of-silently-decorative\",\n \"reduced-motion-freezes-the-frame-rather-than-removing-the-asset\",\n \"an-accessory-sits-on-the-frames-outer-corner-and-never-covers-the-media\",\n ],\n} as const satisfies BehaviorContract;\n"]}
|
package/dist/base-recipes.d.ts
CHANGED
|
@@ -30,7 +30,7 @@ export declare const buttonRecipe: {
|
|
|
30
30
|
readonly paddingHorizontal: null;
|
|
31
31
|
};
|
|
32
32
|
readonly secondary: {
|
|
33
|
-
readonly background: "
|
|
33
|
+
readonly background: "bg";
|
|
34
34
|
readonly content: "text";
|
|
35
35
|
readonly border: "borderControl";
|
|
36
36
|
readonly paddingHorizontal: null;
|
|
@@ -61,7 +61,7 @@ export declare const buttonRecipe: {
|
|
|
61
61
|
*/
|
|
62
62
|
readonly states: {
|
|
63
63
|
readonly selected: {
|
|
64
|
-
readonly background: "
|
|
64
|
+
readonly background: "bg";
|
|
65
65
|
readonly content: "contentBrand";
|
|
66
66
|
readonly border: "contentBrand";
|
|
67
67
|
};
|
|
@@ -120,11 +120,11 @@ export declare const buttonRecipe: {
|
|
|
120
120
|
export declare function resolveButtonLabelLines(largeText: boolean): number | null;
|
|
121
121
|
export declare const surfaceRecipe: {
|
|
122
122
|
readonly default: {
|
|
123
|
-
readonly background: "
|
|
123
|
+
readonly background: "bg";
|
|
124
124
|
readonly border: "border";
|
|
125
125
|
readonly borderAlpha: 1;
|
|
126
126
|
readonly elevated: false;
|
|
127
|
-
readonly borderAlways:
|
|
127
|
+
readonly borderAlways: true;
|
|
128
128
|
readonly clipsContent: true;
|
|
129
129
|
};
|
|
130
130
|
readonly raised: {
|
|
@@ -132,23 +132,23 @@ export declare const surfaceRecipe: {
|
|
|
132
132
|
readonly border: "border";
|
|
133
133
|
readonly borderAlpha: 1;
|
|
134
134
|
readonly elevated: true;
|
|
135
|
-
readonly borderAlways:
|
|
135
|
+
readonly borderAlways: true;
|
|
136
136
|
readonly clipsContent: false;
|
|
137
137
|
};
|
|
138
138
|
readonly sunken: {
|
|
139
|
-
readonly background: "
|
|
139
|
+
readonly background: "bg";
|
|
140
140
|
readonly border: "border";
|
|
141
141
|
readonly borderAlpha: 1;
|
|
142
142
|
readonly elevated: false;
|
|
143
|
-
readonly borderAlways:
|
|
143
|
+
readonly borderAlways: true;
|
|
144
144
|
readonly clipsContent: true;
|
|
145
145
|
};
|
|
146
146
|
readonly accent: {
|
|
147
|
-
readonly background: "
|
|
147
|
+
readonly background: "bg";
|
|
148
148
|
readonly border: "primary";
|
|
149
|
-
readonly borderAlpha:
|
|
149
|
+
readonly borderAlpha: 1;
|
|
150
150
|
readonly elevated: false;
|
|
151
|
-
readonly borderAlways:
|
|
151
|
+
readonly borderAlways: true;
|
|
152
152
|
readonly clipsContent: true;
|
|
153
153
|
};
|
|
154
154
|
readonly subtle: {
|
|
@@ -171,7 +171,7 @@ export declare const fieldRecipe: {
|
|
|
171
171
|
};
|
|
172
172
|
readonly variants: {
|
|
173
173
|
readonly surface: {
|
|
174
|
-
readonly background: "
|
|
174
|
+
readonly background: "bg";
|
|
175
175
|
};
|
|
176
176
|
readonly inset: {
|
|
177
177
|
readonly background: "bg";
|
|
@@ -184,7 +184,7 @@ export declare const fieldRecipe: {
|
|
|
184
184
|
};
|
|
185
185
|
readonly states: {
|
|
186
186
|
readonly idle: {
|
|
187
|
-
readonly border: "
|
|
187
|
+
readonly border: "borderControl";
|
|
188
188
|
};
|
|
189
189
|
readonly focused: {
|
|
190
190
|
readonly border: "contentBrand";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"base-recipes.d.ts","sourceRoot":"","sources":["../src/base-recipes.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAc,MAAM,EAAE,OAAO,EAAc,MAAM,kBAAkB,CAAC;AAGpF,MAAM,MAAM,UAAU,GAAG,SAAS,GAAG,WAAW,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAC;AAC/E,uEAAuE;AACvE,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,MAAM,CAAC;AAC7C;;;GAGG;AACH,MAAM,MAAM,WAAW,GAAG,QAAQ,GAAG,SAAS,CAAC;AAC/C,MAAM,MAAM,UAAU,GAAG,MAAM,OAAO,OAAO,CAAC,YAAY,CAAC;AAC3D,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAChF,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,MAAM,OAAO,OAAO,CAAC;AAC3D,MAAM,MAAM,aAAa,GAAG,MAAM,OAAO,MAAM,CAAC;AAChD,MAAM,MAAM,YAAY,GAAG,SAAS,GAAG,OAAO,CAAC;AAC/C,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,OAAO,GAAG,MAAM,CAAC;AAErD,4EAA4E;AAC5E,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAcvB;;;;OAIG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IA2BH;;;;;;;;;;;OAWG;;;;;;CAmCJ,CAAC;AAEF,yFAAyF;AACzF,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAEzE;AAED,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAwDzB,CAAC;AAEF,6CAA6C;AAC7C,MAAM,MAAM,UAAU,GAAG,OAAO,GAAG,QAAQ,CAAC;AAE5C,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"base-recipes.d.ts","sourceRoot":"","sources":["../src/base-recipes.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAc,MAAM,EAAE,OAAO,EAAc,MAAM,kBAAkB,CAAC;AAGpF,MAAM,MAAM,UAAU,GAAG,SAAS,GAAG,WAAW,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAC;AAC/E,uEAAuE;AACvE,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,MAAM,CAAC;AAC7C;;;GAGG;AACH,MAAM,MAAM,WAAW,GAAG,QAAQ,GAAG,SAAS,CAAC;AAC/C,MAAM,MAAM,UAAU,GAAG,MAAM,OAAO,OAAO,CAAC,YAAY,CAAC;AAC3D,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAChF,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,MAAM,OAAO,OAAO,CAAC;AAC3D,MAAM,MAAM,aAAa,GAAG,MAAM,OAAO,MAAM,CAAC;AAChD,MAAM,MAAM,YAAY,GAAG,SAAS,GAAG,OAAO,CAAC;AAC/C,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,OAAO,GAAG,MAAM,CAAC;AAErD,4EAA4E;AAC5E,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAcvB;;;;OAIG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IA2BH;;;;;;;;;;;OAWG;;;;;;CAmCJ,CAAC;AAEF,yFAAyF;AACzF,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAEzE;AAED,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAwDzB,CAAC;AAEF,6CAA6C;AAC7C,MAAM,MAAM,UAAU,GAAG,OAAO,GAAG,QAAQ,CAAC;AAE5C,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IA6BtB;;;;OAIG;uCAC+B,MAAM,GAAG,IAAI;;;;;;;;;;;;;;;;;;;;;;;CAqDhD,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,eAAe;;;;;CAU3B,CAAC;AAEF,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;CAM3B,CAAC"}
|
package/dist/base-recipes.js
CHANGED
|
@@ -7,7 +7,7 @@ export const buttonRecipe = {
|
|
|
7
7
|
primary: { background: "primary", content: "onPrimary", border: null, paddingHorizontal: null },
|
|
8
8
|
// The outline is a border role, not a text color. Drawing it in `textSub`
|
|
9
9
|
// made a resting control read heavier than the selected one beside it.
|
|
10
|
-
secondary: { background: "
|
|
10
|
+
secondary: { background: "bg", content: "text", border: "borderControl", paddingHorizontal: null },
|
|
11
11
|
ghost: { background: null, content: "textMuted", border: null, paddingHorizontal: null },
|
|
12
12
|
danger: { background: "dangerFill", content: "onDanger", border: null, paddingHorizontal: null },
|
|
13
13
|
// A link-tone control is inline copy, so the size axis' horizontal padding
|
|
@@ -20,7 +20,7 @@ export const buttonRecipe = {
|
|
|
20
20
|
* consumer painted the selected background in product styles.
|
|
21
21
|
*/
|
|
22
22
|
states: {
|
|
23
|
-
selected: { background: "
|
|
23
|
+
selected: { background: "bg", content: "contentBrand", border: "contentBrand" },
|
|
24
24
|
},
|
|
25
25
|
sizes: {
|
|
26
26
|
small: {
|
|
@@ -65,11 +65,11 @@ export function resolveButtonLabelLines(largeText) {
|
|
|
65
65
|
}
|
|
66
66
|
export const surfaceRecipe = {
|
|
67
67
|
default: {
|
|
68
|
-
background: "
|
|
68
|
+
background: "bg",
|
|
69
69
|
border: "border",
|
|
70
70
|
borderAlpha: 1,
|
|
71
71
|
elevated: false,
|
|
72
|
-
borderAlways:
|
|
72
|
+
borderAlways: true,
|
|
73
73
|
clipsContent: true,
|
|
74
74
|
},
|
|
75
75
|
raised: {
|
|
@@ -77,28 +77,28 @@ export const surfaceRecipe = {
|
|
|
77
77
|
border: "border",
|
|
78
78
|
borderAlpha: 1,
|
|
79
79
|
elevated: true,
|
|
80
|
-
borderAlways:
|
|
80
|
+
borderAlways: true,
|
|
81
81
|
// An elevated surface must not clip: `overflow: hidden` cuts off its own
|
|
82
82
|
// shadow. Every other tone clips so a child image cannot spill past the
|
|
83
83
|
// rounded corner, which consumers were fixing in product styles.
|
|
84
84
|
clipsContent: false,
|
|
85
85
|
},
|
|
86
|
-
//
|
|
87
|
-
//
|
|
86
|
+
// White surfaces retain a boundary; tonal fills were removed at the user
|
|
87
|
+
// review, so elevation and border now carry hierarchy.
|
|
88
88
|
sunken: {
|
|
89
|
-
background: "
|
|
89
|
+
background: "bg",
|
|
90
90
|
border: "border",
|
|
91
91
|
borderAlpha: 1,
|
|
92
92
|
elevated: false,
|
|
93
|
-
borderAlways:
|
|
93
|
+
borderAlways: true,
|
|
94
94
|
clipsContent: true,
|
|
95
95
|
},
|
|
96
96
|
accent: {
|
|
97
|
-
background: "
|
|
97
|
+
background: "bg",
|
|
98
98
|
border: "primary",
|
|
99
|
-
borderAlpha:
|
|
99
|
+
borderAlpha: 1,
|
|
100
100
|
elevated: false,
|
|
101
|
-
borderAlways:
|
|
101
|
+
borderAlways: true,
|
|
102
102
|
clipsContent: true,
|
|
103
103
|
},
|
|
104
104
|
subtle: {
|
|
@@ -123,7 +123,8 @@ export const fieldRecipe = {
|
|
|
123
123
|
],
|
|
124
124
|
defaults: { variant: "surface", shape: "medium", align: "start" },
|
|
125
125
|
variants: {
|
|
126
|
-
|
|
126
|
+
// Input interiors stay on the canvas; focus is conveyed by the blue outline, not a grey or blue fill.
|
|
127
|
+
surface: { background: "bg" },
|
|
127
128
|
inset: { background: "bg" },
|
|
128
129
|
},
|
|
129
130
|
shapes: {
|
|
@@ -132,7 +133,7 @@ export const fieldRecipe = {
|
|
|
132
133
|
full: "full",
|
|
133
134
|
},
|
|
134
135
|
states: {
|
|
135
|
-
idle: { border: "
|
|
136
|
+
idle: { border: "borderControl" },
|
|
136
137
|
focused: { border: "contentBrand" },
|
|
137
138
|
invalid: { border: "danger" },
|
|
138
139
|
},
|
package/dist/base-recipes.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"base-recipes.js","sourceRoot":"","sources":["../src/base-recipes.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ThemeColors } from \"./colors.js\";\nimport { control, fontWeight, radius, spacing, typography } from \"./foundations.js\";\nimport type { FontWeightValue, TextVariant } from \"./foundations.js\";\n\nexport type ButtonTone = \"primary\" | \"secondary\" | \"ghost\" | \"danger\" | \"link\";\n/** Corner geometry of the control frame. Mirrors `IconButtonShape`. */\nexport type ButtonShape = \"rounded\" | \"pill\";\n/**\n * Where the label sits inside the frame. `center` is the action default;\n * `leading` is for a full-width row action whose label reads as list copy.\n */\nexport type ButtonAlign = \"center\" | \"leading\";\nexport type ButtonSize = keyof typeof control.buttonHeight;\nexport type SurfaceTone = \"default\" | \"raised\" | \"accent\" | \"sunken\" | \"subtle\";\nexport type SurfacePadding = \"none\" | keyof typeof spacing;\nexport type SurfaceRadius = keyof typeof radius;\nexport type FieldVariant = \"surface\" | \"inset\";\nexport type FieldShape = \"medium\" | \"large\" | \"full\";\n\n/** Small renderer entry point for the three foundational visual recipes. */\nexport const buttonRecipe = {\n slots: [\"root\", \"leading\", \"label\", \"trailing\", \"spinner\"] as const,\n defaults: { tone: \"primary\", size: \"medium\", shape: \"rounded\", align: \"center\" } as const,\n tones: {\n primary: { background: \"primary\", content: \"onPrimary\", border: null, paddingHorizontal: null },\n // The outline is a border role, not a text color. Drawing it in `textSub`\n // made a resting control read heavier than the selected one beside it.\n secondary: { background: \"surfaceAlt\", content: \"text\", border: \"borderControl\", paddingHorizontal: null },\n ghost: { background: null, content: \"textMuted\", border: null, paddingHorizontal: null },\n danger: { background: \"dangerFill\", content: \"onDanger\", border: null, paddingHorizontal: null },\n // A link-tone control is inline copy, so the size axis' horizontal padding\n // would push it out of alignment with the text around it.\n link: { background: null, content: \"contentBrand\", border: null, paddingHorizontal: 0 },\n },\n /**\n * Visual treatment for a control that is also a toggle. `accessibilityState`\n * / `aria-pressed` already expressed the state; without a paired visual every\n * consumer painted the selected background in product styles.\n */\n states: {\n selected: { background: \"surfaceAccent\", content: \"contentBrand\", border: \"contentBrand\" },\n },\n sizes: {\n small: {\n height: control.buttonHeight.small,\n hitSlop: control.buttonHitSlop.small,\n paddingHorizontal: spacing.sm,\n textVariant: \"label\",\n },\n medium: {\n height: control.buttonHeight.medium,\n hitSlop: control.buttonHitSlop.medium,\n paddingHorizontal: spacing.md,\n textVariant: \"body\",\n },\n large: {\n height: control.buttonHeight.large,\n hitSlop: control.buttonHitSlop.large,\n paddingHorizontal: spacing.lg,\n textVariant: \"bodyLarge\",\n },\n },\n shapes: { rounded: \"md\", pill: \"full\" },\n aligns: { center: \"center\", leading: \"flex-start\" },\n opacity: { disabled: 0.5, pressed: 0.86 },\n /**\n * 긴 라벨의 처리 규칙. 지금까지 이 판단이 없어서 Web은 무한히 줄바꿈하고 RN은 한 줄로\n * 잘렸다 — 같은 번역문이 두 표면에서 다르게 보였다.\n *\n * 자르지 않고 **두 줄까지 접는다**. 잘린 행동 라벨(\"삭제하...\"))은 무엇을 하는 버튼인지\n * 잃는다. 대신 무제한 줄바꿈도 막는다 — 하단 CTA 행처럼 버튼이 남의 레이아웃을 밀어내는\n * 자리가 있고, 두 줄을 넘는 라벨은 레이아웃이 아니라 카피의 문제다.\n *\n * 큰 글자 설정에서는 상한을 **푼다**. 사용자가 키운 글자에서 두 줄로 자르면 내용이\n * 사라지고, 그건 WCAG 1.4.4를 어긴다. 제품 카피가 아니라 사용자 설정이 원인이기 때문에\n * 같은 규칙을 적용할 수 없다.\n */\n label: { overflow: \"wrap\", maxLines: 2, liftCapOnLargeText: true },\n} as const satisfies {\n slots: readonly string[];\n defaults: { tone: ButtonTone; size: ButtonSize; shape: ButtonShape; align: ButtonAlign };\n tones: Record<\n ButtonTone,\n {\n background: keyof ThemeColors | null;\n content: keyof ThemeColors;\n border: keyof ThemeColors | null;\n /** `null` keeps the size axis' padding. */\n paddingHorizontal: number | null;\n }\n >;\n states: {\n selected: {\n background: keyof ThemeColors;\n content: keyof ThemeColors;\n border: keyof ThemeColors;\n };\n };\n sizes: Record<\n ButtonSize,\n {\n height: number;\n hitSlop: number;\n paddingHorizontal: number;\n textVariant: TextVariant;\n }\n >;\n shapes: Record<ButtonShape, keyof typeof radius>;\n aligns: Record<ButtonAlign, \"center\" | \"flex-start\">;\n opacity: { disabled: number; pressed: number };\n label: { overflow: \"wrap\"; maxLines: number; liftCapOnLargeText: boolean };\n};\n\n/** Resolves the label's line cap for one resolved environment. `null` means uncapped. */\nexport function resolveButtonLabelLines(largeText: boolean): number | null {\n return largeText && buttonRecipe.label.liftCapOnLargeText ? null : buttonRecipe.label.maxLines;\n}\n\nexport const surfaceRecipe = {\n default: {\n background: \"surface\",\n border: \"border\",\n borderAlpha: 1,\n elevated: false,\n borderAlways: false,\n clipsContent: true,\n },\n raised: {\n background: \"bg\",\n border: \"border\",\n borderAlpha: 1,\n elevated: true,\n borderAlways: false,\n // An elevated surface must not clip: `overflow: hidden` cuts off its own\n // shadow. Every other tone clips so a child image cannot spill past the\n // rounded corner, which consumers were fixing in product styles.\n clipsContent: false,\n },\n // `semanticColors.surface.sunken` already named this role; without a paired\n // tone a consumer had to paint `surfaceAlt` in its own product styles.\n sunken: {\n background: \"surfaceAlt\",\n border: \"border\",\n borderAlpha: 1,\n elevated: false,\n borderAlways: false,\n clipsContent: true,\n },\n accent: {\n background: \"surfaceAccent\",\n border: \"primary\",\n borderAlpha: 0.3,\n elevated: false,\n borderAlways: false,\n clipsContent: true,\n },\n subtle: {\n background: \"bg\",\n border: \"border\",\n borderAlpha: 1,\n elevated: false,\n borderAlways: true,\n clipsContent: true,\n },\n} as const satisfies Record<\n SurfaceTone,\n {\n background: keyof ThemeColors;\n border: keyof ThemeColors;\n borderAlpha: number;\n elevated: boolean;\n clipsContent: boolean;\n borderAlways: boolean;\n }\n>;\n\n/** Text placement inside a field control. */\nexport type FieldAlign = \"start\" | \"center\";\n\nexport const fieldRecipe = {\n slots: [\n \"root\",\n \"label\",\n \"control\",\n \"leading\",\n \"input\",\n \"trailing\",\n \"hint\",\n \"error\",\n ] as const,\n defaults: { variant: \"surface\", shape: \"medium\", align: \"start\" } as const,\n variants: {\n surface: { background: \"surface\" },\n inset: { background: \"bg\" },\n },\n shapes: {\n medium: \"md\",\n large: \"lg\",\n full: \"full\",\n },\n states: {\n idle: { border: \"textMuted\" },\n focused: { border: \"contentBrand\" },\n invalid: { border: \"danger\" },\n },\n minHeight: control.minTouchTarget,\n multilineMinHeight: 80,\n /**\n * Upper bound for a growing multiline field, expressed in visible lines. A\n * consumer otherwise reaches for `inputStyle={{ maxHeight }}`, which moves a\n * recipe-owned dimension into product code. `null` keeps unbounded growth.\n */\n multilineMaxVisibleLines: null as number | null,\n borderWidth: 1,\n focusRingWidth: 2,\n focusRingOffset: 2,\n paddingHorizontal: spacing.md,\n paddingVertical: spacing.sm,\n textVariant: \"body\",\n label: {\n color: \"textBody\",\n textVariant: \"body\",\n fontWeight: fontWeight.semibold,\n gap: spacing.xs,\n },\n support: {\n hintColor: \"textMuted\",\n errorColor: \"danger\",\n textVariant: \"label\",\n gap: 6,\n },\n placeholder: { color: \"textMuted\" },\n disabledOpacity: 0.6,\n} as const satisfies {\n slots: readonly string[];\n defaults: { variant: FieldVariant; shape: FieldShape; align: FieldAlign };\n variants: Record<FieldVariant, { background: keyof ThemeColors }>;\n shapes: Record<FieldShape, keyof typeof radius>;\n states: Record<\n \"idle\" | \"focused\" | \"invalid\",\n { border: keyof ThemeColors }\n >;\n minHeight: number;\n multilineMinHeight: number;\n multilineMaxVisibleLines: number | null;\n borderWidth: number;\n focusRingWidth: number;\n focusRingOffset: number;\n paddingHorizontal: number;\n paddingVertical: number;\n textVariant: keyof typeof typography;\n label: {\n color: keyof ThemeColors;\n textVariant: keyof typeof typography;\n fontWeight: FontWeightValue;\n gap: number;\n };\n support: {\n hintColor: keyof ThemeColors;\n errorColor: keyof ThemeColors;\n textVariant: keyof typeof typography;\n gap: number;\n };\n placeholder: { color: keyof ThemeColors };\n disabledOpacity: number;\n};\n\n/**\n * Renderer-neutral Surface geometry. Tone colors stay in `surfaceRecipe` for\n * compatibility; these axes make the previously implicit Web/Native defaults\n * explicit without changing that public recipe shape.\n */\nexport const surfaceDefaults = {\n tone: \"default\",\n padding: \"none\",\n radius: \"lg\",\n bordered: false,\n} as const satisfies {\n tone: SurfaceTone;\n padding: SurfacePadding;\n radius: SurfaceRadius;\n bordered: boolean;\n};\n\nexport const surfaceGeometry = {\n paddings: { none: 0, ...spacing },\n radii: radius,\n} as const satisfies {\n paddings: Record<SurfacePadding, number>;\n radii: Record<SurfaceRadius, number>;\n};\n"]}
|
|
1
|
+
{"version":3,"file":"base-recipes.js","sourceRoot":"","sources":["../src/base-recipes.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ThemeColors } from \"./colors.js\";\nimport { control, fontWeight, radius, spacing, typography } from \"./foundations.js\";\nimport type { FontWeightValue, TextVariant } from \"./foundations.js\";\n\nexport type ButtonTone = \"primary\" | \"secondary\" | \"ghost\" | \"danger\" | \"link\";\n/** Corner geometry of the control frame. Mirrors `IconButtonShape`. */\nexport type ButtonShape = \"rounded\" | \"pill\";\n/**\n * Where the label sits inside the frame. `center` is the action default;\n * `leading` is for a full-width row action whose label reads as list copy.\n */\nexport type ButtonAlign = \"center\" | \"leading\";\nexport type ButtonSize = keyof typeof control.buttonHeight;\nexport type SurfaceTone = \"default\" | \"raised\" | \"accent\" | \"sunken\" | \"subtle\";\nexport type SurfacePadding = \"none\" | keyof typeof spacing;\nexport type SurfaceRadius = keyof typeof radius;\nexport type FieldVariant = \"surface\" | \"inset\";\nexport type FieldShape = \"medium\" | \"large\" | \"full\";\n\n/** Small renderer entry point for the three foundational visual recipes. */\nexport const buttonRecipe = {\n slots: [\"root\", \"leading\", \"label\", \"trailing\", \"spinner\"] as const,\n defaults: { tone: \"primary\", size: \"medium\", shape: \"rounded\", align: \"center\" } as const,\n tones: {\n primary: { background: \"primary\", content: \"onPrimary\", border: null, paddingHorizontal: null },\n // The outline is a border role, not a text color. Drawing it in `textSub`\n // made a resting control read heavier than the selected one beside it.\n secondary: { background: \"bg\", content: \"text\", border: \"borderControl\", paddingHorizontal: null },\n ghost: { background: null, content: \"textMuted\", border: null, paddingHorizontal: null },\n danger: { background: \"dangerFill\", content: \"onDanger\", border: null, paddingHorizontal: null },\n // A link-tone control is inline copy, so the size axis' horizontal padding\n // would push it out of alignment with the text around it.\n link: { background: null, content: \"contentBrand\", border: null, paddingHorizontal: 0 },\n },\n /**\n * Visual treatment for a control that is also a toggle. `accessibilityState`\n * / `aria-pressed` already expressed the state; without a paired visual every\n * consumer painted the selected background in product styles.\n */\n states: {\n selected: { background: \"bg\", content: \"contentBrand\", border: \"contentBrand\" },\n },\n sizes: {\n small: {\n height: control.buttonHeight.small,\n hitSlop: control.buttonHitSlop.small,\n paddingHorizontal: spacing.sm,\n textVariant: \"label\",\n },\n medium: {\n height: control.buttonHeight.medium,\n hitSlop: control.buttonHitSlop.medium,\n paddingHorizontal: spacing.md,\n textVariant: \"body\",\n },\n large: {\n height: control.buttonHeight.large,\n hitSlop: control.buttonHitSlop.large,\n paddingHorizontal: spacing.lg,\n textVariant: \"bodyLarge\",\n },\n },\n shapes: { rounded: \"md\", pill: \"full\" },\n aligns: { center: \"center\", leading: \"flex-start\" },\n opacity: { disabled: 0.5, pressed: 0.86 },\n /**\n * 긴 라벨의 처리 규칙. 지금까지 이 판단이 없어서 Web은 무한히 줄바꿈하고 RN은 한 줄로\n * 잘렸다 — 같은 번역문이 두 표면에서 다르게 보였다.\n *\n * 자르지 않고 **두 줄까지 접는다**. 잘린 행동 라벨(\"삭제하...\"))은 무엇을 하는 버튼인지\n * 잃는다. 대신 무제한 줄바꿈도 막는다 — 하단 CTA 행처럼 버튼이 남의 레이아웃을 밀어내는\n * 자리가 있고, 두 줄을 넘는 라벨은 레이아웃이 아니라 카피의 문제다.\n *\n * 큰 글자 설정에서는 상한을 **푼다**. 사용자가 키운 글자에서 두 줄로 자르면 내용이\n * 사라지고, 그건 WCAG 1.4.4를 어긴다. 제품 카피가 아니라 사용자 설정이 원인이기 때문에\n * 같은 규칙을 적용할 수 없다.\n */\n label: { overflow: \"wrap\", maxLines: 2, liftCapOnLargeText: true },\n} as const satisfies {\n slots: readonly string[];\n defaults: { tone: ButtonTone; size: ButtonSize; shape: ButtonShape; align: ButtonAlign };\n tones: Record<\n ButtonTone,\n {\n background: keyof ThemeColors | null;\n content: keyof ThemeColors;\n border: keyof ThemeColors | null;\n /** `null` keeps the size axis' padding. */\n paddingHorizontal: number | null;\n }\n >;\n states: {\n selected: {\n background: keyof ThemeColors;\n content: keyof ThemeColors;\n border: keyof ThemeColors;\n };\n };\n sizes: Record<\n ButtonSize,\n {\n height: number;\n hitSlop: number;\n paddingHorizontal: number;\n textVariant: TextVariant;\n }\n >;\n shapes: Record<ButtonShape, keyof typeof radius>;\n aligns: Record<ButtonAlign, \"center\" | \"flex-start\">;\n opacity: { disabled: number; pressed: number };\n label: { overflow: \"wrap\"; maxLines: number; liftCapOnLargeText: boolean };\n};\n\n/** Resolves the label's line cap for one resolved environment. `null` means uncapped. */\nexport function resolveButtonLabelLines(largeText: boolean): number | null {\n return largeText && buttonRecipe.label.liftCapOnLargeText ? null : buttonRecipe.label.maxLines;\n}\n\nexport const surfaceRecipe = {\n default: {\n background: \"bg\",\n border: \"border\",\n borderAlpha: 1,\n elevated: false,\n borderAlways: true,\n clipsContent: true,\n },\n raised: {\n background: \"bg\",\n border: \"border\",\n borderAlpha: 1,\n elevated: true,\n borderAlways: true,\n // An elevated surface must not clip: `overflow: hidden` cuts off its own\n // shadow. Every other tone clips so a child image cannot spill past the\n // rounded corner, which consumers were fixing in product styles.\n clipsContent: false,\n },\n // White surfaces retain a boundary; tonal fills were removed at the user\n // review, so elevation and border now carry hierarchy.\n sunken: {\n background: \"bg\",\n border: \"border\",\n borderAlpha: 1,\n elevated: false,\n borderAlways: true,\n clipsContent: true,\n },\n accent: {\n background: \"bg\",\n border: \"primary\",\n borderAlpha: 1,\n elevated: false,\n borderAlways: true,\n clipsContent: true,\n },\n subtle: {\n background: \"bg\",\n border: \"border\",\n borderAlpha: 1,\n elevated: false,\n borderAlways: true,\n clipsContent: true,\n },\n} as const satisfies Record<\n SurfaceTone,\n {\n background: keyof ThemeColors;\n border: keyof ThemeColors;\n borderAlpha: number;\n elevated: boolean;\n clipsContent: boolean;\n borderAlways: boolean;\n }\n>;\n\n/** Text placement inside a field control. */\nexport type FieldAlign = \"start\" | \"center\";\n\nexport const fieldRecipe = {\n slots: [\n \"root\",\n \"label\",\n \"control\",\n \"leading\",\n \"input\",\n \"trailing\",\n \"hint\",\n \"error\",\n ] as const,\n defaults: { variant: \"surface\", shape: \"medium\", align: \"start\" } as const,\n variants: {\n // Input interiors stay on the canvas; focus is conveyed by the blue outline, not a grey or blue fill.\n surface: { background: \"bg\" },\n inset: { background: \"bg\" },\n },\n shapes: {\n medium: \"md\",\n large: \"lg\",\n full: \"full\",\n },\n states: {\n idle: { border: \"borderControl\" },\n focused: { border: \"contentBrand\" },\n invalid: { border: \"danger\" },\n },\n minHeight: control.minTouchTarget,\n multilineMinHeight: 80,\n /**\n * Upper bound for a growing multiline field, expressed in visible lines. A\n * consumer otherwise reaches for `inputStyle={{ maxHeight }}`, which moves a\n * recipe-owned dimension into product code. `null` keeps unbounded growth.\n */\n multilineMaxVisibleLines: null as number | null,\n borderWidth: 1,\n focusRingWidth: 2,\n focusRingOffset: 2,\n paddingHorizontal: spacing.md,\n paddingVertical: spacing.sm,\n textVariant: \"body\",\n label: {\n color: \"textBody\",\n textVariant: \"body\",\n fontWeight: fontWeight.semibold,\n gap: spacing.xs,\n },\n support: {\n hintColor: \"textMuted\",\n errorColor: \"danger\",\n textVariant: \"label\",\n gap: 6,\n },\n placeholder: { color: \"textMuted\" },\n disabledOpacity: 0.6,\n} as const satisfies {\n slots: readonly string[];\n defaults: { variant: FieldVariant; shape: FieldShape; align: FieldAlign };\n variants: Record<FieldVariant, { background: keyof ThemeColors }>;\n shapes: Record<FieldShape, keyof typeof radius>;\n states: Record<\n \"idle\" | \"focused\" | \"invalid\",\n { border: keyof ThemeColors }\n >;\n minHeight: number;\n multilineMinHeight: number;\n multilineMaxVisibleLines: number | null;\n borderWidth: number;\n focusRingWidth: number;\n focusRingOffset: number;\n paddingHorizontal: number;\n paddingVertical: number;\n textVariant: keyof typeof typography;\n label: {\n color: keyof ThemeColors;\n textVariant: keyof typeof typography;\n fontWeight: FontWeightValue;\n gap: number;\n };\n support: {\n hintColor: keyof ThemeColors;\n errorColor: keyof ThemeColors;\n textVariant: keyof typeof typography;\n gap: number;\n };\n placeholder: { color: keyof ThemeColors };\n disabledOpacity: number;\n};\n\n/**\n * Renderer-neutral Surface geometry. Tone colors stay in `surfaceRecipe` for\n * compatibility; these axes make the previously implicit Web/Native defaults\n * explicit without changing that public recipe shape.\n */\nexport const surfaceDefaults = {\n tone: \"default\",\n padding: \"none\",\n radius: \"lg\",\n bordered: false,\n} as const satisfies {\n tone: SurfaceTone;\n padding: SurfacePadding;\n radius: SurfaceRadius;\n bordered: boolean;\n};\n\nexport const surfaceGeometry = {\n paddings: { none: 0, ...spacing },\n radii: radius,\n} as const satisfies {\n paddings: Record<SurfacePadding, number>;\n radii: Record<SurfaceRadius, number>;\n};\n"]}
|
package/dist/behaviors.d.ts
CHANGED
|
@@ -1402,7 +1402,7 @@ export declare const behaviorRegistry: {
|
|
|
1402
1402
|
readonly states: readonly [];
|
|
1403
1403
|
readonly actions: readonly [];
|
|
1404
1404
|
};
|
|
1405
|
-
readonly scenarios: readonly ["focus-enters-surface-on-open", "escape-closes-and-restores-trigger-focus", "outside-pointer-close-does-not-cancel-the-original-interaction", "tabbing-past-last-focusable-child-closes-without-trapping", "controlled-owner-programmatic-close-always-wins", "close-action-inside-content-closes-exactly-once", "trigger-while-open-does-not-reopen", "one-visible-popover-per-trigger"];
|
|
1405
|
+
readonly scenarios: readonly ["focus-enters-surface-on-open", "escape-closes-and-restores-trigger-focus", "outside-pointer-close-does-not-cancel-the-original-interaction", "tabbing-past-last-focusable-child-closes-without-trapping", "optional-hover-opens-after-delay-and-survives-pointer-crossing", "hover-mode-retains-press-activation-for-touch-and-keyboard", "controlled-owner-programmatic-close-always-wins", "close-action-inside-content-closes-exactly-once", "trigger-while-open-does-not-reopen", "one-visible-popover-per-trigger"];
|
|
1406
1406
|
};
|
|
1407
1407
|
readonly tree: {
|
|
1408
1408
|
readonly controlled: readonly ["expandedKeys", "defaultExpandedKeys", "onExpandedKeysChange", "selection", "asyncState"];
|