@hjmds/design-contracts 1.39.0 → 1.41.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. package/dist/agreement.d.ts +2 -2
  2. package/dist/base-recipes.d.ts +11 -3
  3. package/dist/base-recipes.d.ts.map +1 -1
  4. package/dist/base-recipes.js +9 -4
  5. package/dist/base-recipes.js.map +1 -1
  6. package/dist/behaviors.d.ts +4 -4
  7. package/dist/card.d.ts +1 -1
  8. package/dist/card.js +1 -1
  9. package/dist/card.js.map +1 -1
  10. package/dist/catalog.d.ts +119 -85
  11. package/dist/catalog.d.ts.map +1 -1
  12. package/dist/choice-row.d.ts +26 -0
  13. package/dist/choice-row.d.ts.map +1 -0
  14. package/dist/choice-row.js +24 -0
  15. package/dist/choice-row.js.map +1 -0
  16. package/dist/colors.d.ts +2 -0
  17. package/dist/colors.d.ts.map +1 -1
  18. package/dist/colors.js +3 -1
  19. package/dist/colors.js.map +1 -1
  20. package/dist/command-palette.d.ts +2 -2
  21. package/dist/component-contracts.d.ts +2 -2
  22. package/dist/component-contracts.js +2 -2
  23. package/dist/component-contracts.js.map +1 -1
  24. package/dist/component-recipes.d.ts +76 -64
  25. package/dist/component-recipes.d.ts.map +1 -1
  26. package/dist/component-recipes.js +18 -16
  27. package/dist/component-recipes.js.map +1 -1
  28. package/dist/data-table.d.ts +1 -1
  29. package/dist/floating-action-button.d.ts +14 -2
  30. package/dist/floating-action-button.d.ts.map +1 -1
  31. package/dist/floating-action-button.js +5 -3
  32. package/dist/floating-action-button.js.map +1 -1
  33. package/dist/icon-button-recipe.d.ts +2 -2
  34. package/dist/icon-button-recipe.js +3 -3
  35. package/dist/icon-button-recipe.js.map +1 -1
  36. package/dist/menubar.d.ts +2 -2
  37. package/dist/palette-contrast.d.ts.map +1 -1
  38. package/dist/palette-contrast.js +2 -0
  39. package/dist/palette-contrast.js.map +1 -1
  40. package/dist/semantic-colors.d.ts +18 -1
  41. package/dist/semantic-colors.d.ts.map +1 -1
  42. package/dist/semantic-colors.js +7 -1
  43. package/dist/semantic-colors.js.map +1 -1
  44. package/dist/sidebar.d.ts +2 -2
  45. package/dist/time-picker.d.ts +16 -4
  46. package/dist/time-picker.d.ts.map +1 -1
  47. package/dist/time-picker.js +26 -5
  48. package/dist/time-picker.js.map +1 -1
  49. package/dist/toggle-group.d.ts +3 -3
  50. package/dist/toggle-group.js +3 -3
  51. package/dist/toggle-group.js.map +1 -1
  52. package/dist/transfer-list.d.ts +2 -2
  53. package/dist/tree.d.ts +2 -2
  54. package/dist/version.d.ts +1 -1
  55. package/dist/version.js +1 -1
  56. package/dist/version.js.map +1 -1
  57. package/docs/ant-design-coverage.md +6 -1
  58. package/docs/brand-boundary.md +1 -0
  59. package/docs/floating-action-button.md +6 -4
  60. package/docs/generated/component-maturity.md +1 -1
  61. package/docs/generated/renderer-evidence.json +3 -3
  62. package/docs/generated/renderer-evidence.md +1 -1
  63. package/docs/generated/showcase-manifest.json +1 -1
  64. package/docs/optional-adapters.md +1 -1
  65. package/docs/theme-palette.md +60 -0
  66. package/docs/time-picker.md +21 -0
  67. package/docs/toast.md +11 -0
  68. package/docs/usage/FINDING.md +71 -0
  69. package/docs/usage/README.md +5 -3
  70. package/docs/usage/SELECTION.md +8 -2
  71. package/docs/usage/components/bottom-navigation.md +5 -0
  72. package/docs/usage/components/card.md +2 -2
  73. package/docs/usage/components/chart.md +3 -1
  74. package/docs/usage/components/chip.md +1 -1
  75. package/docs/usage/components/choice-row.md +77 -0
  76. package/docs/usage/components/floating-action-button.md +5 -4
  77. package/docs/usage/components/image.md +18 -3
  78. package/docs/usage/components/keyboard-avoidance-context.md +3 -3
  79. package/docs/usage/components/segmented-control.md +1 -1
  80. package/docs/usage/components/sheet.md +1 -0
  81. package/docs/usage/components/surface.md +7 -1
  82. package/docs/usage/components/tabs.md +5 -0
  83. package/docs/usage/components/time-picker.md +20 -2
  84. package/docs/usage/components/toggle-group.md +5 -0
  85. package/docs/usage/compositions/save-feedback.md +43 -21
  86. package/docs/usage/tokens/color.md +17 -3
  87. package/package.json +7 -1
@@ -118,12 +118,12 @@ export declare const agreementRecipe: {
118
118
  };
119
119
  readonly selectedBackground: Readonly<{
120
120
  source: "theme";
121
- key: "bg";
121
+ key: "surfaceSelected";
122
122
  alpha?: number;
123
123
  }>;
124
124
  readonly selectedIndicator: Readonly<{
125
125
  source: "theme";
126
- key: "contentBrand";
126
+ key: "text";
127
127
  alpha?: number;
128
128
  }>;
129
129
  readonly danger: Readonly<{
@@ -9,7 +9,7 @@ export type ButtonShape = "rounded" | "pill";
9
9
  */
10
10
  export type ButtonAlign = "center" | "leading";
11
11
  export type ButtonSize = keyof typeof control.buttonHeight;
12
- export type SurfaceTone = "default" | "raised" | "accent" | "sunken" | "subtle";
12
+ export type SurfaceTone = "default" | "raised" | "accent" | "sunken" | "subtle" | "selected";
13
13
  export type SurfacePadding = "none" | keyof typeof spacing;
14
14
  export type SurfaceRadius = keyof typeof radius;
15
15
  export type FieldVariant = "surface" | "inset";
@@ -72,8 +72,8 @@ export declare const buttonRecipe: {
72
72
  */
73
73
  readonly states: {
74
74
  readonly selected: {
75
- readonly background: "bg";
76
- readonly content: "contentBrand";
75
+ readonly background: "surfaceSelected";
76
+ readonly content: "text";
77
77
  readonly border: null;
78
78
  };
79
79
  };
@@ -172,6 +172,14 @@ export declare const surfaceRecipe: {
172
172
  readonly borderAlways: true;
173
173
  readonly clipsContent: true;
174
174
  };
175
+ readonly selected: {
176
+ readonly background: "surfaceSelected";
177
+ readonly border: "borderControl";
178
+ readonly borderAlpha: 1;
179
+ readonly elevated: false;
180
+ readonly borderAlways: true;
181
+ readonly clipsContent: true;
182
+ };
175
183
  readonly subtle: {
176
184
  readonly background: "bg";
177
185
  readonly border: "border";
@@ -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,gBAAgB,GAAG,MAAM,GAAG,QAAQ,CAAC;AACjD,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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAgBvB;;;;OAIG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IA4BH;;;;;;;;;;;OAWG;;;;;;CAoCJ,CAAC;AAEF,wEAAwE;AACxE,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,gBAAgB,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,GAAG,MAAM,CAI3G;AAED;;;;;GAKG;AACH,MAAM,MAAM,UAAU,GAAG,OAAO,GAAG,KAAK,GAAG,MAAM,CAAC;AAClD,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,GAAG,MAAM,CAIpF;AAED,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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IA8BtB;;;;OAIG;uCAC+B,MAAM,GAAG,IAAI;;;;;;;;;;;;;;;;;;;;;;;IAqB/C;;;;;;;;;;;;OAYG;;;;;CAwCJ,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,eAAe;;;;;CAU3B,CAAC;AAEF,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;CAM3B,CAAC"}
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,gBAAgB,GAAG,MAAM,GAAG,QAAQ,CAAC;AACjD,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,GAAG,UAAU,CAAC;AAC7F,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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAgBvB;;;;OAIG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IA4BH;;;;;;;;;;;OAWG;;;;;;CAoCJ,CAAC;AAEF,wEAAwE;AACxE,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,gBAAgB,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,GAAG,MAAM,CAI3G;AAED;;;;;GAKG;AACH,MAAM,MAAM,UAAU,GAAG,OAAO,GAAG,KAAK,GAAG,MAAM,CAAC;AAClD,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,GAAG,MAAM,CAIpF;AAED,yFAAyF;AACzF,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAEzE;AAED,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6DzB,CAAC;AAEF,6CAA6C;AAC7C,MAAM,MAAM,UAAU,GAAG,OAAO,GAAG,QAAQ,CAAC;AAE5C,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IA8BtB;;;;OAIG;uCAC+B,MAAM,GAAG,IAAI;;;;;;;;;;;;;;;;;;;;;;;IAqB/C;;;;;;;;;;;;OAYG;;;;;CAwCJ,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,eAAe;;;;;CAU3B,CAAC;AAEF,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;CAM3B,CAAC"}
@@ -22,8 +22,8 @@ export const buttonRecipe = {
22
22
  * consumer painted the selected background in product styles.
23
23
  */
24
24
  states: {
25
- // Selected reactions use content color, without adding an outline (2026-10-10 user request).
26
- selected: { background: "bg", content: "contentBrand", border: null },
25
+ // Persistent toggles share the neutral selection pair (2026-10-23); focus stays independent.
26
+ selected: { background: "surfaceSelected", content: "text", border: null },
27
27
  },
28
28
  sizes: {
29
29
  small: {
@@ -100,8 +100,8 @@ export const surfaceRecipe = {
100
100
  // rounded corner, which consumers were fixing in product styles.
101
101
  clipsContent: false,
102
102
  },
103
- // White surfaces retain a boundary; tonal fills were removed at the user
104
- // review, so elevation and border now carry hierarchy.
103
+ // Resting surfaces keep canvas fills; elevation and borders carry hierarchy.
104
+ // Persistent selection has its own neutral tone below.
105
105
  sunken: {
106
106
  background: "bg",
107
107
  border: "border",
@@ -118,6 +118,11 @@ export const surfaceRecipe = {
118
118
  borderAlways: true,
119
119
  clipsContent: true,
120
120
  },
121
+ // Selected cards need their own surface role, without repurposing a brand accent.
122
+ selected: {
123
+ background: "surfaceSelected", border: "borderControl", borderAlpha: 1,
124
+ elevated: false, borderAlways: true, clipsContent: true,
125
+ },
121
126
  subtle: {
122
127
  background: "bg",
123
128
  border: "border",
@@ -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 ButtonAppearance = \"flat\" | \"raised\";\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\", \"face\", \"side\", \"leading\", \"label\", \"trailing\", \"spinner\"] as const,\n defaults: { tone: \"primary\", size: \"medium\", shape: \"rounded\", align: \"center\", appearance: \"flat\" } as const,\n // A solid underside belongs to the button, rather than a product's second press/state engine.\n raised: { depths: { small: 3, medium: 4, large: 5 }, sideShade: 0.25, settleDuration: 120 },\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 reactions use content color, without adding an outline (2026-10-10 user request).\n selected: { background: \"bg\", content: \"contentBrand\", border: null },\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; appearance: ButtonAppearance };\n raised: { depths: Record<ButtonSize, number>; sideShade: number; settleDuration: number };\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 | null;\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/** Raised paint never adds a frame to a frameless ghost/link action. */\nexport function resolveButtonDepth(appearance: ButtonAppearance, tone: ButtonTone, size: ButtonSize): number {\n if (appearance !== \"flat\" && appearance !== \"raised\") throw new TypeError(\"Unknown Button appearance\");\n if (appearance === \"flat\" || tone === \"ghost\" || tone === \"link\") return 0;\n return buttonRecipe.raised.depths[size];\n}\n\n/**\n * Edge alignment for a ghost text Button at a row/header edge (2026-10-17 measured audit: a sort trigger's chevron\n * sat 29px from the edge against a 16px inset). Same rule as `resolveIconButtonEdgeOverhang`: a frameless control\n * overhangs the edge by its own inline padding so its label/glyph, not the transparent box, sets the inset.\n * Framed tones (primary, secondary, danger) align their frame instead, and `link` already has no padding: 0.\n */\nexport type ButtonEdge = \"start\" | \"end\" | \"both\";\nexport function resolveButtonEdgeOverhang(tone: ButtonTone, size: ButtonSize): number {\n const toneContract = buttonRecipe.tones[tone];\n if (toneContract.background !== null || toneContract.border !== null) return 0;\n return toneContract.paddingHorizontal ?? buttonRecipe.sizes[size].paddingHorizontal;\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 // Error and focus can share a hue in a product palette; thickness keeps validation distinct without color alone.\n invalid: { border: \"danger\", borderWidth: 2 },\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.medium,\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 /**\n * Which slots `disabledOpacity` fades (2026-10-06). Label and control dim; the\n * hint and the error keep their contrast, because they are the text that says\n * why the field is locked or what to fix. Renderers used to fade the whole\n * frame, so the small support text (`support.textVariant`) — already the\n * lowest-contrast text in the field — lost contrast too. Fading nothing was\n * rejected: the label and the control are what tell the user the field is off.\n *\n * Every field-family input follows this scope. The amount is the component\n * recipe's own `states.disabledOpacity` where it has one (SearchField,\n * PasswordField, OtpField, NumberField, Select); otherwise this recipe's\n * `disabledOpacity` (TextField, TextArea, Field, Combobox, DatePicker, TagsInput).\n */\n disabledScope: {\n dimmed: [\"label\", \"control\"],\n unchanged: [\"hint\", \"error\"],\n },\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<\"idle\" | \"focused\", { border: keyof ThemeColors }> & {\n invalid: { border: keyof ThemeColors; borderWidth: number };\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 disabledScope: {\n dimmed: readonly (\"label\" | \"control\")[];\n unchanged: readonly (\"hint\" | \"error\")[];\n };\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":"AACA,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAmBpF,4EAA4E;AAC5E,MAAM,CAAC,MAAM,YAAY,GAAG;IAC1B,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,UAAU,EAAE,SAAS,CAAU;IACnF,QAAQ,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,EAAW;IAC7G,8FAA8F;IAC9F,MAAM,EAAE,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,cAAc,EAAE,GAAG,EAAE;IAC3F,KAAK,EAAE;QACL,OAAO,EAAE,EAAE,UAAU,EAAE,SAAS,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,iBAAiB,EAAE,IAAI,EAAE;QAC/F,0EAA0E;QAC1E,uEAAuE;QACvE,SAAS,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,eAAe,EAAE,iBAAiB,EAAE,IAAI,EAAE;QAClG,KAAK,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,iBAAiB,EAAE,IAAI,EAAE;QACxF,MAAM,EAAE,EAAE,UAAU,EAAE,YAAY,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,iBAAiB,EAAE,IAAI,EAAE;QAChG,2EAA2E;QAC3E,0DAA0D;QAC1D,IAAI,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,EAAE,IAAI,EAAE,iBAAiB,EAAE,CAAC,EAAE;KACxF;IACD;;;;OAIG;IACH,MAAM,EAAE;QACN,6FAA6F;QAC7F,QAAQ,EAAE,EAAE,UAAU,EAAE,iBAAiB,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE;KAC3E;IACD,KAAK,EAAE;QACL,KAAK,EAAE;YACL,MAAM,EAAE,OAAO,CAAC,YAAY,CAAC,KAAK;YAClC,OAAO,EAAE,OAAO,CAAC,aAAa,CAAC,KAAK;YACpC,iBAAiB,EAAE,OAAO,CAAC,EAAE;YAC7B,WAAW,EAAE,OAAO;SACrB;QACD,MAAM,EAAE;YACN,MAAM,EAAE,OAAO,CAAC,YAAY,CAAC,MAAM;YACnC,OAAO,EAAE,OAAO,CAAC,aAAa,CAAC,MAAM;YACrC,iBAAiB,EAAE,OAAO,CAAC,EAAE;YAC7B,WAAW,EAAE,MAAM;SACpB;QACD,KAAK,EAAE;YACL,MAAM,EAAE,OAAO,CAAC,YAAY,CAAC,KAAK;YAClC,OAAO,EAAE,OAAO,CAAC,aAAa,CAAC,KAAK;YACpC,iBAAiB,EAAE,OAAO,CAAC,EAAE;YAC7B,WAAW,EAAE,WAAW;SACzB;KACF;IACD,MAAM,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE;IACvC,MAAM,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,YAAY,EAAE;IACnD,OAAO,EAAE,EAAE,QAAQ,EAAE,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE;IACzC;;;;;;;;;;;OAWG;IACH,KAAK,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,EAAE,kBAAkB,EAAE,IAAI,EAAE;CAmCnE,CAAC;AAEF,wEAAwE;AACxE,MAAM,UAAU,kBAAkB,CAAC,UAA4B,EAAE,IAAgB,EAAE,IAAgB;IACjG,IAAI,UAAU,KAAK,MAAM,IAAI,UAAU,KAAK,QAAQ;QAAE,MAAM,IAAI,SAAS,CAAC,2BAA2B,CAAC,CAAC;IACvG,IAAI,UAAU,KAAK,MAAM,IAAI,IAAI,KAAK,OAAO,IAAI,IAAI,KAAK,MAAM;QAAE,OAAO,CAAC,CAAC;IAC3E,OAAO,YAAY,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;AAC1C,CAAC;AASD,MAAM,UAAU,yBAAyB,CAAC,IAAgB,EAAE,IAAgB;IAC1E,MAAM,YAAY,GAAG,YAAY,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC9C,IAAI,YAAY,CAAC,UAAU,KAAK,IAAI,IAAI,YAAY,CAAC,MAAM,KAAK,IAAI;QAAE,OAAO,CAAC,CAAC;IAC/E,OAAO,YAAY,CAAC,iBAAiB,IAAI,YAAY,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,iBAAiB,CAAC;AACtF,CAAC;AAED,yFAAyF;AACzF,MAAM,UAAU,uBAAuB,CAAC,SAAkB;IACxD,OAAO,SAAS,IAAI,YAAY,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,YAAY,CAAC,KAAK,CAAC,QAAQ,CAAC;AACjG,CAAC;AAED,MAAM,CAAC,MAAM,aAAa,GAAG;IAC3B,OAAO,EAAE;QACP,UAAU,EAAE,IAAI;QAChB,MAAM,EAAE,QAAQ;QAChB,WAAW,EAAE,CAAC;QACd,QAAQ,EAAE,KAAK;QACf,YAAY,EAAE,IAAI;QAClB,YAAY,EAAE,IAAI;KACnB;IACD,MAAM,EAAE;QACN,UAAU,EAAE,IAAI;QAChB,MAAM,EAAE,QAAQ;QAChB,WAAW,EAAE,CAAC;QACd,QAAQ,EAAE,IAAI;QACd,YAAY,EAAE,IAAI;QAClB,yEAAyE;QACzE,wEAAwE;QACxE,iEAAiE;QACjE,YAAY,EAAE,KAAK;KACpB;IACD,6EAA6E;IAC7E,uDAAuD;IACvD,MAAM,EAAE;QACN,UAAU,EAAE,IAAI;QAChB,MAAM,EAAE,QAAQ;QAChB,WAAW,EAAE,CAAC;QACd,QAAQ,EAAE,KAAK;QACf,YAAY,EAAE,IAAI;QAClB,YAAY,EAAE,IAAI;KACnB;IACD,MAAM,EAAE;QACN,UAAU,EAAE,IAAI;QAChB,MAAM,EAAE,SAAS;QACjB,WAAW,EAAE,CAAC;QACd,QAAQ,EAAE,KAAK;QACf,YAAY,EAAE,IAAI;QAClB,YAAY,EAAE,IAAI;KACnB;IACD,kFAAkF;IAClF,QAAQ,EAAE;QACR,UAAU,EAAE,iBAAiB,EAAE,MAAM,EAAE,eAAe,EAAE,WAAW,EAAE,CAAC;QACtE,QAAQ,EAAE,KAAK,EAAE,YAAY,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI;KACxD;IACD,MAAM,EAAE;QACN,UAAU,EAAE,IAAI;QAChB,MAAM,EAAE,QAAQ;QAChB,WAAW,EAAE,CAAC;QACd,QAAQ,EAAE,KAAK;QACf,YAAY,EAAE,IAAI;QAClB,YAAY,EAAE,IAAI;KACnB;CAWF,CAAC;AAKF,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB,KAAK,EAAE;QACL,MAAM;QACN,OAAO;QACP,SAAS;QACT,SAAS;QACT,OAAO;QACP,UAAU;QACV,MAAM;QACN,OAAO;KACC;IACV,QAAQ,EAAE,EAAE,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,OAAO,EAAW;IAC1E,QAAQ,EAAE;QACR,sGAAsG;QACtG,OAAO,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE;QAC7B,KAAK,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE;KAC5B;IACD,MAAM,EAAE;QACN,MAAM,EAAE,IAAI;QACZ,KAAK,EAAE,IAAI;QACX,IAAI,EAAE,MAAM;KACb;IACD,MAAM,EAAE;QACN,IAAI,EAAE,EAAE,MAAM,EAAE,eAAe,EAAE;QACjC,OAAO,EAAE,EAAE,MAAM,EAAE,cAAc,EAAE;QACnC,iHAAiH;QACjH,OAAO,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,WAAW,EAAE,CAAC,EAAE;KAC9C;IACD,SAAS,EAAE,OAAO,CAAC,cAAc;IACjC,kBAAkB,EAAE,EAAE;IACtB;;;;OAIG;IACH,wBAAwB,EAAE,IAAqB;IAC/C,WAAW,EAAE,CAAC;IACd,cAAc,EAAE,CAAC;IACjB,eAAe,EAAE,CAAC;IAClB,iBAAiB,EAAE,OAAO,CAAC,EAAE;IAC7B,eAAe,EAAE,OAAO,CAAC,EAAE;IAC3B,WAAW,EAAE,MAAM;IACnB,KAAK,EAAE;QACL,KAAK,EAAE,UAAU;QACjB,WAAW,EAAE,MAAM;QACnB,UAAU,EAAE,UAAU,CAAC,MAAM;QAC7B,GAAG,EAAE,OAAO,CAAC,EAAE;KAChB;IACD,OAAO,EAAE;QACP,SAAS,EAAE,WAAW;QACtB,UAAU,EAAE,QAAQ;QACpB,WAAW,EAAE,OAAO;QACpB,GAAG,EAAE,CAAC;KACP;IACD,WAAW,EAAE,EAAE,KAAK,EAAE,WAAW,EAAE;IACnC,eAAe,EAAE,GAAG;IACpB;;;;;;;;;;;;OAYG;IACH,aAAa,EAAE;QACb,MAAM,EAAE,CAAC,OAAO,EAAE,SAAS,CAAC;QAC5B,SAAS,EAAE,CAAC,MAAM,EAAE,OAAO,CAAC;KAC7B;CAoCF,CAAC;AAEF;;;;GAIG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG;IAC7B,IAAI,EAAE,SAAS;IACf,OAAO,EAAE,MAAM;IACf,MAAM,EAAE,IAAI;IACZ,QAAQ,EAAE,KAAK;CAMhB,CAAC;AAEF,MAAM,CAAC,MAAM,eAAe,GAAG;IAC7B,QAAQ,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE,GAAG,OAAO,EAAE;IACjC,KAAK,EAAE,MAAM;CAId,CAAC","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 ButtonAppearance = \"flat\" | \"raised\";\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\" | \"selected\";\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\", \"face\", \"side\", \"leading\", \"label\", \"trailing\", \"spinner\"] as const,\n defaults: { tone: \"primary\", size: \"medium\", shape: \"rounded\", align: \"center\", appearance: \"flat\" } as const,\n // A solid underside belongs to the button, rather than a product's second press/state engine.\n raised: { depths: { small: 3, medium: 4, large: 5 }, sideShade: 0.25, settleDuration: 120 },\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 // Persistent toggles share the neutral selection pair (2026-10-23); focus stays independent.\n selected: { background: \"surfaceSelected\", content: \"text\", border: null },\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; appearance: ButtonAppearance };\n raised: { depths: Record<ButtonSize, number>; sideShade: number; settleDuration: number };\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 | null;\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/** Raised paint never adds a frame to a frameless ghost/link action. */\nexport function resolveButtonDepth(appearance: ButtonAppearance, tone: ButtonTone, size: ButtonSize): number {\n if (appearance !== \"flat\" && appearance !== \"raised\") throw new TypeError(\"Unknown Button appearance\");\n if (appearance === \"flat\" || tone === \"ghost\" || tone === \"link\") return 0;\n return buttonRecipe.raised.depths[size];\n}\n\n/**\n * Edge alignment for a ghost text Button at a row/header edge (2026-10-17 measured audit: a sort trigger's chevron\n * sat 29px from the edge against a 16px inset). Same rule as `resolveIconButtonEdgeOverhang`: a frameless control\n * overhangs the edge by its own inline padding so its label/glyph, not the transparent box, sets the inset.\n * Framed tones (primary, secondary, danger) align their frame instead, and `link` already has no padding: 0.\n */\nexport type ButtonEdge = \"start\" | \"end\" | \"both\";\nexport function resolveButtonEdgeOverhang(tone: ButtonTone, size: ButtonSize): number {\n const toneContract = buttonRecipe.tones[tone];\n if (toneContract.background !== null || toneContract.border !== null) return 0;\n return toneContract.paddingHorizontal ?? buttonRecipe.sizes[size].paddingHorizontal;\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 // Resting surfaces keep canvas fills; elevation and borders carry hierarchy.\n // Persistent selection has its own neutral tone below.\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 // Selected cards need their own surface role, without repurposing a brand accent.\n selected: {\n background: \"surfaceSelected\", border: \"borderControl\", borderAlpha: 1,\n elevated: false, borderAlways: true, 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 // Error and focus can share a hue in a product palette; thickness keeps validation distinct without color alone.\n invalid: { border: \"danger\", borderWidth: 2 },\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.medium,\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 /**\n * Which slots `disabledOpacity` fades (2026-10-06). Label and control dim; the\n * hint and the error keep their contrast, because they are the text that says\n * why the field is locked or what to fix. Renderers used to fade the whole\n * frame, so the small support text (`support.textVariant`) — already the\n * lowest-contrast text in the field — lost contrast too. Fading nothing was\n * rejected: the label and the control are what tell the user the field is off.\n *\n * Every field-family input follows this scope. The amount is the component\n * recipe's own `states.disabledOpacity` where it has one (SearchField,\n * PasswordField, OtpField, NumberField, Select); otherwise this recipe's\n * `disabledOpacity` (TextField, TextArea, Field, Combobox, DatePicker, TagsInput).\n */\n disabledScope: {\n dimmed: [\"label\", \"control\"],\n unchanged: [\"hint\", \"error\"],\n },\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<\"idle\" | \"focused\", { border: keyof ThemeColors }> & {\n invalid: { border: keyof ThemeColors; borderWidth: number };\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 disabledScope: {\n dimmed: readonly (\"label\" | \"control\")[];\n unchanged: readonly (\"hint\" | \"error\")[];\n };\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"]}
@@ -1343,7 +1343,7 @@ export declare const behaviorRegistry: {
1343
1343
  };
1344
1344
  readonly timePicker: {
1345
1345
  readonly controlled: readonly ["value", "onValueChange"];
1346
- readonly inputs: readonly ["labels", "minuteStep", "isTimeUnavailable", "presentation"];
1346
+ readonly inputs: readonly ["labels", "minuteStep", "isTimeUnavailable", "presentation", "selectionStyle"];
1347
1347
  readonly stateAxes: {
1348
1348
  readonly availability: readonly ["enabled", "disabled", "readOnly"];
1349
1349
  readonly value: readonly ["empty", "partial", "selected"];
@@ -1356,12 +1356,12 @@ export declare const behaviorRegistry: {
1356
1356
  readonly dismiss: readonly ["action", "escape", "outside", "blur"];
1357
1357
  };
1358
1358
  readonly native: {
1359
- readonly roles: readonly ["button", "dialog", "radio"];
1359
+ readonly roles: readonly ["button", "dialog", "radio", "adjustable"];
1360
1360
  readonly states: readonly ["disabled", "expanded", "checked"];
1361
- readonly actions: readonly ["activate", "dismiss"];
1361
+ readonly actions: readonly ["activate", "dismiss", "increment", "decrement"];
1362
1362
  readonly dismiss: readonly ["action", "back", "outside"];
1363
1363
  };
1364
- readonly scenarios: readonly ["two-columns-share-one-draft-and-overlay", "column-selection-never-dismisses", "confirm-commits-a-complete-available-HH:mm", "cancel-discards-edits", "external-value-reconciles-draft", "inline-parent-owns-confirmation", "unavailable-options-never-activate", "midnight-is-a-valid-value"];
1364
+ readonly scenarios: readonly ["two-columns-share-one-draft-and-overlay", "column-selection-never-dismisses", "confirm-commits-a-complete-available-HH:mm", "cancel-discards-edits", "external-value-reconciles-draft", "inline-parent-owns-confirmation", "unavailable-options-never-activate", "midnight-is-a-valid-value", "wheel-centers-available-slots-without-initial-commit", "wheel-adjustment-preserves-confirm-and-cancel"];
1365
1365
  };
1366
1366
  readonly sidePanel: {
1367
1367
  readonly controlled: readonly ["open", "defaultOpen", "onOpenChange", "dismissPolicy"];
package/dist/card.d.ts CHANGED
@@ -13,7 +13,7 @@ export declare const cardRecipe: {
13
13
  readonly badgesAlign: "start";
14
14
  readonly padding: "md";
15
15
  };
16
- readonly selectedTone: "accent";
16
+ readonly selectedTone: "selected";
17
17
  readonly interaction: {
18
18
  readonly disabledOpacity: 0.5;
19
19
  readonly pressedOpacity: 0.86;
package/dist/card.js CHANGED
@@ -31,7 +31,7 @@ export const cardRecipe = {
31
31
  badgesAlign: "start",
32
32
  padding: "md",
33
33
  },
34
- selectedTone: "accent",
34
+ selectedTone: "selected",
35
35
  // BurnTok's compact 3-column picker (2026-10-10) needs the whole card to activate.
36
36
  // Reuse control state opacity instead of a product Pressable with a second visual contract.
37
37
  interaction: { disabledOpacity: buttonRecipe.opacity.disabled, pressedOpacity: buttonRecipe.opacity.pressed },
package/dist/card.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"card.js","sourceRoot":"","sources":["../src/card.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAC3D,OAAO,EACL,YAAY,GAGb,MAAM,mBAAmB,CAAC;AAI3B;;;GAGG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG;IACxB,KAAK,EAAE;QACL,MAAM;QACN,OAAO;QACP,iBAAiB;QACjB,uBAAuB;QACvB,aAAa;QACb,QAAQ;QACR,aAAa;QACb,MAAM;QACN,QAAQ;QACR,SAAS;QACT,OAAO;QACP,aAAa;QACb,SAAS;QACT,SAAS;KACD;IACV,QAAQ,EAAE;QACR,8EAA8E;QAC9E,0EAA0E;QAC1E,IAAI,EAAE,QAAQ;QACd,QAAQ,EAAE,KAAK;QACf,QAAQ,EAAE,IAAI;QACd,YAAY,EAAE,CAAC;QACf,WAAW,EAAE,OAAO;QACpB,OAAO,EAAE,IAAI;KACd;IACD,YAAY,EAAE,QAAQ;IACtB,mFAAmF;IACnF,4FAA4F;IAC5F,WAAW,EAAE,EAAE,eAAe,EAAE,YAAY,CAAC,OAAO,CAAC,QAAQ,EAAE,cAAc,EAAE,YAAY,CAAC,OAAO,CAAC,OAAO,EAAE;IAC7G,wGAAwG;IACxG,WAAW,EAAE,EAAE,KAAK,EAAE,OAAO,CAAC,EAAE,EAAE,QAAQ,EAAE,OAAO,CAAC,cAAc,EAAE,QAAQ,EAAE,KAAK,CAAC,EAAE,EAAE;IACxF,8FAA8F;IAC9F,mFAAmF;IACnF,eAAe,EAAE,EAAE,KAAK,EAAE,oBAAoB,EAAE,UAAU,EAAE,SAAS,EAAE;IACvE,SAAS,EAAE,EAAE,GAAG,EAAE,OAAO,CAAC,EAAE,EAAE,QAAQ,EAAE,KAAK,CAAC,EAAE,EAAE;IAClD,IAAI,EAAE;QACJ,OAAO,EAAE,OAAO,CAAC,EAAE;QACnB,GAAG,EAAE,OAAO,CAAC,EAAE;KAChB;IACD,MAAM,EAAE;QACN,GAAG,EAAE,OAAO,CAAC,EAAE;QACf,+FAA+F;QAC/F,UAAU,EAAE,QAAQ;KACrB;IACD,KAAK,EAAE;QACL,OAAO,EAAE,OAAO;QAChB,IAAI,EAAE,SAAS;QACf,QAAQ,EAAE,QAAQ;KACnB;IACD,WAAW,EAAE;QACX,OAAO,EAAE,MAAM;QACf,IAAI,EAAE,OAAO;QACb,QAAQ,EAAE,SAAS;KACpB;IACD,OAAO,EAAE;QACP,+FAA+F;QAC/F,GAAG,EAAE,OAAO,CAAC,EAAE;QACf,iBAAiB,EAAE,OAAO,CAAC,EAAE;QAC7B,aAAa,EAAE,OAAO,CAAC,EAAE;KAC1B;CA4CF,CAAC","sourcesContent":["import { control, glyph, spacing } from \"./foundations.js\";\nimport {\n buttonRecipe,\n type SurfacePadding,\n type SurfaceTone,\n} from \"./base-recipes.js\";\n\nexport type CardHeadingLevel = 2 | 3 | 4;\n\n/**\n * Shared Card anatomy. Renderers own their host nodes (`article` on Web,\n * `View` on Native), while these slots and defaults stay identical.\n */\nexport const cardRecipe = {\n slots: [\n \"root\",\n \"media\",\n \"backgroundMedia\",\n \"backgroundInteraction\",\n \"mediaBadges\",\n \"badges\",\n \"mediaAction\",\n \"body\",\n \"header\",\n \"leading\",\n \"title\",\n \"description\",\n \"content\",\n \"actions\",\n ] as const,\n defaults: {\n // Today Baseball's schedule cards establish the shared raised card treatment.\n // Keep plain Surface defaults independent so layout containers stay flat.\n tone: \"raised\",\n selected: false,\n bordered: true,\n headingLevel: 3,\n badgesAlign: \"start\",\n padding: \"md\",\n },\n selectedTone: \"accent\",\n // BurnTok's compact 3-column picker (2026-10-10) needs the whole card to activate.\n // Reuse control state opacity instead of a product Pressable with a second visual contract.\n interaction: { disabledOpacity: buttonRecipe.opacity.disabled, pressedOpacity: buttonRecipe.opacity.pressed },\n // A playable cover is one target beside independent creator/comment actions (BurnTok screen migration).\n mediaAction: { inset: spacing.sm, diameter: control.minTouchTarget, iconSize: glyph.sm },\n // Decorative artwork needs fixed contrast independent of brand onPrimary (which can be dark).\n // A 60% black scrim keeps white card text readable even over a white source image.\n backgroundMedia: { scrim: \"rgba(0, 0, 0, 0.6)\", foreground: \"#ffffff\" },\n quotation: { gap: spacing.xs, markSize: glyph.md },\n body: {\n padding: spacing.md,\n gap: spacing.xs,\n },\n header: {\n gap: spacing.sm,\n // Short copy and independent commands share one vertical center (BurnTok profile, 2026-10-20).\n alignItems: \"center\",\n },\n title: {\n variant: \"title\",\n tone: \"primary\",\n emphasis: \"strong\",\n },\n description: {\n variant: \"body\",\n tone: \"muted\",\n emphasis: \"regular\",\n },\n actions: {\n // Button groups share the 8px actionGroupRecipe contract in both renderers (2026-10-21 audit).\n gap: spacing.xs,\n paddingHorizontal: spacing.md,\n paddingBottom: spacing.md,\n },\n} as const satisfies {\n slots: readonly [\n \"root\",\n \"media\",\n \"backgroundMedia\",\n \"backgroundInteraction\",\n \"mediaBadges\",\n \"badges\",\n \"mediaAction\",\n \"body\",\n \"header\",\n \"leading\",\n \"title\",\n \"description\",\n \"content\",\n \"actions\",\n ];\n defaults: {\n tone: SurfaceTone;\n selected: boolean;\n bordered: boolean;\n headingLevel: CardHeadingLevel;\n badgesAlign: \"start\" | \"center\";\n padding: SurfacePadding;\n };\n selectedTone: SurfaceTone;\n interaction: { disabledOpacity: number; pressedOpacity: number };\n mediaAction: { inset: number; diameter: number; iconSize: number };\n backgroundMedia: { scrim: string; foreground: string };\n quotation: { gap: number; markSize: number };\n body: { padding: number; gap: number };\n header: { gap: number; alignItems: \"center\" };\n title: {\n variant: \"title\";\n tone: \"primary\";\n emphasis: \"strong\";\n };\n description: {\n variant: \"body\";\n tone: \"muted\";\n emphasis: \"regular\";\n };\n actions: { gap: number; paddingHorizontal: number; paddingBottom: number };\n};\n"]}
1
+ {"version":3,"file":"card.js","sourceRoot":"","sources":["../src/card.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAC3D,OAAO,EACL,YAAY,GAGb,MAAM,mBAAmB,CAAC;AAI3B;;;GAGG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG;IACxB,KAAK,EAAE;QACL,MAAM;QACN,OAAO;QACP,iBAAiB;QACjB,uBAAuB;QACvB,aAAa;QACb,QAAQ;QACR,aAAa;QACb,MAAM;QACN,QAAQ;QACR,SAAS;QACT,OAAO;QACP,aAAa;QACb,SAAS;QACT,SAAS;KACD;IACV,QAAQ,EAAE;QACR,8EAA8E;QAC9E,0EAA0E;QAC1E,IAAI,EAAE,QAAQ;QACd,QAAQ,EAAE,KAAK;QACf,QAAQ,EAAE,IAAI;QACd,YAAY,EAAE,CAAC;QACf,WAAW,EAAE,OAAO;QACpB,OAAO,EAAE,IAAI;KACd;IACD,YAAY,EAAE,UAAU;IACxB,mFAAmF;IACnF,4FAA4F;IAC5F,WAAW,EAAE,EAAE,eAAe,EAAE,YAAY,CAAC,OAAO,CAAC,QAAQ,EAAE,cAAc,EAAE,YAAY,CAAC,OAAO,CAAC,OAAO,EAAE;IAC7G,wGAAwG;IACxG,WAAW,EAAE,EAAE,KAAK,EAAE,OAAO,CAAC,EAAE,EAAE,QAAQ,EAAE,OAAO,CAAC,cAAc,EAAE,QAAQ,EAAE,KAAK,CAAC,EAAE,EAAE;IACxF,8FAA8F;IAC9F,mFAAmF;IACnF,eAAe,EAAE,EAAE,KAAK,EAAE,oBAAoB,EAAE,UAAU,EAAE,SAAS,EAAE;IACvE,SAAS,EAAE,EAAE,GAAG,EAAE,OAAO,CAAC,EAAE,EAAE,QAAQ,EAAE,KAAK,CAAC,EAAE,EAAE;IAClD,IAAI,EAAE;QACJ,OAAO,EAAE,OAAO,CAAC,EAAE;QACnB,GAAG,EAAE,OAAO,CAAC,EAAE;KAChB;IACD,MAAM,EAAE;QACN,GAAG,EAAE,OAAO,CAAC,EAAE;QACf,+FAA+F;QAC/F,UAAU,EAAE,QAAQ;KACrB;IACD,KAAK,EAAE;QACL,OAAO,EAAE,OAAO;QAChB,IAAI,EAAE,SAAS;QACf,QAAQ,EAAE,QAAQ;KACnB;IACD,WAAW,EAAE;QACX,OAAO,EAAE,MAAM;QACf,IAAI,EAAE,OAAO;QACb,QAAQ,EAAE,SAAS;KACpB;IACD,OAAO,EAAE;QACP,+FAA+F;QAC/F,GAAG,EAAE,OAAO,CAAC,EAAE;QACf,iBAAiB,EAAE,OAAO,CAAC,EAAE;QAC7B,aAAa,EAAE,OAAO,CAAC,EAAE;KAC1B;CA4CF,CAAC","sourcesContent":["import { control, glyph, spacing } from \"./foundations.js\";\nimport {\n buttonRecipe,\n type SurfacePadding,\n type SurfaceTone,\n} from \"./base-recipes.js\";\n\nexport type CardHeadingLevel = 2 | 3 | 4;\n\n/**\n * Shared Card anatomy. Renderers own their host nodes (`article` on Web,\n * `View` on Native), while these slots and defaults stay identical.\n */\nexport const cardRecipe = {\n slots: [\n \"root\",\n \"media\",\n \"backgroundMedia\",\n \"backgroundInteraction\",\n \"mediaBadges\",\n \"badges\",\n \"mediaAction\",\n \"body\",\n \"header\",\n \"leading\",\n \"title\",\n \"description\",\n \"content\",\n \"actions\",\n ] as const,\n defaults: {\n // Today Baseball's schedule cards establish the shared raised card treatment.\n // Keep plain Surface defaults independent so layout containers stay flat.\n tone: \"raised\",\n selected: false,\n bordered: true,\n headingLevel: 3,\n badgesAlign: \"start\",\n padding: \"md\",\n },\n selectedTone: \"selected\",\n // BurnTok's compact 3-column picker (2026-10-10) needs the whole card to activate.\n // Reuse control state opacity instead of a product Pressable with a second visual contract.\n interaction: { disabledOpacity: buttonRecipe.opacity.disabled, pressedOpacity: buttonRecipe.opacity.pressed },\n // A playable cover is one target beside independent creator/comment actions (BurnTok screen migration).\n mediaAction: { inset: spacing.sm, diameter: control.minTouchTarget, iconSize: glyph.sm },\n // Decorative artwork needs fixed contrast independent of brand onPrimary (which can be dark).\n // A 60% black scrim keeps white card text readable even over a white source image.\n backgroundMedia: { scrim: \"rgba(0, 0, 0, 0.6)\", foreground: \"#ffffff\" },\n quotation: { gap: spacing.xs, markSize: glyph.md },\n body: {\n padding: spacing.md,\n gap: spacing.xs,\n },\n header: {\n gap: spacing.sm,\n // Short copy and independent commands share one vertical center (BurnTok profile, 2026-10-20).\n alignItems: \"center\",\n },\n title: {\n variant: \"title\",\n tone: \"primary\",\n emphasis: \"strong\",\n },\n description: {\n variant: \"body\",\n tone: \"muted\",\n emphasis: \"regular\",\n },\n actions: {\n // Button groups share the 8px actionGroupRecipe contract in both renderers (2026-10-21 audit).\n gap: spacing.xs,\n paddingHorizontal: spacing.md,\n paddingBottom: spacing.md,\n },\n} as const satisfies {\n slots: readonly [\n \"root\",\n \"media\",\n \"backgroundMedia\",\n \"backgroundInteraction\",\n \"mediaBadges\",\n \"badges\",\n \"mediaAction\",\n \"body\",\n \"header\",\n \"leading\",\n \"title\",\n \"description\",\n \"content\",\n \"actions\",\n ];\n defaults: {\n tone: SurfaceTone;\n selected: boolean;\n bordered: boolean;\n headingLevel: CardHeadingLevel;\n badgesAlign: \"start\" | \"center\";\n padding: SurfacePadding;\n };\n selectedTone: SurfaceTone;\n interaction: { disabledOpacity: number; pressedOpacity: number };\n mediaAction: { inset: number; diameter: number; iconSize: number };\n backgroundMedia: { scrim: string; foreground: string };\n quotation: { gap: number; markSize: number };\n body: { padding: number; gap: number };\n header: { gap: number; alignItems: \"center\" };\n title: {\n variant: \"title\";\n tone: \"primary\";\n emphasis: \"strong\";\n };\n description: {\n variant: \"body\";\n tone: \"muted\";\n emphasis: \"regular\";\n };\n actions: { gap: number; paddingHorizontal: number; paddingBottom: number };\n};\n"]}