@hjmds/design-contracts 1.27.2 → 1.28.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 (129) hide show
  1. package/dist/activity-chip.d.ts +1 -1
  2. package/dist/activity-chip.js +1 -1
  3. package/dist/activity-chip.js.map +1 -1
  4. package/dist/auth-screen.d.ts +71 -5
  5. package/dist/auth-screen.d.ts.map +1 -1
  6. package/dist/auth-screen.js +60 -2
  7. package/dist/auth-screen.js.map +1 -1
  8. package/dist/base-recipes.d.ts +1 -1
  9. package/dist/base-recipes.js +1 -1
  10. package/dist/base-recipes.js.map +1 -1
  11. package/dist/behaviors.d.ts +1 -1
  12. package/dist/breadcrumb.d.ts +1 -1
  13. package/dist/breadcrumb.js +1 -1
  14. package/dist/breadcrumb.js.map +1 -1
  15. package/dist/calendar.d.ts +1 -1
  16. package/dist/calendar.js +2 -2
  17. package/dist/calendar.js.map +1 -1
  18. package/dist/catalog.d.ts +131 -87
  19. package/dist/catalog.d.ts.map +1 -1
  20. package/dist/component-contracts.d.ts +1 -1
  21. package/dist/component-contracts.js +1 -1
  22. package/dist/component-contracts.js.map +1 -1
  23. package/dist/component-recipes.d.ts +85 -57
  24. package/dist/component-recipes.d.ts.map +1 -1
  25. package/dist/component-recipes.js +95 -60
  26. package/dist/component-recipes.js.map +1 -1
  27. package/dist/conversation-row.d.ts +2 -2
  28. package/dist/conversation-row.d.ts.map +1 -1
  29. package/dist/conversation-row.js +6 -4
  30. package/dist/conversation-row.js.map +1 -1
  31. package/dist/counter-badge-recipe.d.ts +1 -1
  32. package/dist/counter-badge-recipe.js +1 -1
  33. package/dist/counter-badge-recipe.js.map +1 -1
  34. package/dist/data-table.d.ts +4 -4
  35. package/dist/data-table.js +4 -4
  36. package/dist/data-table.js.map +1 -1
  37. package/dist/date-picker.d.ts +1 -1
  38. package/dist/design-profile.d.ts.map +1 -1
  39. package/dist/design-profile.js +19 -16
  40. package/dist/design-profile.js.map +1 -1
  41. package/dist/file-picker.d.ts +1 -1
  42. package/dist/file-picker.js +1 -1
  43. package/dist/file-picker.js.map +1 -1
  44. package/dist/foundations.d.ts +18 -14
  45. package/dist/foundations.d.ts.map +1 -1
  46. package/dist/foundations.js +18 -13
  47. package/dist/foundations.js.map +1 -1
  48. package/dist/heading.d.ts +13 -13
  49. package/dist/heading.js.map +1 -1
  50. package/dist/number-field.d.ts +1 -1
  51. package/dist/otp-field.d.ts +1 -1
  52. package/dist/password-field.d.ts +1 -1
  53. package/dist/result.d.ts +1 -1
  54. package/dist/result.js +2 -2
  55. package/dist/result.js.map +1 -1
  56. package/dist/semantic-colors.d.ts +10 -0
  57. package/dist/semantic-colors.d.ts.map +1 -1
  58. package/dist/semantic-colors.js +6 -0
  59. package/dist/semantic-colors.js.map +1 -1
  60. package/dist/sheet.d.ts +7 -4
  61. package/dist/sheet.d.ts.map +1 -1
  62. package/dist/sheet.js +8 -5
  63. package/dist/sheet.js.map +1 -1
  64. package/dist/side-panel.d.ts +1 -1
  65. package/dist/side-panel.js +2 -2
  66. package/dist/side-panel.js.map +1 -1
  67. package/dist/steps.d.ts +1 -1
  68. package/dist/steps.js +1 -1
  69. package/dist/steps.js.map +1 -1
  70. package/dist/tag.d.ts +1 -1
  71. package/dist/tag.js +1 -1
  72. package/dist/tag.js.map +1 -1
  73. package/dist/timeline.d.ts +1 -1
  74. package/dist/timeline.js +1 -1
  75. package/dist/timeline.js.map +1 -1
  76. package/dist/top.d.ts +4 -4
  77. package/dist/top.d.ts.map +1 -1
  78. package/dist/top.js +3 -1
  79. package/dist/top.js.map +1 -1
  80. package/dist/version.d.ts +1 -1
  81. package/dist/version.js +1 -1
  82. package/dist/version.js.map +1 -1
  83. package/docs/activity-chip.md +5 -1
  84. package/docs/auth-screen.md +2 -0
  85. package/docs/design-profile.md +14 -10
  86. package/docs/generated/component-maturity.md +1 -1
  87. package/docs/generated/renderer-evidence.json +9 -5
  88. package/docs/generated/renderer-evidence.md +1 -1
  89. package/docs/generated/showcase-manifest.json +1 -1
  90. package/docs/heading.md +14 -9
  91. package/docs/sheet.md +2 -0
  92. package/docs/top.md +4 -3
  93. package/docs/usage/README.md +1 -1
  94. package/docs/usage/components/auth-screen-layout.md +26 -9
  95. package/docs/usage/components/bottom-cta.md +6 -2
  96. package/docs/usage/components/breadcrumb.md +5 -1
  97. package/docs/usage/components/checkbox-group.md +5 -1
  98. package/docs/usage/components/collapsible.md +1 -0
  99. package/docs/usage/components/effect-surface.md +2 -2
  100. package/docs/usage/components/heading.md +14 -12
  101. package/docs/usage/components/list-row.md +7 -3
  102. package/docs/usage/components/list.md +5 -4
  103. package/docs/usage/components/notification-item.md +5 -1
  104. package/docs/usage/components/photo-source-sheet.md +1 -1
  105. package/docs/usage/components/screen-layout.md +7 -3
  106. package/docs/usage/components/search-screen.md +1 -1
  107. package/docs/usage/components/section.md +5 -1
  108. package/docs/usage/components/segmented-control.md +1 -1
  109. package/docs/usage/components/sheet.md +17 -13
  110. package/docs/usage/components/skeleton.md +41 -15
  111. package/docs/usage/components/statistic.md +5 -1
  112. package/docs/usage/components/switch.md +3 -2
  113. package/docs/usage/components/tag.md +5 -1
  114. package/docs/usage/components/text.md +6 -4
  115. package/docs/usage/components/top.md +1 -1
  116. package/docs/usage/compositions/adaptive-content.md +5 -1
  117. package/docs/usage/compositions/compound-controls.md +2 -1
  118. package/docs/usage/compositions/design-profile-comparison.md +1 -1
  119. package/docs/usage/compositions/family-drawer.md +5 -3
  120. package/docs/usage/compositions/input-sheet.md +1 -1
  121. package/docs/usage/compositions/interaction-flow-apply.md +3 -3
  122. package/docs/usage/compositions/photo-source.md +3 -3
  123. package/docs/usage/compositions/selection-motion.md +5 -1
  124. package/docs/usage/compositions/visual-foundations.md +5 -4
  125. package/docs/usage/screens/common-login.md +9 -7
  126. package/docs/usage/screens/landing.md +15 -14
  127. package/docs/usage/screens/notification-settings.md +4 -2
  128. package/docs/usage/tokens/typography.md +21 -13
  129. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"foundations.js","sourceRoot":"","sources":["../src/foundations.ts"],"names":[],"mappings":"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","sourcesContent":["/** Numeric units are consumed as CSS pixels on web and density-independent points on native. */\nexport const spacing = {\n xxs: 4,\n xs: 8,\n sm: 12,\n md: 16,\n lg: 20,\n xl: 24,\n xxl: 32,\n xxxl: 40,\n} as const;\n\nexport const radius = {\n sm: 8,\n md: 12,\n lg: 16,\n xl: 24,\n full: 999,\n} as const;\n\n/**\n * Ordered fallbacks keep the contract platform-neutral: Web renderers join\n * the list as a CSS stack, while native renderers request the first named\n * family (or their OS default mapping), rather than receiving a CSS stack.\n */\nexport const fontFamily = {\n // Pretendard is bundled by HJM (Web `@hjmds/react/fonts/pretendard.css`, Native `@hjmds/react-native/fonts`)\n // so every device renders the same face (2026-10-17: Inter/Pretendard were listed but never loaded, so the\n // result depended on what each device had installed). System fonts remain the fallback until it loads.\n ui: [\n \"Pretendard Variable\",\n \"Pretendard\",\n \"-apple-system\",\n \"BlinkMacSystemFont\",\n \"Segoe UI\",\n \"sans-serif\",\n ],\n // Chrome ignores ui-monospace and cannot address SF Mono as \"SFMono-Regular\", so name the macOS/\n // Windows monospace faces before the generic fallback (2026-10-17: Chrome rendered code in Courier).\n code: [\n \"ui-monospace\",\n \"SFMono-Regular\",\n \"SF Mono\",\n \"Menlo\",\n \"Monaco\",\n \"Cascadia Mono\",\n \"Consolas\",\n \"Liberation Mono\",\n \"monospace\",\n ],\n} as const;\n\nexport type FontFamily = keyof typeof fontFamily;\n\n/**\n * Native has no variable-weight selection on every platform, so each weight is its own registered face.\n * Keys match the asset map exported by `@hjmds/react-native/fonts`; 400 doubles as the family name inputs use.\n */\nexport const pretendardNativeFaces = {\n \"400\": \"Pretendard\",\n \"500\": \"Pretendard-Medium\",\n \"600\": \"Pretendard-SemiBold\",\n \"700\": \"Pretendard-Bold\",\n \"800\": \"Pretendard-ExtraBold\",\n} as const;\n\n/** Nearest bundled face for a CSS/RN font weight (\"normal\", \"bold\", 100–900). */\nexport function resolvePretendardNativeFace(weight: string | number | undefined): (typeof pretendardNativeFaces)[keyof typeof pretendardNativeFaces] {\n const numeric = weight === undefined || weight === \"normal\" ? 400 : weight === \"bold\" ? 700 : Number(weight);\n const steps = [400, 500, 600, 700, 800] as const;\n const nearest = Number.isFinite(numeric) ? steps.reduce((best, step) => Math.abs(step - numeric) < Math.abs(best - numeric) ? step : best, 400) : 400;\n return pretendardNativeFaces[String(nearest) as keyof typeof pretendardNativeFaces];\n}\n\n/** Display/reading roles are optional so existing ui/code product profiles retain their fonts. */\nexport type FontRole = \"ui\" | \"display\" | \"reading\" | \"code\";\nexport type FontFamilyRoles = Readonly<{ ui: readonly string[]; code: readonly string[]; display?: readonly string[]; reading?: readonly string[] }>;\n\nexport function resolveFontFamilyStack(families: FontFamilyRoles, role: FontRole): readonly string[] {\n if (![\"ui\", \"display\", \"reading\", \"code\"].includes(role)) throw new TypeError(\"Unsupported font role\");\n // Unspecified reading/display follow the current ui stack, rather than a\n // frozen neutral stack that would silently undo an app's existing ui override.\n return families[role] ?? families.ui;\n}\n\n\n/** String weights translate unchanged to CSS and React Native text styles. */\nexport const fontWeight = {\n regular: \"400\",\n medium: \"500\",\n semibold: \"600\",\n bold: \"700\",\n heavy: \"800\",\n} as const;\n\nexport type FontWeight = keyof typeof fontWeight;\nexport type FontWeightValue = (typeof fontWeight)[FontWeight];\n\n/** Numeric tracking uses CSS pixels on Web and density-independent points on Native. */\nexport const letterSpacing = {\n tight: -0.2,\n normal: 0,\n wide: 0.2,\n} as const;\n\nexport type LetterSpacing = keyof typeof letterSpacing;\n\n/** Renderers map the shared intent to `font-variant-numeric` / `fontVariant`. */\nexport const numeric = {\n proportional: \"proportional-nums\",\n tabular: \"tabular-nums\",\n} as const;\n\nexport type NumericVariant = keyof typeof numeric;\n\nexport const typography = {\n caption: { fontSize: 11, lineHeight: 16, fontWeight: fontWeight.regular },\n // Label (form labels, section subtitles) sits between body 400 and titles 600: at 600 it competed with\n // titles, and Text rendered it 400 outside a profile, too weak against body (2026-10-17 user decision).\n label: { fontSize: 12, lineHeight: 18, fontWeight: fontWeight.medium },\n body: { fontSize: 14, lineHeight: 20, fontWeight: fontWeight.regular },\n bodyLarge: { fontSize: 16, lineHeight: 24, fontWeight: fontWeight.regular },\n // Title steps are semibold (2026-10-17 user review: 800, then 700, still read too heavy on route\n // titles). Display levels 1–2 are bold, see `heading`.\n title: { fontSize: 18, lineHeight: 26, fontWeight: fontWeight.semibold },\n titleLarge: { fontSize: 20, lineHeight: 28, fontWeight: fontWeight.semibold },\n heading: { fontSize: 24, lineHeight: 32, fontWeight: fontWeight.semibold },\n} as const;\n\nexport type TextVariant = keyof typeof typography;\n\n/** Visual variants choose a default family role; semantics and sizes remain independent. */\nexport function resolveTextFontRole(variant: TextVariant, role?: FontRole): FontRole {\n if (role !== undefined) {\n if (![\"ui\", \"display\", \"reading\", \"code\"].includes(role)) throw new TypeError(\"Unsupported font role\");\n return role;\n }\n if (variant === \"body\" || variant === \"bodyLarge\") return \"reading\";\n if (variant === \"title\" || variant === \"titleLarge\" || variant === \"heading\") return \"display\";\n return \"ui\";\n}\n\n\n/**\n * Document heading hierarchy without widening the established `TextVariant`\n * union. Levels 3–5 reuse the existing semantic styles; larger levels are\n * additive display roles for dense product pages and documentation.\n */\nexport const heading = {\n // Bold, not heavy: Pretendard 800 read heavy and rough at 32–40px (2026-10-17 user decision), while\n // staying one step above the semibold title levels 3–5.\n level1: { fontSize: 40, lineHeight: 48, fontWeight: fontWeight.bold },\n level2: { fontSize: 32, lineHeight: 40, fontWeight: fontWeight.bold },\n level3: typography.heading,\n level4: typography.titleLarge,\n level5: typography.title,\n} as const;\n\nexport type HeadingLevel = keyof typeof heading;\n\n/** Glyphs include icons and avatars; they do not inherit paragraph line-height. */\nexport const glyph = {\n xs: 14,\n sm: 20,\n md: 24,\n lg: 28,\n xl: 32,\n xxl: 44,\n xxxl: 48,\n} as const;\n\nexport type GlyphSize = keyof typeof glyph;\n\nexport const motion = {\n fast: 120,\n normal: 200,\n slow: 320,\n} as const;\n\n/**\n * Curves are stored as normalized cubic-bezier tuples so CSS and native\n * animation drivers can translate the same motion intent without sharing a\n * renderer dependency.\n */\nexport const easing = {\n standard: [0.2, 0, 0, 1],\n enter: [0, 0, 0, 1],\n exit: [0.3, 0, 1, 1],\n emphasized: [0.2, 0, 0, 1],\n} as const;\n\nexport type ReducedMotionBehavior = \"instant\" | \"opacity\" | \"static\";\n\n/** Shared transition intent; renderers translate easing tuples to their animation API. */\nexport const motionPreset = {\n micro: {\n duration: motion.fast,\n easing: \"standard\",\n reducedMotion: \"instant\",\n },\n enter: {\n duration: motion.normal,\n easing: \"enter\",\n reducedMotion: \"opacity\",\n },\n exit: {\n duration: motion.fast,\n easing: \"exit\",\n reducedMotion: \"instant\",\n },\n context: {\n duration: motion.slow,\n easing: \"emphasized\",\n reducedMotion: \"opacity\",\n },\n} as const satisfies Record<\n \"micro\" | \"enter\" | \"exit\" | \"context\",\n {\n duration: number;\n easing: keyof typeof easing;\n reducedMotion: ReducedMotionBehavior;\n }\n>;\n\n/** Native renderers may use these values directly; web renderers use easing. */\nexport const spring = {\n responsive: { stiffness: 760, damping: 52, mass: 1 },\n expressive: { stiffness: 520, damping: 38, mass: 1 },\n} as const;\n\n/** Reusable state strengths. Components still decide which states are valid. */\nexport const opacity = {\n disabled: 0.5,\n muted: 0.72,\n pressed: 0.86,\n dragged: 0.64,\n} as const;\n\n/** Overlaying the content color at these strengths creates predictable states. */\nexport const stateLayer = {\n hover: 0.06,\n focus: 0.08,\n pressed: 0.1,\n selected: 0.1,\n} as const;\n\nexport const stroke = {\n subtle: 1,\n default: 1,\n strong: 2,\n focus: 2,\n} as const;\n\nexport const control = {\n minTouchTarget: 44,\n buttonHeight: {\n small: 36,\n medium: 44,\n large: 52,\n },\n buttonHitSlop: {\n small: 4,\n medium: 0,\n large: 0,\n },\n fieldHeight: 44,\n chipHeight: {\n small: 36,\n medium: 44,\n },\n selectionIndicator: 24,\n} as const;\n\n/**\n * Font scale at which components switch to a large-text layout. One decision,\n * previously two literals in `segmentedControlRecipe` and `topBarRecipe`; see\n * issue #20 for why it sits with the tokens instead of beside the scale axis.\n */\nexport const largeTextThreshold = 1.6;\n\n/** Product renderers may narrow these widths, but should not invent new rhythm. */\nexport const layout = {\n pagePadding: {\n compact: spacing.md,\n regular: spacing.lg,\n spacious: spacing.xl,\n },\n sectionGap: spacing.xl,\n contentGap: spacing.md,\n rowHeight: {\n singleLine: 56,\n twoLine: 68,\n },\n readingMaxWidth: 720,\n contentMaxWidth: 1200,\n} as const;\n\n/** Width thresholds use CSS pixels on Web and density-independent points on Native. */\nexport const breakpoint = {\n compact: 0,\n medium: 600,\n expanded: 960,\n wide: 1280,\n} as const;\n\n/** Shared stacking intent. Values remain sparse to leave room for app layers. */\nexport const layer = {\n base: 0,\n sticky: 100,\n dropdown: 400,\n overlay: 800,\n modal: 900,\n tooltip: 950,\n toast: 1000,\n} as const;\n\nexport const overlay = {\n scrim: 0.6,\n veil: 0.25,\n} as const;\n\nexport type BackdropReference = Readonly<{\n color: \"#000000\";\n opacity: number;\n}>;\n\n/** Fixed backdrop contracts avoid renderer-specific names such as CSS `scrim`. */\nexport const backdrop = {\n modal: { color: \"#000000\", opacity: overlay.scrim },\n veil: { color: \"#000000\", opacity: overlay.veil },\n} as const satisfies Record<\"modal\" | \"veil\", BackdropReference>;\n\nexport const scrim = `rgba(0, 0, 0, ${overlay.scrim})`;\n\n/** Renderers translate this contract to box-shadow or native shadow/elevation properties. */\nexport const shadow = {\n raised: {\n color: \"#000000\",\n opacity: 0.08,\n radius: 4,\n offsetY: 1,\n },\n floating: {\n color: \"#000000\",\n opacity: 0.12,\n radius: 12,\n offsetY: 4,\n },\n overlay: {\n color: \"#000000\",\n opacity: 0.16,\n radius: 24,\n offsetY: 8,\n },\n} as const;\n"]}
1
+ {"version":3,"file":"foundations.js","sourceRoot":"","sources":["../src/foundations.ts"],"names":[],"mappings":"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","sourcesContent":["/** Numeric units are consumed as CSS pixels on web and density-independent points on native. */\nexport const spacing = {\n xxs: 4,\n xs: 8,\n sm: 12,\n md: 16,\n lg: 20,\n xl: 24,\n xxl: 32,\n xxxl: 40,\n} as const;\n\nexport const radius = {\n sm: 8,\n md: 12,\n lg: 16,\n xl: 24,\n full: 999,\n} as const;\n\n/**\n * Ordered fallbacks keep the contract platform-neutral: Web renderers join\n * the list as a CSS stack, while native renderers request the first named\n * family (or their OS default mapping), rather than receiving a CSS stack.\n */\nexport const fontFamily = {\n // Pretendard is bundled by HJM (Web `@hjmds/react/fonts/pretendard.css`, Native `@hjmds/react-native/fonts`)\n // so every device renders the same face (2026-10-17: Inter/Pretendard were listed but never loaded, so the\n // result depended on what each device had installed). System fonts remain the fallback until it loads.\n ui: [\n \"Pretendard Variable\",\n \"Pretendard\",\n \"-apple-system\",\n \"BlinkMacSystemFont\",\n \"Segoe UI\",\n \"sans-serif\",\n ],\n // Chrome ignores ui-monospace and cannot address SF Mono as \"SFMono-Regular\", so name the macOS/\n // Windows monospace faces before the generic fallback (2026-10-17: Chrome rendered code in Courier).\n code: [\n \"ui-monospace\",\n \"SFMono-Regular\",\n \"SF Mono\",\n \"Menlo\",\n \"Monaco\",\n \"Cascadia Mono\",\n \"Consolas\",\n \"Liberation Mono\",\n \"monospace\",\n ],\n} as const;\n\nexport type FontFamily = keyof typeof fontFamily;\n\n/**\n * Native has no variable-weight selection on every platform, so each weight is its own registered face.\n * Keys match the asset map exported by `@hjmds/react-native/fonts`; 400 doubles as the family name inputs use.\n */\nexport const pretendardNativeFaces = {\n \"400\": \"Pretendard\",\n \"500\": \"Pretendard-Medium\",\n \"600\": \"Pretendard-SemiBold\",\n \"700\": \"Pretendard-Bold\",\n \"800\": \"Pretendard-ExtraBold\",\n} as const;\n\n/** Nearest bundled face for a CSS/RN font weight (\"normal\", \"bold\", 100–900). */\nexport function resolvePretendardNativeFace(weight: string | number | undefined): (typeof pretendardNativeFaces)[keyof typeof pretendardNativeFaces] {\n const numeric = weight === undefined || weight === \"normal\" ? 400 : weight === \"bold\" ? 700 : Number(weight);\n const steps = [400, 500, 600, 700, 800] as const;\n const nearest = Number.isFinite(numeric) ? steps.reduce((best, step) => Math.abs(step - numeric) < Math.abs(best - numeric) ? step : best, 400) : 400;\n return pretendardNativeFaces[String(nearest) as keyof typeof pretendardNativeFaces];\n}\n\n/** Display/reading roles are optional so existing ui/code product profiles retain their fonts. */\nexport type FontRole = \"ui\" | \"display\" | \"reading\" | \"code\";\nexport type FontFamilyRoles = Readonly<{ ui: readonly string[]; code: readonly string[]; display?: readonly string[]; reading?: readonly string[] }>;\n\nexport function resolveFontFamilyStack(families: FontFamilyRoles, role: FontRole): readonly string[] {\n if (![\"ui\", \"display\", \"reading\", \"code\"].includes(role)) throw new TypeError(\"Unsupported font role\");\n // Unspecified reading/display follow the current ui stack, rather than a\n // frozen neutral stack that would silently undo an app's existing ui override.\n return families[role] ?? families.ui;\n}\n\n\n/** String weights translate unchanged to CSS and React Native text styles. */\nexport const fontWeight = {\n regular: \"400\",\n medium: \"500\",\n semibold: \"600\",\n bold: \"700\",\n heavy: \"800\",\n} as const;\n\nexport type FontWeight = keyof typeof fontWeight;\nexport type FontWeightValue = (typeof fontWeight)[FontWeight];\n\n/** Numeric tracking uses CSS pixels on Web and density-independent points on Native. */\nexport const letterSpacing = {\n tight: -0.2,\n normal: 0,\n wide: 0.2,\n} as const;\n\nexport type LetterSpacing = keyof typeof letterSpacing;\n\n/** Renderers map the shared intent to `font-variant-numeric` / `fontVariant`. */\nexport const numeric = {\n proportional: \"proportional-nums\",\n tabular: \"tabular-nums\",\n} as const;\n\nexport type NumericVariant = keyof typeof numeric;\n\nexport const typography = {\n caption: { fontSize: 11, lineHeight: 16, fontWeight: fontWeight.regular },\n // Label (form labels, section subtitles) stays 500 between body 400 and the titles: at 600 it competed\n // with titles, and Text rendered it 400 outside a profile, too weak against body (2026-10-17 user decision).\n label: { fontSize: 12, lineHeight: 18, fontWeight: fontWeight.medium },\n body: { fontSize: 14, lineHeight: 20, fontWeight: fontWeight.regular },\n bodyLarge: { fontSize: 16, lineHeight: 24, fontWeight: fontWeight.regular },\n // Title steps are medium (2026-10-17 user review: 800, then 700, then 600 still read too heavy —\n // \"굵기 좀더 줄여\").\n title: { fontSize: 18, lineHeight: 26, fontWeight: fontWeight.medium },\n titleLarge: { fontSize: 20, lineHeight: 28, fontWeight: fontWeight.medium },\n // `heading` is the largest text HJM draws. 2026-10-17 user decision (\"글자 너무 커\", \"큰 글자 정책은 없애\"):\n // the 40/32 display tier looked far too big on the service-intro screen and was removed; design profiles\n // reject any type step above this size (design-profile.ts `merge`).\n heading: { fontSize: 24, lineHeight: 32, fontWeight: fontWeight.medium },\n} as const;\n\nexport type TextVariant = keyof typeof typography;\n\n/** Visual variants choose a default family role; semantics and sizes remain independent. */\nexport function resolveTextFontRole(variant: TextVariant, role?: FontRole): FontRole {\n if (role !== undefined) {\n if (![\"ui\", \"display\", \"reading\", \"code\"].includes(role)) throw new TypeError(\"Unsupported font role\");\n return role;\n }\n if (variant === \"body\" || variant === \"bodyLarge\") return \"reading\";\n if (variant === \"title\" || variant === \"titleLarge\" || variant === \"heading\") return \"display\";\n return \"ui\";\n}\n\n\n/**\n * Document heading hierarchy without widening the established `TextVariant`\n * union. Every level reuses a semantic text style, so no heading exceeds `typography.heading`.\n */\nexport const heading = {\n /**\n * @deprecated Same as `level3` since the display tier was removed (2026-10-17 user decision, \"큰 글자\n * 정책은 없애\"; it was 40/48/600). Kept so existing consumers keep compiling; use `level3`.\n */\n level1: typography.heading,\n /** @deprecated Same as `level3` since the display tier was removed (was 32/40/600); use `level3`. */\n level2: typography.heading,\n level3: typography.heading,\n level4: typography.titleLarge,\n level5: typography.title,\n} as const;\n\nexport type HeadingLevel = keyof typeof heading;\n\n/** Glyphs include icons and avatars; they do not inherit paragraph line-height. */\nexport const glyph = {\n xs: 14,\n sm: 20,\n md: 24,\n lg: 28,\n xl: 32,\n xxl: 44,\n xxxl: 48,\n} as const;\n\nexport type GlyphSize = keyof typeof glyph;\n\nexport const motion = {\n fast: 120,\n normal: 200,\n slow: 320,\n} as const;\n\n/**\n * Curves are stored as normalized cubic-bezier tuples so CSS and native\n * animation drivers can translate the same motion intent without sharing a\n * renderer dependency.\n */\nexport const easing = {\n standard: [0.2, 0, 0, 1],\n enter: [0, 0, 0, 1],\n exit: [0.3, 0, 1, 1],\n emphasized: [0.2, 0, 0, 1],\n} as const;\n\nexport type ReducedMotionBehavior = \"instant\" | \"opacity\" | \"static\";\n\n/** Shared transition intent; renderers translate easing tuples to their animation API. */\nexport const motionPreset = {\n micro: {\n duration: motion.fast,\n easing: \"standard\",\n reducedMotion: \"instant\",\n },\n enter: {\n duration: motion.normal,\n easing: \"enter\",\n reducedMotion: \"opacity\",\n },\n exit: {\n duration: motion.fast,\n easing: \"exit\",\n reducedMotion: \"instant\",\n },\n context: {\n duration: motion.slow,\n easing: \"emphasized\",\n reducedMotion: \"opacity\",\n },\n} as const satisfies Record<\n \"micro\" | \"enter\" | \"exit\" | \"context\",\n {\n duration: number;\n easing: keyof typeof easing;\n reducedMotion: ReducedMotionBehavior;\n }\n>;\n\n/** Native renderers may use these values directly; web renderers use easing. */\nexport const spring = {\n responsive: { stiffness: 760, damping: 52, mass: 1 },\n expressive: { stiffness: 520, damping: 38, mass: 1 },\n} as const;\n\n/** Reusable state strengths. Components still decide which states are valid. */\nexport const opacity = {\n disabled: 0.5,\n muted: 0.72,\n pressed: 0.86,\n dragged: 0.64,\n} as const;\n\n/** Overlaying the content color at these strengths creates predictable states. */\nexport const stateLayer = {\n hover: 0.06,\n focus: 0.08,\n pressed: 0.1,\n selected: 0.1,\n} as const;\n\nexport const stroke = {\n subtle: 1,\n default: 1,\n strong: 2,\n focus: 2,\n} as const;\n\nexport const control = {\n minTouchTarget: 44,\n buttonHeight: {\n small: 36,\n medium: 44,\n large: 52,\n },\n buttonHitSlop: {\n small: 4,\n medium: 0,\n large: 0,\n },\n fieldHeight: 44,\n chipHeight: {\n small: 36,\n medium: 44,\n },\n selectionIndicator: 24,\n} as const;\n\n/**\n * Font scale at which components switch to a large-text layout. One decision,\n * previously two literals in `segmentedControlRecipe` and `topBarRecipe`; see\n * issue #20 for why it sits with the tokens instead of beside the scale axis.\n */\nexport const largeTextThreshold = 1.6;\n\n/** Product renderers may narrow these widths, but should not invent new rhythm. */\nexport const layout = {\n pagePadding: {\n compact: spacing.md,\n regular: spacing.lg,\n spacious: spacing.xl,\n },\n sectionGap: spacing.xl,\n contentGap: spacing.md,\n rowHeight: {\n singleLine: 56,\n twoLine: 68,\n },\n readingMaxWidth: 720,\n contentMaxWidth: 1200,\n} as const;\n\n/** Width thresholds use CSS pixels on Web and density-independent points on Native. */\nexport const breakpoint = {\n compact: 0,\n medium: 600,\n expanded: 960,\n wide: 1280,\n} as const;\n\n/** Shared stacking intent. Values remain sparse to leave room for app layers. */\nexport const layer = {\n base: 0,\n sticky: 100,\n dropdown: 400,\n overlay: 800,\n modal: 900,\n tooltip: 950,\n toast: 1000,\n} as const;\n\nexport const overlay = {\n scrim: 0.6,\n veil: 0.25,\n} as const;\n\nexport type BackdropReference = Readonly<{\n color: \"#000000\";\n opacity: number;\n}>;\n\n/** Fixed backdrop contracts avoid renderer-specific names such as CSS `scrim`. */\nexport const backdrop = {\n modal: { color: \"#000000\", opacity: overlay.scrim },\n veil: { color: \"#000000\", opacity: overlay.veil },\n} as const satisfies Record<\"modal\" | \"veil\", BackdropReference>;\n\nexport const scrim = `rgba(0, 0, 0, ${overlay.scrim})`;\n\n/** Renderers translate this contract to box-shadow or native shadow/elevation properties. */\nexport const shadow = {\n raised: {\n color: \"#000000\",\n opacity: 0.08,\n radius: 4,\n offsetY: 1,\n },\n floating: {\n color: \"#000000\",\n opacity: 0.12,\n radius: 12,\n offsetY: 4,\n },\n overlay: {\n color: \"#000000\",\n opacity: 0.16,\n radius: 24,\n offsetY: 8,\n },\n} as const;\n"]}
package/dist/heading.d.ts CHANGED
@@ -2,10 +2,10 @@ import { type HeadingLevel } from "./foundations.js";
2
2
  /**
3
3
  * 문서 제목 단계를 실제로 그리는 primitive다.
4
4
  *
5
- * `heading`(foundations)에는 이미 level1 40px부터 level5 18px까지 다섯 단계가 있었지만
6
- * **어떤 renderer도 노출하지 않았다** — `Text`는 `TextVariant`(최대 24px)만 받는다.
7
- * 그래서 랜딩 히어로나 큰 숫자가 필요한 화면은 매번 제품 CSS로 폰트 크기를 직접 썼다.
8
- * 이 계약은 새 크기를 만들지 않는다. 있던 스케일을 꺼내 쓸 수 있게 하는 것이 전부다.
5
+ * `heading`(foundations)의 단계를 문서 제목 단계(`h1`~`h6`)와 함께 꺼내 쓰게 한다.
6
+ * 이 계약은 새 크기를 만들지 않는다. 가장 큰 단계는 `typography.heading` 24px이며,
7
+ * level1 40px·level2 32px 큰 글자 단계는 2026-10-17 사용자 결정("큰 글자 정책은 없애")으로
8
+ * 폐지돼 두 이름은 level3과 같은 값이다(소비 코드 호환용, 새 코드는 level3~5).
9
9
  *
10
10
  * `Top`(화면 첫 제목)·`Section`(본문 묶음 제목)과 겹치지 않는다. 그 둘은 **자리**를
11
11
  * 아는 블록이고 자기 여백·보조 문장·보조 행동을 갖는다. `Heading`은 자리를 모르는
@@ -30,29 +30,29 @@ export declare const headingRecipe: {
30
30
  };
31
31
  readonly levels: {
32
32
  readonly level1: {
33
- readonly fontSize: 40;
34
- readonly lineHeight: 48;
35
- readonly fontWeight: "700";
33
+ readonly fontSize: 24;
34
+ readonly lineHeight: 32;
35
+ readonly fontWeight: "500";
36
36
  };
37
37
  readonly level2: {
38
- readonly fontSize: 32;
39
- readonly lineHeight: 40;
40
- readonly fontWeight: "700";
38
+ readonly fontSize: 24;
39
+ readonly lineHeight: 32;
40
+ readonly fontWeight: "500";
41
41
  };
42
42
  readonly level3: {
43
43
  readonly fontSize: 24;
44
44
  readonly lineHeight: 32;
45
- readonly fontWeight: "600";
45
+ readonly fontWeight: "500";
46
46
  };
47
47
  readonly level4: {
48
48
  readonly fontSize: 20;
49
49
  readonly lineHeight: 28;
50
- readonly fontWeight: "600";
50
+ readonly fontWeight: "500";
51
51
  };
52
52
  readonly level5: {
53
53
  readonly fontSize: 18;
54
54
  readonly lineHeight: 26;
55
- readonly fontWeight: "600";
55
+ readonly fontWeight: "500";
56
56
  };
57
57
  };
58
58
  readonly color: Readonly<{
@@ -1 +1 @@
1
- {"version":3,"file":"heading.js","sourceRoot":"","sources":["../src/heading.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAE,OAAO,EAAqB,MAAM,kBAAkB,CAAC;AACvE,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAwBtD,MAAM,YAAY,GAAsD;IACtE,MAAM,EAAE,CAAC;IACT,MAAM,EAAE,CAAC;IACT,MAAM,EAAE,CAAC;IACT,MAAM,EAAE,CAAC;IACT,MAAM,EAAE,CAAC;CACV,CAAC;AAEF,MAAM,UAAU,yBAAyB,CAAC,UAA6B;IACrE,IAAI,UAAU,KAAK,IAAI,IAAI,OAAO,UAAU,KAAK,QAAQ,EAAE,CAAC;QAC1D,MAAM,IAAI,SAAS,CAAC,sCAAsC,CAAC,CAAC;IAC9D,CAAC;IACD,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,IAAI,CAAC,OAAO,EAAE,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;QACrE,MAAM,IAAI,SAAS,CAAC,8BAA8B,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IAChF,CAAC;IACD,IACE,UAAU,CAAC,aAAa,KAAK,SAAS;QACtC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,UAAU,CAAC,aAAa,CAAC,EACtD,CAAC;QACD,MAAM,IAAI,SAAS,CAAC,sCAAsC,MAAM,CAAC,UAAU,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC;IAChG,CAAC;AACH,CAAC;AAED,8CAA8C;AAC9C,MAAM,UAAU,2BAA2B,CACzC,UAA6B;IAE7B,yBAAyB,CAAC,UAAU,CAAC,CAAC;IACtC,OAAO,UAAU,CAAC,aAAa,IAAI,YAAY,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;AACpE,CAAC;AAED,MAAM,CAAC,MAAM,aAAa,GAAG;IAC3B,KAAK,EAAE,CAAC,MAAM,CAAU;IACxB,QAAQ,EAAE,EAAE,KAAK,EAAE,QAAwB,EAAE;IAC7C,MAAM,EAAE,OAAO;IACf,KAAK,EAAE,cAAc,CAAC,OAAO,CAAC,OAAO;IACrC,wCAAwC;IACxC,YAAY,EAAE,OAAO,CAAC,EAAE;CAOzB,CAAC;AAEF,MAAM,CAAC,MAAM,eAAe,GAAG;IAC7B,UAAU,EAAE,EAAE;IACd,MAAM,EAAE,CAAC,OAAO,EAAE,eAAe,CAAC;IAClC,SAAS,EAAE,EAAE;IACb,GAAG,EAAE,EAAE,KAAK,EAAE,CAAC,SAAS,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE;IACxD,MAAM,EAAE,EAAE,KAAK,EAAE,CAAC,QAAQ,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE;IACtD,SAAS,EAAE;QACT,+EAA+E;QAC/E,mEAAmE;QACnE,gFAAgF;QAChF,oEAAoE;KACrE;CACkC,CAAC","sourcesContent":["import type { BehaviorContract } from \"./behaviors.js\";\nimport type { ColorReference } from \"./color-references.js\";\nimport { heading, spacing, type HeadingLevel } from \"./foundations.js\";\nimport { semanticColors } from \"./semantic-colors.js\";\n\n/**\n * 문서 제목 단계를 실제로 그리는 primitive다.\n *\n * `heading`(foundations)에는 이미 level1 40px부터 level5 18px까지 다섯 단계가 있었지만\n * **어떤 renderer도 노출하지 않았다** — `Text`는 `TextVariant`(최대 24px)만 받는다.\n * 그래서 랜딩 히어로나 큰 숫자가 필요한 화면은 매번 제품 CSS로 폰트 크기를 직접 썼다.\n * 이 계약은 새 크기를 만들지 않는다. 있던 스케일을 꺼내 쓸 수 있게 하는 것이 전부다.\n *\n * `Top`(화면 첫 제목)·`Section`(본문 묶음 제목)과 겹치지 않는다. 그 둘은 **자리**를\n * 아는 블록이고 자기 여백·보조 문장·보조 행동을 갖는다. `Heading`은 자리를 모르는\n * 글자 하나다 — 카드 안, 표 위, 빈 상태 안 어디에나 놓인다.\n */\nexport type HeadingDescriptor = Readonly<{\n /** 시각적 크기. 문서 구조상의 단계와 분리돼 있다. */\n level: HeadingLevel;\n /**\n * 실제로 낼 요소 단계. 생략하면 `level`의 숫자를 따른다. 시각적 크기와 문서 구조가\n * 어긋나는 경우(카드 제목이 크지만 h4인 경우)에 따로 지정한다.\n */\n semanticLevel?: 1 | 2 | 3 | 4 | 5 | 6;\n}>;\n\nconst levelNumbers: Readonly<Record<HeadingLevel, 1 | 2 | 3 | 4 | 5>> = {\n level1: 1,\n level2: 2,\n level3: 3,\n level4: 4,\n level5: 5,\n};\n\nexport function validateHeadingDescriptor(descriptor: HeadingDescriptor): void {\n if (descriptor === null || typeof descriptor !== \"object\") {\n throw new TypeError(\"Heading descriptor must be an object\");\n }\n if (!Object.prototype.hasOwnProperty.call(heading, descriptor.level)) {\n throw new TypeError(`Unsupported Heading level: ${String(descriptor.level)}`);\n }\n if (\n descriptor.semanticLevel !== undefined &&\n ![1, 2, 3, 4, 5, 6].includes(descriptor.semanticLevel)\n ) {\n throw new TypeError(`Unsupported Heading semanticLevel: ${String(descriptor.semanticLevel)}`);\n }\n}\n\n/** 시각적 단계에서 문서 단계를 뽑되, 명시된 값이 있으면 그것이 이긴다. */\nexport function resolveHeadingSemanticLevel(\n descriptor: HeadingDescriptor,\n): 1 | 2 | 3 | 4 | 5 | 6 {\n validateHeadingDescriptor(descriptor);\n return descriptor.semanticLevel ?? levelNumbers[descriptor.level];\n}\n\nexport const headingRecipe = {\n slots: [\"root\"] as const,\n defaults: { level: \"level3\" as HeadingLevel },\n levels: heading,\n color: semanticColors.content.primary,\n /** 제목 아래 간격은 제목이 아니라 그것을 담는 블록이 정한다. */\n marginBottom: spacing.xs,\n} as const satisfies {\n slots: readonly [\"root\"];\n defaults: { level: HeadingLevel };\n levels: typeof heading;\n color: ColorReference;\n marginBottom: number;\n};\n\nexport const headingBehavior = {\n controlled: [],\n inputs: [\"level\", \"semanticLevel\"],\n stateAxes: {},\n web: { roles: [\"heading\"], keyboard: [], focus: \"none\" },\n native: { roles: [\"header\"], states: [], actions: [] },\n scenarios: [\n \"visual-size-and-document-level-are-separate-axes-that-may-disagree-on-purpose\",\n \"the-element-is-a-real-heading-so-the-rotor-and-skip-links-find-it\",\n \"no-new-type-sizes-are-introduced-the-existing-heading-scale-is-what-is-exposed\",\n \"heading-owns-no-surrounding-layout-the-block-that-contains-it-does\",\n ],\n} as const satisfies BehaviorContract;\n"]}
1
+ {"version":3,"file":"heading.js","sourceRoot":"","sources":["../src/heading.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAE,OAAO,EAAqB,MAAM,kBAAkB,CAAC;AACvE,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAwBtD,MAAM,YAAY,GAAsD;IACtE,MAAM,EAAE,CAAC;IACT,MAAM,EAAE,CAAC;IACT,MAAM,EAAE,CAAC;IACT,MAAM,EAAE,CAAC;IACT,MAAM,EAAE,CAAC;CACV,CAAC;AAEF,MAAM,UAAU,yBAAyB,CAAC,UAA6B;IACrE,IAAI,UAAU,KAAK,IAAI,IAAI,OAAO,UAAU,KAAK,QAAQ,EAAE,CAAC;QAC1D,MAAM,IAAI,SAAS,CAAC,sCAAsC,CAAC,CAAC;IAC9D,CAAC;IACD,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,IAAI,CAAC,OAAO,EAAE,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;QACrE,MAAM,IAAI,SAAS,CAAC,8BAA8B,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IAChF,CAAC;IACD,IACE,UAAU,CAAC,aAAa,KAAK,SAAS;QACtC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,UAAU,CAAC,aAAa,CAAC,EACtD,CAAC;QACD,MAAM,IAAI,SAAS,CAAC,sCAAsC,MAAM,CAAC,UAAU,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC;IAChG,CAAC;AACH,CAAC;AAED,8CAA8C;AAC9C,MAAM,UAAU,2BAA2B,CACzC,UAA6B;IAE7B,yBAAyB,CAAC,UAAU,CAAC,CAAC;IACtC,OAAO,UAAU,CAAC,aAAa,IAAI,YAAY,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;AACpE,CAAC;AAED,MAAM,CAAC,MAAM,aAAa,GAAG;IAC3B,KAAK,EAAE,CAAC,MAAM,CAAU;IACxB,QAAQ,EAAE,EAAE,KAAK,EAAE,QAAwB,EAAE;IAC7C,MAAM,EAAE,OAAO;IACf,KAAK,EAAE,cAAc,CAAC,OAAO,CAAC,OAAO;IACrC,wCAAwC;IACxC,YAAY,EAAE,OAAO,CAAC,EAAE;CAOzB,CAAC;AAEF,MAAM,CAAC,MAAM,eAAe,GAAG;IAC7B,UAAU,EAAE,EAAE;IACd,MAAM,EAAE,CAAC,OAAO,EAAE,eAAe,CAAC;IAClC,SAAS,EAAE,EAAE;IACb,GAAG,EAAE,EAAE,KAAK,EAAE,CAAC,SAAS,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE;IACxD,MAAM,EAAE,EAAE,KAAK,EAAE,CAAC,QAAQ,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE;IACtD,SAAS,EAAE;QACT,+EAA+E;QAC/E,mEAAmE;QACnE,gFAAgF;QAChF,oEAAoE;KACrE;CACkC,CAAC","sourcesContent":["import type { BehaviorContract } from \"./behaviors.js\";\nimport type { ColorReference } from \"./color-references.js\";\nimport { heading, spacing, type HeadingLevel } from \"./foundations.js\";\nimport { semanticColors } from \"./semantic-colors.js\";\n\n/**\n * 문서 제목 단계를 실제로 그리는 primitive다.\n *\n * `heading`(foundations)의 단계를 문서 제목 단계(`h1`~`h6`)와 함께 꺼내 쓰게 한다.\n * 이 계약은 새 크기를 만들지 않는다. 가장 큰 단계는 `typography.heading` 24px이며,\n * level1 40px·level2 32px 큰 글자 단계는 2026-10-17 사용자 결정(\"큰 글자 정책은 없애\")으로\n * 폐지돼 두 이름은 level3과 같은 값이다(소비 코드 호환용, 새 코드는 level3~5).\n *\n * `Top`(화면 첫 제목)·`Section`(본문 묶음 제목)과 겹치지 않는다. 그 둘은 **자리**를\n * 아는 블록이고 자기 여백·보조 문장·보조 행동을 갖는다. `Heading`은 자리를 모르는\n * 글자 하나다 — 카드 안, 표 위, 빈 상태 안 어디에나 놓인다.\n */\nexport type HeadingDescriptor = Readonly<{\n /** 시각적 크기. 문서 구조상의 단계와 분리돼 있다. */\n level: HeadingLevel;\n /**\n * 실제로 낼 요소 단계. 생략하면 `level`의 숫자를 따른다. 시각적 크기와 문서 구조가\n * 어긋나는 경우(카드 제목이 크지만 h4인 경우)에 따로 지정한다.\n */\n semanticLevel?: 1 | 2 | 3 | 4 | 5 | 6;\n}>;\n\nconst levelNumbers: Readonly<Record<HeadingLevel, 1 | 2 | 3 | 4 | 5>> = {\n level1: 1,\n level2: 2,\n level3: 3,\n level4: 4,\n level5: 5,\n};\n\nexport function validateHeadingDescriptor(descriptor: HeadingDescriptor): void {\n if (descriptor === null || typeof descriptor !== \"object\") {\n throw new TypeError(\"Heading descriptor must be an object\");\n }\n if (!Object.prototype.hasOwnProperty.call(heading, descriptor.level)) {\n throw new TypeError(`Unsupported Heading level: ${String(descriptor.level)}`);\n }\n if (\n descriptor.semanticLevel !== undefined &&\n ![1, 2, 3, 4, 5, 6].includes(descriptor.semanticLevel)\n ) {\n throw new TypeError(`Unsupported Heading semanticLevel: ${String(descriptor.semanticLevel)}`);\n }\n}\n\n/** 시각적 단계에서 문서 단계를 뽑되, 명시된 값이 있으면 그것이 이긴다. */\nexport function resolveHeadingSemanticLevel(\n descriptor: HeadingDescriptor,\n): 1 | 2 | 3 | 4 | 5 | 6 {\n validateHeadingDescriptor(descriptor);\n return descriptor.semanticLevel ?? levelNumbers[descriptor.level];\n}\n\nexport const headingRecipe = {\n slots: [\"root\"] as const,\n defaults: { level: \"level3\" as HeadingLevel },\n levels: heading,\n color: semanticColors.content.primary,\n /** 제목 아래 간격은 제목이 아니라 그것을 담는 블록이 정한다. */\n marginBottom: spacing.xs,\n} as const satisfies {\n slots: readonly [\"root\"];\n defaults: { level: HeadingLevel };\n levels: typeof heading;\n color: ColorReference;\n marginBottom: number;\n};\n\nexport const headingBehavior = {\n controlled: [],\n inputs: [\"level\", \"semanticLevel\"],\n stateAxes: {},\n web: { roles: [\"heading\"], keyboard: [], focus: \"none\" },\n native: { roles: [\"header\"], states: [], actions: [] },\n scenarios: [\n \"visual-size-and-document-level-are-separate-axes-that-may-disagree-on-purpose\",\n \"the-element-is-a-real-heading-so-the-rotor-and-skip-links-find-it\",\n \"no-new-type-sizes-are-introduced-the-existing-heading-scale-is-what-is-exposed\",\n \"heading-owns-no-surrounding-layout-the-block-that-contains-it-does\",\n ],\n} as const satisfies BehaviorContract;\n"]}
@@ -112,7 +112,7 @@ export declare const numberFieldRecipe: {
112
112
  alpha?: number;
113
113
  }>;
114
114
  readonly textVariant: "body";
115
- readonly fontWeight: "600";
115
+ readonly fontWeight: "500";
116
116
  };
117
117
  readonly hint: {
118
118
  readonly color: Readonly<{
@@ -56,7 +56,7 @@ export declare const otpFieldRecipe: {
56
56
  alpha?: number;
57
57
  }>;
58
58
  readonly textVariant: "body";
59
- readonly fontWeight: "600";
59
+ readonly fontWeight: "500";
60
60
  };
61
61
  readonly hint: {
62
62
  readonly color: Readonly<{
@@ -89,7 +89,7 @@ export declare const passwordFieldRecipe: {
89
89
  alpha?: number;
90
90
  }>;
91
91
  readonly textVariant: "body";
92
- readonly fontWeight: "600";
92
+ readonly fontWeight: "500";
93
93
  };
94
94
  readonly hint: {
95
95
  readonly color: Readonly<{
package/dist/result.d.ts CHANGED
@@ -105,7 +105,7 @@ export declare const resultRecipe: {
105
105
  key: "text";
106
106
  alpha?: number;
107
107
  }>;
108
- readonly fontWeight: "700";
108
+ readonly fontWeight: "500";
109
109
  };
110
110
  readonly description: {
111
111
  readonly textVariant: "body";
package/dist/result.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { semanticColors } from "./semantic-colors.js";
2
- import { fontWeight, spacing } from "./foundations.js";
2
+ import { spacing, typography } from "./foundations.js";
3
3
  export const resultDefaults = {
4
4
  status: "info",
5
5
  };
@@ -91,7 +91,7 @@ export const resultRecipe = {
91
91
  title: {
92
92
  textVariant: "titleLarge",
93
93
  color: semanticColors.content.primary,
94
- fontWeight: fontWeight.bold,
94
+ fontWeight: typography.titleLarge.fontWeight,
95
95
  },
96
96
  description: {
97
97
  textVariant: "body",
@@ -1 +1 @@
1
- {"version":3,"file":"result.js","sourceRoot":"","sources":["../src/result.ts"],"names":[],"mappings":"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","sourcesContent":["import { semanticColors } from \"./semantic-colors.js\";\nimport { fontWeight, spacing } from \"./foundations.js\";\n\n/**\n * Web-page HTTP status vocabulary (403/404/500) does not belong in a\n * platform-neutral contract. Products/adapters translate those into\n * `failure` with their own localized copy.\n */\nexport type ResultStatus = \"success\" | \"failure\" | \"info\";\n\nexport const resultDefaults = {\n status: \"info\",\n} as const satisfies Readonly<{ status: ResultStatus }>;\n\nexport type ResultActionDescriptor = Readonly<{\n label: string;\n accessibilityLabel?: string;\n onAction(): void;\n}>;\n\n/**\n * A flow terminus screen (success, failure, 404-equivalent). Unlike\n * `EmptyState`, which describes a place that can still be filled, Result\n * means this flow ends here — there is no pending content to wait for.\n *\n * `actions` holds at most one primary and one optional secondary action;\n * the first entry is the primary. A third action is refused, not silently\n * dropped, so a screen author notices instead of shipping a truncated row.\n */\nexport type ResultDescriptor = Readonly<{\n status: ResultStatus;\n title: string;\n description?: string;\n actions?: readonly ResultActionDescriptor[];\n}>;\n\nexport type ResolvedResultActionDescriptor = Readonly<{\n label: string;\n accessibilityLabel: string;\n onAction(): void;\n}>;\n\nexport type ResolvedResultDescriptor = Readonly<{\n status: ResultStatus;\n title: string;\n description: string | null;\n primaryAction: ResolvedResultActionDescriptor | null;\n secondaryAction: ResolvedResultActionDescriptor | null;\n}>;\n\nfunction assertCopy(value: string, field: string): void {\n if (value.trim().length === 0) {\n throw new TypeError(`Result ${field} must not be empty`);\n }\n}\n\nexport function validateResultAction(\n action: ResultActionDescriptor,\n field: string,\n): void {\n assertCopy(action.label, `${field}.label`);\n if (action.accessibilityLabel !== undefined) {\n assertCopy(action.accessibilityLabel, `${field}.accessibilityLabel`);\n }\n if (typeof action.onAction !== \"function\") {\n throw new TypeError(`Result ${field}.onAction must be a function`);\n }\n}\n\nexport function validateResultDescriptor(descriptor: ResultDescriptor): void {\n if (\n descriptor.status !== \"success\" &&\n descriptor.status !== \"failure\" &&\n descriptor.status !== \"info\"\n ) {\n throw new TypeError(`Unsupported Result status: ${String(descriptor.status)}`);\n }\n assertCopy(descriptor.title, \"title\");\n if (descriptor.description !== undefined) {\n assertCopy(descriptor.description, \"description\");\n }\n const actions = descriptor.actions ?? [];\n if (actions.length > 2) {\n throw new RangeError(\n \"Result supports at most one primary and one secondary action\",\n );\n }\n actions.forEach((action, index) => {\n validateResultAction(action, index === 0 ? \"primaryAction\" : \"secondaryAction\");\n });\n}\n\nfunction resolveAction(\n action: ResultActionDescriptor | undefined,\n): ResolvedResultActionDescriptor | null {\n if (!action) return null;\n return {\n label: action.label,\n accessibilityLabel: action.accessibilityLabel ?? action.label,\n onAction: action.onAction,\n };\n}\n\nexport function resolveResultDescriptor(\n descriptor: ResultDescriptor,\n): ResolvedResultDescriptor {\n validateResultDescriptor(descriptor);\n const actions = descriptor.actions ?? [];\n return {\n status: descriptor.status,\n title: descriptor.title,\n description: descriptor.description ?? null,\n primaryAction: resolveAction(actions[0]),\n secondaryAction: resolveAction(actions[1]),\n };\n}\n\nexport const resultRecipe = {\n slots: [\n \"root\",\n \"icon\",\n \"title\",\n \"description\",\n \"primaryAction\",\n \"secondaryAction\",\n ] as const,\n defaults: resultDefaults,\n tones: {\n success: {\n icon: semanticColors.feedback.success.foreground,\n iconBackground: semanticColors.feedback.success.badgeBackground,\n },\n failure: {\n icon: semanticColors.feedback.danger.foreground,\n iconBackground: semanticColors.feedback.danger.badgeBackground,\n },\n info: {\n icon: semanticColors.feedback.info.foreground,\n iconBackground: semanticColors.feedback.info.badgeBackground,\n },\n },\n iconSize: \"xl\",\n /**\n * Status mark drawn when the host passes no icon. Web painted these from CSS `::before` literals while Native drew\n * an empty circle (2026-10-17 review F N1); the recipe owns them so both renderers draw the same mark.\n */\n glyphs: { success: \"✓\", failure: \"!\", info: \"i\" },\n paddingVertical: spacing.xxxl,\n paddingHorizontal: spacing.xl,\n gap: spacing.sm,\n title: {\n textVariant: \"titleLarge\",\n color: semanticColors.content.primary,\n fontWeight: fontWeight.bold,\n },\n description: {\n textVariant: \"body\",\n color: semanticColors.content.secondary,\n },\n actionsGap: spacing.sm,\n} as const;\n"]}
1
+ {"version":3,"file":"result.js","sourceRoot":"","sources":["../src/result.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AASvD,MAAM,CAAC,MAAM,cAAc,GAAG;IAC5B,MAAM,EAAE,MAAM;CACuC,CAAC;AAsCxD,SAAS,UAAU,CAAC,KAAa,EAAE,KAAa;IAC9C,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC9B,MAAM,IAAI,SAAS,CAAC,UAAU,KAAK,oBAAoB,CAAC,CAAC;IAC3D,CAAC;AACH,CAAC;AAED,MAAM,UAAU,oBAAoB,CAClC,MAA8B,EAC9B,KAAa;IAEb,UAAU,CAAC,MAAM,CAAC,KAAK,EAAE,GAAG,KAAK,QAAQ,CAAC,CAAC;IAC3C,IAAI,MAAM,CAAC,kBAAkB,KAAK,SAAS,EAAE,CAAC;QAC5C,UAAU,CAAC,MAAM,CAAC,kBAAkB,EAAE,GAAG,KAAK,qBAAqB,CAAC,CAAC;IACvE,CAAC;IACD,IAAI,OAAO,MAAM,CAAC,QAAQ,KAAK,UAAU,EAAE,CAAC;QAC1C,MAAM,IAAI,SAAS,CAAC,UAAU,KAAK,8BAA8B,CAAC,CAAC;IACrE,CAAC;AACH,CAAC;AAED,MAAM,UAAU,wBAAwB,CAAC,UAA4B;IACnE,IACE,UAAU,CAAC,MAAM,KAAK,SAAS;QAC/B,UAAU,CAAC,MAAM,KAAK,SAAS;QAC/B,UAAU,CAAC,MAAM,KAAK,MAAM,EAC5B,CAAC;QACD,MAAM,IAAI,SAAS,CAAC,8BAA8B,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IACjF,CAAC;IACD,UAAU,CAAC,UAAU,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;IACtC,IAAI,UAAU,CAAC,WAAW,KAAK,SAAS,EAAE,CAAC;QACzC,UAAU,CAAC,UAAU,CAAC,WAAW,EAAE,aAAa,CAAC,CAAC;IACpD,CAAC;IACD,MAAM,OAAO,GAAG,UAAU,CAAC,OAAO,IAAI,EAAE,CAAC;IACzC,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvB,MAAM,IAAI,UAAU,CAClB,8DAA8D,CAC/D,CAAC;IACJ,CAAC;IACD,OAAO,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE;QAChC,oBAAoB,CAAC,MAAM,EAAE,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC;IAClF,CAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,aAAa,CACpB,MAA0C;IAE1C,IAAI,CAAC,MAAM;QAAE,OAAO,IAAI,CAAC;IACzB,OAAO;QACL,KAAK,EAAE,MAAM,CAAC,KAAK;QACnB,kBAAkB,EAAE,MAAM,CAAC,kBAAkB,IAAI,MAAM,CAAC,KAAK;QAC7D,QAAQ,EAAE,MAAM,CAAC,QAAQ;KAC1B,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,uBAAuB,CACrC,UAA4B;IAE5B,wBAAwB,CAAC,UAAU,CAAC,CAAC;IACrC,MAAM,OAAO,GAAG,UAAU,CAAC,OAAO,IAAI,EAAE,CAAC;IACzC,OAAO;QACL,MAAM,EAAE,UAAU,CAAC,MAAM;QACzB,KAAK,EAAE,UAAU,CAAC,KAAK;QACvB,WAAW,EAAE,UAAU,CAAC,WAAW,IAAI,IAAI;QAC3C,aAAa,EAAE,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;QACxC,eAAe,EAAE,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;KAC3C,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,MAAM,YAAY,GAAG;IAC1B,KAAK,EAAE;QACL,MAAM;QACN,MAAM;QACN,OAAO;QACP,aAAa;QACb,eAAe;QACf,iBAAiB;KACT;IACV,QAAQ,EAAE,cAAc;IACxB,KAAK,EAAE;QACL,OAAO,EAAE;YACP,IAAI,EAAE,cAAc,CAAC,QAAQ,CAAC,OAAO,CAAC,UAAU;YAChD,cAAc,EAAE,cAAc,CAAC,QAAQ,CAAC,OAAO,CAAC,eAAe;SAChE;QACD,OAAO,EAAE;YACP,IAAI,EAAE,cAAc,CAAC,QAAQ,CAAC,MAAM,CAAC,UAAU;YAC/C,cAAc,EAAE,cAAc,CAAC,QAAQ,CAAC,MAAM,CAAC,eAAe;SAC/D;QACD,IAAI,EAAE;YACJ,IAAI,EAAE,cAAc,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU;YAC7C,cAAc,EAAE,cAAc,CAAC,QAAQ,CAAC,IAAI,CAAC,eAAe;SAC7D;KACF;IACD,QAAQ,EAAE,IAAI;IACd;;;OAGG;IACH,MAAM,EAAE,EAAE,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE;IACjD,eAAe,EAAE,OAAO,CAAC,IAAI;IAC7B,iBAAiB,EAAE,OAAO,CAAC,EAAE;IAC7B,GAAG,EAAE,OAAO,CAAC,EAAE;IACf,KAAK,EAAE;QACL,WAAW,EAAE,YAAY;QACzB,KAAK,EAAE,cAAc,CAAC,OAAO,CAAC,OAAO;QACrC,UAAU,EAAE,UAAU,CAAC,UAAU,CAAC,UAAU;KAC7C;IACD,WAAW,EAAE;QACX,WAAW,EAAE,MAAM;QACnB,KAAK,EAAE,cAAc,CAAC,OAAO,CAAC,SAAS;KACxC;IACD,UAAU,EAAE,OAAO,CAAC,EAAE;CACd,CAAC","sourcesContent":["import { semanticColors } from \"./semantic-colors.js\";\nimport { spacing, typography } from \"./foundations.js\";\n\n/**\n * Web-page HTTP status vocabulary (403/404/500) does not belong in a\n * platform-neutral contract. Products/adapters translate those into\n * `failure` with their own localized copy.\n */\nexport type ResultStatus = \"success\" | \"failure\" | \"info\";\n\nexport const resultDefaults = {\n status: \"info\",\n} as const satisfies Readonly<{ status: ResultStatus }>;\n\nexport type ResultActionDescriptor = Readonly<{\n label: string;\n accessibilityLabel?: string;\n onAction(): void;\n}>;\n\n/**\n * A flow terminus screen (success, failure, 404-equivalent). Unlike\n * `EmptyState`, which describes a place that can still be filled, Result\n * means this flow ends here — there is no pending content to wait for.\n *\n * `actions` holds at most one primary and one optional secondary action;\n * the first entry is the primary. A third action is refused, not silently\n * dropped, so a screen author notices instead of shipping a truncated row.\n */\nexport type ResultDescriptor = Readonly<{\n status: ResultStatus;\n title: string;\n description?: string;\n actions?: readonly ResultActionDescriptor[];\n}>;\n\nexport type ResolvedResultActionDescriptor = Readonly<{\n label: string;\n accessibilityLabel: string;\n onAction(): void;\n}>;\n\nexport type ResolvedResultDescriptor = Readonly<{\n status: ResultStatus;\n title: string;\n description: string | null;\n primaryAction: ResolvedResultActionDescriptor | null;\n secondaryAction: ResolvedResultActionDescriptor | null;\n}>;\n\nfunction assertCopy(value: string, field: string): void {\n if (value.trim().length === 0) {\n throw new TypeError(`Result ${field} must not be empty`);\n }\n}\n\nexport function validateResultAction(\n action: ResultActionDescriptor,\n field: string,\n): void {\n assertCopy(action.label, `${field}.label`);\n if (action.accessibilityLabel !== undefined) {\n assertCopy(action.accessibilityLabel, `${field}.accessibilityLabel`);\n }\n if (typeof action.onAction !== \"function\") {\n throw new TypeError(`Result ${field}.onAction must be a function`);\n }\n}\n\nexport function validateResultDescriptor(descriptor: ResultDescriptor): void {\n if (\n descriptor.status !== \"success\" &&\n descriptor.status !== \"failure\" &&\n descriptor.status !== \"info\"\n ) {\n throw new TypeError(`Unsupported Result status: ${String(descriptor.status)}`);\n }\n assertCopy(descriptor.title, \"title\");\n if (descriptor.description !== undefined) {\n assertCopy(descriptor.description, \"description\");\n }\n const actions = descriptor.actions ?? [];\n if (actions.length > 2) {\n throw new RangeError(\n \"Result supports at most one primary and one secondary action\",\n );\n }\n actions.forEach((action, index) => {\n validateResultAction(action, index === 0 ? \"primaryAction\" : \"secondaryAction\");\n });\n}\n\nfunction resolveAction(\n action: ResultActionDescriptor | undefined,\n): ResolvedResultActionDescriptor | null {\n if (!action) return null;\n return {\n label: action.label,\n accessibilityLabel: action.accessibilityLabel ?? action.label,\n onAction: action.onAction,\n };\n}\n\nexport function resolveResultDescriptor(\n descriptor: ResultDescriptor,\n): ResolvedResultDescriptor {\n validateResultDescriptor(descriptor);\n const actions = descriptor.actions ?? [];\n return {\n status: descriptor.status,\n title: descriptor.title,\n description: descriptor.description ?? null,\n primaryAction: resolveAction(actions[0]),\n secondaryAction: resolveAction(actions[1]),\n };\n}\n\nexport const resultRecipe = {\n slots: [\n \"root\",\n \"icon\",\n \"title\",\n \"description\",\n \"primaryAction\",\n \"secondaryAction\",\n ] as const,\n defaults: resultDefaults,\n tones: {\n success: {\n icon: semanticColors.feedback.success.foreground,\n iconBackground: semanticColors.feedback.success.badgeBackground,\n },\n failure: {\n icon: semanticColors.feedback.danger.foreground,\n iconBackground: semanticColors.feedback.danger.badgeBackground,\n },\n info: {\n icon: semanticColors.feedback.info.foreground,\n iconBackground: semanticColors.feedback.info.badgeBackground,\n },\n },\n iconSize: \"xl\",\n /**\n * Status mark drawn when the host passes no icon. Web painted these from CSS `::before` literals while Native drew\n * an empty circle (2026-10-17 review F N1); the recipe owns them so both renderers draw the same mark.\n */\n glyphs: { success: \"✓\", failure: \"!\", info: \"i\" },\n paddingVertical: spacing.xxxl,\n paddingHorizontal: spacing.xl,\n gap: spacing.sm,\n title: {\n textVariant: \"titleLarge\",\n color: semanticColors.content.primary,\n fontWeight: typography.titleLarge.fontWeight,\n },\n description: {\n textVariant: \"body\",\n color: semanticColors.content.secondary,\n },\n actionsGap: spacing.sm,\n} as const;\n"]}
@@ -29,6 +29,16 @@ export declare const semanticColors: {
29
29
  key: "surfaceAccent";
30
30
  alpha?: number;
31
31
  }>;
32
+ /**
33
+ * Loading placeholder fill (Skeleton, ListRow `loading`). A translucent text tint instead of an opaque
34
+ * neutral: it darkens/lightens whatever it sits on, so it stays visible on canvas, Card surfaces and
35
+ * profile palettes whose `surfaceAlt` is as light as `bg` (2026-10-17 Skeleton review, skeleton.md 근거).
36
+ */
37
+ readonly placeholder: Readonly<{
38
+ source: "theme";
39
+ key: "text";
40
+ alpha?: number;
41
+ }>;
32
42
  };
33
43
  readonly content: {
34
44
  readonly primary: Readonly<{
@@ -1 +1 @@
1
- {"version":3,"file":"semantic-colors.d.ts","sourceRoot":"","sources":["../src/semantic-colors.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAqBvB,iDAAiD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QA4DjD;;;WAGG;;;;;;;CAGG,CAAC"}
1
+ {"version":3,"file":"semantic-colors.d.ts","sourceRoot":"","sources":["../src/semantic-colors.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;QAOvB;;;;WAIG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAgBH,iDAAiD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QA4DjD;;;WAGG;;;;;;;CAGG,CAAC"}
@@ -10,6 +10,12 @@ export const semanticColors = {
10
10
  sunken: themeColor("surfaceAlt"),
11
11
  raised: themeColor("bg"),
12
12
  brand: themeColor("surfaceAccent"),
13
+ /**
14
+ * Loading placeholder fill (Skeleton, ListRow `loading`). A translucent text tint instead of an opaque
15
+ * neutral: it darkens/lightens whatever it sits on, so it stays visible on canvas, Card surfaces and
16
+ * profile palettes whose `surfaceAlt` is as light as `bg` (2026-10-17 Skeleton review, skeleton.md 근거).
17
+ */
18
+ placeholder: themeColor("text", 0.12),
13
19
  },
14
20
  content: {
15
21
  primary: themeColor("text"),
@@ -1 +1 @@
1
- {"version":3,"file":"semantic-colors.js","sourceRoot":"","sources":["../src/semantic-colors.ts"],"names":[],"mappings":"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","sourcesContent":["import { accentColor, themeColor } from \"./color-references.js\";\n\n/**\n * Stable role aliases above the legacy ThemeColors key set. New recipes should\n * prefer these roles so the underlying theme shape can evolve independently.\n */\nexport const semanticColors = {\n canvas: themeColor(\"bg\"),\n surface: {\n default: themeColor(\"surface\"),\n sunken: themeColor(\"surfaceAlt\"),\n raised: themeColor(\"bg\"),\n brand: themeColor(\"surfaceAccent\"),\n },\n content: {\n primary: themeColor(\"text\"),\n body: themeColor(\"textBody\"),\n secondary: themeColor(\"textMuted\"),\n tertiary: themeColor(\"textSub\"),\n decorative: themeColor(\"textWeak\"),\n brand: themeColor(\"contentBrand\"),\n danger: themeColor(\"danger\"),\n inverse: themeColor(\"onPrimary\"),\n },\n border: {\n subtle: themeColor(\"border\", 0.7),\n default: themeColor(\"border\"),\n /** Resting outline of an interactive control. */\n control: themeColor(\"borderControl\"),\n strong: themeColor(\"textWeak\"),\n focus: themeColor(\"contentBrand\"),\n danger: themeColor(\"danger\"),\n },\n action: {\n brand: {\n background: themeColor(\"primary\"),\n content: themeColor(\"onPrimary\"),\n },\n neutral: {\n background: themeColor(\"bg\"),\n content: themeColor(\"text\"),\n // A control outline is a border role. `textSub` made a resting neutral\n // action read heavier than the selected control beside it.\n border: themeColor(\"borderControl\"),\n },\n danger: {\n background: themeColor(\"dangerFill\"),\n content: themeColor(\"onDanger\"),\n },\n },\n feedback: {\n info: {\n foreground: accentColor(\"info\"),\n background: accentColor(\"info\", 0.1),\n badgeBackground: accentColor(\"info\", 0.1),\n border: accentColor(\"info\", 0.3),\n },\n success: {\n foreground: accentColor(\"success\"),\n background: accentColor(\"success\", 0.1),\n badgeBackground: accentColor(\"success\", 0.1),\n border: accentColor(\"success\", 0.3),\n },\n warning: {\n foreground: accentColor(\"warning\"),\n background: accentColor(\"warning\", 0.1),\n badgeBackground: accentColor(\"warning\", 0.1),\n border: accentColor(\"warning\", 0.3),\n },\n attention: {\n foreground: accentColor(\"attention\"),\n background: accentColor(\"attention\", 0.1),\n badgeBackground: accentColor(\"attention\", 0.1),\n border: accentColor(\"attention\", 0.3),\n },\n danger: {\n foreground: themeColor(\"danger\"),\n background: themeColor(\"danger\", 0.1),\n badgeBackground: themeColor(\"danger\", 0.1),\n border: themeColor(\"danger\", 0.3),\n },\n },\n interaction: {\n hover: themeColor(\"text\", 0.06),\n focus: themeColor(\"contentBrand\", 0.08),\n pressed: themeColor(\"text\", 0.1),\n selected: themeColor(\"primary\", 0.1),\n /**\n * Lower edge of a raised object, composited over its own fill so one shade\n * darkens any brand color (BottomNavigation raised tile, Spint 2026-10-13).\n */\n depth: themeColor(\"text\", 0.45),\n },\n} as const;\n"]}
1
+ {"version":3,"file":"semantic-colors.js","sourceRoot":"","sources":["../src/semantic-colors.ts"],"names":[],"mappings":"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","sourcesContent":["import { accentColor, themeColor } from \"./color-references.js\";\n\n/**\n * Stable role aliases above the legacy ThemeColors key set. New recipes should\n * prefer these roles so the underlying theme shape can evolve independently.\n */\nexport const semanticColors = {\n canvas: themeColor(\"bg\"),\n surface: {\n default: themeColor(\"surface\"),\n sunken: themeColor(\"surfaceAlt\"),\n raised: themeColor(\"bg\"),\n brand: themeColor(\"surfaceAccent\"),\n /**\n * Loading placeholder fill (Skeleton, ListRow `loading`). A translucent text tint instead of an opaque\n * neutral: it darkens/lightens whatever it sits on, so it stays visible on canvas, Card surfaces and\n * profile palettes whose `surfaceAlt` is as light as `bg` (2026-10-17 Skeleton review, skeleton.md 근거).\n */\n placeholder: themeColor(\"text\", 0.12),\n },\n content: {\n primary: themeColor(\"text\"),\n body: themeColor(\"textBody\"),\n secondary: themeColor(\"textMuted\"),\n tertiary: themeColor(\"textSub\"),\n decorative: themeColor(\"textWeak\"),\n brand: themeColor(\"contentBrand\"),\n danger: themeColor(\"danger\"),\n inverse: themeColor(\"onPrimary\"),\n },\n border: {\n subtle: themeColor(\"border\", 0.7),\n default: themeColor(\"border\"),\n /** Resting outline of an interactive control. */\n control: themeColor(\"borderControl\"),\n strong: themeColor(\"textWeak\"),\n focus: themeColor(\"contentBrand\"),\n danger: themeColor(\"danger\"),\n },\n action: {\n brand: {\n background: themeColor(\"primary\"),\n content: themeColor(\"onPrimary\"),\n },\n neutral: {\n background: themeColor(\"bg\"),\n content: themeColor(\"text\"),\n // A control outline is a border role. `textSub` made a resting neutral\n // action read heavier than the selected control beside it.\n border: themeColor(\"borderControl\"),\n },\n danger: {\n background: themeColor(\"dangerFill\"),\n content: themeColor(\"onDanger\"),\n },\n },\n feedback: {\n info: {\n foreground: accentColor(\"info\"),\n background: accentColor(\"info\", 0.1),\n badgeBackground: accentColor(\"info\", 0.1),\n border: accentColor(\"info\", 0.3),\n },\n success: {\n foreground: accentColor(\"success\"),\n background: accentColor(\"success\", 0.1),\n badgeBackground: accentColor(\"success\", 0.1),\n border: accentColor(\"success\", 0.3),\n },\n warning: {\n foreground: accentColor(\"warning\"),\n background: accentColor(\"warning\", 0.1),\n badgeBackground: accentColor(\"warning\", 0.1),\n border: accentColor(\"warning\", 0.3),\n },\n attention: {\n foreground: accentColor(\"attention\"),\n background: accentColor(\"attention\", 0.1),\n badgeBackground: accentColor(\"attention\", 0.1),\n border: accentColor(\"attention\", 0.3),\n },\n danger: {\n foreground: themeColor(\"danger\"),\n background: themeColor(\"danger\", 0.1),\n badgeBackground: themeColor(\"danger\", 0.1),\n border: themeColor(\"danger\", 0.3),\n },\n },\n interaction: {\n hover: themeColor(\"text\", 0.06),\n focus: themeColor(\"contentBrand\", 0.08),\n pressed: themeColor(\"text\", 0.1),\n selected: themeColor(\"primary\", 0.1),\n /**\n * Lower edge of a raised object, composited over its own fill so one shade\n * darkens any brand color (BottomNavigation raised tile, Spint 2026-10-13).\n */\n depth: themeColor(\"text\", 0.45),\n },\n} as const;\n"]}
package/dist/sheet.d.ts CHANGED
@@ -32,11 +32,14 @@ export declare const sheetBehaviorDefaults: {
32
32
  readonly swipeDismiss: true;
33
33
  };
34
34
  /**
35
- * Bottom sheets close by dragging only (2026-10-16 user decision): no backdrop tap and no visible ×
36
- * by default. Escape/system back and the handle's close action stay so keyboard, switch and
37
- * screen-reader users can still dismiss without a drag gesture. Other placements keep the old defaults.
35
+ * Every placement closes on a backdrop press (2026-10-17 user decision; bottom sheets had been drag-only
36
+ * since 2026-10-16). Bottom sheets still show no × by default: drag, backdrop, Escape/system back and the
37
+ * handle's close action cover pointer, keyboard, switch and screen-reader users. `outsideDismiss: false`
38
+ * (with `swipeDismiss: false`) is only for flows where an accidental close loses work, such as payment
39
+ * confirmation; unsaved-input confirmation belongs in the controlled owner's `onOpenChange`, which every
40
+ * reason, `outside` included, passes through. `placement` stays in the signature for published callers.
38
41
  */
39
- export declare function resolveSheetDismissPolicy(placement: string, override?: Partial<SheetDismissPolicy>): SheetDismissPolicy;
42
+ export declare function resolveSheetDismissPolicy(_placement: string, override?: Partial<SheetDismissPolicy>): SheetDismissPolicy;
40
43
  export declare function resolveSheetCloseButton(placement: string, showClose?: boolean): boolean;
41
44
  /** Release thresholds for the drag-to-dismiss gesture shared by both renderers. */
42
45
  export declare const sheetDragRecipe: {
@@ -1 +1 @@
1
- {"version":3,"file":"sheet.d.ts","sourceRoot":"","sources":["../src/sheet.ts"],"names":[],"mappings":"AAAA,iDAAiD;AACjD,MAAM,MAAM,kBAAkB,GAC1B,cAAc,GACd,QAAQ,GACR,MAAM,GACN,SAAS,GACT,OAAO,GACP,cAAc,CAAC;AAEnB;;;GAGG;AACH,MAAM,MAAM,sBAAsB,GAAG,QAAQ,CAAC;IAC5C,MAAM,EAAE,SAAS,GAAG,kBAAkB,CAAC;CACxC,CAAC,CAAC;AAEH,iFAAiF;AACjF,MAAM,MAAM,kBAAkB,GAAG,QAAQ,CAAC;IACxC,WAAW,EAAE,OAAO,CAAC;IACrB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,cAAc,EAAE,OAAO,CAAC;IACxB,mBAAmB,EAAE,OAAO,CAAC;IAC7B,YAAY,EAAE,OAAO,CAAC;CACvB,CAAC,CAAC;AAEH,MAAM,MAAM,cAAc,GACtB,QAAQ,CAAC;IACP,IAAI,EAAE,OAAO,CAAC;IACd,WAAW,CAAC,EAAE,KAAK,CAAC;IACpB,YAAY,CAAC,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,sBAAsB,GAAG,IAAI,CAAC;CACnE,CAAC,GACF,QAAQ,CAAC;IACP,IAAI,CAAC,EAAE,KAAK,CAAC;IACb,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,sBAAsB,KAAK,IAAI,CAAC;CACxE,CAAC,CAAC;AAEP,eAAO,MAAM,qBAAqB;;;;;;CAOK,CAAC;AAExC;;;;GAIG;AACH,wBAAgB,yBAAyB,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,GAAE,OAAO,CAAC,kBAAkB,CAAM,GAAG,kBAAkB,CAE3H;AACD,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,OAAO,GAAG,OAAO,CAEvF;AAED,mFAAmF;AACnF,eAAO,MAAM,eAAe;;;IAG1B,8EAA8E;;CAEtE,CAAC;AAEX;;;;GAIG;AACH,wBAAgB,eAAe,CAC7B,MAAM,EAAE,kBAAkB,EAC1B,IAAI,EAAE,OAAO,EACb,MAAM,GAAE,kBAA0C,GACjD,OAAO,CAUT;AAED,MAAM,MAAM,cAAc,GAAG,QAAQ,CAAC;IACpC,IAAI,IAAI,MAAM,CAAC;IACf,YAAY,IAAI,MAAM,GAAG,IAAI,CAAC;IAC9B,YAAY,CACV,MAAM,EAAE,kBAAkB,EAC1B,IAAI,EAAE,OAAO,EACb,MAAM,CAAC,EAAE,kBAAkB,GAC1B,OAAO,CAAC;IACX,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;CACzC,CAAC,CAAC;AAEH;;;GAGG;AACH,wBAAgB,oBAAoB,CAClC,gBAAgB,UAAQ,GACvB,cAAc,CAgChB;AAED;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,WAAW,GAAG,QAAQ,GAAG,OAAO,GAAG,MAAM,CAAC;AAEtD,eAAO,MAAM,gBAAgB,sCAAwE,CAAC;AAEtG,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,SAAS,WAAW,EAAE,GAAG,IAAI,CAsB1E;AAED,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,SAAS,WAAW,EAAE,EAC/B,OAAO,EAAE,WAAW,EACpB,SAAS,EAAE,QAAQ,GAAG,UAAU,GAC/B,WAAW,GAAG,IAAI,CASpB"}
1
+ {"version":3,"file":"sheet.d.ts","sourceRoot":"","sources":["../src/sheet.ts"],"names":[],"mappings":"AAAA,iDAAiD;AACjD,MAAM,MAAM,kBAAkB,GAC1B,cAAc,GACd,QAAQ,GACR,MAAM,GACN,SAAS,GACT,OAAO,GACP,cAAc,CAAC;AAEnB;;;GAGG;AACH,MAAM,MAAM,sBAAsB,GAAG,QAAQ,CAAC;IAC5C,MAAM,EAAE,SAAS,GAAG,kBAAkB,CAAC;CACxC,CAAC,CAAC;AAEH,iFAAiF;AACjF,MAAM,MAAM,kBAAkB,GAAG,QAAQ,CAAC;IACxC,WAAW,EAAE,OAAO,CAAC;IACrB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,cAAc,EAAE,OAAO,CAAC;IACxB,mBAAmB,EAAE,OAAO,CAAC;IAC7B,YAAY,EAAE,OAAO,CAAC;CACvB,CAAC,CAAC;AAEH,MAAM,MAAM,cAAc,GACtB,QAAQ,CAAC;IACP,IAAI,EAAE,OAAO,CAAC;IACd,WAAW,CAAC,EAAE,KAAK,CAAC;IACpB,YAAY,CAAC,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,sBAAsB,GAAG,IAAI,CAAC;CACnE,CAAC,GACF,QAAQ,CAAC;IACP,IAAI,CAAC,EAAE,KAAK,CAAC;IACb,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,sBAAsB,KAAK,IAAI,CAAC;CACxE,CAAC,CAAC;AAEP,eAAO,MAAM,qBAAqB;;;;;;CAOK,CAAC;AAExC;;;;;;;GAOG;AACH,wBAAgB,yBAAyB,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,GAAE,OAAO,CAAC,kBAAkB,CAAM,GAAG,kBAAkB,CAE5H;AACD,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,OAAO,GAAG,OAAO,CAEvF;AAED,mFAAmF;AACnF,eAAO,MAAM,eAAe;;;IAG1B,8EAA8E;;CAEtE,CAAC;AAEX;;;;GAIG;AACH,wBAAgB,eAAe,CAC7B,MAAM,EAAE,kBAAkB,EAC1B,IAAI,EAAE,OAAO,EACb,MAAM,GAAE,kBAA0C,GACjD,OAAO,CAUT;AAED,MAAM,MAAM,cAAc,GAAG,QAAQ,CAAC;IACpC,IAAI,IAAI,MAAM,CAAC;IACf,YAAY,IAAI,MAAM,GAAG,IAAI,CAAC;IAC9B,YAAY,CACV,MAAM,EAAE,kBAAkB,EAC1B,IAAI,EAAE,OAAO,EACb,MAAM,CAAC,EAAE,kBAAkB,GAC1B,OAAO,CAAC;IACX,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;CACzC,CAAC,CAAC;AAEH;;;GAGG;AACH,wBAAgB,oBAAoB,CAClC,gBAAgB,UAAQ,GACvB,cAAc,CAgChB;AAED;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,WAAW,GAAG,QAAQ,GAAG,OAAO,GAAG,MAAM,CAAC;AAEtD,eAAO,MAAM,gBAAgB,sCAAwE,CAAC;AAEtG,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,SAAS,WAAW,EAAE,GAAG,IAAI,CAsB1E;AAED,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,SAAS,WAAW,EAAE,EAC/B,OAAO,EAAE,WAAW,EACpB,SAAS,EAAE,QAAQ,GAAG,UAAU,GAC/B,WAAW,GAAG,IAAI,CASpB"}
package/dist/sheet.js CHANGED
@@ -7,12 +7,15 @@ export const sheetBehaviorDefaults = {
7
7
  swipeDismiss: true,
8
8
  };
9
9
  /**
10
- * Bottom sheets close by dragging only (2026-10-16 user decision): no backdrop tap and no visible ×
11
- * by default. Escape/system back and the handle's close action stay so keyboard, switch and
12
- * screen-reader users can still dismiss without a drag gesture. Other placements keep the old defaults.
10
+ * Every placement closes on a backdrop press (2026-10-17 user decision; bottom sheets had been drag-only
11
+ * since 2026-10-16). Bottom sheets still show no × by default: drag, backdrop, Escape/system back and the
12
+ * handle's close action cover pointer, keyboard, switch and screen-reader users. `outsideDismiss: false`
13
+ * (with `swipeDismiss: false`) is only for flows where an accidental close loses work, such as payment
14
+ * confirmation; unsaved-input confirmation belongs in the controlled owner's `onOpenChange`, which every
15
+ * reason, `outside` included, passes through. `placement` stays in the signature for published callers.
13
16
  */
14
- export function resolveSheetDismissPolicy(placement, override = {}) {
15
- return { ...sheetBehaviorDefaults, ...(placement === "bottom" ? { outsideDismiss: false } : {}), ...override };
17
+ export function resolveSheetDismissPolicy(_placement, override = {}) {
18
+ return { ...sheetBehaviorDefaults, ...override };
16
19
  }
17
20
  export function resolveSheetCloseButton(placement, showClose) {
18
21
  return showClose ?? placement !== "bottom";
package/dist/sheet.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"sheet.js","sourceRoot":"","sources":["../src/sheet.ts"],"names":[],"mappings":"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","sourcesContent":["/** Why an open Sheet is being asked to close. */\nexport type SheetDismissReason =\n | \"close-action\"\n | \"escape\"\n | \"back\"\n | \"outside\"\n | \"swipe\"\n | \"programmatic\";\n\n/**\n * `trigger` only opens a Sheet. Every close reports the concrete dismiss reason\n * so renderers and product analytics do not have to infer it from platform events.\n */\nexport type SheetOpenChangeDetails = Readonly<{\n reason: \"trigger\" | SheetDismissReason;\n}>;\n\n/** User-dismiss policy. A controlled owner may always close programmatically. */\nexport type SheetDismissPolicy = Readonly<{\n dismissible: boolean;\n dismissWhileBusy: boolean;\n outsideDismiss: boolean;\n escapeOrBackDismiss: boolean;\n swipeDismiss: boolean;\n}>;\n\nexport type SheetOpenState =\n | Readonly<{\n open: boolean;\n defaultOpen?: never;\n onOpenChange(open: boolean, detail: SheetOpenChangeDetails): void;\n }>\n | Readonly<{\n open?: never;\n defaultOpen?: boolean;\n onOpenChange?: (open: boolean, detail: SheetOpenChangeDetails) => void;\n }>;\n\nexport const sheetBehaviorDefaults = {\n dismissible: true,\n dismissWhileBusy: false,\n outsideDismiss: true,\n escapeOrBackDismiss: true,\n // 2026-10-16 user decision: dragging a bottom sheet down is a required way to close it.\n swipeDismiss: true,\n} as const satisfies SheetDismissPolicy;\n\n/**\n * Bottom sheets close by dragging only (2026-10-16 user decision): no backdrop tap and no visible ×\n * by default. Escape/system back and the handle's close action stay so keyboard, switch and\n * screen-reader users can still dismiss without a drag gesture. Other placements keep the old defaults.\n */\nexport function resolveSheetDismissPolicy(placement: string, override: Partial<SheetDismissPolicy> = {}): SheetDismissPolicy {\n return { ...sheetBehaviorDefaults, ...(placement === \"bottom\" ? { outsideDismiss: false } : {}), ...override };\n}\nexport function resolveSheetCloseButton(placement: string, showClose?: boolean): boolean {\n return showClose ?? placement !== \"bottom\";\n}\n\n/** Release thresholds for the drag-to-dismiss gesture shared by both renderers. */\nexport const sheetDragRecipe = {\n activationDistance: 6,\n dismissDistanceRatio: 0.25,\n /** px per millisecond: a quick flick closes before the distance threshold. */\n dismissVelocity: 0.5,\n} as const;\n\n/**\n * Resolves an attempted close without platform knowledge. Programmatic close is\n * intentionally an owner override: a controlled `open={false}` cannot be vetoed\n * by a renderer, even while the Sheet is busy or not user-dismissible.\n */\nexport function canDismissSheet(\n reason: SheetDismissReason,\n busy: boolean,\n policy: SheetDismissPolicy = sheetBehaviorDefaults,\n): boolean {\n if (reason === \"programmatic\") return true;\n if (!policy.dismissible) return false;\n if (busy && !policy.dismissWhileBusy) return false;\n if (reason === \"outside\") return policy.outsideDismiss;\n if (reason === \"escape\" || reason === \"back\") {\n return policy.escapeOrBackDismiss;\n }\n if (reason === \"swipe\") return policy.swipeDismiss;\n return true;\n}\n\nexport type SheetLifecycle = Readonly<{\n open(): number;\n beginDismiss(): number | null;\n requestClose(\n reason: SheetDismissReason,\n busy: boolean,\n policy?: SheetDismissPolicy,\n ): boolean;\n completeDismiss(cycle: number): boolean;\n}>;\n\n/**\n * Makes persistent native Modal renderers settle each visible cycle once.\n * Platform adapters still decide when native dismissal has actually completed.\n */\nexport function createSheetLifecycle(\n initiallyVisible = false,\n): SheetLifecycle {\n let sequence = initiallyVisible ? 1 : 0;\n let activeCycle: number | null = initiallyVisible ? sequence : null;\n let closeRequested = false;\n const dismissingCycles = new Set<number>();\n\n return {\n open() {\n if (activeCycle !== null) return activeCycle;\n sequence += 1;\n activeCycle = sequence;\n closeRequested = false;\n return activeCycle;\n },\n beginDismiss() {\n if (activeCycle === null) return null;\n const cycle = activeCycle;\n activeCycle = null;\n closeRequested = false;\n dismissingCycles.add(cycle);\n return cycle;\n },\n requestClose(reason, busy, policy = sheetBehaviorDefaults) {\n if (activeCycle === null || closeRequested) return false;\n if (!canDismissSheet(reason, busy, policy)) return false;\n closeRequested = true;\n return true;\n },\n completeDismiss(cycle) {\n return dismissingCycles.delete(cycle);\n },\n };\n}\n\n/**\n * 사용자가 시트 높이를 바꾸는 축이다. `sheetRecipe.sizes`는 제품이 여는 높이를 정하고,\n * 이것은 열린 뒤 **사용자가** 단계를 옮기는 문제다 — 지도 위 목록처럼 \"조금 보기 ↔ 크게\n * 보기\"가 필요한 화면이 그 자리다.\n *\n * `auto`는 단계에 들어가지 않는다. 내용이 정하는 높이라 \"다음 단계\"가 정의되지 않는다.\n *\n * **드래그 물리는 여기 없다.** 이 계약은 단계 목록과 \"다음/이전 단계가 무엇인가\"만 갖고,\n * 손가락 속도·관성·고무줄은 넣지 않았다 — 실제 제품 화면 없이 그 값을 정하면 기기에서\n * 다시 다 고치게 된다. 대신 **핸들이 접근 가능한 컨트롤**이라 키보드·보조기기에서도\n * 단계를 옮길 수 있다. 제스처는 제품이 얹고, 결과를 같은 `onDetentChange`로 보낸다.\n */\nexport type SheetDetent = \"medium\" | \"large\" | \"full\";\n\nexport const sheetDetentOrder = [\"medium\", \"large\", \"full\"] as const satisfies readonly SheetDetent[];\n\nexport function validateSheetDetents(detents: readonly SheetDetent[]): void {\n if (detents.length === 0) {\n throw new RangeError(\"Sheet detents must not be empty\");\n }\n const seen = new Set<SheetDetent>();\n for (const detent of detents) {\n if (!sheetDetentOrder.includes(detent)) {\n throw new TypeError(`Unsupported Sheet detent: ${String(detent)}`);\n }\n if (seen.has(detent)) throw new TypeError(`Duplicate Sheet detent: ${detent}`);\n seen.add(detent);\n }\n const ordered = [...detents].sort(\n (left, right) => sheetDetentOrder.indexOf(left) - sheetDetentOrder.indexOf(right),\n );\n if (ordered.some((detent, index) => detent !== detents[index])) {\n /*\n 정렬을 대신 해 주지 않는 이유: 순서가 곧 \"다음 단계\"의 의미라서, 제품이 적은 순서와\n 실제 이동 순서가 다르면 디버깅할 수 없는 화면이 된다.\n */\n throw new TypeError(\"Sheet detents must be listed from smallest to largest\");\n }\n}\n\nexport function resolveNextSheetDetent(\n detents: readonly SheetDetent[],\n current: SheetDetent,\n direction: \"expand\" | \"collapse\",\n): SheetDetent | null {\n validateSheetDetents(detents);\n const index = detents.indexOf(current);\n if (index === -1) {\n throw new RangeError(`Sheet current detent is not in the list: ${current}`);\n }\n const next = direction === \"expand\" ? index + 1 : index - 1;\n /** 끝에서는 `null`이다 — renderer가 \"더 갈 수 없다\"를 컨트롤 상태로 표현한다. */\n return next < 0 || next >= detents.length ? null : detents[next]!;\n}\n\n"]}
1
+ {"version":3,"file":"sheet.js","sourceRoot":"","sources":["../src/sheet.ts"],"names":[],"mappings":"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","sourcesContent":["/** Why an open Sheet is being asked to close. */\nexport type SheetDismissReason =\n | \"close-action\"\n | \"escape\"\n | \"back\"\n | \"outside\"\n | \"swipe\"\n | \"programmatic\";\n\n/**\n * `trigger` only opens a Sheet. Every close reports the concrete dismiss reason\n * so renderers and product analytics do not have to infer it from platform events.\n */\nexport type SheetOpenChangeDetails = Readonly<{\n reason: \"trigger\" | SheetDismissReason;\n}>;\n\n/** User-dismiss policy. A controlled owner may always close programmatically. */\nexport type SheetDismissPolicy = Readonly<{\n dismissible: boolean;\n dismissWhileBusy: boolean;\n outsideDismiss: boolean;\n escapeOrBackDismiss: boolean;\n swipeDismiss: boolean;\n}>;\n\nexport type SheetOpenState =\n | Readonly<{\n open: boolean;\n defaultOpen?: never;\n onOpenChange(open: boolean, detail: SheetOpenChangeDetails): void;\n }>\n | Readonly<{\n open?: never;\n defaultOpen?: boolean;\n onOpenChange?: (open: boolean, detail: SheetOpenChangeDetails) => void;\n }>;\n\nexport const sheetBehaviorDefaults = {\n dismissible: true,\n dismissWhileBusy: false,\n outsideDismiss: true,\n escapeOrBackDismiss: true,\n // 2026-10-16 user decision: dragging a bottom sheet down is a required way to close it.\n swipeDismiss: true,\n} as const satisfies SheetDismissPolicy;\n\n/**\n * Every placement closes on a backdrop press (2026-10-17 user decision; bottom sheets had been drag-only\n * since 2026-10-16). Bottom sheets still show no × by default: drag, backdrop, Escape/system back and the\n * handle's close action cover pointer, keyboard, switch and screen-reader users. `outsideDismiss: false`\n * (with `swipeDismiss: false`) is only for flows where an accidental close loses work, such as payment\n * confirmation; unsaved-input confirmation belongs in the controlled owner's `onOpenChange`, which every\n * reason, `outside` included, passes through. `placement` stays in the signature for published callers.\n */\nexport function resolveSheetDismissPolicy(_placement: string, override: Partial<SheetDismissPolicy> = {}): SheetDismissPolicy {\n return { ...sheetBehaviorDefaults, ...override };\n}\nexport function resolveSheetCloseButton(placement: string, showClose?: boolean): boolean {\n return showClose ?? placement !== \"bottom\";\n}\n\n/** Release thresholds for the drag-to-dismiss gesture shared by both renderers. */\nexport const sheetDragRecipe = {\n activationDistance: 6,\n dismissDistanceRatio: 0.25,\n /** px per millisecond: a quick flick closes before the distance threshold. */\n dismissVelocity: 0.5,\n} as const;\n\n/**\n * Resolves an attempted close without platform knowledge. Programmatic close is\n * intentionally an owner override: a controlled `open={false}` cannot be vetoed\n * by a renderer, even while the Sheet is busy or not user-dismissible.\n */\nexport function canDismissSheet(\n reason: SheetDismissReason,\n busy: boolean,\n policy: SheetDismissPolicy = sheetBehaviorDefaults,\n): boolean {\n if (reason === \"programmatic\") return true;\n if (!policy.dismissible) return false;\n if (busy && !policy.dismissWhileBusy) return false;\n if (reason === \"outside\") return policy.outsideDismiss;\n if (reason === \"escape\" || reason === \"back\") {\n return policy.escapeOrBackDismiss;\n }\n if (reason === \"swipe\") return policy.swipeDismiss;\n return true;\n}\n\nexport type SheetLifecycle = Readonly<{\n open(): number;\n beginDismiss(): number | null;\n requestClose(\n reason: SheetDismissReason,\n busy: boolean,\n policy?: SheetDismissPolicy,\n ): boolean;\n completeDismiss(cycle: number): boolean;\n}>;\n\n/**\n * Makes persistent native Modal renderers settle each visible cycle once.\n * Platform adapters still decide when native dismissal has actually completed.\n */\nexport function createSheetLifecycle(\n initiallyVisible = false,\n): SheetLifecycle {\n let sequence = initiallyVisible ? 1 : 0;\n let activeCycle: number | null = initiallyVisible ? sequence : null;\n let closeRequested = false;\n const dismissingCycles = new Set<number>();\n\n return {\n open() {\n if (activeCycle !== null) return activeCycle;\n sequence += 1;\n activeCycle = sequence;\n closeRequested = false;\n return activeCycle;\n },\n beginDismiss() {\n if (activeCycle === null) return null;\n const cycle = activeCycle;\n activeCycle = null;\n closeRequested = false;\n dismissingCycles.add(cycle);\n return cycle;\n },\n requestClose(reason, busy, policy = sheetBehaviorDefaults) {\n if (activeCycle === null || closeRequested) return false;\n if (!canDismissSheet(reason, busy, policy)) return false;\n closeRequested = true;\n return true;\n },\n completeDismiss(cycle) {\n return dismissingCycles.delete(cycle);\n },\n };\n}\n\n/**\n * 사용자가 시트 높이를 바꾸는 축이다. `sheetRecipe.sizes`는 제품이 여는 높이를 정하고,\n * 이것은 열린 뒤 **사용자가** 단계를 옮기는 문제다 — 지도 위 목록처럼 \"조금 보기 ↔ 크게\n * 보기\"가 필요한 화면이 그 자리다.\n *\n * `auto`는 단계에 들어가지 않는다. 내용이 정하는 높이라 \"다음 단계\"가 정의되지 않는다.\n *\n * **드래그 물리는 여기 없다.** 이 계약은 단계 목록과 \"다음/이전 단계가 무엇인가\"만 갖고,\n * 손가락 속도·관성·고무줄은 넣지 않았다 — 실제 제품 화면 없이 그 값을 정하면 기기에서\n * 다시 다 고치게 된다. 대신 **핸들이 접근 가능한 컨트롤**이라 키보드·보조기기에서도\n * 단계를 옮길 수 있다. 제스처는 제품이 얹고, 결과를 같은 `onDetentChange`로 보낸다.\n */\nexport type SheetDetent = \"medium\" | \"large\" | \"full\";\n\nexport const sheetDetentOrder = [\"medium\", \"large\", \"full\"] as const satisfies readonly SheetDetent[];\n\nexport function validateSheetDetents(detents: readonly SheetDetent[]): void {\n if (detents.length === 0) {\n throw new RangeError(\"Sheet detents must not be empty\");\n }\n const seen = new Set<SheetDetent>();\n for (const detent of detents) {\n if (!sheetDetentOrder.includes(detent)) {\n throw new TypeError(`Unsupported Sheet detent: ${String(detent)}`);\n }\n if (seen.has(detent)) throw new TypeError(`Duplicate Sheet detent: ${detent}`);\n seen.add(detent);\n }\n const ordered = [...detents].sort(\n (left, right) => sheetDetentOrder.indexOf(left) - sheetDetentOrder.indexOf(right),\n );\n if (ordered.some((detent, index) => detent !== detents[index])) {\n /*\n 정렬을 대신 해 주지 않는 이유: 순서가 곧 \"다음 단계\"의 의미라서, 제품이 적은 순서와\n 실제 이동 순서가 다르면 디버깅할 수 없는 화면이 된다.\n */\n throw new TypeError(\"Sheet detents must be listed from smallest to largest\");\n }\n}\n\nexport function resolveNextSheetDetent(\n detents: readonly SheetDetent[],\n current: SheetDetent,\n direction: \"expand\" | \"collapse\",\n): SheetDetent | null {\n validateSheetDetents(detents);\n const index = detents.indexOf(current);\n if (index === -1) {\n throw new RangeError(`Sheet current detent is not in the list: ${current}`);\n }\n const next = direction === \"expand\" ? index + 1 : index - 1;\n /** 끝에서는 `null`이다 — renderer가 \"더 갈 수 없다\"를 컨트롤 상태로 표현한다. */\n return next < 0 || next >= detents.length ? null : detents[next]!;\n}\n\n"]}
@@ -113,7 +113,7 @@ export declare const sidePanelRecipe: {
113
113
  alpha?: number;
114
114
  }>;
115
115
  readonly textVariant: "title";
116
- readonly fontWeight: "700";
116
+ readonly fontWeight: "500";
117
117
  };
118
118
  readonly body: {
119
119
  readonly color: Readonly<{
@@ -1,5 +1,5 @@
1
1
  import { floatingSurfaceContract, focusIndicatorContract } from "./component-contracts.js";
2
- import { backdrop, control, fontWeight, motionPreset, shadow, spacing, } from "./foundations.js";
2
+ import { backdrop, control, motionPreset, shadow, spacing, typography, } from "./foundations.js";
3
3
  import { semanticColors } from "./semantic-colors.js";
4
4
  export const sidePanelBehaviorDefaults = {
5
5
  modal: true,
@@ -55,7 +55,7 @@ export const sidePanelRecipe = {
55
55
  title: {
56
56
  color: semanticColors.content.primary,
57
57
  textVariant: "title",
58
- fontWeight: fontWeight.bold,
58
+ fontWeight: typography.title.fontWeight,
59
59
  },
60
60
  body: {
61
61
  color: semanticColors.content.body,
@@ -1 +1 @@
1
- {"version":3,"file":"side-panel.js","sourceRoot":"","sources":["../src/side-panel.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ColorReference } from \"./color-references.js\";\nimport type { BehaviorContract } from \"./behaviors.js\";\nimport { floatingSurfaceContract, focusIndicatorContract } from \"./component-contracts.js\";\nimport {\n backdrop,\n control,\n fontWeight,\n motionPreset,\n shadow,\n spacing,\n type FontWeightValue,\n type TextVariant,\n} from \"./foundations.js\";\nimport { semanticColors } from \"./semantic-colors.js\";\n\n/** Logical, RTL-aware docking side. `top`/`bottom` stay Sheet's job — see docs/side-panel.md. */\nexport type SidePanelEdge = \"start\" | \"end\";\n\n/**\n * No `\"back\"`/`\"swipe\"`: SidePanel is Web-only (no hardware back, no\n * measured demand for a swipe-to-dismiss drawer). Everything else mirrors\n * `SheetDismissReason` (`src/sheet.ts`) because the *reasons* a panel closes\n * are the same on Web; only which reasons are *permitted* differs by `modal`.\n */\nexport type SidePanelDismissReason = \"close-action\" | \"escape\" | \"outside\" | \"programmatic\";\n\nexport type SidePanelOpenChangeDetails = Readonly<{\n reason: \"trigger\" | SidePanelDismissReason;\n}>;\n\nexport type SidePanelOpenState =\n | Readonly<{\n open: boolean;\n defaultOpen?: never;\n onOpenChange(open: boolean, detail: SidePanelOpenChangeDetails): void;\n }>\n | Readonly<{\n open?: never;\n defaultOpen?: boolean;\n onOpenChange?: (open: boolean, detail: SidePanelOpenChangeDetails) => void;\n }>;\n\n/**\n * `modal` is the axis Sheet does not need (Sheet is always modal). A\n * non-modal panel has no backdrop to click \"outside\" of — the rest of the\n * page stays live and interactive — so `outsideDismiss` is not merely\n * defaulted to `false` there, the type forbids it from existing at all.\n * This is the same \"make the invalid combination unrepresentable\" move as\n * `SheetOpenState`'s controlled/uncontrolled split.\n */\nexport type SidePanelDismissPolicy =\n | Readonly<{\n modal: true;\n dismissible: boolean;\n dismissWhileBusy: boolean;\n escapeDismiss: boolean;\n outsideDismiss: boolean;\n }>\n | Readonly<{\n modal: false;\n dismissible: boolean;\n dismissWhileBusy: boolean;\n escapeDismiss: boolean;\n outsideDismiss?: never;\n }>;\n\nexport const sidePanelBehaviorDefaults = {\n modal: true,\n dismissible: true,\n dismissWhileBusy: false,\n escapeDismiss: true,\n outsideDismiss: true,\n} as const satisfies Extract<SidePanelDismissPolicy, { modal: true }>;\n\n/**\n * Same shape and role as `canDismissSheet`, kept as a separate function\n * because the two owning types are not generic over each other (`sheet.ts`\n * is a shared file this module must not edit) and the `modal` branch is\n * genuine new logic, not a copy.\n */\nexport function canDismissSidePanel(\n reason: SidePanelDismissReason,\n busy: boolean,\n policy: SidePanelDismissPolicy = sidePanelBehaviorDefaults,\n): boolean {\n if (reason === \"programmatic\") return true;\n if (!policy.dismissible) return false;\n if (busy && !policy.dismissWhileBusy) return false;\n if (reason === \"outside\") return policy.modal ? policy.outsideDismiss : false;\n if (reason === \"escape\") return policy.escapeDismiss;\n return true;\n}\n\nexport type SidePanelSize = \"compact\" | \"regular\" | \"wide\";\n\n/**\n * No `createSidePanelLifecycle` counterpart to `createSheetLifecycle`: that\n * machinery exists solely to make Android's persistently-mounted native\n * Modal settle one visible cycle at a time. SidePanel is Web-only, where a\n * plain CSS `transitionend`/exit-callback (the same pattern `sheetRecipe`\n * and `dialogRecipe` already assume for Web) is the whole story — adding a\n * cycle counter here would solve a problem this platform does not have.\n */\nexport const sidePanelRecipe = {\n slots: [\"backdrop\", \"positioner\", \"content\", \"header\", \"title\", \"body\", \"footer\", \"close\"] as const,\n defaults: { edge: \"end\", size: \"regular\" },\n sizes: { compact: 320, regular: 400, wide: 560 },\n backdrop: backdrop.modal,\n content: {\n background: semanticColors.canvas,\n border: semanticColors.border.default,\n borderWidth: floatingSurfaceContract.borderWidth,\n /** Flush to the viewport edge it docks to — unlike Sheet's floating `xl` radius. */\n radius: null,\n shadow: shadow.overlay,\n paddingHorizontal: spacing.lg,\n paddingTop: spacing.sm,\n paddingBottom: spacing.sm,\n },\n header: { minHeight: control.minTouchTarget, gap: spacing.sm },\n title: {\n color: semanticColors.content.primary,\n textVariant: \"title\",\n fontWeight: fontWeight.bold,\n },\n body: {\n color: semanticColors.content.body,\n textVariant: \"body\",\n gap: spacing.md,\n },\n footer: {\n color: semanticColors.content.body,\n textVariant: \"body\",\n gap: spacing.sm,\n paddingTop: spacing.sm,\n },\n transition: { enter: motionPreset.enter, exit: motionPreset.exit },\n states: { focus: focusIndicatorContract },\n} as const satisfies {\n slots: readonly [\"backdrop\", \"positioner\", \"content\", \"header\", \"title\", \"body\", \"footer\", \"close\"];\n defaults: { edge: SidePanelEdge; size: SidePanelSize };\n sizes: Record<SidePanelSize, number>;\n backdrop: typeof backdrop.modal;\n content: {\n background: ColorReference;\n border: ColorReference;\n borderWidth: number;\n radius: null;\n shadow: typeof shadow.overlay;\n paddingHorizontal: number;\n paddingTop: number;\n paddingBottom: number;\n };\n header: { minHeight: number; gap: number };\n title: { color: ColorReference; textVariant: TextVariant; fontWeight: FontWeightValue };\n body: { color: ColorReference; textVariant: TextVariant; gap: number };\n footer: { color: ColorReference; textVariant: TextVariant; gap: number; paddingTop: number };\n transition: { enter: typeof motionPreset.enter; exit: typeof motionPreset.exit };\n states: { focus: typeof focusIndicatorContract };\n};\n\n/**\n * `web.focus` can only hold one value, but the real behavior branches on\n * `modal`: `\"trap\"` (default, modal) vs. no trap at all when `modal: false`.\n * The field records the default configuration; the non-modal case is a\n * documented exception in `docs/side-panel.md`, the same way this contract\n * records one representative value elsewhere and pushes edge cases to\n * `scenarios`.\n */\nexport const sidePanelBehavior = {\n controlled: [\"open\", \"defaultOpen\", \"onOpenChange\", \"dismissPolicy\"],\n defaults: sidePanelBehaviorDefaults,\n configuration: {\n edge: [\"start\", \"end\"],\n modal: [\"true\", \"false\"],\n },\n stateAxes: {\n availability: [\"enabled\", \"busy\"],\n value: [\"open\"],\n },\n web: {\n roles: [\"dialog\"],\n keyboard: [\"Tab\", \"Escape\"],\n focus: \"trap\",\n dismiss: [\"escape\", \"outside\"],\n },\n native: { roles: [], states: [], actions: [] },\n scenarios: [\n \"edge-is-a-logical-start-or-end-direction-never-left-or-right\",\n \"modal-panels-trap-focus-and-lock-scroll-non-modal-panels-do-neither\",\n \"non-modal-panels-never-expose-outside-dismiss-the-type-forbids-it\",\n \"single-dismiss-callback-reports-the-concrete-reason\",\n \"busy-blocks-user-dismiss-programmatic-owner-close-is-always-allowed\",\n \"escape-dismisses-in-both-modal-and-non-modal-panels\",\n \"no-back-or-swipe-dismiss-reason-exists-on-this-web-only-platform\",\n \"reduced-motion-still-completes-the-exit-callback-once\",\n ],\n} as const satisfies BehaviorContract;\n"]}
1
+ {"version":3,"file":"side-panel.js","sourceRoot":"","sources":["../src/side-panel.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ColorReference } from \"./color-references.js\";\nimport type { BehaviorContract } from \"./behaviors.js\";\nimport { floatingSurfaceContract, focusIndicatorContract } from \"./component-contracts.js\";\nimport {\n backdrop,\n control,\n motionPreset,\n shadow,\n spacing,\n typography,\n type FontWeightValue,\n type TextVariant,\n} from \"./foundations.js\";\nimport { semanticColors } from \"./semantic-colors.js\";\n\n/** Logical, RTL-aware docking side. `top`/`bottom` stay Sheet's job — see docs/side-panel.md. */\nexport type SidePanelEdge = \"start\" | \"end\";\n\n/**\n * No `\"back\"`/`\"swipe\"`: SidePanel is Web-only (no hardware back, no\n * measured demand for a swipe-to-dismiss drawer). Everything else mirrors\n * `SheetDismissReason` (`src/sheet.ts`) because the *reasons* a panel closes\n * are the same on Web; only which reasons are *permitted* differs by `modal`.\n */\nexport type SidePanelDismissReason = \"close-action\" | \"escape\" | \"outside\" | \"programmatic\";\n\nexport type SidePanelOpenChangeDetails = Readonly<{\n reason: \"trigger\" | SidePanelDismissReason;\n}>;\n\nexport type SidePanelOpenState =\n | Readonly<{\n open: boolean;\n defaultOpen?: never;\n onOpenChange(open: boolean, detail: SidePanelOpenChangeDetails): void;\n }>\n | Readonly<{\n open?: never;\n defaultOpen?: boolean;\n onOpenChange?: (open: boolean, detail: SidePanelOpenChangeDetails) => void;\n }>;\n\n/**\n * `modal` is the axis Sheet does not need (Sheet is always modal). A\n * non-modal panel has no backdrop to click \"outside\" of — the rest of the\n * page stays live and interactive — so `outsideDismiss` is not merely\n * defaulted to `false` there, the type forbids it from existing at all.\n * This is the same \"make the invalid combination unrepresentable\" move as\n * `SheetOpenState`'s controlled/uncontrolled split.\n */\nexport type SidePanelDismissPolicy =\n | Readonly<{\n modal: true;\n dismissible: boolean;\n dismissWhileBusy: boolean;\n escapeDismiss: boolean;\n outsideDismiss: boolean;\n }>\n | Readonly<{\n modal: false;\n dismissible: boolean;\n dismissWhileBusy: boolean;\n escapeDismiss: boolean;\n outsideDismiss?: never;\n }>;\n\nexport const sidePanelBehaviorDefaults = {\n modal: true,\n dismissible: true,\n dismissWhileBusy: false,\n escapeDismiss: true,\n outsideDismiss: true,\n} as const satisfies Extract<SidePanelDismissPolicy, { modal: true }>;\n\n/**\n * Same shape and role as `canDismissSheet`, kept as a separate function\n * because the two owning types are not generic over each other (`sheet.ts`\n * is a shared file this module must not edit) and the `modal` branch is\n * genuine new logic, not a copy.\n */\nexport function canDismissSidePanel(\n reason: SidePanelDismissReason,\n busy: boolean,\n policy: SidePanelDismissPolicy = sidePanelBehaviorDefaults,\n): boolean {\n if (reason === \"programmatic\") return true;\n if (!policy.dismissible) return false;\n if (busy && !policy.dismissWhileBusy) return false;\n if (reason === \"outside\") return policy.modal ? policy.outsideDismiss : false;\n if (reason === \"escape\") return policy.escapeDismiss;\n return true;\n}\n\nexport type SidePanelSize = \"compact\" | \"regular\" | \"wide\";\n\n/**\n * No `createSidePanelLifecycle` counterpart to `createSheetLifecycle`: that\n * machinery exists solely to make Android's persistently-mounted native\n * Modal settle one visible cycle at a time. SidePanel is Web-only, where a\n * plain CSS `transitionend`/exit-callback (the same pattern `sheetRecipe`\n * and `dialogRecipe` already assume for Web) is the whole story — adding a\n * cycle counter here would solve a problem this platform does not have.\n */\nexport const sidePanelRecipe = {\n slots: [\"backdrop\", \"positioner\", \"content\", \"header\", \"title\", \"body\", \"footer\", \"close\"] as const,\n defaults: { edge: \"end\", size: \"regular\" },\n sizes: { compact: 320, regular: 400, wide: 560 },\n backdrop: backdrop.modal,\n content: {\n background: semanticColors.canvas,\n border: semanticColors.border.default,\n borderWidth: floatingSurfaceContract.borderWidth,\n /** Flush to the viewport edge it docks to — unlike Sheet's floating `xl` radius. */\n radius: null,\n shadow: shadow.overlay,\n paddingHorizontal: spacing.lg,\n paddingTop: spacing.sm,\n paddingBottom: spacing.sm,\n },\n header: { minHeight: control.minTouchTarget, gap: spacing.sm },\n title: {\n color: semanticColors.content.primary,\n textVariant: \"title\",\n fontWeight: typography.title.fontWeight,\n },\n body: {\n color: semanticColors.content.body,\n textVariant: \"body\",\n gap: spacing.md,\n },\n footer: {\n color: semanticColors.content.body,\n textVariant: \"body\",\n gap: spacing.sm,\n paddingTop: spacing.sm,\n },\n transition: { enter: motionPreset.enter, exit: motionPreset.exit },\n states: { focus: focusIndicatorContract },\n} as const satisfies {\n slots: readonly [\"backdrop\", \"positioner\", \"content\", \"header\", \"title\", \"body\", \"footer\", \"close\"];\n defaults: { edge: SidePanelEdge; size: SidePanelSize };\n sizes: Record<SidePanelSize, number>;\n backdrop: typeof backdrop.modal;\n content: {\n background: ColorReference;\n border: ColorReference;\n borderWidth: number;\n radius: null;\n shadow: typeof shadow.overlay;\n paddingHorizontal: number;\n paddingTop: number;\n paddingBottom: number;\n };\n header: { minHeight: number; gap: number };\n title: { color: ColorReference; textVariant: TextVariant; fontWeight: FontWeightValue };\n body: { color: ColorReference; textVariant: TextVariant; gap: number };\n footer: { color: ColorReference; textVariant: TextVariant; gap: number; paddingTop: number };\n transition: { enter: typeof motionPreset.enter; exit: typeof motionPreset.exit };\n states: { focus: typeof focusIndicatorContract };\n};\n\n/**\n * `web.focus` can only hold one value, but the real behavior branches on\n * `modal`: `\"trap\"` (default, modal) vs. no trap at all when `modal: false`.\n * The field records the default configuration; the non-modal case is a\n * documented exception in `docs/side-panel.md`, the same way this contract\n * records one representative value elsewhere and pushes edge cases to\n * `scenarios`.\n */\nexport const sidePanelBehavior = {\n controlled: [\"open\", \"defaultOpen\", \"onOpenChange\", \"dismissPolicy\"],\n defaults: sidePanelBehaviorDefaults,\n configuration: {\n edge: [\"start\", \"end\"],\n modal: [\"true\", \"false\"],\n },\n stateAxes: {\n availability: [\"enabled\", \"busy\"],\n value: [\"open\"],\n },\n web: {\n roles: [\"dialog\"],\n keyboard: [\"Tab\", \"Escape\"],\n focus: \"trap\",\n dismiss: [\"escape\", \"outside\"],\n },\n native: { roles: [], states: [], actions: [] },\n scenarios: [\n \"edge-is-a-logical-start-or-end-direction-never-left-or-right\",\n \"modal-panels-trap-focus-and-lock-scroll-non-modal-panels-do-neither\",\n \"non-modal-panels-never-expose-outside-dismiss-the-type-forbids-it\",\n \"single-dismiss-callback-reports-the-concrete-reason\",\n \"busy-blocks-user-dismiss-programmatic-owner-close-is-always-allowed\",\n \"escape-dismisses-in-both-modal-and-non-modal-panels\",\n \"no-back-or-swipe-dismiss-reason-exists-on-this-web-only-platform\",\n \"reduced-motion-still-completes-the-exit-callback-once\",\n ],\n} as const satisfies BehaviorContract;\n"]}
package/dist/steps.d.ts CHANGED
@@ -160,7 +160,7 @@ export declare const stepsRecipe: {
160
160
  };
161
161
  readonly label: {
162
162
  readonly textVariant: "label";
163
- readonly fontWeight: "600";
163
+ readonly fontWeight: "500";
164
164
  readonly color: {
165
165
  readonly pending: Readonly<{
166
166
  source: "theme";
package/dist/steps.js CHANGED
@@ -145,7 +145,7 @@ export const stepsRecipe = {
145
145
  },
146
146
  label: {
147
147
  textVariant: "label",
148
- fontWeight: fontWeight.semibold,
148
+ fontWeight: fontWeight.medium,
149
149
  color: {
150
150
  pending: semanticColors.content.secondary,
151
151
  current: semanticColors.content.primary,