@hjmds/design-contracts 1.13.1 → 1.15.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 (200) hide show
  1. package/dist/agreement.d.ts +7 -1
  2. package/dist/agreement.d.ts.map +1 -1
  3. package/dist/agreement.js +14 -3
  4. package/dist/agreement.js.map +1 -1
  5. package/dist/behaviors.d.ts +1 -1
  6. package/dist/catalog.d.ts +4 -0
  7. package/dist/catalog.d.ts.map +1 -1
  8. package/dist/content-transition.d.ts +17 -0
  9. package/dist/content-transition.d.ts.map +1 -1
  10. package/dist/content-transition.js +21 -0
  11. package/dist/content-transition.js.map +1 -1
  12. package/dist/date-entry.d.ts +71 -0
  13. package/dist/date-entry.d.ts.map +1 -0
  14. package/dist/date-entry.js +78 -0
  15. package/dist/date-entry.js.map +1 -0
  16. package/dist/design-profile-layout.d.ts +11 -0
  17. package/dist/design-profile-layout.d.ts.map +1 -0
  18. package/dist/design-profile-layout.js +18 -0
  19. package/dist/design-profile-layout.js.map +1 -0
  20. package/dist/design-profile.d.ts +89 -0
  21. package/dist/design-profile.d.ts.map +1 -0
  22. package/dist/design-profile.js +262 -0
  23. package/dist/design-profile.js.map +1 -0
  24. package/dist/design-system-provider.d.ts +6 -0
  25. package/dist/design-system-provider.d.ts.map +1 -1
  26. package/dist/design-system-provider.js +4 -2
  27. package/dist/design-system-provider.js.map +1 -1
  28. package/dist/document-resource.d.ts +104 -0
  29. package/dist/document-resource.d.ts.map +1 -0
  30. package/dist/document-resource.js +77 -0
  31. package/dist/document-resource.js.map +1 -0
  32. package/dist/effect-surface.d.ts +6 -1
  33. package/dist/effect-surface.d.ts.map +1 -1
  34. package/dist/effect-surface.js +5 -2
  35. package/dist/effect-surface.js.map +1 -1
  36. package/dist/field-group.d.ts +47 -0
  37. package/dist/field-group.d.ts.map +1 -0
  38. package/dist/field-group.js +92 -0
  39. package/dist/field-group.js.map +1 -0
  40. package/dist/gooey-navigation.d.ts +19 -1
  41. package/dist/gooey-navigation.d.ts.map +1 -1
  42. package/dist/gooey-navigation.js +37 -2
  43. package/dist/gooey-navigation.js.map +1 -1
  44. package/dist/image.d.ts +17 -0
  45. package/dist/image.d.ts.map +1 -1
  46. package/dist/image.js +19 -0
  47. package/dist/image.js.map +1 -1
  48. package/dist/internal/effect-noise.d.ts +2 -0
  49. package/dist/internal/effect-noise.d.ts.map +1 -0
  50. package/dist/internal/effect-noise.js +4 -0
  51. package/dist/internal/effect-noise.js.map +1 -0
  52. package/dist/palette-contrast.d.ts +6 -0
  53. package/dist/palette-contrast.d.ts.map +1 -1
  54. package/dist/palette-contrast.js +17 -0
  55. package/dist/palette-contrast.js.map +1 -1
  56. package/dist/progressive-blur.d.ts +32 -0
  57. package/dist/progressive-blur.d.ts.map +1 -0
  58. package/dist/progressive-blur.js +28 -0
  59. package/dist/progressive-blur.js.map +1 -0
  60. package/dist/reference-controls.d.ts +32 -0
  61. package/dist/reference-controls.d.ts.map +1 -0
  62. package/dist/reference-controls.js +28 -0
  63. package/dist/reference-controls.js.map +1 -0
  64. package/dist/screen-patterns.d.ts +16 -1
  65. package/dist/screen-patterns.d.ts.map +1 -1
  66. package/dist/screen-patterns.js +4 -0
  67. package/dist/screen-patterns.js.map +1 -1
  68. package/dist/scroll-progress.d.ts +7 -1
  69. package/dist/scroll-progress.d.ts.map +1 -1
  70. package/dist/scroll-progress.js +21 -2
  71. package/dist/scroll-progress.js.map +1 -1
  72. package/dist/text-annotation.d.ts +43 -0
  73. package/dist/text-annotation.d.ts.map +1 -0
  74. package/dist/text-annotation.js +137 -0
  75. package/dist/text-annotation.js.map +1 -0
  76. package/dist/toast-liquid.d.ts +3 -1
  77. package/dist/toast-liquid.d.ts.map +1 -1
  78. package/dist/toast-liquid.js +6 -2
  79. package/dist/toast-liquid.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/agreement.md +14 -0
  84. package/docs/asset.md +7 -0
  85. package/docs/brand-boundary.md +14 -5
  86. package/docs/code-block.md +12 -1
  87. package/docs/collapsible.md +6 -0
  88. package/docs/design-profile.md +263 -0
  89. package/docs/design-system-provider.md +7 -0
  90. package/docs/dialog.md +20 -1
  91. package/docs/effect-surface.md +19 -3
  92. package/docs/generated/component-maturity.md +1 -1
  93. package/docs/generated/renderer-evidence.json +3 -3
  94. package/docs/generated/renderer-evidence.md +1 -1
  95. package/docs/generated/showcase-manifest.json +1 -1
  96. package/docs/gooey-navigation.md +37 -6
  97. package/docs/heading.md +15 -0
  98. package/docs/image.md +17 -0
  99. package/docs/optional-adapters.md +25 -0
  100. package/docs/popover.md +15 -0
  101. package/docs/rating.md +6 -1
  102. package/docs/reference-controls.md +40 -0
  103. package/docs/task-list.md +15 -1
  104. package/docs/text-annotation.md +85 -0
  105. package/docs/theming.md +18 -5
  106. package/docs/usage/README.md +23 -1
  107. package/docs/usage/components/activity-heatmap.md +3 -1
  108. package/docs/usage/components/agreement.md +15 -3
  109. package/docs/usage/components/alert-dialog.md +16 -1
  110. package/docs/usage/components/asset.md +9 -2
  111. package/docs/usage/components/avatar.md +33 -1
  112. package/docs/usage/components/badge.md +3 -1
  113. package/docs/usage/components/bottom-cta.md +3 -1
  114. package/docs/usage/components/bottom-navigation.md +5 -1
  115. package/docs/usage/components/button.md +7 -1
  116. package/docs/usage/components/calendar.md +3 -1
  117. package/docs/usage/components/card.md +26 -3
  118. package/docs/usage/components/carousel.md +10 -1
  119. package/docs/usage/components/chat-message.md +11 -1
  120. package/docs/usage/components/chip.md +5 -0
  121. package/docs/usage/components/code-block.md +14 -2
  122. package/docs/usage/components/collapsible.md +10 -2
  123. package/docs/usage/components/combobox.md +12 -1
  124. package/docs/usage/components/command-palette.md +11 -6
  125. package/docs/usage/components/content-transition.md +29 -5
  126. package/docs/usage/components/context-menu.md +7 -1
  127. package/docs/usage/components/date-picker.md +3 -1
  128. package/docs/usage/components/design-system-provider.md +7 -5
  129. package/docs/usage/components/dialog.md +70 -1
  130. package/docs/usage/components/effect-surface.md +4 -2
  131. package/docs/usage/components/empty-state.md +10 -2
  132. package/docs/usage/components/field.md +26 -1
  133. package/docs/usage/components/form.md +13 -3
  134. package/docs/usage/components/heading.md +7 -1
  135. package/docs/usage/components/image-comparison.md +82 -0
  136. package/docs/usage/components/image.md +83 -2
  137. package/docs/usage/components/keyboard-avoiding.md +6 -1
  138. package/docs/usage/components/link.md +3 -1
  139. package/docs/usage/components/list-row.md +5 -1
  140. package/docs/usage/components/list.md +8 -1
  141. package/docs/usage/components/load-more.md +3 -1
  142. package/docs/usage/components/mentions.md +3 -1
  143. package/docs/usage/components/menu.md +3 -1
  144. package/docs/usage/components/menubar.md +7 -1
  145. package/docs/usage/components/message-composer.md +16 -5
  146. package/docs/usage/components/notice.md +9 -0
  147. package/docs/usage/components/number-field.md +3 -1
  148. package/docs/usage/components/onboarding-screen.md +16 -9
  149. package/docs/usage/components/overview-screen.md +73 -0
  150. package/docs/usage/components/password-field.md +5 -1
  151. package/docs/usage/components/popover.md +14 -1
  152. package/docs/usage/components/progress.md +28 -0
  153. package/docs/usage/components/progressive-blur.md +113 -0
  154. package/docs/usage/components/rating.md +74 -0
  155. package/docs/usage/components/saved-items-screen.md +3 -1
  156. package/docs/usage/components/screen-layout.md +9 -1
  157. package/docs/usage/components/search-field.md +13 -1
  158. package/docs/usage/components/search-screen.md +5 -0
  159. package/docs/usage/components/segmented-control.md +17 -0
  160. package/docs/usage/components/select.md +9 -0
  161. package/docs/usage/components/sheet.md +14 -1
  162. package/docs/usage/components/skeleton.md +9 -0
  163. package/docs/usage/components/slider.md +3 -1
  164. package/docs/usage/components/statistic.md +14 -1
  165. package/docs/usage/components/surface.md +8 -1
  166. package/docs/usage/components/tabs.md +11 -2
  167. package/docs/usage/components/tag.md +3 -1
  168. package/docs/usage/components/tags-input.md +11 -1
  169. package/docs/usage/components/text-area.md +3 -1
  170. package/docs/usage/components/text-transition.md +8 -2
  171. package/docs/usage/components/text.md +3 -1
  172. package/docs/usage/components/toast.md +23 -1
  173. package/docs/usage/components/top-bar.md +3 -1
  174. package/docs/usage/components/upload-item.md +3 -1
  175. package/docs/usage/compositions/action-feedback.md +77 -0
  176. package/docs/usage/compositions/adaptive-content.md +81 -0
  177. package/docs/usage/compositions/command-records.md +106 -0
  178. package/docs/usage/compositions/content-transition-comparison.md +108 -0
  179. package/docs/usage/compositions/context-toolbar.md +85 -0
  180. package/docs/usage/compositions/date-entry.md +108 -0
  181. package/docs/usage/compositions/date-time-selection.md +110 -0
  182. package/docs/usage/compositions/design-profile-comparison.md +114 -0
  183. package/docs/usage/compositions/document-resource.md +124 -0
  184. package/docs/usage/compositions/field-group.md +104 -0
  185. package/docs/usage/compositions/illustrated-outcome.md +91 -0
  186. package/docs/usage/compositions/live-list.md +104 -0
  187. package/docs/usage/compositions/optional-adapters.md +1 -1
  188. package/docs/usage/compositions/origin-dialog.md +108 -0
  189. package/docs/usage/compositions/selection-motion.md +73 -0
  190. package/docs/usage/compositions/texture-comparison.md +86 -0
  191. package/docs/usage/compositions/upload-recovery.md +80 -0
  192. package/docs/usage/compositions/video-dialog.md +100 -0
  193. package/docs/usage/screens/flow-onboarding.md +5 -3
  194. package/docs/usage/screens/product-bento.md +117 -0
  195. package/docs/usage/tokens/color.md +9 -2
  196. package/docs/usage/tokens/elevation-opacity.md +8 -1
  197. package/docs/usage/tokens/motion.md +10 -1
  198. package/docs/usage/tokens/radius.md +8 -1
  199. package/docs/usage/tokens/typography.md +15 -1
  200. package/package.json +49 -1
@@ -1,8 +1,43 @@
1
- /** Stretch only the selected indicator; tab hit targets and text never move. */
2
- export function resolveGooeyIndicator(from, to) {
1
+ import { motion } from "./foundations.js";
2
+ /** A product's explicit appearance wins; vertical tabs keep the canonical line.
3
+ * Plain profile sliding is not an implicit request for elastic gooey stretching. */
4
+ export function resolveTabsAppearance(appearance, selectionMotion = "none", orientation = "horizontal") {
5
+ if (appearance !== undefined && !["standard", "slide", "gooey"].includes(appearance))
6
+ throw new TypeError("Unsupported tabs appearance");
7
+ return orientation === "vertical" ? "standard" : appearance ?? (selectionMotion === "slide" ? "slide" : "standard");
8
+ }
9
+ /** Both renderers interpolate measured bounds without changing selection or panels. */
10
+ export function resolveTabIndicator(from, to, appearance) {
11
+ if (appearance === "gooey")
12
+ return resolveGooeyIndicator(from, to);
13
+ if (appearance !== "slide")
14
+ throw new TypeError("Unsupported moving tab indicator");
15
+ validateRects(from, to);
16
+ // Ordinary selection feedback uses the shared normal duration; retain the
17
+ // existing 320ms elastic recipe for explicit gooey consumers.
18
+ return { duration: motion.normal, input: [0, 1], x: [from.x, to.x], width: [from.width, to.width] };
19
+ }
20
+ /** Capture the current JS-driver frame before cancellation so rapid input starts
21
+ * where the indicator is visible, rather than jumping to the abandoned target. */
22
+ export function sampleTabIndicator(recipe, progress) {
23
+ const value = Number.isFinite(progress) ? Math.max(0, Math.min(1, progress)) : 1;
24
+ const index = recipe.input.findIndex((offset, i) => i > 0 && offset >= value);
25
+ const end = index < 0 ? recipe.input.length - 1 : index;
26
+ const start = Math.max(0, end - 1);
27
+ const fraction = (value - recipe.input[start]) / (recipe.input[end] - recipe.input[start]);
28
+ return {
29
+ x: recipe.x[start] + (recipe.x[end] - recipe.x[start]) * fraction,
30
+ width: recipe.width[start] + (recipe.width[end] - recipe.width[start]) * fraction,
31
+ };
32
+ }
33
+ function validateRects(from, to) {
3
34
  for (const rect of [from, to])
4
35
  if (!Number.isFinite(rect.x) || !Number.isFinite(rect.width) || rect.width <= 0)
5
36
  throw new RangeError("Indicator needs finite coordinates and positive widths");
37
+ }
38
+ /** Stretch only the selected indicator; tab hit targets and text never move. */
39
+ export function resolveGooeyIndicator(from, to) {
40
+ validateRects(from, to);
6
41
  // Keep the elastic bridge within the measured source/destination span, including RTL layouts.
7
42
  const left = Math.min(from.x, to.x);
8
43
  const right = Math.max(from.x + from.width, to.x + to.width);
@@ -1 +1 @@
1
- {"version":3,"file":"gooey-navigation.js","sourceRoot":"","sources":["../src/gooey-navigation.ts"],"names":[],"mappings":"AAEA,gFAAgF;AAChF,MAAM,UAAU,qBAAqB,CAAC,IAAwB,EAAE,EAAsB;IACpF,KAAK,MAAM,IAAI,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC;QAAE,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,KAAK,IAAI,CAAC;YAAE,MAAM,IAAI,UAAU,CAAC,wDAAwD,CAAC,CAAC;IAC/L,8FAA8F;IAC9F,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC;IACpC,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,CAAC;IAC7D,OAAO,EAAE,QAAQ,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI,EAAE,EAAE,CAAC,KAAK,CAAC,EAAW,CAAC;AAC/H,CAAC","sourcesContent":["export type TabsAppearance = \"standard\" | \"gooey\";\nexport type GooeyIndicatorRect = Readonly<{ x: number; width: number }>;\n/** Stretch only the selected indicator; tab hit targets and text never move. */\nexport function resolveGooeyIndicator(from: GooeyIndicatorRect, to: GooeyIndicatorRect) {\n for (const rect of [from, to]) if (!Number.isFinite(rect.x) || !Number.isFinite(rect.width) || rect.width <= 0) throw new RangeError(\"Indicator needs finite coordinates and positive widths\");\n // Keep the elastic bridge within the measured source/destination span, including RTL layouts.\n const left = Math.min(from.x, to.x);\n const right = Math.max(from.x + from.width, to.x + to.width);\n return { duration: 320, input: [0, 0.45, 1], x: [from.x, left, to.x], width: [from.width, right - left, to.width] } as const;\n}\n"]}
1
+ {"version":3,"file":"gooey-navigation.js","sourceRoot":"","sources":["../src/gooey-navigation.ts"],"names":[],"mappings":"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","sourcesContent":["import { motion } from \"./foundations.js\";\n\nexport type TabsAppearance = \"standard\" | \"slide\" | \"gooey\";\nexport type GooeyIndicatorRect = Readonly<{ x: number; width: number }>;\n\n/** A product's explicit appearance wins; vertical tabs keep the canonical line.\n * Plain profile sliding is not an implicit request for elastic gooey stretching. */\nexport function resolveTabsAppearance(\n appearance: TabsAppearance | undefined,\n selectionMotion: \"none\" | \"slide\" = \"none\",\n orientation: \"horizontal\" | \"vertical\" = \"horizontal\",\n): TabsAppearance {\n if (appearance !== undefined && ![\"standard\", \"slide\", \"gooey\"].includes(appearance)) throw new TypeError(\"Unsupported tabs appearance\");\n return orientation === \"vertical\" ? \"standard\" : appearance ?? (selectionMotion === \"slide\" ? \"slide\" : \"standard\");\n}\n\n/** Both renderers interpolate measured bounds without changing selection or panels. */\nexport function resolveTabIndicator(from: GooeyIndicatorRect, to: GooeyIndicatorRect, appearance: \"slide\" | \"gooey\") {\n if (appearance === \"gooey\") return resolveGooeyIndicator(from, to);\n if (appearance !== \"slide\") throw new TypeError(\"Unsupported moving tab indicator\");\n validateRects(from, to);\n // Ordinary selection feedback uses the shared normal duration; retain the\n // existing 320ms elastic recipe for explicit gooey consumers.\n return { duration: motion.normal, input: [0, 1], x: [from.x, to.x], width: [from.width, to.width] } as const;\n}\n\n/** Capture the current JS-driver frame before cancellation so rapid input starts\n * where the indicator is visible, rather than jumping to the abandoned target. */\nexport function sampleTabIndicator(recipe: ReturnType<typeof resolveTabIndicator>, progress: number): GooeyIndicatorRect {\n const value = Number.isFinite(progress) ? Math.max(0, Math.min(1, progress)) : 1;\n const index = recipe.input.findIndex((offset, i) => i > 0 && offset >= value);\n const end = index < 0 ? recipe.input.length - 1 : index;\n const start = Math.max(0, end - 1);\n const fraction = (value - recipe.input[start]!) / (recipe.input[end]! - recipe.input[start]!);\n return {\n x: recipe.x[start]! + (recipe.x[end]! - recipe.x[start]!) * fraction,\n width: recipe.width[start]! + (recipe.width[end]! - recipe.width[start]!) * fraction,\n };\n}\n\nfunction validateRects(from: GooeyIndicatorRect, to: GooeyIndicatorRect) {\n for (const rect of [from, to]) if (!Number.isFinite(rect.x) || !Number.isFinite(rect.width) || rect.width <= 0) throw new RangeError(\"Indicator needs finite coordinates and positive widths\");\n}\n/** Stretch only the selected indicator; tab hit targets and text never move. */\nexport function resolveGooeyIndicator(from: GooeyIndicatorRect, to: GooeyIndicatorRect) {\n validateRects(from, to);\n // Keep the elastic bridge within the measured source/destination span, including RTL layouts.\n const left = Math.min(from.x, to.x);\n const right = Math.max(from.x + from.width, to.x + to.width);\n return { duration: 320, input: [0, 0.45, 1], x: [from.x, left, to.x], width: [from.width, right - left, to.width] } as const;\n}\n"]}
package/dist/image.d.ts CHANGED
@@ -1,5 +1,22 @@
1
1
  export type ImageFit = "cover" | "contain" | "fill";
2
2
  export type ImageLoadStatus = "idle" | "loading" | "loaded" | "error";
3
+ export type ImageInspectionMode = "fit" | "double" | "pixels";
4
+ /** Exact image inspection sizes use layout units, not device physical pixels (Utilverse ADR-0020). */
5
+ export declare function resolveImageInspectionGeometry(image: Readonly<{
6
+ width: number;
7
+ height: number;
8
+ }>, viewport: Readonly<{
9
+ width: number;
10
+ height: number;
11
+ }>, mode: ImageInspectionMode): {
12
+ scale: number;
13
+ width: number;
14
+ height: number;
15
+ panBounds: {
16
+ x: number;
17
+ y: number;
18
+ };
19
+ };
3
20
  export declare const imageDefaults: {
4
21
  readonly fit: "cover";
5
22
  };
@@ -1 +1 @@
1
- {"version":3,"file":"image.d.ts","sourceRoot":"","sources":["../src/image.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,SAAS,GAAG,MAAM,CAAC;AACpD,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,SAAS,GAAG,QAAQ,GAAG,OAAO,CAAC;AAEtE,eAAO,MAAM,aAAa;;CAEsB,CAAC;AAEjD,KAAK,eAAe,GAAG,QAAQ,CAAC;IAC9B,GAAG,EAAE,MAAM,CAAC;IACZ,wEAAwE;IACxE,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,QAAQ,CAAC;CAChB,CAAC,CAAC;AAEH;;;;GAIG;AACH,MAAM,MAAM,yBAAyB,GAAG,eAAe,GACrD,QAAQ,CAAC;IAAE,UAAU,CAAC,EAAE,IAAI,CAAC;IAAC,kBAAkB,CAAC,EAAE,KAAK,CAAA;CAAE,CAAC,CAAC;AAE9D,MAAM,MAAM,0BAA0B,GAAG,eAAe,GACtD,QAAQ,CAAC;IAAE,UAAU,EAAE,KAAK,CAAC;IAAC,kBAAkB,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAE9D,MAAM,MAAM,eAAe,GACvB,yBAAyB,GACzB,0BAA0B,CAAC;AAE/B,MAAM,MAAM,uBAAuB,GAC/B,CAAC,QAAQ,CAAC,IAAI,CAAC,yBAAyB,EAAE,oBAAoB,CAAC,CAAC,GAC9D,QAAQ,CAAC;IAAE,kBAAkB,CAAC,EAAE,KAAK,CAAA;CAAE,CAAC,CAAC,GAC3C,QAAQ,CAAC,0BAA0B,CAAC,CAAC;AAgBzC,wBAAgB,uBAAuB,CAAC,UAAU,EAAE,eAAe,GAAG,IAAI,CA6BzE;AAED,wBAAgB,sBAAsB,CACpC,UAAU,EAAE,eAAe,GAC1B,uBAAuB,CAgBzB;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAI7E;AAED;;;;;GAKG;AACH,wBAAgB,sCAAsC,CACpD,UAAU,EAAE,uBAAuB,GAClC,MAAM,GAAG,SAAS,CAEpB;AAKD;;;;GAIG;AACH,eAAO,MAAM,iBAAiB;;;;CAIe,CAAC;AAE9C,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;CAYd,CAAC"}
1
+ {"version":3,"file":"image.d.ts","sourceRoot":"","sources":["../src/image.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,SAAS,GAAG,MAAM,CAAC;AACpD,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,SAAS,GAAG,QAAQ,GAAG,OAAO,CAAC;AAEtE,MAAM,MAAM,mBAAmB,GAAG,KAAK,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAE9D,sGAAsG;AACtG,wBAAgB,8BAA8B,CAC5C,KAAK,EAAE,QAAQ,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,EAClD,QAAQ,EAAE,QAAQ,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,EACrD,IAAI,EAAE,mBAAmB;;;;;;;;EAiB1B;AAED,eAAO,MAAM,aAAa;;CAEsB,CAAC;AAEjD,KAAK,eAAe,GAAG,QAAQ,CAAC;IAC9B,GAAG,EAAE,MAAM,CAAC;IACZ,wEAAwE;IACxE,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,QAAQ,CAAC;CAChB,CAAC,CAAC;AAEH;;;;GAIG;AACH,MAAM,MAAM,yBAAyB,GAAG,eAAe,GACrD,QAAQ,CAAC;IAAE,UAAU,CAAC,EAAE,IAAI,CAAC;IAAC,kBAAkB,CAAC,EAAE,KAAK,CAAA;CAAE,CAAC,CAAC;AAE9D,MAAM,MAAM,0BAA0B,GAAG,eAAe,GACtD,QAAQ,CAAC;IAAE,UAAU,EAAE,KAAK,CAAC;IAAC,kBAAkB,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAE9D,MAAM,MAAM,eAAe,GACvB,yBAAyB,GACzB,0BAA0B,CAAC;AAE/B,MAAM,MAAM,uBAAuB,GAC/B,CAAC,QAAQ,CAAC,IAAI,CAAC,yBAAyB,EAAE,oBAAoB,CAAC,CAAC,GAC9D,QAAQ,CAAC;IAAE,kBAAkB,CAAC,EAAE,KAAK,CAAA;CAAE,CAAC,CAAC,GAC3C,QAAQ,CAAC,0BAA0B,CAAC,CAAC;AAgBzC,wBAAgB,uBAAuB,CAAC,UAAU,EAAE,eAAe,GAAG,IAAI,CA6BzE;AAED,wBAAgB,sBAAsB,CACpC,UAAU,EAAE,eAAe,GAC1B,uBAAuB,CAgBzB;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAI7E;AAED;;;;;GAKG;AACH,wBAAgB,sCAAsC,CACpD,UAAU,EAAE,uBAAuB,GAClC,MAAM,GAAG,SAAS,CAEpB;AAKD;;;;GAIG;AACH,eAAO,MAAM,iBAAiB;;;;CAIe,CAAC;AAE9C,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;CAYd,CAAC"}
package/dist/image.js CHANGED
@@ -1,4 +1,23 @@
1
1
  import { semanticColors } from "./semantic-colors.js";
2
+ /** Exact image inspection sizes use layout units, not device physical pixels (Utilverse ADR-0020). */
3
+ export function resolveImageInspectionGeometry(image, viewport, mode) {
4
+ if (![image.width, image.height, viewport.width, viewport.height].every(value => Number.isFinite(value) && value > 0)) {
5
+ throw new RangeError("Image inspection needs positive finite image and viewport sizes");
6
+ }
7
+ if (mode !== "fit" && mode !== "double" && mode !== "pixels")
8
+ throw new TypeError("Unknown image inspection mode");
9
+ // Fit can enlarge a small result, as the existing product preview does. Clamping
10
+ // it to 1 would make fit and pixels indistinguishable for those images.
11
+ const scale = mode === "pixels" ? 1 : Math.min(viewport.width / image.width, viewport.height / image.height) * (mode === "double" ? 2 : 1);
12
+ const width = image.width * scale, height = image.height * scale;
13
+ if (![scale, width, height].every(value => Number.isFinite(value) && value > 0)) {
14
+ throw new RangeError("Image inspection geometry exceeds finite layout range");
15
+ }
16
+ return { scale, width, height, panBounds: {
17
+ x: Math.max(0, width - viewport.width) / 2,
18
+ y: Math.max(0, height - viewport.height) / 2,
19
+ } };
20
+ }
2
21
  export const imageDefaults = {
3
22
  fit: "cover",
4
23
  };
package/dist/image.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"image.js","sourceRoot":"","sources":["../src/image.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAKtD,MAAM,CAAC,MAAM,aAAa,GAAG;IAC3B,GAAG,EAAE,OAAO;CACkC,CAAC;AA8BjD,MAAM,IAAI,GAAwB,CAAC,OAAO,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC;AAE/D,SAAS,UAAU,CAAC,KAAa,EAAE,KAAa;IAC9C,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC9B,MAAM,IAAI,SAAS,CAAC,SAAS,KAAK,oBAAoB,CAAC,CAAC;IAC1D,CAAC;AACH,CAAC;AAED,SAAS,eAAe,CAAC,KAAa,EAAE,KAAa;IACnD,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC,EAAE,CAAC;QAC1C,MAAM,IAAI,UAAU,CAAC,SAAS,KAAK,mCAAmC,CAAC,CAAC;IAC1E,CAAC;AACH,CAAC;AAED,MAAM,UAAU,uBAAuB,CAAC,UAA2B;IACjE,UAAU,CAAC,UAAU,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IAClC,eAAe,CAAC,UAAU,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;IAC3C,eAAe,CAAC,UAAU,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IAC7C,IAAI,UAAU,CAAC,GAAG,KAAK,SAAS,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QACnE,MAAM,IAAI,SAAS,CAAC,0BAA0B,MAAM,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAC1E,CAAC;IACD,MAAM,iBAAiB,GACrB,UACD,CAAC,UAAU,CAAC;IACb,MAAM,YAAY,GAChB,UACD,CAAC,kBAAkB,CAAC;IACrB,IACE,iBAAiB,KAAK,SAAS;QAC/B,iBAAiB,KAAK,IAAI;QAC1B,iBAAiB,KAAK,KAAK,EAC3B,CAAC;QACD,MAAM,IAAI,SAAS,CAAC,kDAAkD,CAAC,CAAC;IAC1E,CAAC;IACD,IAAI,iBAAiB,KAAK,KAAK,EAAE,CAAC;QAChC,IAAI,OAAO,YAAY,KAAK,QAAQ,IAAI,YAAY,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACzE,MAAM,IAAI,SAAS,CACjB,wDAAwD,CACzD,CAAC;QACJ,CAAC;IACH,CAAC;SAAM,IAAI,YAAY,KAAK,SAAS,EAAE,CAAC;QACtC,MAAM,IAAI,SAAS,CAAC,sDAAsD,CAAC,CAAC;IAC9E,CAAC;AACH,CAAC;AAED,MAAM,UAAU,sBAAsB,CACpC,UAA2B;IAE3B,uBAAuB,CAAC,UAAU,CAAC,CAAC;IACpC,MAAM,MAAM,GAAG;QACb,GAAG,EAAE,UAAU,CAAC,GAAG;QACnB,KAAK,EAAE,UAAU,CAAC,KAAK;QACvB,MAAM,EAAE,UAAU,CAAC,MAAM;QACzB,GAAG,EAAE,UAAU,CAAC,GAAG,IAAI,aAAa,CAAC,GAAG;KAChC,CAAC;IACX,IAAI,UAAU,CAAC,UAAU,KAAK,KAAK,EAAE,CAAC;QACpC,OAAO;YACL,GAAG,MAAM;YACT,UAAU,EAAE,KAAK;YACjB,kBAAkB,EAAE,UAAU,CAAC,kBAAkB;SACvB,CAAC;IAC/B,CAAC;IACD,OAAO,EAAE,GAAG,MAAM,EAAE,UAAU,EAAE,IAAI,EAA6B,CAAC;AACpE,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,uBAAuB,CAAC,KAAa,EAAE,MAAc;IACnE,eAAe,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;IAChC,eAAe,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IAClC,OAAO,KAAK,GAAG,MAAM,CAAC;AACxB,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,sCAAsC,CACpD,UAAmC;IAEnC,OAAO,UAAU,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,UAAU,CAAC,kBAAkB,CAAC;AAC3E,CAAC;AAED,MAAM,aAAa,GAAqB,OAAO,CAAC;AAChD,MAAM,gBAAgB,GAAa,WAAW,CAAC;AAE/C;;;;GAIG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG;IAC/B,KAAK,EAAE,OAAO;IACd,OAAO,EAAE,SAAS;IAClB,IAAI,EAAE,SAAS;CAC4B,CAAC;AAE9C,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB,KAAK,EAAE,CAAC,MAAM,EAAE,OAAO,EAAE,aAAa,EAAE,cAAc,CAAU;IAChE,QAAQ,EAAE,aAAa;IACvB,IAAI;IACJ,WAAW,EAAE;QACX,UAAU,EAAE,cAAc,CAAC,MAAM;KAClC;IACD,QAAQ,EAAE;QACR,UAAU,EAAE,cAAc,CAAC,MAAM;QACjC,IAAI,EAAE,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,gBAAgB,EAAE;KACtD;IACD,MAAM,EAAE,IAAI;CACJ,CAAC","sourcesContent":["import type { SemanticIconName } from \"./icon.js\";\nimport type { IconTone } from \"./component-recipes.js\";\nimport { semanticColors } from \"./semantic-colors.js\";\n\nexport type ImageFit = \"cover\" | \"contain\" | \"fill\";\nexport type ImageLoadStatus = \"idle\" | \"loading\" | \"loaded\" | \"error\";\n\nexport const imageDefaults = {\n fit: \"cover\",\n} as const satisfies Readonly<{ fit: ImageFit }>;\n\ntype ImageAppearance = Readonly<{\n src: string;\n /** Intrinsic dimensions reserve layout space before the asset loads. */\n width: number;\n height: number;\n fit?: ImageFit;\n}>;\n\n/**\n * Same shape as Icon's decorative/informative split: a picture that only\n * repeats a caption or label already visible nearby stays decorative, and\n * only a self-sufficient picture requires localized alt copy.\n */\nexport type DecorativeImageDescriptor = ImageAppearance &\n Readonly<{ decorative?: true; accessibilityLabel?: never }>;\n\nexport type InformativeImageDescriptor = ImageAppearance &\n Readonly<{ decorative: false; accessibilityLabel: string }>;\n\nexport type ImageDescriptor =\n | DecorativeImageDescriptor\n | InformativeImageDescriptor;\n\nexport type ResolvedImageDescriptor =\n | (Required<Omit<DecorativeImageDescriptor, \"accessibilityLabel\">> &\n Readonly<{ accessibilityLabel?: never }>)\n | Required<InformativeImageDescriptor>;\n\nconst fits: readonly ImageFit[] = [\"cover\", \"contain\", \"fill\"];\n\nfunction assertCopy(value: string, field: string): void {\n if (value.trim().length === 0) {\n throw new TypeError(`Image ${field} must not be empty`);\n }\n}\n\nfunction assertDimension(value: number, field: string): void {\n if (!Number.isFinite(value) || value <= 0) {\n throw new RangeError(`Image ${field} must be a positive finite number`);\n }\n}\n\nexport function validateImageDescriptor(descriptor: ImageDescriptor): void {\n assertCopy(descriptor.src, \"src\");\n assertDimension(descriptor.width, \"width\");\n assertDimension(descriptor.height, \"height\");\n if (descriptor.fit !== undefined && !fits.includes(descriptor.fit)) {\n throw new TypeError(`Unsupported Image fit: ${String(descriptor.fit)}`);\n }\n const runtimeDecorative = (\n descriptor as Readonly<{ decorative?: unknown }>\n ).decorative;\n const runtimeLabel = (\n descriptor as Readonly<{ accessibilityLabel?: unknown }>\n ).accessibilityLabel;\n if (\n runtimeDecorative !== undefined &&\n runtimeDecorative !== true &&\n runtimeDecorative !== false\n ) {\n throw new TypeError(\"Image decorative must be a boolean when provided\");\n }\n if (runtimeDecorative === false) {\n if (typeof runtimeLabel !== \"string\" || runtimeLabel.trim().length === 0) {\n throw new TypeError(\n \"Informative Image accessibilityLabel must not be empty\",\n );\n }\n } else if (runtimeLabel !== undefined) {\n throw new TypeError(\"Decorative Image must not provide accessibilityLabel\");\n }\n}\n\nexport function resolveImageDescriptor(\n descriptor: ImageDescriptor,\n): ResolvedImageDescriptor {\n validateImageDescriptor(descriptor);\n const common = {\n src: descriptor.src,\n width: descriptor.width,\n height: descriptor.height,\n fit: descriptor.fit ?? imageDefaults.fit,\n } as const;\n if (descriptor.decorative === false) {\n return {\n ...common,\n decorative: false,\n accessibilityLabel: descriptor.accessibilityLabel,\n } as ResolvedImageDescriptor;\n }\n return { ...common, decorative: true } as ResolvedImageDescriptor;\n}\n\n/**\n * Reserves layout space ahead of load so a slow asset never shifts\n * surrounding content — the same problem `width`/`height` solve for\n * `next/image`, translated without a bundler dependency.\n */\nexport function resolveImageAspectRatio(width: number, height: number): number {\n assertDimension(width, \"width\");\n assertDimension(height, \"height\");\n return width / height;\n}\n\n/**\n * The fallback node on `error` always carries the resolved\n * `accessibilityLabel`, never a generic \"broken image\" string. An\n * informative picture's meaning does not disappear because the asset\n * failed to load; only its visual form changes.\n */\nexport function resolveImageFallbackAccessibilityLabel(\n descriptor: ResolvedImageDescriptor,\n): string | undefined {\n return descriptor.decorative ? undefined : descriptor.accessibilityLabel;\n}\n\nconst errorIconName: SemanticIconName = \"error\";\nconst fallbackIconTone: IconTone = \"secondary\";\n\n/**\n * Web `object-fit` and RN `resizeMode` diverge only in the `fill` case;\n * `fills` is the platform-neutral name and `nativeResizeModes` is the one\n * translation renderers need, kept here instead of re-derived per product.\n */\nexport const nativeResizeModes = {\n cover: \"cover\",\n contain: \"contain\",\n fill: \"stretch\",\n} as const satisfies Record<ImageFit, string>;\n\nexport const imageRecipe = {\n slots: [\"root\", \"image\", \"placeholder\", \"fallbackIcon\"] as const,\n defaults: imageDefaults,\n fits,\n placeholder: {\n background: semanticColors.canvas,\n },\n fallback: {\n background: semanticColors.canvas,\n icon: { name: errorIconName, tone: fallbackIconTone },\n },\n radius: \"md\",\n} as const;\n"]}
1
+ {"version":3,"file":"image.js","sourceRoot":"","sources":["../src/image.ts"],"names":[],"mappings":"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","sourcesContent":["import type { SemanticIconName } from \"./icon.js\";\nimport type { IconTone } from \"./component-recipes.js\";\nimport { semanticColors } from \"./semantic-colors.js\";\n\nexport type ImageFit = \"cover\" | \"contain\" | \"fill\";\nexport type ImageLoadStatus = \"idle\" | \"loading\" | \"loaded\" | \"error\";\n\nexport type ImageInspectionMode = \"fit\" | \"double\" | \"pixels\";\n\n/** Exact image inspection sizes use layout units, not device physical pixels (Utilverse ADR-0020). */\nexport function resolveImageInspectionGeometry(\n image: Readonly<{ width: number; height: number }>,\n viewport: Readonly<{ width: number; height: number }>,\n mode: ImageInspectionMode,\n) {\n if (![image.width, image.height, viewport.width, viewport.height].every(value => Number.isFinite(value) && value > 0)) {\n throw new RangeError(\"Image inspection needs positive finite image and viewport sizes\");\n }\n if (mode !== \"fit\" && mode !== \"double\" && mode !== \"pixels\") throw new TypeError(\"Unknown image inspection mode\");\n // Fit can enlarge a small result, as the existing product preview does. Clamping\n // it to 1 would make fit and pixels indistinguishable for those images.\n const scale = mode === \"pixels\" ? 1 : Math.min(viewport.width / image.width, viewport.height / image.height) * (mode === \"double\" ? 2 : 1);\n const width = image.width * scale, height = image.height * scale;\n if (![scale, width, height].every(value => Number.isFinite(value) && value > 0)) {\n throw new RangeError(\"Image inspection geometry exceeds finite layout range\");\n }\n return { scale, width, height, panBounds: {\n x: Math.max(0, width - viewport.width) / 2,\n y: Math.max(0, height - viewport.height) / 2,\n } };\n}\n\nexport const imageDefaults = {\n fit: \"cover\",\n} as const satisfies Readonly<{ fit: ImageFit }>;\n\ntype ImageAppearance = Readonly<{\n src: string;\n /** Intrinsic dimensions reserve layout space before the asset loads. */\n width: number;\n height: number;\n fit?: ImageFit;\n}>;\n\n/**\n * Same shape as Icon's decorative/informative split: a picture that only\n * repeats a caption or label already visible nearby stays decorative, and\n * only a self-sufficient picture requires localized alt copy.\n */\nexport type DecorativeImageDescriptor = ImageAppearance &\n Readonly<{ decorative?: true; accessibilityLabel?: never }>;\n\nexport type InformativeImageDescriptor = ImageAppearance &\n Readonly<{ decorative: false; accessibilityLabel: string }>;\n\nexport type ImageDescriptor =\n | DecorativeImageDescriptor\n | InformativeImageDescriptor;\n\nexport type ResolvedImageDescriptor =\n | (Required<Omit<DecorativeImageDescriptor, \"accessibilityLabel\">> &\n Readonly<{ accessibilityLabel?: never }>)\n | Required<InformativeImageDescriptor>;\n\nconst fits: readonly ImageFit[] = [\"cover\", \"contain\", \"fill\"];\n\nfunction assertCopy(value: string, field: string): void {\n if (value.trim().length === 0) {\n throw new TypeError(`Image ${field} must not be empty`);\n }\n}\n\nfunction assertDimension(value: number, field: string): void {\n if (!Number.isFinite(value) || value <= 0) {\n throw new RangeError(`Image ${field} must be a positive finite number`);\n }\n}\n\nexport function validateImageDescriptor(descriptor: ImageDescriptor): void {\n assertCopy(descriptor.src, \"src\");\n assertDimension(descriptor.width, \"width\");\n assertDimension(descriptor.height, \"height\");\n if (descriptor.fit !== undefined && !fits.includes(descriptor.fit)) {\n throw new TypeError(`Unsupported Image fit: ${String(descriptor.fit)}`);\n }\n const runtimeDecorative = (\n descriptor as Readonly<{ decorative?: unknown }>\n ).decorative;\n const runtimeLabel = (\n descriptor as Readonly<{ accessibilityLabel?: unknown }>\n ).accessibilityLabel;\n if (\n runtimeDecorative !== undefined &&\n runtimeDecorative !== true &&\n runtimeDecorative !== false\n ) {\n throw new TypeError(\"Image decorative must be a boolean when provided\");\n }\n if (runtimeDecorative === false) {\n if (typeof runtimeLabel !== \"string\" || runtimeLabel.trim().length === 0) {\n throw new TypeError(\n \"Informative Image accessibilityLabel must not be empty\",\n );\n }\n } else if (runtimeLabel !== undefined) {\n throw new TypeError(\"Decorative Image must not provide accessibilityLabel\");\n }\n}\n\nexport function resolveImageDescriptor(\n descriptor: ImageDescriptor,\n): ResolvedImageDescriptor {\n validateImageDescriptor(descriptor);\n const common = {\n src: descriptor.src,\n width: descriptor.width,\n height: descriptor.height,\n fit: descriptor.fit ?? imageDefaults.fit,\n } as const;\n if (descriptor.decorative === false) {\n return {\n ...common,\n decorative: false,\n accessibilityLabel: descriptor.accessibilityLabel,\n } as ResolvedImageDescriptor;\n }\n return { ...common, decorative: true } as ResolvedImageDescriptor;\n}\n\n/**\n * Reserves layout space ahead of load so a slow asset never shifts\n * surrounding content — the same problem `width`/`height` solve for\n * `next/image`, translated without a bundler dependency.\n */\nexport function resolveImageAspectRatio(width: number, height: number): number {\n assertDimension(width, \"width\");\n assertDimension(height, \"height\");\n return width / height;\n}\n\n/**\n * The fallback node on `error` always carries the resolved\n * `accessibilityLabel`, never a generic \"broken image\" string. An\n * informative picture's meaning does not disappear because the asset\n * failed to load; only its visual form changes.\n */\nexport function resolveImageFallbackAccessibilityLabel(\n descriptor: ResolvedImageDescriptor,\n): string | undefined {\n return descriptor.decorative ? undefined : descriptor.accessibilityLabel;\n}\n\nconst errorIconName: SemanticIconName = \"error\";\nconst fallbackIconTone: IconTone = \"secondary\";\n\n/**\n * Web `object-fit` and RN `resizeMode` diverge only in the `fill` case;\n * `fills` is the platform-neutral name and `nativeResizeModes` is the one\n * translation renderers need, kept here instead of re-derived per product.\n */\nexport const nativeResizeModes = {\n cover: \"cover\",\n contain: \"contain\",\n fill: \"stretch\",\n} as const satisfies Record<ImageFit, string>;\n\nexport const imageRecipe = {\n slots: [\"root\", \"image\", \"placeholder\", \"fallbackIcon\"] as const,\n defaults: imageDefaults,\n fits,\n placeholder: {\n background: semanticColors.canvas,\n },\n fallback: {\n background: semanticColors.canvas,\n icon: { name: errorIconName, tone: fallbackIconTone },\n },\n radius: \"md\",\n} as const;\n"]}
@@ -0,0 +1,2 @@
1
+ export declare const effectNoiseTile = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAQAAAAAYLlVAAAUaklEQVR42i3Z93dV15UH8JdMHGeW7ZhiG4xtjDHdGJAQkkAFoQYISUhIQh1QAQk1kAQSTRQJ0TG9GuO4xrHjdK9kViYzkzWz5peZ/+nM55zMeuu9d+895+z93d9dTrmZ0BraQ014K+wMk6EvHAyZ8E5YF6pDdygKPws/Dj8N74f8cChUacmEPWFZqAwXwx9Df5gNu8JVT3aGgbAitJA0E06E/wy/Ch2hN5SF42GjXh2hJ7wQcsP28FH4KgyHW6HRmLrwy3Al7AjlmVAcSkN9aCB8wONa/69QuD2MuF7pbg41vf4/8M0j8B2tFYR8pndXeB6+YcDhMBTuhEuU9VPyWXik9/Ewjxl7wwbqzoYDlOWHY+FyuEF2Nl0TwBaE25kwRcDnYVFYBV12OMLCAoKLwhadMuz/EUGZ9FlHVGFoI7LFf1VYHh4S+WW44PdAEl8W3gX2XjgHfGV4ObzNmF2eXw0l2FiLy4lwEt/54NzD+P5QlQnjkDRQ0hn+Ce194RTRR0ITAI1hqYHbw2qK54QleHqfhZvChwYuIno4XGP3A3CzgD2Njd1aH4IxEtbo3cqhm/3fA3EfJ3zgeRswFXrVYTeXnpKMh1UoLAwvUbqUikLDnum4hHM6qD/of4mnL+Co0vMp18v0XO23B8ANoTnc5dFhbfeAOATM3jBf/xFtHeE3WndywlpAf+m6HIDa8HOMHBY5wxm+2gP5EKK6BNE1nz40XSPivJar4TqVle4a4C2kdlrPcVe1aK/g5WGi87kxG6W7ue54eByOCtBFVDUL151kXDN6FbvzQT6h/2tcleu6NORlXK7W9bHBzcS08mlFOAN9Xxg09DJVvdxxAIwRLEXLNyPwbQqiiN0+4wIzCxeZsFXrVa2TWGsM77n7AC/ZTOvh4gp9luvdlQDX69kYLmfCm2J7PwaqkgVdwqQbPR9yxln47xBxmlcvu96gvcygYeBWEfgyleuJzuaMdVjaLGRruWspe5spazW2EOydHFkYtrF9eZjLpYVCcDLkhE/Dk5CTIaoNJcWorSK0LLxKQItPTbhN7SXu+FpilVJ7nNeKRPU+zmgmZg71m4RuBqmr+fMNihYb1xZGyYiRsB/kEnIPkX8kLGRWI0ClIqUchNtaNmY0bpV4hfx9Rbd3iNktQuuIrGRZzPAxUdwaPiE2l9BSllZRssCIlxOIEg55A8EVQF7FxzBDYrBOkbeN/T2UjQOzE4dZOH6blFYa8oGpz+jSqMtDv5fEw3vhnyVYdXidv3shXubpPtDOYCqH4g5F5imndOu1iNDX9a1G+U62d6M3Jl2PVG6mfEBQV2AnRkmOviuw9xOwW0k5qla00XA+o0A2IPa8Dquof4UPV/FoeaJrPuW7xUE5Jcd9mkRHRD7jW6Kl2Kj1SlU7en+qrVOdOJjy/BB35IOUxdptgJ/myhEGviY9h8RACR7vkdeaSX7fKeL3Q7mKoGOo3o3oaQFVA/85pG0mPIcd191vcr8dtFjX/lEjV/J4G6glYI4oxbfwMIu1NnL3hu/Bu0DlrB5L/OcCt0bbATw9Cw8z4QtqNvNLNsWVHudSNMX6myyJZTPGyCoi8j3tZ1M1Igv0raf2XcpfFSfruWK5fuPUPBUtVfirk0/ryLgBxGWwZl0dJiOWpGdA3dCvKJbiQdZm8+c+wuqx0QLZBFWLcfOagHpu2GT4WMsFHuyn/DCrc/y26hMjZylxCyTzPC4sxM82asow+gbia3y/D3/hvityaUaQlrr6Owj5nk2HbXE2PEroWwCsEDpPJUeFqNiIlXUgbAahh9BiT9cTPw/+nwNQgYtePKwWniXGrqbyAIs2G3OZUYtBfUXbuOjaHu5zZy33fISHMmHcaexGZnWGvgxBi9izAfp2je3APHLXZ3gzUeVs7BUsHZjo58NuLopFuE4016dpucKIYdfDov46Y05SckvqvsCMOdxyGSPLOHSXTzeo7QpSE1lZUn5F2JCBJC9lZCkY9TCXU38d3XOR2GZ4CaLGKGoicNLAN4jYhYXj4uZD0dFk3F793+OUx2ntcBFfWdL4TRLO6jMstvbRcMicMM2Z5zyvF8zFHHQwo7kAsnxo2lEcSVwuBup4qdawMklYjMQ9rs4LrmJi2lKsLJNwA0actST5SGrtNrIAwD7Qss0erRzXx99vuK5Rdu9i9hkZEeZWUuL01B1nw+sqdiwKa1A3Q8Ewqxvk6ITrXnfnda/xv0KfZmonOeFVdvVL2GrWZwFerFx3kBTvY5ieBrvQqKskb8HKAZH1RHhvTWA2UL0UyAouGsuw8hq/7aN01KAxgRGj9py5u4+dWbod59mdBlUbnCW8FFBum59mjP0sioutX6ql58G4y+N9ku4kt+wAbJa8i2bY/w7/Q84a419hQp0a0p1qyIJMon7K8EIEnUTmE01P0PWtofmmkNU6XwcyJmI5YVcJXilVW6heLFLmiZIYvPtlTSHRA1wX8+iG7wnyruDtjuvTaX2xNHm/w/066hWujNksC+ZLrLwP20UdYzieAuAONzwUEXmU7Q1/EqALBNssMCeSz2txNkjIKUqPAJCn1xBZNQAska6lmHwSfqd9g7wYAD0XhEYjsyivFx0/CT2ZtNB6gLj3NTWGX6PxOx6fBKmeol7iSkT6rOfl/FZmWFzl7hDPTSw+x8MxqLI5b47fOCHlglEmC4ZBOo+9gjRt36SpHafLPFvHOa8Z/XZclnez6DTEW+AaQtwl9P+JmBo++wL6PImar89jFgyYKzvDi8TfAy6P3Y8BuU98IVKXgphRtuaamOZK1CLtZ3B6jNwjRvQK9z7MLOD2IdWnF7tvZcT2FpjWGzzGzjto/cIyfT8lufz3DD8z7kfCvwrE6bQrKGB7LjfN4qYu/A2AA2lDs9z9Mpw04yjX7NAkEcvJf6bndU9OyZAa6dkNVpkqsVb/rgz0L5gDc6xev0dtp4TZLUufwFgnKE+x7E/hr3Y7o9jZo9+o1vXCtonanpT33xH4UogL/Hyh+iTFyIdsbgG5moyLIucQ6HUUnuHYG3SMccigZ3sz/H4EAx9zw3emi4/TYush0eM8VOT/mQh5zDFPtZ6WUMd4vZqguFIaEXazVMZcWUhdpYLzCIzbWN2unvSx93MMdYiO4/pUex63aoOAR9eNhoZMKiG/Eh7fEL4VaRflwxKUFrB2huK4CTse/mxAAz4+EkxtlLZob0FwXFHeAawNyAdklVB+wu8DPeMG76JcmaLqUZo9o5uzxdI4N7doGQ6nMkJvlPgfWB6j+gP07qX0TZAGzdhdLN8l5q/EmQt928AoBzkuPVZSny+YWqTrOZ9r7KvV0qhfeXJXs0816htZvI/aOIc26j/q+jAjx8OTOBlVSL5PWNFFcC4qd+meK47HWL5CxzythcKoT3QcBussZ8UdX46xiz3PBqAMlDrx9LvwH57Ezcqw7J9yXcegWtZXaWvhpBX6Zqfdd45IOZEhdC/Pn0+TZpXvPI7oM/Atk8t+wzdqu5jq3LQn70M/wUkVwM5J0+xjoJqx0Ux9qVJ8VqTfJHWYI54rQPvDH7ilh4PvpHnlOOl7SVkjiNeGwYxsPJeWjBWmmE0csBgTT/h+VLGYR80Sbbdg3a04naF6hIjXRECDMOzGw8dq5nMqrgHWolLUp8o5IgS3ipm/IfqoqGhXB4Y8KXO/USVY6clpLQcyQuI2jHet7woETY5wyqdyk8mmEO4slmxzfx+QuNU45a4JtMUsLkXoZXbdY8t9nxPaZkRLDd5KU1H+XMt/GXebCV9yxASZ1wBYrS2LnLLQm4H/96I37nmHDNhMfaMo359WeBdYEovzFXYd5P17wiwD9x5QN/nN9ht3FdtxcJKfv8fLYfExwKBRChfp/znfDwrBFgk9JbYmsHmUeT/XY3u4lRFgv0BlPLGIWb0eDwdZUpaW6KfgfciaWPuqWfs87fLaPa/HVUyjEaC+Siu9m6bkOpJqtF0j4SsKD6okn8ijfKNyuKYvAY/18bAQfTPynVFiHwicdnhO6ViehO9NS6tsgu4lB8St6x9kxSYwqwg+xGGHWHWSE56mA4oGinfgpDqtL3Mp/lT9uMgtFQpabF3j+TOOq5RfWWlDu/Qfu+NGnQ4aeoANN/1PEl6kW7OncQqJ+4C7XJMjBO/j4jybLgigY8RWY+8IFywA7jwlx0TKJtxdxU0d0u+DckBLjruCVA/nMK9O/836xZL/NJNoG4c+C/0b1OmDqM3lp2qBk0fpWbB+4feIGI5HN/fYXKVXW6r5v7XWeaxuVDGkGJfj1JYyop3wWo7NSrF/gAuOS+TNlC7mhhJPfkxDe7gfZ8Nias5Iwg6UNQNUpLk47ezjWm6SU8Y46ArFeyRdH0BxzViVovoPntSnY4qv9Fvs24qd28h+Dsq0UdMUXyB7FXA1Km2Tqyys5YExExck93WKB3TxgGEa+ik8HBPrS81VN/j3WDqG+YYl190N6X2F908YvEWu/DnVxRk9HrA5rqfrKbiU1orfM2GJmjEfrMPgjOmRB/wr1gvZILxL644MtOc83A/EReWhnK/iwqOJtxZJxG2cMcOCqyaXSwStE0zD+j02N7RjY1x+X8TiGNXjaB5MEJZQ/ShNSnFH1cW569JJSjW5Q7Jrhz79ZGfHyWg30QWQPTC41pCj/FvqGyv2WwKwHagdrJ/Va76n77GpjJvicmwnGKfSAvYs4msF1lb8LUPxKoF7JW3nWpkz679CyYrEV5LZkXZYW6X4k0w6TNsB2VmCLsFYIEaLhNRKEVDAnld1jTPaFFiDLI1HNFFoXHzOeLoWAzPAjBnRy9pO42YpGDWqmStfkqzb2T2CjbNGfiaq2v5/IXwhPIvHdAWpLj+y7pmF8cV0LNHraom6cAa4QbWwP62DfqRCjKVz0JsioAHsClByiTpAaIzwxXy9hVviJjybaXGxu4JBSwXtxXSe2JN6Tytr7aosAE8gnRHVVzghTpxWqsJkHfUdvNqh4xJKL6ct6gJCWw0+mNLqXQB3i541xh2kOO7/TqaN7AXg5vNzB4eVWkeXAVqGgSpMPsZSLiNOGHU2jGZYfZg9n1mSfJcOKE9SGE9zTgMRV0MfpR1yOWqn5EWl+wcIngZ7moB46FSrbRtndTLkAQDxXGwK4FVAxVOxeES7Kfm8nEkDgMbAHJbWJ8LuTPg3f3Hh8AMRTf7jdFrOtufAbE9Hr8XyYYwT4gZ1Dd9NG74L0FpA30X4IQacAfe0oLzhLvYb174LX1myKK6cKvDQalHfbdRDBe1Omkd+iKfl3yIsxvgnaDmallSTOl+kZhTGrz35EsAStux0vYfn6oAZFVwF+OgEdhuqT7JvoZBbktaUlelU/ZaJd6kp5yVu3ZQObl9kyAxdv1W+vvH5dbiUUbMi0VdSldvG4l3Q9guUa9ROp9q1JZHVKr22s/QAK1rS64kJn5jd41zRQ+2HuJvS/4jgWy09D7HxkvbDwKzC43LgN1B7H8vdwnFQkftrPCfsSsdmBX6rUNibys0wi84pP2+ysSGdHA2m46r4biCmUB6l27imVYR3EnlcGF9G9r500P8QB/VS7xxjrjBpvdElVgATwI0z4ySnNYuXr+KC5H2dG9JSM551fI2DuPx+hy1D0JeibRlaB9POfyFgX1M8gNJ4GDGV9kG1GOqxtJ/V8gj5n7J7Lze+Q10rSAdBWMC1j2TAhIltGotb3cczuep4Wj6k+0P2xb38sFXcYDqem2vv+lNhthJdsbK/ry5m0pJrCt0b0NoW/pgWaPHVy01j+tMiLL4HGJArtenAtwxXb+D4PW1HzByxoA8bE18FrQQnK8PXz8xplwx/angPSmNVXJiOqdan46f1nvX6xOVoJSfsSQeNvWDd1astzYZ7/Q+R0c+yo0A2qqC7+D2er65Nh/dxv/WRUR1Y7VHO9wnIjfF9wbfC4p64nOSTNemNwWbiYpz3UrUnLcSvY6VQHMQDpgE9r6bV0Wacfa7vJ+HfievmqF9Q0kXGUFovzRf91cC0CsE4zzamEcVpsi+SFe+Kh4mMQXvD39NZ5pSu8UxgPRJH0yYiG31NVJ5I6574SqZGfOxIG65YbvYRfIRd3/JvAXi/B7Bc7zMifo3rSkHYaUV0j+IKIwsFYB13NaYVeJVw3RaXZF8lC+6xdhHFawVIPpSNLHknpVu3QQsJekDwTDr76cHBWcSfw805DOSjvYuiG8D+yN1+wOpS6Z1OS9VJn0HtTentYTyyrdSSLdw7M34G2B/XxNM+p9LedYtJZbm87kjr2SrfuWg8lLI9voS5mbYwXTIjnqLHw7f4IqPEf4zseubUiq2b/i/Zhk4pOBPgN4Mf11+T6X3DdHqXlpdJR7Fn3PSlN18TaabOSV4uJCqeZJWyYZFhscg2pDdlMS+W8nAHqOfQ28y7n2FrDzaGKY7W3wHhIJBlKkfMr9/i7DfirQyoQcugR0Y/CfmxED3QtUXneLqXm+p3O3UjCFvoeZECcoSgB6mtMtm+QwBVs6w6zWgjxGdj8Xr4C4ddprAdkAr2xZOQfmXqcTpXaAfgMAcX0bRLNF2I2RXfdBWn5eF7lOwRAf2pvuf5LaKyncJ+hXU2rYriy6kj8neJCjGSTsEuI/NLjtsoZr4I/5uWb7dEd7eCNiUD4guM7+VTJ87iUrSJU/vSUq1d68L4zmgSqkb2bfWJb7zmy9EMCA0idaOrArCyiBzl/Ri369Ix6+ZkQdyWfUrcJ7hbSc4P3PiYfR+nFxOXRUyTjPkGtE7KagRgPWkFoE+kPeSLYVWcjO7L28O67qPuDaTPVwM/wEcGK3ORuzW87nqDlXxGNRwQnouJreC85aBV+q4mrCvVyL+TNMv66yIh7g/ugHlX3G8EvAnceIYa38UXpcm/K2RnNNex9z5BOYS/Lo3WhpfVsfg6cxMV8fRrh/sdMnueb1F6OXOC5c+Qvd1/KesrxcLTdNJ4FguNaWHemM5Sx1KJipk0g4l/EXhxPR2PNk/Efeb/AZ1MmsQDuaBqAAAAAElFTkSuQmCC";
2
+ //# sourceMappingURL=effect-noise.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"effect-noise.d.ts","sourceRoot":"","sources":["../../src/internal/effect-noise.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,eAAe,+5NAA+5N,CAAC"}
@@ -0,0 +1,4 @@
1
+ // Generated by scripts/generate-effect-noise.py. Native FeTurbulence is unimplemented;
2
+ // a shared static mask avoids a new runtime and keeps noise separate from dotted grain.
3
+ export const effectNoiseTile = "data:image/png;base64,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";
4
+ //# sourceMappingURL=effect-noise.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"effect-noise.js","sourceRoot":"","sources":["../../src/internal/effect-noise.ts"],"names":[],"mappings":"AAAA,uFAAuF;AACvF,wFAAwF;AACxF,MAAM,CAAC,MAAM,eAAe,GAAG,45NAA45N,CAAC","sourcesContent":["// Generated by scripts/generate-effect-noise.py. Native FeTurbulence is unimplemented;\n// a shared static mask avoids a new runtime and keeps noise separate from dotted grain.\nexport const effectNoiseTile = \"data:image/png;base64,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\";\n"]}
@@ -16,4 +16,10 @@ export declare function contrastRatio(foreground: string, background: string): n
16
16
  export declare function checkPaletteContrast(palette: Readonly<ThemeColors>): readonly PaletteContrastFinding[];
17
17
  /** Checks a `brandPalette` the way the Provider applies it: each theme merged over the HJM defaults. */
18
18
  export declare function checkBrandPaletteContrast(brandPalette: Readonly<Partial<Record<ResolvedTheme, Readonly<Partial<ThemeColors>>>>>): Readonly<Record<ResolvedTheme, readonly PaletteContrastFinding[]>>;
19
+ /** Shared whole-surface fill adaptation. This palette-only entry keeps ordinary
20
+ * renderer imports independent of the optional preset registry/effect descriptors.
21
+ * The supported 0.85..1 interval keeps readable foregrounds outside the backdrop
22
+ * luminance interval; testing its black/white endpoints bounds any opaque backdrop.
23
+ * See docs/design-profile.md for why a reference card's low alpha is not copied. */
24
+ export declare function resolveSurfaceFillOpacity(requested: number, palette: Readonly<ThemeColors>): number;
19
25
  //# sourceMappingURL=palette-contrast.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"palette-contrast.d.ts","sourceRoot":"","sources":["../src/palette-contrast.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,KAAK,aAAa,EAAE,KAAK,WAAW,EAAE,MAAM,aAAa,CAAC;AAE3E,mEAAmE;AACnE,MAAM,MAAM,mBAAmB,GAAG,QAAQ,CAAC;IACzC,UAAU,EAAE,MAAM,WAAW,CAAC;IAC9B,UAAU,EAAE,MAAM,WAAW,CAAC;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,GAAG,UAAU,CAAC;CAC3B,CAAC,CAAC;AAEH,MAAM,MAAM,sBAAsB,GAAG,mBAAmB,GAAG,QAAQ,CAAC;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAKvF,eAAO,MAAM,oBAAoB,EAAE,SAAS,mBAAmB,EAY9D,CAAC;AAaF,gEAAgE;AAChE,wBAAgB,aAAa,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAI5E;AAED,gGAAgG;AAChG,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,QAAQ,CAAC,WAAW,CAAC,GAC7B,SAAS,sBAAsB,EAAE,CAOnC;AAED,wGAAwG;AACxG,wBAAgB,yBAAyB,CACvC,YAAY,EAAE,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,aAAa,EAAE,QAAQ,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,GACrF,QAAQ,CAAC,MAAM,CAAC,aAAa,EAAE,SAAS,sBAAsB,EAAE,CAAC,CAAC,CAKpE"}
1
+ {"version":3,"file":"palette-contrast.d.ts","sourceRoot":"","sources":["../src/palette-contrast.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,KAAK,aAAa,EAAE,KAAK,WAAW,EAAE,MAAM,aAAa,CAAC;AAE3E,mEAAmE;AACnE,MAAM,MAAM,mBAAmB,GAAG,QAAQ,CAAC;IACzC,UAAU,EAAE,MAAM,WAAW,CAAC;IAC9B,UAAU,EAAE,MAAM,WAAW,CAAC;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,GAAG,UAAU,CAAC;CAC3B,CAAC,CAAC;AAEH,MAAM,MAAM,sBAAsB,GAAG,mBAAmB,GAAG,QAAQ,CAAC;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAKvF,eAAO,MAAM,oBAAoB,EAAE,SAAS,mBAAmB,EAY9D,CAAC;AAaF,gEAAgE;AAChE,wBAAgB,aAAa,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAI5E;AAED,gGAAgG;AAChG,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,QAAQ,CAAC,WAAW,CAAC,GAC7B,SAAS,sBAAsB,EAAE,CAOnC;AAED,wGAAwG;AACxG,wBAAgB,yBAAyB,CACvC,YAAY,EAAE,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,aAAa,EAAE,QAAQ,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,GACrF,QAAQ,CAAC,MAAM,CAAC,aAAa,EAAE,SAAS,sBAAsB,EAAE,CAAC,CAAC,CAKpE;AAED;;;;oFAIoF;AACpF,wBAAgB,yBAAyB,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,CAAC,WAAW,CAAC,GAAG,MAAM,CASnG"}
@@ -43,4 +43,21 @@ export function checkBrandPaletteContrast(brandPalette) {
43
43
  dark: checkPaletteContrast({ ...THEMES.dark, ...brandPalette.dark }),
44
44
  };
45
45
  }
46
+ /** Shared whole-surface fill adaptation. This palette-only entry keeps ordinary
47
+ * renderer imports independent of the optional preset registry/effect descriptors.
48
+ * The supported 0.85..1 interval keeps readable foregrounds outside the backdrop
49
+ * luminance interval; testing its black/white endpoints bounds any opaque backdrop.
50
+ * See docs/design-profile.md for why a reference card's low alpha is not copied. */
51
+ export function resolveSurfaceFillOpacity(requested, palette) {
52
+ if (!Number.isFinite(requested) || requested < 0.85 || requested > 1)
53
+ throw new RangeError("Surface fill opacity must be between 0.85 and 1");
54
+ const channels = [1, 3, 5].map(offset => Number.parseInt(palette.bg.slice(offset, offset + 2), 16));
55
+ const rules = paletteContrastRules.filter(rule => rule.background === "bg");
56
+ for (let opacity = requested; opacity < 1; opacity = Math.min(1, opacity + 0.01)) {
57
+ const endpoints = [0, 255].map(backdrop => "#" + channels.map(channel => Math.round(channel * opacity + backdrop * (1 - opacity)).toString(16).padStart(2, "0")).join(""));
58
+ if (endpoints.every(color => rules.every(rule => contrastRatio(palette[rule.foreground], color) >= rule.minimum)))
59
+ return opacity;
60
+ }
61
+ return 1;
62
+ }
46
63
  //# sourceMappingURL=palette-contrast.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"palette-contrast.js","sourceRoot":"","sources":["../src/palette-contrast.ts"],"names":[],"mappings":"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","sourcesContent":["import { THEMES, type ResolvedTheme, type ThemeColors } from \"./colors.js\";\n\n/** Pair thresholds and their rationale: docs/brand-boundary.md. */\nexport type PaletteContrastRule = Readonly<{\n foreground: keyof ThemeColors;\n background: keyof ThemeColors;\n minimum: number;\n kind: \"text\" | \"non-text\";\n}>;\n\nexport type PaletteContrastFinding = PaletteContrastRule & Readonly<{ ratio: number }>;\n\nconst readable = [\"text\", \"textBody\", \"textMuted\", \"textSub\", \"contentBrand\", \"danger\"] as const;\nconst surfaces = [\"bg\", \"surface\"] as const;\n\nexport const paletteContrastRules: readonly PaletteContrastRule[] = [\n ...readable.flatMap((foreground) =>\n surfaces.map((background) => ({ foreground, background, minimum: 4.5, kind: \"text\" as const })),\n ),\n { foreground: \"onPrimary\", background: \"primary\", minimum: 4.5, kind: \"text\" },\n { foreground: \"onDanger\", background: \"dangerFill\", minimum: 4.5, kind: \"text\" },\n ...([\"primary\", \"borderControl\"] as const).flatMap((foreground) =>\n surfaces.map((background) => ({ foreground, background, minimum: 3, kind: \"non-text\" as const })),\n ),\n // textWeak is the disabled/decorative/placeholder tier, exempt from text AA;\n // it also paints border.strong on canvas, which must stay a visible boundary.\n { foreground: \"textWeak\", background: \"bg\", minimum: 3, kind: \"non-text\" },\n];\n\nconst sixDigitHex = /^#[0-9a-f]{6}$/i;\n\nfunction luminance(hex: string): number {\n if (!sixDigitHex.test(hex)) throw new TypeError(`Expected a six-digit hex color, got ${hex}`);\n const [r, g, b] = [1, 3, 5].map((offset) => {\n const channel = Number.parseInt(hex.slice(offset, offset + 2), 16) / 255;\n return channel <= 0.04045 ? channel / 12.92 : ((channel + 0.055) / 1.055) ** 2.4;\n }) as [number, number, number];\n return 0.2126 * r + 0.7152 * g + 0.0722 * b;\n}\n\n/** WCAG 2.x contrast ratio between two six-digit hex colors. */\nexport function contrastRatio(foreground: string, background: string): number {\n const a = luminance(foreground);\n const b = luminance(background);\n return (Math.max(a, b) + 0.05) / (Math.min(a, b) + 0.05);\n}\n\n/** Pairs of a resolved theme palette that fall below their threshold; empty means it passes. */\nexport function checkPaletteContrast(\n palette: Readonly<ThemeColors>,\n): readonly PaletteContrastFinding[] {\n const findings: PaletteContrastFinding[] = [];\n for (const rule of paletteContrastRules) {\n const ratio = contrastRatio(palette[rule.foreground], palette[rule.background]);\n if (ratio < rule.minimum) findings.push({ ...rule, ratio: Math.round(ratio * 100) / 100 });\n }\n return findings;\n}\n\n/** Checks a `brandPalette` the way the Provider applies it: each theme merged over the HJM defaults. */\nexport function checkBrandPaletteContrast(\n brandPalette: Readonly<Partial<Record<ResolvedTheme, Readonly<Partial<ThemeColors>>>>>,\n): Readonly<Record<ResolvedTheme, readonly PaletteContrastFinding[]>> {\n return {\n light: checkPaletteContrast({ ...THEMES.light, ...brandPalette.light }),\n dark: checkPaletteContrast({ ...THEMES.dark, ...brandPalette.dark }),\n };\n}\n"]}
1
+ {"version":3,"file":"palette-contrast.js","sourceRoot":"","sources":["../src/palette-contrast.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAwC,MAAM,aAAa,CAAC;AAY3E,MAAM,QAAQ,GAAG,CAAC,MAAM,EAAE,UAAU,EAAE,WAAW,EAAE,SAAS,EAAE,cAAc,EAAE,QAAQ,CAAU,CAAC;AACjG,MAAM,QAAQ,GAAG,CAAC,IAAI,EAAE,SAAS,CAAU,CAAC;AAE5C,MAAM,CAAC,MAAM,oBAAoB,GAAmC;IAClE,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC,UAAU,EAAE,EAAE,CACjC,QAAQ,CAAC,GAAG,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC,EAAE,UAAU,EAAE,UAAU,EAAE,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAe,EAAE,CAAC,CAAC,CAChG;IACD,EAAE,UAAU,EAAE,WAAW,EAAE,UAAU,EAAE,SAAS,EAAE,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE;IAC9E,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,YAAY,EAAE,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE;IAChF,GAAI,CAAC,SAAS,EAAE,eAAe,CAAW,CAAC,OAAO,CAAC,CAAC,UAAU,EAAE,EAAE,CAChE,QAAQ,CAAC,GAAG,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC,EAAE,UAAU,EAAE,UAAU,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,UAAmB,EAAE,CAAC,CAAC,CAClG;IACD,6EAA6E;IAC7E,8EAA8E;IAC9E,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE;CAC3E,CAAC;AAEF,MAAM,WAAW,GAAG,iBAAiB,CAAC;AAEtC,SAAS,SAAS,CAAC,GAAW;IAC5B,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC;QAAE,MAAM,IAAI,SAAS,CAAC,uCAAuC,GAAG,EAAE,CAAC,CAAC;IAC9F,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE;QACzC,MAAM,OAAO,GAAG,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC;QACzE,OAAO,OAAO,IAAI,OAAO,CAAC,CAAC,CAAC,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC,IAAI,GAAG,CAAC;IACnF,CAAC,CAA6B,CAAC;IAC/B,OAAO,MAAM,GAAG,CAAC,GAAG,MAAM,GAAG,CAAC,GAAG,MAAM,GAAG,CAAC,CAAC;AAC9C,CAAC;AAED,gEAAgE;AAChE,MAAM,UAAU,aAAa,CAAC,UAAkB,EAAE,UAAkB;IAClE,MAAM,CAAC,GAAG,SAAS,CAAC,UAAU,CAAC,CAAC;IAChC,MAAM,CAAC,GAAG,SAAS,CAAC,UAAU,CAAC,CAAC;IAChC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;AAC3D,CAAC;AAED,gGAAgG;AAChG,MAAM,UAAU,oBAAoB,CAClC,OAA8B;IAE9B,MAAM,QAAQ,GAA6B,EAAE,CAAC;IAC9C,KAAK,MAAM,IAAI,IAAI,oBAAoB,EAAE,CAAC;QACxC,MAAM,KAAK,GAAG,aAAa,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC;QAChF,IAAI,KAAK,GAAG,IAAI,CAAC,OAAO;YAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,GAAG,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,GAAG,CAAC,GAAG,GAAG,EAAE,CAAC,CAAC;IAC7F,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,wGAAwG;AACxG,MAAM,UAAU,yBAAyB,CACvC,YAAsF;IAEtF,OAAO;QACL,KAAK,EAAE,oBAAoB,CAAC,EAAE,GAAG,MAAM,CAAC,KAAK,EAAE,GAAG,YAAY,CAAC,KAAK,EAAE,CAAC;QACvE,IAAI,EAAE,oBAAoB,CAAC,EAAE,GAAG,MAAM,CAAC,IAAI,EAAE,GAAG,YAAY,CAAC,IAAI,EAAE,CAAC;KACrE,CAAC;AACJ,CAAC;AAED;;;;oFAIoF;AACpF,MAAM,UAAU,yBAAyB,CAAC,SAAiB,EAAE,OAA8B;IACzF,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,SAAS,GAAG,IAAI,IAAI,SAAS,GAAG,CAAC;QAAE,MAAM,IAAI,UAAU,CAAC,iDAAiD,CAAC,CAAC;IAC9I,MAAM,QAAQ,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;IACpG,MAAM,KAAK,GAAG,oBAAoB,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,UAAU,KAAK,IAAI,CAAC,CAAC;IAC5E,KAAK,IAAI,OAAO,GAAG,SAAS,EAAE,OAAO,GAAG,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC,EAAE,CAAC;QACjF,MAAM,SAAS,GAAG,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,GAAG,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,GAAG,OAAO,GAAG,QAAQ,GAAG,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;QAC3K,IAAI,SAAS,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,aAAa,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,KAAK,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,CAAC;YAAE,OAAO,OAAO,CAAC;IACpI,CAAC;IACD,OAAO,CAAC,CAAC;AACX,CAAC","sourcesContent":["import { THEMES, type ResolvedTheme, type ThemeColors } from \"./colors.js\";\n\n/** Pair thresholds and their rationale: docs/brand-boundary.md. */\nexport type PaletteContrastRule = Readonly<{\n foreground: keyof ThemeColors;\n background: keyof ThemeColors;\n minimum: number;\n kind: \"text\" | \"non-text\";\n}>;\n\nexport type PaletteContrastFinding = PaletteContrastRule & Readonly<{ ratio: number }>;\n\nconst readable = [\"text\", \"textBody\", \"textMuted\", \"textSub\", \"contentBrand\", \"danger\"] as const;\nconst surfaces = [\"bg\", \"surface\"] as const;\n\nexport const paletteContrastRules: readonly PaletteContrastRule[] = [\n ...readable.flatMap((foreground) =>\n surfaces.map((background) => ({ foreground, background, minimum: 4.5, kind: \"text\" as const })),\n ),\n { foreground: \"onPrimary\", background: \"primary\", minimum: 4.5, kind: \"text\" },\n { foreground: \"onDanger\", background: \"dangerFill\", minimum: 4.5, kind: \"text\" },\n ...([\"primary\", \"borderControl\"] as const).flatMap((foreground) =>\n surfaces.map((background) => ({ foreground, background, minimum: 3, kind: \"non-text\" as const })),\n ),\n // textWeak is the disabled/decorative/placeholder tier, exempt from text AA;\n // it also paints border.strong on canvas, which must stay a visible boundary.\n { foreground: \"textWeak\", background: \"bg\", minimum: 3, kind: \"non-text\" },\n];\n\nconst sixDigitHex = /^#[0-9a-f]{6}$/i;\n\nfunction luminance(hex: string): number {\n if (!sixDigitHex.test(hex)) throw new TypeError(`Expected a six-digit hex color, got ${hex}`);\n const [r, g, b] = [1, 3, 5].map((offset) => {\n const channel = Number.parseInt(hex.slice(offset, offset + 2), 16) / 255;\n return channel <= 0.04045 ? channel / 12.92 : ((channel + 0.055) / 1.055) ** 2.4;\n }) as [number, number, number];\n return 0.2126 * r + 0.7152 * g + 0.0722 * b;\n}\n\n/** WCAG 2.x contrast ratio between two six-digit hex colors. */\nexport function contrastRatio(foreground: string, background: string): number {\n const a = luminance(foreground);\n const b = luminance(background);\n return (Math.max(a, b) + 0.05) / (Math.min(a, b) + 0.05);\n}\n\n/** Pairs of a resolved theme palette that fall below their threshold; empty means it passes. */\nexport function checkPaletteContrast(\n palette: Readonly<ThemeColors>,\n): readonly PaletteContrastFinding[] {\n const findings: PaletteContrastFinding[] = [];\n for (const rule of paletteContrastRules) {\n const ratio = contrastRatio(palette[rule.foreground], palette[rule.background]);\n if (ratio < rule.minimum) findings.push({ ...rule, ratio: Math.round(ratio * 100) / 100 });\n }\n return findings;\n}\n\n/** Checks a `brandPalette` the way the Provider applies it: each theme merged over the HJM defaults. */\nexport function checkBrandPaletteContrast(\n brandPalette: Readonly<Partial<Record<ResolvedTheme, Readonly<Partial<ThemeColors>>>>>,\n): Readonly<Record<ResolvedTheme, readonly PaletteContrastFinding[]>> {\n return {\n light: checkPaletteContrast({ ...THEMES.light, ...brandPalette.light }),\n dark: checkPaletteContrast({ ...THEMES.dark, ...brandPalette.dark }),\n };\n}\n\n/** Shared whole-surface fill adaptation. This palette-only entry keeps ordinary\n * renderer imports independent of the optional preset registry/effect descriptors.\n * The supported 0.85..1 interval keeps readable foregrounds outside the backdrop\n * luminance interval; testing its black/white endpoints bounds any opaque backdrop.\n * See docs/design-profile.md for why a reference card's low alpha is not copied. */\nexport function resolveSurfaceFillOpacity(requested: number, palette: Readonly<ThemeColors>): number {\n if (!Number.isFinite(requested) || requested < 0.85 || requested > 1) throw new RangeError(\"Surface fill opacity must be between 0.85 and 1\");\n const channels = [1, 3, 5].map(offset => Number.parseInt(palette.bg.slice(offset, offset + 2), 16));\n const rules = paletteContrastRules.filter(rule => rule.background === \"bg\");\n for (let opacity = requested; opacity < 1; opacity = Math.min(1, opacity + 0.01)) {\n const endpoints = [0, 255].map(backdrop => \"#\" + channels.map(channel => Math.round(channel * opacity + backdrop * (1 - opacity)).toString(16).padStart(2, \"0\")).join(\"\"));\n if (endpoints.every(color => rules.every(rule => contrastRatio(palette[rule.foreground], color) >= rule.minimum))) return opacity;\n }\n return 1;\n}\n"]}
@@ -0,0 +1,32 @@
1
+ import { type ScrollMetrics } from './scroll-progress.js';
2
+ export type ProgressiveBlurDescriptor = Readonly<{
3
+ edge: 'top' | 'bottom' | 'start' | 'end';
4
+ /** Physical extent in logical pixels; choose after measuring the content host. */
5
+ extent: number;
6
+ /** Host-relative blur strength, not a cross-platform pixel-equivalence claim. */
7
+ strength: number;
8
+ layers?: number;
9
+ content: {
10
+ kind: 'decoration';
11
+ } | {
12
+ kind: 'scroll';
13
+ metrics: ScrollMetrics;
14
+ focused: boolean;
15
+ };
16
+ }>;
17
+ export type ProgressiveBlurLayer = Readonly<{
18
+ strength: number;
19
+ start: number;
20
+ end: number;
21
+ }>;
22
+ export declare function resolveProgressiveBlur(descriptor: ProgressiveBlurDescriptor, direction?: 'ltr' | 'rtl'): {
23
+ side: "top" | "bottom" | "left" | "right";
24
+ extent: number;
25
+ visible: boolean;
26
+ layers: Readonly<{
27
+ strength: number;
28
+ start: number;
29
+ end: number;
30
+ }>[];
31
+ };
32
+ //# sourceMappingURL=progressive-blur.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"progressive-blur.d.ts","sourceRoot":"","sources":["../src/progressive-blur.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,KAAK,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAC9E,MAAM,MAAM,yBAAyB,GAAG,QAAQ,CAAC;IAC/C,IAAI,EAAE,KAAK,GAAG,QAAQ,GAAG,OAAO,GAAG,KAAK,CAAC;IACzC,kFAAkF;IAClF,MAAM,EAAE,MAAM,CAAC;IACf,iFAAiF;IACjF,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE;QAAE,IAAI,EAAE,YAAY,CAAA;KAAE,GAAG;QAAE,IAAI,EAAE,QAAQ,CAAC;QAAC,OAAO,EAAE,aAAa,CAAC;QAAC,OAAO,EAAE,OAAO,CAAA;KAAE,CAAC;CAChG,CAAC,CAAC;AACH,MAAM,MAAM,oBAAoB,GAAG,QAAQ,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAC9F,wBAAgB,sBAAsB,CAAC,UAAU,EAAE,yBAAyB,EAAE,SAAS,GAAE,KAAK,GAAG,KAAa;;;;;kBADtD,MAAM;eAAS,MAAM;aAAO,MAAM;;EAqBzF"}
@@ -0,0 +1,28 @@
1
+ import { resolveScrollEdges } from './scroll-progress.js';
2
+ export function resolveProgressiveBlur(descriptor, direction = 'ltr') {
3
+ const { edge, extent, strength, content } = descriptor;
4
+ if (!['top', 'bottom', 'start', 'end'].includes(edge))
5
+ throw new TypeError('Unknown blur edge');
6
+ if (!Number.isFinite(extent) || extent <= 0 || extent > 160)
7
+ throw new RangeError('Blur extent must be between 0 and 160');
8
+ if (!Number.isFinite(strength) || strength < 0 || strength > 1)
9
+ throw new RangeError('Blur strength must be between 0 and 1');
10
+ // Four layers are an experimental bounded starting point, not a measured
11
+ // performance promise. Unlike copying the upstream eight layers, callers can
12
+ // compare 2–8 on their real host before enabling the decoration.
13
+ const count = descriptor.layers ?? 4;
14
+ if (!Number.isInteger(count) || count < 2 || count > 8)
15
+ throw new RangeError('Blur layers must be an integer between 2 and 8');
16
+ if (content.kind !== 'scroll' && content.kind !== 'decoration')
17
+ throw new TypeError('Unknown blur content kind');
18
+ const side = edge === 'start' ? (direction === 'rtl' ? 'right' : 'left') : edge === 'end' ? (direction === 'rtl' ? 'left' : 'right') : edge;
19
+ let visible = strength > 0;
20
+ if (content.kind === 'scroll') {
21
+ const edges = resolveScrollEdges(content.metrics);
22
+ visible &&= !content.focused && (edge === 'top' || edge === 'start' ? edges.before : edges.after);
23
+ }
24
+ return { side, extent, visible, layers: Array.from({ length: count }, (_, index) => ({
25
+ strength: strength * (index + 1) / count, start: index / count, end: (index + 1) / count,
26
+ })) };
27
+ }
28
+ //# sourceMappingURL=progressive-blur.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"progressive-blur.js","sourceRoot":"","sources":["../src/progressive-blur.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAsB,MAAM,sBAAsB,CAAC;AAW9E,MAAM,UAAU,sBAAsB,CAAC,UAAqC,EAAE,YAA2B,KAAK;IAC5G,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,UAAU,CAAC;IACvD,IAAI,CAAC,CAAC,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC;QAAE,MAAM,IAAI,SAAS,CAAC,mBAAmB,CAAC,CAAC;IAChG,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,MAAM,IAAI,CAAC,IAAI,MAAM,GAAG,GAAG;QAAE,MAAM,IAAI,UAAU,CAAC,uCAAuC,CAAC,CAAC;IAC3H,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,QAAQ,GAAG,CAAC,IAAI,QAAQ,GAAG,CAAC;QAAE,MAAM,IAAI,UAAU,CAAC,uCAAuC,CAAC,CAAC;IAC9H,yEAAyE;IACzE,6EAA6E;IAC7E,iEAAiE;IACjE,MAAM,KAAK,GAAG,UAAU,CAAC,MAAM,IAAI,CAAC,CAAC;IACrC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,KAAK,GAAG,CAAC,IAAI,KAAK,GAAG,CAAC;QAAE,MAAM,IAAI,UAAU,CAAC,gDAAgD,CAAC,CAAC;IAC/H,IAAI,OAAO,CAAC,IAAI,KAAK,QAAQ,IAAI,OAAO,CAAC,IAAI,KAAK,YAAY;QAAE,MAAM,IAAI,SAAS,CAAC,2BAA2B,CAAC,CAAC;IACjH,MAAM,IAAI,GAAwC,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS,KAAK,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,KAAK,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IACjL,IAAI,OAAO,GAAG,QAAQ,GAAG,CAAC,CAAC;IAC3B,IAAI,OAAO,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;QAC9B,MAAM,KAAK,GAAG,kBAAkB,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QAClD,OAAO,KAAK,CAAC,OAAO,CAAC,OAAO,IAAI,CAAC,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IACpG,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAwB,EAAE,CAAC,CAAC;YACzG,QAAQ,EAAE,QAAQ,GAAG,CAAC,KAAK,GAAG,CAAC,CAAC,GAAG,KAAK,EAAE,KAAK,EAAE,KAAK,GAAG,KAAK,EAAE,GAAG,EAAE,CAAC,KAAK,GAAG,CAAC,CAAC,GAAG,KAAK;SACzF,CAAC,CAAC,EAAE,CAAC;AACR,CAAC","sourcesContent":["import { resolveScrollEdges, type ScrollMetrics } from './scroll-progress.js';\nexport type ProgressiveBlurDescriptor = Readonly<{\n edge: 'top' | 'bottom' | 'start' | 'end';\n /** Physical extent in logical pixels; choose after measuring the content host. */\n extent: number;\n /** Host-relative blur strength, not a cross-platform pixel-equivalence claim. */\n strength: number;\n layers?: number;\n content: { kind: 'decoration' } | { kind: 'scroll'; metrics: ScrollMetrics; focused: boolean };\n}>;\nexport type ProgressiveBlurLayer = Readonly<{ strength: number; start: number; end: number }>;\nexport function resolveProgressiveBlur(descriptor: ProgressiveBlurDescriptor, direction: 'ltr' | 'rtl' = 'ltr') {\n const { edge, extent, strength, content } = descriptor;\n if (!['top', 'bottom', 'start', 'end'].includes(edge)) throw new TypeError('Unknown blur edge');\n if (!Number.isFinite(extent) || extent <= 0 || extent > 160) throw new RangeError('Blur extent must be between 0 and 160');\n if (!Number.isFinite(strength) || strength < 0 || strength > 1) throw new RangeError('Blur strength must be between 0 and 1');\n // Four layers are an experimental bounded starting point, not a measured\n // performance promise. Unlike copying the upstream eight layers, callers can\n // compare 2–8 on their real host before enabling the decoration.\n const count = descriptor.layers ?? 4;\n if (!Number.isInteger(count) || count < 2 || count > 8) throw new RangeError('Blur layers must be an integer between 2 and 8');\n if (content.kind !== 'scroll' && content.kind !== 'decoration') throw new TypeError('Unknown blur content kind');\n const side: 'top' | 'bottom' | 'left' | 'right' = edge === 'start' ? (direction === 'rtl' ? 'right' : 'left') : edge === 'end' ? (direction === 'rtl' ? 'left' : 'right') : edge;\n let visible = strength > 0;\n if (content.kind === 'scroll') {\n const edges = resolveScrollEdges(content.metrics);\n visible &&= !content.focused && (edge === 'top' || edge === 'start' ? edges.before : edges.after);\n }\n return { side, extent, visible, layers: Array.from({ length: count }, (_, index): ProgressiveBlurLayer => ({\n strength: strength * (index + 1) / count, start: index / count, end: (index + 1) / count,\n })) };\n}\n"]}
@@ -0,0 +1,32 @@
1
+ export type RatingDescriptor = Readonly<{
2
+ label: string;
3
+ value: number | null;
4
+ max?: number;
5
+ readOnly?: boolean;
6
+ }>;
7
+ /** A bounded row remains a rating rather than an unbounded repeated-icon list.
8
+ * Null means unrated; zero and fractional averages are meaningful only in read-only summaries. */
9
+ export declare function resolveRating({ label, value, max, readOnly }: RatingDescriptor): {
10
+ max: number;
11
+ value: number | null;
12
+ fractions: number[];
13
+ };
14
+ export type ComparisonImage = Readonly<{
15
+ src: string;
16
+ width: number;
17
+ height: number;
18
+ label: string;
19
+ }>;
20
+ export type ImageComparisonDescriptor = Readonly<{
21
+ label: string;
22
+ before: ComparisonImage;
23
+ after: ComparisonImage;
24
+ value: number;
25
+ }>;
26
+ /** Both pictures share one coordinate system. Reject mismatched aspect ratios
27
+ * instead of silently stretching or cropping the evidence being compared. */
28
+ export declare function resolveImageComparison({ label, before, after, value }: ImageComparisonDescriptor): {
29
+ aspectRatio: number;
30
+ fraction: number;
31
+ };
32
+ //# sourceMappingURL=reference-controls.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reference-controls.d.ts","sourceRoot":"","sources":["../src/reference-controls.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,gBAAgB,GAAG,QAAQ,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,CAAC;AACnH;kGACkG;AAClG,wBAAgB,aAAa,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,GAAO,EAAE,QAAgB,EAAE,EAAE,gBAAgB;;;;EAO1F;AACD,MAAM,MAAM,eAAe,GAAG,QAAQ,CAAC;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AACtG,MAAM,MAAM,yBAAyB,GAAG,QAAQ,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,eAAe,CAAC;IAAC,KAAK,EAAE,eAAe,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AACpI;6EAC6E;AAC7E,wBAAgB,sBAAsB,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,yBAAyB;;;EAOhG"}
@@ -0,0 +1,28 @@
1
+ import { validateImageDescriptor } from "./image.js";
2
+ /** A bounded row remains a rating rather than an unbounded repeated-icon list.
3
+ * Null means unrated; zero and fractional averages are meaningful only in read-only summaries. */
4
+ export function resolveRating({ label, value, max = 5, readOnly = false }) {
5
+ if (!label.trim())
6
+ throw new TypeError("Rating requires a label");
7
+ if (!Number.isInteger(max) || max < 1 || max > 10)
8
+ throw new RangeError("Rating max must be an integer from 1 to 10");
9
+ if (value !== null && (!Number.isFinite(value) || value < 0 || value > max || (!readOnly && (!Number.isInteger(value) || value === 0)))) {
10
+ throw new RangeError("Interactive ratings require whole scores from 1 to max, or null");
11
+ }
12
+ return { max, value, fractions: Array.from({ length: max }, (_, index) => Math.max(0, Math.min(1, (value ?? 0) - index))) };
13
+ }
14
+ /** Both pictures share one coordinate system. Reject mismatched aspect ratios
15
+ * instead of silently stretching or cropping the evidence being compared. */
16
+ export function resolveImageComparison({ label, before, after, value }) {
17
+ if (!label.trim())
18
+ throw new TypeError("ImageComparison requires a label");
19
+ for (const image of [before, after])
20
+ validateImageDescriptor({ ...image, decorative: false, accessibilityLabel: image.label });
21
+ if (!Number.isFinite(value) || value < 0 || value > 100)
22
+ throw new RangeError("ImageComparison value must be from 0 to 100");
23
+ const aspectRatio = before.width / before.height;
24
+ if (Math.abs(aspectRatio - after.width / after.height) > 0.000001)
25
+ throw new RangeError("Compared images require the same aspect ratio");
26
+ return { aspectRatio, fraction: value / 100 };
27
+ }
28
+ //# sourceMappingURL=reference-controls.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reference-controls.js","sourceRoot":"","sources":["../src/reference-controls.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC;AAGrD;kGACkG;AAClG,MAAM,UAAU,aAAa,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,GAAG,CAAC,EAAE,QAAQ,GAAG,KAAK,EAAoB;IACzF,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE;QAAE,MAAM,IAAI,SAAS,CAAC,yBAAyB,CAAC,CAAC;IAClE,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,GAAG,GAAG,CAAC,IAAI,GAAG,GAAG,EAAE;QAAE,MAAM,IAAI,UAAU,CAAC,4CAA4C,CAAC,CAAC;IACtH,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,GAAG,CAAC,IAAI,KAAK,GAAG,GAAG,IAAI,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QACxI,MAAM,IAAI,UAAU,CAAC,iEAAiE,CAAC,CAAC;IAC1F,CAAC;IACD,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,KAAK,IAAI,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;AAC9H,CAAC;AAGD;6EAC6E;AAC7E,MAAM,UAAU,sBAAsB,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAA6B;IAC/F,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE;QAAE,MAAM,IAAI,SAAS,CAAC,kCAAkC,CAAC,CAAC;IAC3E,KAAK,MAAM,KAAK,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC;QAAE,uBAAuB,CAAC,EAAE,GAAG,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,kBAAkB,EAAE,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC;IAC/H,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,GAAG,CAAC,IAAI,KAAK,GAAG,GAAG;QAAE,MAAM,IAAI,UAAU,CAAC,6CAA6C,CAAC,CAAC;IAC7H,MAAM,WAAW,GAAG,MAAM,CAAC,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC;IACjD,IAAI,IAAI,CAAC,GAAG,CAAC,WAAW,GAAG,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC,GAAG,QAAQ;QAAE,MAAM,IAAI,UAAU,CAAC,+CAA+C,CAAC,CAAC;IACzI,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,KAAK,GAAG,GAAG,EAAE,CAAC;AAChD,CAAC","sourcesContent":["import { validateImageDescriptor } from \"./image.js\";\n\nexport type RatingDescriptor = Readonly<{ label: string; value: number | null; max?: number; readOnly?: boolean }>;\n/** A bounded row remains a rating rather than an unbounded repeated-icon list.\n * Null means unrated; zero and fractional averages are meaningful only in read-only summaries. */\nexport function resolveRating({ label, value, max = 5, readOnly = false }: RatingDescriptor) {\n if (!label.trim()) throw new TypeError(\"Rating requires a label\");\n if (!Number.isInteger(max) || max < 1 || max > 10) throw new RangeError(\"Rating max must be an integer from 1 to 10\");\n if (value !== null && (!Number.isFinite(value) || value < 0 || value > max || (!readOnly && (!Number.isInteger(value) || value === 0)))) {\n throw new RangeError(\"Interactive ratings require whole scores from 1 to max, or null\");\n }\n return { max, value, fractions: Array.from({ length: max }, (_, index) => Math.max(0, Math.min(1, (value ?? 0) - index))) };\n}\nexport type ComparisonImage = Readonly<{ src: string; width: number; height: number; label: string }>;\nexport type ImageComparisonDescriptor = Readonly<{ label: string; before: ComparisonImage; after: ComparisonImage; value: number }>;\n/** Both pictures share one coordinate system. Reject mismatched aspect ratios\n * instead of silently stretching or cropping the evidence being compared. */\nexport function resolveImageComparison({ label, before, after, value }: ImageComparisonDescriptor) {\n if (!label.trim()) throw new TypeError(\"ImageComparison requires a label\");\n for (const image of [before, after]) validateImageDescriptor({ ...image, decorative: false, accessibilityLabel: image.label });\n if (!Number.isFinite(value) || value < 0 || value > 100) throw new RangeError(\"ImageComparison value must be from 0 to 100\");\n const aspectRatio = before.width / before.height;\n if (Math.abs(aspectRatio - after.width / after.height) > 0.000001) throw new RangeError(\"Compared images require the same aspect ratio\");\n return { aspectRatio, fraction: value / 100 };\n}\n"]}
@@ -34,10 +34,24 @@ export type MessageComposerDescriptor = Readonly<{
34
34
  value: string;
35
35
  label: string;
36
36
  sendLabel: string;
37
+ /** Short visual copy may differ from the complete accessible input name. */
38
+ placeholder?: string;
39
+ description?: string;
40
+ error?: string;
41
+ invalid?: boolean;
42
+ /** Newline remains the compatible default; desktop chat may explicitly opt into send. */
43
+ submitMode?: "newline" | "send";
37
44
  disabled?: boolean;
38
45
  pending?: boolean;
39
46
  attachmentCount?: number;
40
47
  }>;
48
+ /** Safari may report the final IME Enter as keyCode 229 after isComposing becomes false. */
49
+ export declare function shouldSubmitMessageKey(event: Readonly<{
50
+ key: string;
51
+ shiftKey?: boolean;
52
+ isComposing?: boolean;
53
+ keyCode?: number;
54
+ }>, mode?: "newline" | "send"): boolean;
41
55
  export declare function canSubmitMessage({ value, disabled, pending, attachmentCount }: MessageComposerDescriptor): boolean;
42
56
  /** Bubble alignment expresses authorship, not delivery; delivery text always comes from the product receipt. */
43
57
  export type ChatMessageDescriptor = Readonly<{
@@ -61,7 +75,8 @@ export declare function validateCommentThread(items: readonly {
61
75
  /** Source bytes, permission requests, ordering and upload limits remain product-owned. */
62
76
  export type MessageAttachmentDescriptor = Readonly<{
63
77
  id: string;
64
- removeLabel: string;
78
+ removeLabel: string; /** Local preparation can lock removal without locking text entry. */
79
+ disabled?: boolean;
65
80
  }>;
66
81
  export declare function validateMessageAttachments(attachments: readonly MessageAttachmentDescriptor[]): void;
67
82
  /** Require horizontal intent so a timeline scroll cannot accidentally start a reply. */
@@ -1 +1 @@
1
- {"version":3,"file":"screen-patterns.d.ts","sourceRoot":"","sources":["../src/screen-patterns.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"screen-patterns.d.ts","sourceRoot":"","sources":["../src/screen-patterns.ts"],"names":[],"mappings":"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"}
@@ -34,6 +34,10 @@ export const screenPatternRecipe = {
34
34
  composerMinLines: 1,
35
35
  composerMaxLines: 5,
36
36
  };
37
+ /** Safari may report the final IME Enter as keyCode 229 after isComposing becomes false. */
38
+ export function shouldSubmitMessageKey(event, mode = "newline") {
39
+ return mode === "send" && event.key === "Enter" && !event.shiftKey && !event.isComposing && event.keyCode !== 229;
40
+ }
37
41
  export function canSubmitMessage({ value, disabled = false, pending = false, attachmentCount = 0 }) {
38
42
  if (!Number.isSafeInteger(attachmentCount) || attachmentCount < 0)
39
43
  throw new RangeError("Attachment count must be a nonnegative integer");