@hjmds/design-contracts 1.9.0 → 1.11.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 (190) hide show
  1. package/dist/action-session.d.ts +47 -0
  2. package/dist/action-session.d.ts.map +1 -0
  3. package/dist/action-session.js +60 -0
  4. package/dist/action-session.js.map +1 -0
  5. package/dist/activity-heatmap.d.ts +22 -0
  6. package/dist/activity-heatmap.d.ts.map +1 -0
  7. package/dist/activity-heatmap.js +29 -0
  8. package/dist/activity-heatmap.js.map +1 -0
  9. package/dist/auth-screen.d.ts +4 -0
  10. package/dist/auth-screen.d.ts.map +1 -1
  11. package/dist/auth-screen.js +2 -0
  12. package/dist/auth-screen.js.map +1 -1
  13. package/dist/avatar-fallback.d.ts +25 -0
  14. package/dist/avatar-fallback.d.ts.map +1 -0
  15. package/dist/avatar-fallback.js +17 -0
  16. package/dist/avatar-fallback.js.map +1 -0
  17. package/dist/behaviors.d.ts +2 -2
  18. package/dist/bottom-navigation-defaults.d.ts +1 -1
  19. package/dist/bottom-navigation-defaults.d.ts.map +1 -1
  20. package/dist/bottom-navigation-defaults.js.map +1 -1
  21. package/dist/bottom-navigation.d.ts.map +1 -1
  22. package/dist/bottom-navigation.js +5 -1
  23. package/dist/bottom-navigation.js.map +1 -1
  24. package/dist/catalog.d.ts +67 -5
  25. package/dist/catalog.d.ts.map +1 -1
  26. package/dist/code-block.d.ts +23 -0
  27. package/dist/code-block.d.ts.map +1 -0
  28. package/dist/code-block.js +13 -0
  29. package/dist/code-block.js.map +1 -0
  30. package/dist/component-definitions.d.ts +2 -3
  31. package/dist/component-definitions.d.ts.map +1 -1
  32. package/dist/component-definitions.js +1 -2
  33. package/dist/component-definitions.js.map +1 -1
  34. package/dist/component-recipes.d.ts +63 -5
  35. package/dist/component-recipes.d.ts.map +1 -1
  36. package/dist/component-recipes.js +33 -6
  37. package/dist/component-recipes.js.map +1 -1
  38. package/dist/component-references.d.ts +0 -6
  39. package/dist/component-references.d.ts.map +1 -1
  40. package/dist/component-references.js +0 -5
  41. package/dist/component-references.js.map +1 -1
  42. package/dist/content-transition.d.ts +17 -0
  43. package/dist/content-transition.d.ts.map +1 -0
  44. package/dist/content-transition.js +15 -0
  45. package/dist/content-transition.js.map +1 -0
  46. package/dist/duration-field.d.ts +22 -0
  47. package/dist/duration-field.d.ts.map +1 -0
  48. package/dist/duration-field.js +20 -0
  49. package/dist/duration-field.js.map +1 -0
  50. package/dist/effect-surface.d.ts +29 -0
  51. package/dist/effect-surface.d.ts.map +1 -0
  52. package/dist/effect-surface.js +26 -0
  53. package/dist/effect-surface.js.map +1 -0
  54. package/dist/gooey-navigation.d.ts +13 -0
  55. package/dist/gooey-navigation.d.ts.map +1 -0
  56. package/dist/gooey-navigation.js +11 -0
  57. package/dist/gooey-navigation.js.map +1 -0
  58. package/dist/gravity-letters.d.ts +12 -0
  59. package/dist/gravity-letters.d.ts.map +1 -0
  60. package/dist/gravity-letters.js +11 -0
  61. package/dist/gravity-letters.js.map +1 -0
  62. package/dist/grid-reveal.d.ts +8 -0
  63. package/dist/grid-reveal.d.ts.map +1 -0
  64. package/dist/grid-reveal.js +5 -0
  65. package/dist/grid-reveal.js.map +1 -0
  66. package/dist/internal/object-validation.d.ts +3 -0
  67. package/dist/internal/object-validation.d.ts.map +1 -0
  68. package/dist/internal/object-validation.js +12 -0
  69. package/dist/internal/object-validation.js.map +1 -0
  70. package/dist/internal/thinking-orb/braid.d.ts.map +1 -1
  71. package/dist/internal/thinking-orb/braid.js +2 -9
  72. package/dist/internal/thinking-orb/braid.js.map +1 -1
  73. package/dist/internal/thinking-orb/core.d.ts +1 -0
  74. package/dist/internal/thinking-orb/core.d.ts.map +1 -1
  75. package/dist/internal/thinking-orb/core.js +12 -0
  76. package/dist/internal/thinking-orb/core.js.map +1 -1
  77. package/dist/internal/thinking-orb/presentation.d.ts +4 -0
  78. package/dist/internal/thinking-orb/presentation.d.ts.map +1 -0
  79. package/dist/internal/thinking-orb/presentation.js +28 -0
  80. package/dist/internal/thinking-orb/presentation.js.map +1 -0
  81. package/dist/internal/thinking-orb/ribbon.d.ts.map +1 -1
  82. package/dist/internal/thinking-orb/ribbon.js +2 -9
  83. package/dist/internal/thinking-orb/ribbon.js.map +1 -1
  84. package/dist/layout.d.ts +0 -5
  85. package/dist/layout.d.ts.map +1 -1
  86. package/dist/layout.js +0 -7
  87. package/dist/layout.js.map +1 -1
  88. package/dist/otp-field.d.ts +2 -0
  89. package/dist/otp-field.d.ts.map +1 -1
  90. package/dist/otp-field.js.map +1 -1
  91. package/dist/popover.d.ts.map +1 -1
  92. package/dist/popover.js +3 -12
  93. package/dist/popover.js.map +1 -1
  94. package/dist/reactions.d.ts +10 -0
  95. package/dist/reactions.d.ts.map +1 -0
  96. package/dist/reactions.js +20 -0
  97. package/dist/reactions.js.map +1 -0
  98. package/dist/scroll-progress.d.ts +8 -0
  99. package/dist/scroll-progress.d.ts.map +1 -0
  100. package/dist/scroll-progress.js +10 -0
  101. package/dist/scroll-progress.js.map +1 -0
  102. package/dist/task-list.d.ts +7 -0
  103. package/dist/task-list.d.ts.map +1 -0
  104. package/dist/task-list.js +4 -0
  105. package/dist/task-list.js.map +1 -0
  106. package/dist/theme-studio.d.ts +14 -0
  107. package/dist/theme-studio.d.ts.map +1 -0
  108. package/dist/theme-studio.js +16 -0
  109. package/dist/theme-studio.js.map +1 -0
  110. package/dist/thinking-orb.d.ts +4 -2
  111. package/dist/thinking-orb.d.ts.map +1 -1
  112. package/dist/thinking-orb.js +8 -3
  113. package/dist/thinking-orb.js.map +1 -1
  114. package/dist/toast-liquid.d.ts +4 -4
  115. package/dist/toast-liquid.d.ts.map +1 -1
  116. package/dist/toast-liquid.js +11 -10
  117. package/dist/toast-liquid.js.map +1 -1
  118. package/dist/toast.d.ts +4 -4
  119. package/dist/toast.d.ts.map +1 -1
  120. package/dist/toast.js +4 -3
  121. package/dist/toast.js.map +1 -1
  122. package/dist/tooltip.d.ts.map +1 -1
  123. package/dist/tooltip.js +3 -12
  124. package/dist/tooltip.js.map +1 -1
  125. package/dist/version.d.ts +1 -1
  126. package/dist/version.d.ts.map +1 -1
  127. package/dist/version.js +1 -1
  128. package/dist/version.js.map +1 -1
  129. package/dist/voice-note.d.ts +20 -0
  130. package/dist/voice-note.d.ts.map +1 -0
  131. package/dist/voice-note.js +16 -0
  132. package/dist/voice-note.js.map +1 -0
  133. package/docs/action-session.md +73 -0
  134. package/docs/activity-heatmap.md +32 -0
  135. package/docs/anchor.md +1 -1
  136. package/docs/auth-screen.md +44 -4
  137. package/docs/authoring-brief.md +5 -0
  138. package/docs/avatar-fallback.md +74 -0
  139. package/docs/bottom-navigation.md +16 -1
  140. package/docs/breadcrumb.md +1 -1
  141. package/docs/calendar.md +1 -1
  142. package/docs/cascader.md +1 -1
  143. package/docs/code-block.md +32 -0
  144. package/docs/command-palette.md +1 -1
  145. package/docs/compound-controls.md +83 -0
  146. package/docs/confirm-popover.md +1 -1
  147. package/docs/consumer-policy.md +30 -23
  148. package/docs/cross-platform-core-normalization.md +19 -21
  149. package/docs/data-table.md +8 -5
  150. package/docs/dialog.md +2 -0
  151. package/docs/effect-surface.md +50 -0
  152. package/docs/floating-action-button.md +1 -1
  153. package/docs/folder-preview.md +26 -0
  154. package/docs/generated/component-maturity.md +1 -1
  155. package/docs/generated/renderer-evidence.json +3 -3
  156. package/docs/generated/renderer-evidence.md +1 -1
  157. package/docs/generated/showcase-manifest.json +1 -1
  158. package/docs/gooey-navigation.md +36 -0
  159. package/docs/gravity-letters.md +26 -0
  160. package/docs/grid-reveal.md +11 -0
  161. package/docs/icon.md +26 -0
  162. package/docs/image.md +2 -2
  163. package/docs/layout.md +1 -2
  164. package/docs/migration-0.5.md +4 -1
  165. package/docs/migration-native-legacy-removal.md +59 -0
  166. package/docs/navigation-bar.md +28 -0
  167. package/docs/optional-adapters.md +24 -1
  168. package/docs/otp-field.md +15 -0
  169. package/docs/pagination.md +1 -1
  170. package/docs/popover.md +2 -2
  171. package/docs/product-adoption-1.4.md +7 -0
  172. package/docs/product-audit-2026-09-15.md +1 -1
  173. package/docs/provider-button.md +6 -3
  174. package/docs/rating.md +1 -1
  175. package/docs/react-native-completion.md +4 -4
  176. package/docs/screen-chrome.md +1 -1
  177. package/docs/scroll-progress.md +29 -0
  178. package/docs/sheet.md +2 -0
  179. package/docs/sidebar.md +6 -0
  180. package/docs/splitter.md +1 -1
  181. package/docs/step-player.md +16 -0
  182. package/docs/task-list.md +32 -0
  183. package/docs/theme-studio.md +13 -0
  184. package/docs/thinking-orb.md +9 -2
  185. package/docs/time-picker.md +1 -1
  186. package/docs/toast.md +27 -8
  187. package/docs/tour.md +1 -1
  188. package/docs/tree-select.md +2 -2
  189. package/docs/voice-note.md +19 -0
  190. package/package.json +91 -1
@@ -0,0 +1,28 @@
1
+ /** Independently authored decorative forms; no reference-site engine or presets. */
2
+ export function buildOrbPresentation(appearance, size, time) {
3
+ const dots = [];
4
+ const center = size / 2;
5
+ if (appearance === 'matrix') {
6
+ // Fixed 9×9 maximum bounds frame cost on both 20px and 64px surfaces.
7
+ for (let row = 0; row < 9; row++)
8
+ for (let column = 0; column < 9; column++) {
9
+ const x = (column - 4) / 4, y = (row - 4) / 4, distance = Math.hypot(x, y);
10
+ if (distance > 1)
11
+ continue;
12
+ const wave = (Math.sin(time * 2 - distance * 5 + column * .3) + 1) / 2;
13
+ dots.push({ x: center + x * size * .38, y: center + y * size * .38, z: 0, r: size * (.012 + .016 * wave), white: 1 - (.3 + .7 * wave), a: 1 });
14
+ }
15
+ }
16
+ else {
17
+ // Six organic rings keep a bounded silhouette without expensive blur/shader passes.
18
+ for (let ring = 1; ring <= 6; ring++)
19
+ for (let point = 0; point < 32; point++) {
20
+ const angle = point * Math.PI / 16;
21
+ const wave = 1 + .09 * Math.sin(angle * 3 + time * 1.4 + ring * .5);
22
+ const distance = size * .38 * ring / 6 * wave;
23
+ dots.push({ x: center + Math.cos(angle) * distance, y: center + Math.sin(angle) * distance, z: ring, r: size * .012, white: .15 + ring * .08, a: 1 });
24
+ }
25
+ }
26
+ return { dots, lines: [] };
27
+ }
28
+ //# sourceMappingURL=presentation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"presentation.js","sourceRoot":"","sources":["../../../src/internal/thinking-orb/presentation.ts"],"names":[],"mappings":"AACA,oFAAoF;AACpF,MAAM,UAAU,oBAAoB,CAAC,UAA2B,EAAC,IAAY,EAAC,IAAW;IACxF,MAAM,IAAI,GAAkB,EAAE,CAAC;IAAA,MAAM,MAAM,GAAC,IAAI,GAAC,CAAC,CAAC;IACnD,IAAG,UAAU,KAAG,QAAQ,EAAC,CAAC;QACzB,sEAAsE;QACtE,KAAI,IAAI,GAAG,GAAC,CAAC,EAAC,GAAG,GAAC,CAAC,EAAC,GAAG,EAAE;YAAC,KAAI,IAAI,MAAM,GAAC,CAAC,EAAC,MAAM,GAAC,CAAC,EAAC,MAAM,EAAE,EAAC,CAAC;gBAAA,MAAM,CAAC,GAAC,CAAC,MAAM,GAAC,CAAC,CAAC,GAAC,CAAC,EAAC,CAAC,GAAC,CAAC,GAAG,GAAC,CAAC,CAAC,GAAC,CAAC,EAAC,QAAQ,GAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC;gBAAA,IAAG,QAAQ,GAAC,CAAC;oBAAC,SAAS;gBAAA,MAAM,IAAI,GAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,GAAC,CAAC,GAAC,QAAQ,GAAC,CAAC,GAAC,MAAM,GAAC,EAAE,CAAC,GAAC,CAAC,CAAC,GAAC,CAAC,CAAC;gBAAA,IAAI,CAAC,IAAI,CAAC,EAAC,CAAC,EAAC,MAAM,GAAC,CAAC,GAAC,IAAI,GAAC,GAAG,EAAC,CAAC,EAAC,MAAM,GAAC,CAAC,GAAC,IAAI,GAAC,GAAG,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,IAAI,GAAC,CAAC,IAAI,GAAC,IAAI,GAAC,IAAI,CAAC,EAAC,KAAK,EAAC,CAAC,GAAC,CAAC,EAAE,GAAC,EAAE,GAAC,IAAI,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC;YAAA,CAAC;IAClT,CAAC;SAAI,CAAC;QACL,oFAAoF;QACpF,KAAI,IAAI,IAAI,GAAC,CAAC,EAAC,IAAI,IAAE,CAAC,EAAC,IAAI,EAAE;YAAC,KAAI,IAAI,KAAK,GAAC,CAAC,EAAC,KAAK,GAAC,EAAE,EAAC,KAAK,EAAE,EAAC,CAAC;gBAAA,MAAM,KAAK,GAAC,KAAK,GAAC,IAAI,CAAC,EAAE,GAAC,EAAE,CAAC;gBAAA,MAAM,IAAI,GAAC,CAAC,GAAC,GAAG,GAAC,IAAI,CAAC,GAAG,CAAC,KAAK,GAAC,CAAC,GAAC,IAAI,GAAC,GAAG,GAAC,IAAI,GAAC,EAAE,CAAC,CAAC;gBAAA,MAAM,QAAQ,GAAC,IAAI,GAAC,GAAG,GAAC,IAAI,GAAC,CAAC,GAAC,IAAI,CAAC;gBAAA,IAAI,CAAC,IAAI,CAAC,EAAC,CAAC,EAAC,MAAM,GAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,GAAC,QAAQ,EAAC,CAAC,EAAC,MAAM,GAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,GAAC,QAAQ,EAAC,CAAC,EAAC,IAAI,EAAC,CAAC,EAAC,IAAI,GAAC,IAAI,EAAC,KAAK,EAAC,GAAG,GAAC,IAAI,GAAC,GAAG,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC;YAAA,CAAC;IAClT,CAAC;IACD,OAAM,EAAC,IAAI,EAAC,KAAK,EAAC,EAAE,EAAC,CAAC;AACvB,CAAC","sourcesContent":["import type{OrbFrame,OrbSize}from'./types.js';\n/** Independently authored decorative forms; no reference-site engine or presets. */\nexport function buildOrbPresentation(appearance:'fluid'|'matrix',size:OrbSize,time:number):OrbFrame{\n const dots:OrbFrame['dots']=[];const center=size/2;\n if(appearance==='matrix'){\n // Fixed 9×9 maximum bounds frame cost on both 20px and 64px surfaces.\n for(let row=0;row<9;row++)for(let column=0;column<9;column++){const x=(column-4)/4,y=(row-4)/4,distance=Math.hypot(x,y);if(distance>1)continue;const wave=(Math.sin(time*2-distance*5+column*.3)+1)/2;dots.push({x:center+x*size*.38,y:center+y*size*.38,z:0,r:size*(.012+.016*wave),white:1-(.3+.7*wave),a:1});}\n }else{\n // Six organic rings keep a bounded silhouette without expensive blur/shader passes.\n for(let ring=1;ring<=6;ring++)for(let point=0;point<32;point++){const angle=point*Math.PI/16;const wave=1+.09*Math.sin(angle*3+time*1.4+ring*.5);const distance=size*.38*ring/6*wave;dots.push({x:center+Math.cos(angle)*distance,y:center+Math.sin(angle)*distance,z:ring,r:size*.012,white:.15+ring*.08,a:1});}\n }\n return{dots,lines:[]};\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"ribbon.d.ts","sourceRoot":"","sources":["../../../src/internal/thinking-orb/ribbon.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAO,SAAS,EAAE,MAAM,YAAY,CAAC;AAGjD,eAAO,MAAM,WAAW,EAAE,SAiFzB,CAAC"}
1
+ {"version":3,"file":"ribbon.d.ts","sourceRoot":"","sources":["../../../src/internal/thinking-orb/ribbon.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAG5C,eAAO,MAAM,WAAW,EAAE,SA0EzB,CAAC"}
@@ -6,7 +6,7 @@
6
6
  // The same painter also drives "breathing" (ring), via the `faceOn` flag:
7
7
  // a face-on circle whose radius — not its out-of-plane offset — undulates,
8
8
  // so it reads as a ring slowly morphing rather than a sash in orbit.
9
- import { fibDir, finalizeFrame, makeProj, radiusScale } from './core.js';
9
+ import { ghostSphereDots, finalizeFrame, makeProj, radiusScale } from './core.js';
10
10
  export const frameRibbon = (size, t, o) => {
11
11
  const cx = size / 2;
12
12
  const cy = size / 2;
@@ -17,14 +17,7 @@ export const frameRibbon = (size, t, o) => {
17
17
  const camTilt = 0.3;
18
18
  const pt = makeProj(t * 0.1 * spin, camTilt, cx, cy, 1);
19
19
  const rs = radiusScale(size, o.rsPow ?? 0.6);
20
- const dots = [];
21
- const ghostN = o.ghostN ?? 150;
22
- for (let i = 0; i < ghostN; i++) {
23
- const d = fibDir(i, ghostN);
24
- const [px, py, z] = pt(d[0] * R, d[1] * R, d[2] * R);
25
- const depth = (z / R + 1) / 2;
26
- dots.push({ x: px, y: py, z, r: 0.8 * rs, white: 0.78, a: 0.1 + 0.22 * depth });
27
- }
20
+ const dots = ghostSphereDots(pt, R, rs, o.ghostN ?? 150);
28
21
  // The band plane, precessing (frozen when spin=0). The projection squashes
29
22
  // the band's great circle vertically by cos(ta + camTilt); face-on sets
30
23
  // ta = -camTilt so that term is 1 and the band reads as a true circle
@@ -1 +1 @@
1
- {"version":3,"file":"ribbon.js","sourceRoot":"","sources":["../../../src/internal/thinking-orb/ribbon.ts"],"names":[],"mappings":"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","sourcesContent":["// Adapted from Thinking Orbs de85557 (MIT); see THIRD_PARTY_NOTICES.md.\n// Ribbon: an undulating sash of parallel strands rides a great circle —\n// the \"composing\" state. The tuned preset freezes the 3D tumble\n// (spin 0), leaving the traveling undulation on a fixed band.\n//\n// The same painter also drives \"breathing\" (ring), via the `faceOn` flag:\n// a face-on circle whose radius — not its out-of-plane offset — undulates,\n// so it reads as a ring slowly morphing rather than a sash in orbit.\n\nimport type { Dot, ModeFrame } from './types.js';\nimport { fibDir, finalizeFrame, makeProj, radiusScale } from './core.js';\n\nexport const frameRibbon: ModeFrame = (size, t, o) => {\n const cx = size / 2;\n const cy = size / 2;\n const R = (size / 2) * 0.78;\n // spin scales the 3D tumble; spin=0 freezes the band's orientation,\n // leaving only the traveling undulation\n const spin = o.spin ?? 1;\n const camTilt = 0.3;\n const pt = makeProj(t * 0.1 * spin, camTilt, cx, cy, 1);\n const rs = radiusScale(size, o.rsPow ?? 0.6);\n\n const dots: Dot[] = [];\n const ghostN = o.ghostN ?? 150;\n for (let i = 0; i < ghostN; i++) {\n const d = fibDir(i, ghostN);\n const [px, py, z] = pt(d[0] * R, d[1] * R, d[2] * R);\n const depth = (z / R + 1) / 2;\n dots.push({ x: px, y: py, z, r: 0.8 * rs, white: 0.78, a: 0.1 + 0.22 * depth });\n }\n\n // The band plane, precessing (frozen when spin=0). The projection squashes\n // the band's great circle vertically by cos(ta + camTilt); face-on sets\n // ta = -camTilt so that term is 1 and the band reads as a true circle\n // rather than ribbon's tilted ellipse.\n const ya = t * 0.24 * spin;\n const ta = o.faceOn ? -camTilt : 0.55 + 0.3 * Math.sin(t * 0.18) * spin;\n const ux = Math.cos(ya);\n const uy = 0;\n const uz = Math.sin(ya);\n const vx = -uz * Math.sin(ta);\n const vy = Math.cos(ta);\n const vz = ux * Math.sin(ta);\n // plane normal n = u × v\n const nx = uy * vz - uz * vy;\n const ny = uz * vx - ux * vz;\n const nz = ux * vy - uy * vx;\n\n // Radial lobes swell past R, so pull the base radius in by (most of) the\n // wobble amplitude. The silhouette then stays inside the frame however far\n // the deformation is pushed, while lobes keep getting deeper relative to\n // the mean radius.\n const wobAmp = 0.23 * (o.wobMul ?? 1);\n const baseR = o.faceOn ? R / (1 + 0.85 * wobAmp) : R;\n\n const baseLanes = o.lanes ?? 5;\n const segs = o.segs ?? 88;\n const lanes = Math.max(1, Math.round(baseLanes * (o.bandMul ?? 1)));\n for (let w = 0; w < lanes; w++) {\n const laneOff = (w - (lanes - 1) / 2) * 0.075;\n const edge = Math.abs(w - (lanes - 1) / 2) / Math.max(1, (lanes - 1) / 2);\n for (let k = 0; k < segs; k++) {\n const a = (k / segs) * 2 * Math.PI;\n // the undulation: two traveling waves along the band; wobMul\n // scales the deformation — 0 is a clean band\n const wob =\n (0.16 * Math.sin(a * 3 - t * 1.7 + w * 0.22) + 0.07 * Math.sin(a * 5 + t * 1.1)) * (o.wobMul ?? 1);\n // A normal-direction wobble is cancelled by the re-normalisation below:\n // the point lands back on the sphere, so the silhouette is pinned at R\n // and the deformation can only ever pull dots inward. Face-on instead\n // modulates the in-plane RADIUS, so lobes genuinely swell outward and\n // pinch inward. Ribbon keeps the original out-of-plane sash wobble.\n const radial = o.faceOn ? 1 + wob : 1;\n const off = o.faceOn ? laneOff : laneOff + wob;\n const x = ux * Math.cos(a) + vx * Math.sin(a) + nx * off;\n const y = uy * Math.cos(a) + vy * Math.sin(a) + ny * off;\n const z = uz * Math.cos(a) + vz * Math.sin(a) + nz * off;\n const l = Math.sqrt(x * x + y * y + z * z);\n const rr = baseR * radial;\n const [px, py, zr] = pt((x / l) * rr, (y / l) * rr, (z / l) * rr);\n const depth = (zr / R + 1) / 2;\n dots.push({\n x: px,\n y: py,\n z: zr,\n r: ((o.rBase ?? 1.1) + (o.rDepth ?? 1.7) * depth) * (1 - 0.25 * edge) * rs,\n white: 0.52 - 0.44 * depth + 0.18 * edge,\n a: 0.4 + 0.6 * depth\n });\n }\n }\n return finalizeFrame(dots, [], o.rMin);\n};\n"]}
1
+ {"version":3,"file":"ribbon.js","sourceRoot":"","sources":["../../../src/internal/thinking-orb/ribbon.ts"],"names":[],"mappings":"AAAA,wEAAwE;AACxE,wEAAwE;AACxE,gEAAgE;AAChE,8DAA8D;AAC9D,EAAE;AACF,0EAA0E;AAC1E,2EAA2E;AAC3E,qEAAqE;AAGrE,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAElF,MAAM,CAAC,MAAM,WAAW,GAAc,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE;IACnD,MAAM,EAAE,GAAG,IAAI,GAAG,CAAC,CAAC;IACpB,MAAM,EAAE,GAAG,IAAI,GAAG,CAAC,CAAC;IACpB,MAAM,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC;IAC5B,oEAAoE;IACpE,wCAAwC;IACxC,MAAM,IAAI,GAAG,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC;IACzB,MAAM,OAAO,GAAG,GAAG,CAAC;IACpB,MAAM,EAAE,GAAG,QAAQ,CAAC,CAAC,GAAG,GAAG,GAAG,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC;IACxD,MAAM,EAAE,GAAG,WAAW,CAAC,IAAI,EAAE,CAAC,CAAC,KAAK,IAAI,GAAG,CAAC,CAAC;IAE7C,MAAM,IAAI,GAAG,eAAe,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,MAAM,IAAI,GAAG,CAAC,CAAC;IAEzD,2EAA2E;IAC3E,wEAAwE;IACxE,sEAAsE;IACtE,uCAAuC;IACvC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,GAAG,IAAI,CAAC;IAC3B,MAAM,EAAE,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,GAAG,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC;IACxE,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IACxB,MAAM,EAAE,GAAG,CAAC,CAAC;IACb,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IACxB,MAAM,EAAE,GAAG,CAAC,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAC9B,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IACxB,MAAM,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAC7B,yBAAyB;IACzB,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC;IAC7B,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC;IAC7B,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC;IAE7B,yEAAyE;IACzE,2EAA2E;IAC3E,yEAAyE;IACzE,mBAAmB;IACnB,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC;IACtC,MAAM,KAAK,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,IAAI,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAErD,MAAM,SAAS,GAAG,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC;IAC/B,MAAM,IAAI,GAAG,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC;IAC1B,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IACpE,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC;QAC/B,MAAM,OAAO,GAAG,CAAC,CAAC,GAAG,CAAC,KAAK,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,KAAK,CAAC;QAC9C,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,KAAK,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,KAAK,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QAC1E,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC;YAC9B,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,EAAE,CAAC;YACnC,6DAA6D;YAC7D,6CAA6C;YAC7C,MAAM,GAAG,GACP,CAAC,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,GAAG,GAAG,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC;YACrG,wEAAwE;YACxE,uEAAuE;YACvE,sEAAsE;YACtE,sEAAsE;YACtE,oEAAoE;YACpE,MAAM,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;YACtC,MAAM,GAAG,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,GAAG,GAAG,CAAC;YAC/C,MAAM,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,GAAG,GAAG,CAAC;YACzD,MAAM,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,GAAG,GAAG,CAAC;YACzD,MAAM,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,GAAG,GAAG,CAAC;YACzD,MAAM,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;YAC3C,MAAM,EAAE,GAAG,KAAK,GAAG,MAAM,CAAC;YAC1B,MAAM,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;YAClE,MAAM,KAAK,GAAG,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC;YAC/B,IAAI,CAAC,IAAI,CAAC;gBACR,CAAC,EAAE,EAAE;gBACL,CAAC,EAAE,EAAE;gBACL,CAAC,EAAE,EAAE;gBACL,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,IAAI,GAAG,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,IAAI,GAAG,IAAI,CAAC,GAAG,EAAE;gBAC1E,KAAK,EAAE,IAAI,GAAG,IAAI,GAAG,KAAK,GAAG,IAAI,GAAG,IAAI;gBACxC,CAAC,EAAE,GAAG,GAAG,GAAG,GAAG,KAAK;aACrB,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IACD,OAAO,aAAa,CAAC,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;AACzC,CAAC,CAAC","sourcesContent":["// Adapted from Thinking Orbs de85557 (MIT); see THIRD_PARTY_NOTICES.md.\n// Ribbon: an undulating sash of parallel strands rides a great circle —\n// the \"composing\" state. The tuned preset freezes the 3D tumble\n// (spin 0), leaving the traveling undulation on a fixed band.\n//\n// The same painter also drives \"breathing\" (ring), via the `faceOn` flag:\n// a face-on circle whose radius — not its out-of-plane offset — undulates,\n// so it reads as a ring slowly morphing rather than a sash in orbit.\n\nimport type { ModeFrame } from './types.js';\nimport { ghostSphereDots, finalizeFrame, makeProj, radiusScale } from './core.js';\n\nexport const frameRibbon: ModeFrame = (size, t, o) => {\n const cx = size / 2;\n const cy = size / 2;\n const R = (size / 2) * 0.78;\n // spin scales the 3D tumble; spin=0 freezes the band's orientation,\n // leaving only the traveling undulation\n const spin = o.spin ?? 1;\n const camTilt = 0.3;\n const pt = makeProj(t * 0.1 * spin, camTilt, cx, cy, 1);\n const rs = radiusScale(size, o.rsPow ?? 0.6);\n\n const dots = ghostSphereDots(pt, R, rs, o.ghostN ?? 150);\n\n // The band plane, precessing (frozen when spin=0). The projection squashes\n // the band's great circle vertically by cos(ta + camTilt); face-on sets\n // ta = -camTilt so that term is 1 and the band reads as a true circle\n // rather than ribbon's tilted ellipse.\n const ya = t * 0.24 * spin;\n const ta = o.faceOn ? -camTilt : 0.55 + 0.3 * Math.sin(t * 0.18) * spin;\n const ux = Math.cos(ya);\n const uy = 0;\n const uz = Math.sin(ya);\n const vx = -uz * Math.sin(ta);\n const vy = Math.cos(ta);\n const vz = ux * Math.sin(ta);\n // plane normal n = u × v\n const nx = uy * vz - uz * vy;\n const ny = uz * vx - ux * vz;\n const nz = ux * vy - uy * vx;\n\n // Radial lobes swell past R, so pull the base radius in by (most of) the\n // wobble amplitude. The silhouette then stays inside the frame however far\n // the deformation is pushed, while lobes keep getting deeper relative to\n // the mean radius.\n const wobAmp = 0.23 * (o.wobMul ?? 1);\n const baseR = o.faceOn ? R / (1 + 0.85 * wobAmp) : R;\n\n const baseLanes = o.lanes ?? 5;\n const segs = o.segs ?? 88;\n const lanes = Math.max(1, Math.round(baseLanes * (o.bandMul ?? 1)));\n for (let w = 0; w < lanes; w++) {\n const laneOff = (w - (lanes - 1) / 2) * 0.075;\n const edge = Math.abs(w - (lanes - 1) / 2) / Math.max(1, (lanes - 1) / 2);\n for (let k = 0; k < segs; k++) {\n const a = (k / segs) * 2 * Math.PI;\n // the undulation: two traveling waves along the band; wobMul\n // scales the deformation — 0 is a clean band\n const wob =\n (0.16 * Math.sin(a * 3 - t * 1.7 + w * 0.22) + 0.07 * Math.sin(a * 5 + t * 1.1)) * (o.wobMul ?? 1);\n // A normal-direction wobble is cancelled by the re-normalisation below:\n // the point lands back on the sphere, so the silhouette is pinned at R\n // and the deformation can only ever pull dots inward. Face-on instead\n // modulates the in-plane RADIUS, so lobes genuinely swell outward and\n // pinch inward. Ribbon keeps the original out-of-plane sash wobble.\n const radial = o.faceOn ? 1 + wob : 1;\n const off = o.faceOn ? laneOff : laneOff + wob;\n const x = ux * Math.cos(a) + vx * Math.sin(a) + nx * off;\n const y = uy * Math.cos(a) + vy * Math.sin(a) + ny * off;\n const z = uz * Math.cos(a) + vz * Math.sin(a) + nz * off;\n const l = Math.sqrt(x * x + y * y + z * z);\n const rr = baseR * radial;\n const [px, py, zr] = pt((x / l) * rr, (y / l) * rr, (z / l) * rr);\n const depth = (zr / R + 1) / 2;\n dots.push({\n x: px,\n y: py,\n z: zr,\n r: ((o.rBase ?? 1.1) + (o.rDepth ?? 1.7) * depth) * (1 - 0.25 * edge) * rs,\n white: 0.52 - 0.44 * depth + 0.18 * edge,\n a: 0.4 + 0.6 * depth\n });\n }\n }\n return finalizeFrame(dots, [], o.rMin);\n};\n"]}
package/dist/layout.d.ts CHANGED
@@ -31,11 +31,6 @@ export type LayoutDescriptor = Readonly<{
31
31
  export declare function validateLayoutRegions(descriptor: LayoutDescriptor): void;
32
32
  /** Web landmark validation, including the WCAG 2.4.1 bypass-link invariant. */
33
33
  export declare function validateLayoutWebDescriptor(descriptor: LayoutDescriptor): void;
34
- /**
35
- * @deprecated Use `validateLayoutRegions` for shared/Native structure or
36
- * `validateLayoutWebDescriptor` for a Web app shell.
37
- */
38
- export declare function validateLayoutDescriptor(descriptor: LayoutDescriptor): void;
39
34
  export type LayoutLandmarkRole = "banner" | "navigation" | "complementary" | "main" | "contentinfo";
40
35
  /**
41
36
  * Web-only translation: real landmark elements exist there. Native has no
@@ -1 +1 @@
1
- {"version":3,"file":"layout.d.ts","sourceRoot":"","sources":["../src/layout.ts"],"names":[],"mappings":"AAMA;;;;;;;;;GASG;AACH,MAAM,MAAM,iBAAiB,GAAG,YAAY,GAAG,eAAe,CAAC;AAC/D,MAAM,MAAM,iBAAiB,GAAG,YAAY,GAAG,SAAS,CAAC;AAEzD,MAAM,MAAM,uBAAuB,GAAG,QAAQ,CAAC;IAC7C,0GAA0G;IAC1G,IAAI,EAAE,iBAAiB,CAAC;IACxB,gIAAgI;IAChI,IAAI,EAAE,iBAAiB,CAAC;IACxB,KAAK,EAAE,MAAM,CAAC;CACf,CAAC,CAAC;AAEH,MAAM,MAAM,gBAAgB,GAAG,QAAQ,CAAC;IACtC,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,OAAO,CAAC,EAAE,uBAAuB,CAAC;IAClC,kGAAkG;IAClG,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB,CAAC,CAAC;AAQH;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,UAAU,EAAE,gBAAgB,GAAG,IAAI,CAcxE;AAED,+EAA+E;AAC/E,wBAAgB,2BAA2B,CAAC,UAAU,EAAE,gBAAgB,GAAG,IAAI,CAQ9E;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,UAAU,EAAE,gBAAgB,GAAG,IAAI,CAE3E;AAED,MAAM,MAAM,kBAAkB,GAC1B,QAAQ,GACR,YAAY,GACZ,eAAe,GACf,MAAM,GACN,aAAa,CAAC;AAElB;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CACvC,UAAU,EAAE,gBAAgB,GAC3B,SAAS,kBAAkB,EAAE,CAQ/B;AAED;;;;;GAKG;AACH,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+BxB,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;CAuBU,CAAC"}
1
+ {"version":3,"file":"layout.d.ts","sourceRoot":"","sources":["../src/layout.ts"],"names":[],"mappings":"AAMA;;;;;;;;;GASG;AACH,MAAM,MAAM,iBAAiB,GAAG,YAAY,GAAG,eAAe,CAAC;AAC/D,MAAM,MAAM,iBAAiB,GAAG,YAAY,GAAG,SAAS,CAAC;AAEzD,MAAM,MAAM,uBAAuB,GAAG,QAAQ,CAAC;IAC7C,0GAA0G;IAC1G,IAAI,EAAE,iBAAiB,CAAC;IACxB,gIAAgI;IAChI,IAAI,EAAE,iBAAiB,CAAC;IACxB,KAAK,EAAE,MAAM,CAAC;CACf,CAAC,CAAC;AAEH,MAAM,MAAM,gBAAgB,GAAG,QAAQ,CAAC;IACtC,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,OAAO,CAAC,EAAE,uBAAuB,CAAC;IAClC,kGAAkG;IAClG,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB,CAAC,CAAC;AAQH;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,UAAU,EAAE,gBAAgB,GAAG,IAAI,CAcxE;AAED,+EAA+E;AAC/E,wBAAgB,2BAA2B,CAAC,UAAU,EAAE,gBAAgB,GAAG,IAAI,CAQ9E;AAED,MAAM,MAAM,kBAAkB,GAC1B,QAAQ,GACR,YAAY,GACZ,eAAe,GACf,MAAM,GACN,aAAa,CAAC;AAElB;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CACvC,UAAU,EAAE,gBAAgB,GAC3B,SAAS,kBAAkB,EAAE,CAQ/B;AAED;;;;;GAKG;AACH,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+BxB,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;CAuBU,CAAC"}
package/dist/layout.js CHANGED
@@ -33,13 +33,6 @@ export function validateLayoutWebDescriptor(descriptor) {
33
33
  throw new TypeError("Layout requires skipLinkLabel when a header or sidebar region precedes main");
34
34
  }
35
35
  }
36
- /**
37
- * @deprecated Use `validateLayoutRegions` for shared/Native structure or
38
- * `validateLayoutWebDescriptor` for a Web app shell.
39
- */
40
- export function validateLayoutDescriptor(descriptor) {
41
- validateLayoutWebDescriptor(descriptor);
42
- }
43
36
  /**
44
37
  * Web-only translation: real landmark elements exist there. Native has no
45
38
  * landmark-role equivalent at all (`accessibilityRole` covers headings and
@@ -1 +1 @@
1
- {"version":3,"file":"layout.js","sourceRoot":"","sources":["../src/layout.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ColorReference } from \"./color-references.js\";\nimport type { BehaviorContract } from \"./behaviors.js\";\nimport { focusIndicatorContract } from \"./component-contracts.js\";\nimport { layout as layoutFoundation, spacing } from \"./foundations.js\";\nimport { semanticColors } from \"./semantic-colors.js\";\n\n/**\n * `Layout` (alias `AppShell`) does NOT own header or footer chrome — that is\n * already `TopBar` (native, beta) and `BottomNavigation` (adaptive, beta).\n * What is left after subtracting those: ordered regions, a sidebar that is\n * either always-visible chrome or a dismissible overlay, and Web-only\n * landmark composition (one `main` plus a required skip link whenever\n * repeated navigation precedes it). The overlay case reuses `SidePanel`\n * unchanged — see docs/layout.md for why this module does not redeclare\n * open/dismiss state.\n */\nexport type LayoutSidebarRole = \"navigation\" | \"complementary\";\nexport type LayoutSidebarMode = \"persistent\" | \"overlay\";\n\nexport type LayoutSidebarDescriptor = Readonly<{\n /** Primary site navigation vs. supplementary content (filters, related items) — independent of `mode`. */\n role: LayoutSidebarRole;\n /** `persistent`: always-visible landmark. `overlay`: a `SidePanel` — Layout does not re-contract its open/dismiss lifecycle. */\n mode: LayoutSidebarMode;\n label: string;\n}>;\n\nexport type LayoutDescriptor = Readonly<{\n hasHeader?: boolean;\n hasFooter?: boolean;\n sidebar?: LayoutSidebarDescriptor;\n /** Web-only: required whenever a header or sidebar precedes `main` (WCAG 2.4.1 bypass blocks). */\n skipLinkLabel?: string;\n}>;\n\nfunction assertNonEmpty(value: string, field: string): void {\n if (typeof value !== \"string\" || value.trim().length === 0) {\n throw new TypeError(`Layout ${field} must not be empty`);\n }\n}\n\n/**\n * Cross-platform structure validation. This deliberately does not require a\n * skip link: Native has no page-landmark or bypass-link equivalent.\n */\nexport function validateLayoutRegions(descriptor: LayoutDescriptor): void {\n if (descriptor.sidebar !== undefined) {\n const { role, mode, label } = descriptor.sidebar;\n if (role !== \"navigation\" && role !== \"complementary\") {\n throw new TypeError(`Unsupported Layout sidebar role: ${String(role)}`);\n }\n if (mode !== \"persistent\" && mode !== \"overlay\") {\n throw new TypeError(`Unsupported Layout sidebar mode: ${String(mode)}`);\n }\n assertNonEmpty(label, \"sidebar.label\");\n }\n if (descriptor.skipLinkLabel !== undefined) {\n assertNonEmpty(descriptor.skipLinkLabel, \"skipLinkLabel\");\n }\n}\n\n/** Web landmark validation, including the WCAG 2.4.1 bypass-link invariant. */\nexport function validateLayoutWebDescriptor(descriptor: LayoutDescriptor): void {\n validateLayoutRegions(descriptor);\n const needsSkipLink = descriptor.hasHeader === true || descriptor.sidebar !== undefined;\n if (needsSkipLink && descriptor.skipLinkLabel === undefined) {\n throw new TypeError(\n \"Layout requires skipLinkLabel when a header or sidebar region precedes main\",\n );\n }\n}\n\n/**\n * @deprecated Use `validateLayoutRegions` for shared/Native structure or\n * `validateLayoutWebDescriptor` for a Web app shell.\n */\nexport function validateLayoutDescriptor(descriptor: LayoutDescriptor): void {\n validateLayoutWebDescriptor(descriptor);\n}\n\nexport type LayoutLandmarkRole =\n | \"banner\"\n | \"navigation\"\n | \"complementary\"\n | \"main\"\n | \"contentinfo\";\n\n/**\n * Web-only translation: real landmark elements exist there. Native has no\n * landmark-role equivalent at all (`accessibilityRole` covers headings and\n * controls, not page regions) — RN renderers instead rely on visual/DOM\n * order plus `accessibilityViewIsModal` for the overlay sidebar case. That\n * asymmetry is documented, not papered over with a fake mapping.\n */\nexport function resolveLayoutWebLandmarks(\n descriptor: LayoutDescriptor,\n): readonly LayoutLandmarkRole[] {\n validateLayoutWebDescriptor(descriptor);\n const roles: LayoutLandmarkRole[] = [];\n if (descriptor.hasHeader) roles.push(\"banner\");\n if (descriptor.sidebar) roles.push(descriptor.sidebar.role);\n roles.push(\"main\");\n if (descriptor.hasFooter) roles.push(\"contentinfo\");\n return roles;\n}\n\n/**\n * Skip link is hidden until it matters — visible only on keyboard focus.\n * A skip link visible at rest fights identity.md's \"조용한 화면 위에 중요한\n * 순간만 선명하게\": for a mouse/touch user it is noise every screen, for a\n * keyboard user it is the first landmark on the page.\n */\nexport const layoutRecipe = {\n slots: [\"root\", \"skipLink\", \"header\", \"sidebar\", \"main\", \"footer\"] as const,\n defaults: {},\n main: {\n maxWidth: layoutFoundation.contentMaxWidth,\n paddingHorizontal: layoutFoundation.pagePadding.regular,\n },\n sidebar: {\n width: 280,\n },\n skipLink: {\n visibility: \"focus-only\",\n background: semanticColors.action.brand.background,\n color: semanticColors.action.brand.content,\n paddingHorizontal: spacing.md,\n paddingVertical: spacing.sm,\n },\n states: { focus: focusIndicatorContract },\n} as const satisfies {\n slots: readonly [\"root\", \"skipLink\", \"header\", \"sidebar\", \"main\", \"footer\"];\n defaults: Record<string, never>;\n main: { maxWidth: number; paddingHorizontal: number };\n sidebar: { width: number };\n skipLink: {\n visibility: \"focus-only\";\n background: ColorReference;\n color: ColorReference;\n paddingHorizontal: number;\n paddingVertical: number;\n };\n states: { focus: typeof focusIndicatorContract };\n};\n\n/**\n * `controlled: []` on purpose: an overlay sidebar's open/dismiss lifecycle\n * is a `SidePanel` (`src/side-panel.ts`) composed as-is. Redeclaring\n * `open`/`defaultOpen`/`onOpenChange`/`dismissPolicy` here would be the same\n * mistake DataTable avoided with Pagination/LoadMore — two places owning\n * one piece of state that will drift the first time either one changes.\n */\nexport const layoutBehavior = {\n controlled: [],\n inputs: [\"hasHeader\", \"hasFooter\", \"sidebar\", \"skipLinkLabel\"],\n configuration: {\n \"sidebar.mode\": [\"persistent\", \"overlay\"],\n \"sidebar.role\": [\"navigation\", \"complementary\"],\n },\n stateAxes: {},\n web: {\n roles: [\"banner\", \"navigation\", \"complementary\", \"main\", \"contentinfo\"],\n keyboard: [\"Tab\"],\n focus: \"native\",\n },\n native: { roles: [], states: [], actions: [] },\n scenarios: [\n \"exactly-one-main-landmark-exists-per-layout\",\n \"web-skip-link-is-required-whenever-a-header-or-sidebar-precedes-main\",\n \"sidebar-role-navigation-or-complementary-is-chosen-independent-of-persistent-or-overlay-mode\",\n \"overlay-sidebar-reuses-sidepanel-open-state-and-dismiss-policy-unchanged\",\n \"header-and-footer-content-is-not-owned-here-compose-topbar-and-bottomnavigation\",\n \"skip-link-is-visually-hidden-until-keyboard-focus-reaches-it\",\n \"native-has-no-landmark-role-equivalent-translation-relies-on-order-and-accessibilityviewismodal\",\n ],\n} as const satisfies BehaviorContract;\n"]}
1
+ {"version":3,"file":"layout.js","sourceRoot":"","sources":["../src/layout.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ColorReference } from \"./color-references.js\";\nimport type { BehaviorContract } from \"./behaviors.js\";\nimport { focusIndicatorContract } from \"./component-contracts.js\";\nimport { layout as layoutFoundation, spacing } from \"./foundations.js\";\nimport { semanticColors } from \"./semantic-colors.js\";\n\n/**\n * `Layout` (alias `AppShell`) does NOT own header or footer chrome — that is\n * already `TopBar` (native, beta) and `BottomNavigation` (adaptive, beta).\n * What is left after subtracting those: ordered regions, a sidebar that is\n * either always-visible chrome or a dismissible overlay, and Web-only\n * landmark composition (one `main` plus a required skip link whenever\n * repeated navigation precedes it). The overlay case reuses `SidePanel`\n * unchanged — see docs/layout.md for why this module does not redeclare\n * open/dismiss state.\n */\nexport type LayoutSidebarRole = \"navigation\" | \"complementary\";\nexport type LayoutSidebarMode = \"persistent\" | \"overlay\";\n\nexport type LayoutSidebarDescriptor = Readonly<{\n /** Primary site navigation vs. supplementary content (filters, related items) — independent of `mode`. */\n role: LayoutSidebarRole;\n /** `persistent`: always-visible landmark. `overlay`: a `SidePanel` — Layout does not re-contract its open/dismiss lifecycle. */\n mode: LayoutSidebarMode;\n label: string;\n}>;\n\nexport type LayoutDescriptor = Readonly<{\n hasHeader?: boolean;\n hasFooter?: boolean;\n sidebar?: LayoutSidebarDescriptor;\n /** Web-only: required whenever a header or sidebar precedes `main` (WCAG 2.4.1 bypass blocks). */\n skipLinkLabel?: string;\n}>;\n\nfunction assertNonEmpty(value: string, field: string): void {\n if (typeof value !== \"string\" || value.trim().length === 0) {\n throw new TypeError(`Layout ${field} must not be empty`);\n }\n}\n\n/**\n * Cross-platform structure validation. This deliberately does not require a\n * skip link: Native has no page-landmark or bypass-link equivalent.\n */\nexport function validateLayoutRegions(descriptor: LayoutDescriptor): void {\n if (descriptor.sidebar !== undefined) {\n const { role, mode, label } = descriptor.sidebar;\n if (role !== \"navigation\" && role !== \"complementary\") {\n throw new TypeError(`Unsupported Layout sidebar role: ${String(role)}`);\n }\n if (mode !== \"persistent\" && mode !== \"overlay\") {\n throw new TypeError(`Unsupported Layout sidebar mode: ${String(mode)}`);\n }\n assertNonEmpty(label, \"sidebar.label\");\n }\n if (descriptor.skipLinkLabel !== undefined) {\n assertNonEmpty(descriptor.skipLinkLabel, \"skipLinkLabel\");\n }\n}\n\n/** Web landmark validation, including the WCAG 2.4.1 bypass-link invariant. */\nexport function validateLayoutWebDescriptor(descriptor: LayoutDescriptor): void {\n validateLayoutRegions(descriptor);\n const needsSkipLink = descriptor.hasHeader === true || descriptor.sidebar !== undefined;\n if (needsSkipLink && descriptor.skipLinkLabel === undefined) {\n throw new TypeError(\n \"Layout requires skipLinkLabel when a header or sidebar region precedes main\",\n );\n }\n}\n\nexport type LayoutLandmarkRole =\n | \"banner\"\n | \"navigation\"\n | \"complementary\"\n | \"main\"\n | \"contentinfo\";\n\n/**\n * Web-only translation: real landmark elements exist there. Native has no\n * landmark-role equivalent at all (`accessibilityRole` covers headings and\n * controls, not page regions) — RN renderers instead rely on visual/DOM\n * order plus `accessibilityViewIsModal` for the overlay sidebar case. That\n * asymmetry is documented, not papered over with a fake mapping.\n */\nexport function resolveLayoutWebLandmarks(\n descriptor: LayoutDescriptor,\n): readonly LayoutLandmarkRole[] {\n validateLayoutWebDescriptor(descriptor);\n const roles: LayoutLandmarkRole[] = [];\n if (descriptor.hasHeader) roles.push(\"banner\");\n if (descriptor.sidebar) roles.push(descriptor.sidebar.role);\n roles.push(\"main\");\n if (descriptor.hasFooter) roles.push(\"contentinfo\");\n return roles;\n}\n\n/**\n * Skip link is hidden until it matters — visible only on keyboard focus.\n * A skip link visible at rest fights identity.md's \"조용한 화면 위에 중요한\n * 순간만 선명하게\": for a mouse/touch user it is noise every screen, for a\n * keyboard user it is the first landmark on the page.\n */\nexport const layoutRecipe = {\n slots: [\"root\", \"skipLink\", \"header\", \"sidebar\", \"main\", \"footer\"] as const,\n defaults: {},\n main: {\n maxWidth: layoutFoundation.contentMaxWidth,\n paddingHorizontal: layoutFoundation.pagePadding.regular,\n },\n sidebar: {\n width: 280,\n },\n skipLink: {\n visibility: \"focus-only\",\n background: semanticColors.action.brand.background,\n color: semanticColors.action.brand.content,\n paddingHorizontal: spacing.md,\n paddingVertical: spacing.sm,\n },\n states: { focus: focusIndicatorContract },\n} as const satisfies {\n slots: readonly [\"root\", \"skipLink\", \"header\", \"sidebar\", \"main\", \"footer\"];\n defaults: Record<string, never>;\n main: { maxWidth: number; paddingHorizontal: number };\n sidebar: { width: number };\n skipLink: {\n visibility: \"focus-only\";\n background: ColorReference;\n color: ColorReference;\n paddingHorizontal: number;\n paddingVertical: number;\n };\n states: { focus: typeof focusIndicatorContract };\n};\n\n/**\n * `controlled: []` on purpose: an overlay sidebar's open/dismiss lifecycle\n * is a `SidePanel` (`src/side-panel.ts`) composed as-is. Redeclaring\n * `open`/`defaultOpen`/`onOpenChange`/`dismissPolicy` here would be the same\n * mistake DataTable avoided with Pagination/LoadMore — two places owning\n * one piece of state that will drift the first time either one changes.\n */\nexport const layoutBehavior = {\n controlled: [],\n inputs: [\"hasHeader\", \"hasFooter\", \"sidebar\", \"skipLinkLabel\"],\n configuration: {\n \"sidebar.mode\": [\"persistent\", \"overlay\"],\n \"sidebar.role\": [\"navigation\", \"complementary\"],\n },\n stateAxes: {},\n web: {\n roles: [\"banner\", \"navigation\", \"complementary\", \"main\", \"contentinfo\"],\n keyboard: [\"Tab\"],\n focus: \"native\",\n },\n native: { roles: [], states: [], actions: [] },\n scenarios: [\n \"exactly-one-main-landmark-exists-per-layout\",\n \"web-skip-link-is-required-whenever-a-header-or-sidebar-precedes-main\",\n \"sidebar-role-navigation-or-complementary-is-chosen-independent-of-persistent-or-overlay-mode\",\n \"overlay-sidebar-reuses-sidepanel-open-state-and-dismiss-policy-unchanged\",\n \"header-and-footer-content-is-not-owned-here-compose-topbar-and-bottomnavigation\",\n \"skip-link-is-visually-hidden-until-keyboard-focus-reaches-it\",\n \"native-has-no-landmark-role-equivalent-translation-relies-on-order-and-accessibilityviewismodal\",\n ],\n} as const satisfies BehaviorContract;\n"]}
@@ -149,4 +149,6 @@ export declare const otpFieldBehavior: {
149
149
  };
150
150
  readonly scenarios: readonly ["one-accessible-name-and-value-for-the-whole-field-never-per-slot-announcement", "one-tab-stop-native-text-editing-owns-typing-backspacing-and-paste", "paste-anywhere-in-the-value-is-sanitized-to-digits-and-clamped-to-length", "non-digit-characters-are-stripped-not-rejected-outright", "resolveOtpFieldValue-truncates-typed-or-pasted-overflow-instead-of-throwing", "a-too-long-committed-descriptor-still-throws-as-malformed-state", "alphanumeric-otp-is-out-of-scope-until-a-real-product-need-exists"];
151
151
  };
152
+ /** Visual slots only; all presentations retain one real platform input. */
153
+ export type OtpFieldPresentation = "boxes" | "underline";
152
154
  //# sourceMappingURL=otp-field.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"otp-field.d.ts","sourceRoot":"","sources":["../src/otp-field.ts"],"names":[],"mappings":"AAUA;;;;;GAKG;AACH,MAAM,MAAM,kBAAkB,GAAG,QAAQ,CAAC;IACxC,0LAA0L;IAC1L,MAAM,EAAE,MAAM,CAAC;IACf,yHAAyH;IACzH,KAAK,EAAE,MAAM,CAAC;CACf,CAAC,CAAC;AAEH,wBAAgB,0BAA0B,CAAC,UAAU,EAAE,kBAAkB,GAAG,IAAI,CAU/E;AAED,0GAA0G;AAC1G,wBAAgB,qBAAqB,CACnC,UAAU,EAAE,kBAAkB,GAC7B,SAAS,MAAM,EAAE,CAGnB;AAED,MAAM,MAAM,0BAA0B,GAAG,kBAAkB,GACzD,QAAQ,CAAC;IACP,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IACzB,QAAQ,EAAE,OAAO,CAAC;CACnB,CAAC,CAAC;AAEL,wBAAgB,yBAAyB,CACvC,UAAU,EAAE,kBAAkB,GAC7B,0BAA0B,CAO5B;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAQ5E;AAED,MAAM,MAAM,YAAY,GAAG,QAAQ,GAAG,OAAO,CAAC;AAE9C;;;;GAIG;AACH,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAkD1B,CAAC;AAEF,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;CA0BQ,CAAC"}
1
+ {"version":3,"file":"otp-field.d.ts","sourceRoot":"","sources":["../src/otp-field.ts"],"names":[],"mappings":"AAUA;;;;;GAKG;AACH,MAAM,MAAM,kBAAkB,GAAG,QAAQ,CAAC;IACxC,0LAA0L;IAC1L,MAAM,EAAE,MAAM,CAAC;IACf,yHAAyH;IACzH,KAAK,EAAE,MAAM,CAAC;CACf,CAAC,CAAC;AAEH,wBAAgB,0BAA0B,CAAC,UAAU,EAAE,kBAAkB,GAAG,IAAI,CAU/E;AAED,0GAA0G;AAC1G,wBAAgB,qBAAqB,CACnC,UAAU,EAAE,kBAAkB,GAC7B,SAAS,MAAM,EAAE,CAGnB;AAED,MAAM,MAAM,0BAA0B,GAAG,kBAAkB,GACzD,QAAQ,CAAC;IACP,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IACzB,QAAQ,EAAE,OAAO,CAAC;CACnB,CAAC,CAAC;AAEL,wBAAgB,yBAAyB,CACvC,UAAU,EAAE,kBAAkB,GAC7B,0BAA0B,CAO5B;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAQ5E;AAED,MAAM,MAAM,YAAY,GAAG,QAAQ,GAAG,OAAO,CAAC;AAE9C;;;;GAIG;AACH,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAkD1B,CAAC;AAEF,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;CA0BQ,CAAC;AAEtC,2EAA2E;AAC3E,MAAM,MAAM,oBAAoB,GAAG,OAAO,GAAG,WAAW,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"otp-field.js","sourceRoot":"","sources":["../src/otp-field.ts"],"names":[],"mappings":"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","sourcesContent":["import type { BehaviorContract } from \"./behaviors.js\";\nimport type { ColorReference } from \"./color-references.js\";\nimport {\n fieldFrameContract,\n focusIndicatorContract,\n formSupportContract,\n} from \"./component-contracts.js\";\nimport { control, opacity, spacing, type TextVariant } from \"./foundations.js\";\nimport { semanticColors } from \"./semantic-colors.js\";\n\n/**\n * Numeric-only, matching the domain the brief describes (인증번호). An\n * alphanumeric OTP is out of scope until a real product needs one — adding\n * a configurable character set now would mean guessing at a pattern nobody\n * has validated. See docs/otp-field.md.\n */\nexport type OtpFieldDescriptor = Readonly<{\n /** Number of visible slots. At least two — a single slot is not the multi-slot problem this component solves (Steps applies the same floor to its own step count for the same reason). */\n length: number;\n /** The one logical value, always dense — index i is filled iff i < value.length. Never sparse; see docs/otp-field.md. */\n value: string;\n}>;\n\nexport function validateOtpFieldDescriptor(descriptor: OtpFieldDescriptor): void {\n if (!Number.isInteger(descriptor.length) || descriptor.length < 2) {\n throw new RangeError(\"OtpField length must be an integer of at least two slots\");\n }\n if (typeof descriptor.value !== \"string\" || !/^\\d*$/.test(descriptor.value)) {\n throw new TypeError(\"OtpField value must be a string of digits only\");\n }\n if (descriptor.value.length > descriptor.length) {\n throw new RangeError(\"OtpField value must not be longer than length\");\n }\n}\n\n/** One entry per slot: the digit at that position, or \"\" for an unfilled slot. Always dense — no gaps. */\nexport function getOtpFieldSlotValues(\n descriptor: OtpFieldDescriptor,\n): readonly string[] {\n validateOtpFieldDescriptor(descriptor);\n return Array.from({ length: descriptor.length }, (_, index) => descriptor.value[index] ?? \"\");\n}\n\nexport type ResolvedOtpFieldDescriptor = OtpFieldDescriptor &\n Readonly<{\n slots: readonly string[];\n complete: boolean;\n }>;\n\nexport function resolveOtpFieldDescriptor(\n descriptor: OtpFieldDescriptor,\n): ResolvedOtpFieldDescriptor {\n validateOtpFieldDescriptor(descriptor);\n return {\n ...descriptor,\n slots: getOtpFieldSlotValues(descriptor),\n complete: descriptor.value.length === descriptor.length,\n };\n}\n\n/**\n * The single hard accessibility judgment this contract makes: OtpField is\n * ONE focusable, one accessible-name-and-value text control, not N separate\n * focusable slots. N separate real inputs is the well-documented\n * accessibility anti-pattern the brief names directly — a screen reader\n * announcing \"slot 3 of 6\" tells the user nothing about what they are\n * entering. The N visible boxes are a decorative rendering of one control's\n * characters (`getOtpFieldSlotValues`), the same way a styled `<input>` with\n * letter-spacing can look segmented while remaining one field. See\n * docs/otp-field.md.\n *\n * Because there is one real control, typing, backspacing, and pasting\n * (anywhere, including mid-string) are the platform's own native text\n * editing — insertion, deletion, and paste-over-a-selection are not\n * reimplemented here. The only judgment HJM owns is what happens to the\n * resulting raw string: keep digits only, never exceed `length`. This is\n * intentionally the one function this module needs for every edit path.\n */\nexport function resolveOtpFieldValue(length: number, rawText: string): string {\n if (!Number.isInteger(length) || length < 2) {\n throw new RangeError(\"OtpField length must be an integer of at least two slots\");\n }\n if (typeof rawText !== \"string\") {\n throw new TypeError(\"OtpField rawText must be a string\");\n }\n return rawText.replace(/\\D/g, \"\").slice(0, length);\n}\n\nexport type OtpFieldSize = \"medium\" | \"large\";\n\n/**\n * The `slot` boxes reuse Field's own border/focus/invalid colors\n * (`fieldFrameContract`) instead of inventing a new palette — each is a\n * small Field-frame look-alike, not a new visual language.\n */\nexport const otpFieldRecipe = {\n slots: [\"root\", \"input\", \"slot\", \"description\", \"error\"] as const,\n defaults: { size: \"medium\" },\n support: formSupportContract,\n sizes: {\n medium: {\n slotSize: control.minTouchTarget,\n gap: spacing.xs,\n textVariant: \"title\",\n },\n large: {\n slotSize: control.buttonHeight.large,\n gap: spacing.sm,\n textVariant: \"titleLarge\",\n },\n },\n slot: {\n border: fieldFrameContract.border,\n focusBorder: fieldFrameContract.focusBorder,\n invalidBorder: fieldFrameContract.invalidBorder,\n filledBorder: semanticColors.content.brand,\n radius: fieldFrameContract.radius,\n borderWidth: fieldFrameContract.borderWidth,\n content: semanticColors.content.primary,\n },\n states: {\n focus: focusIndicatorContract,\n disabledOpacity: opacity.disabled,\n },\n} as const satisfies {\n slots: readonly string[];\n defaults: { size: OtpFieldSize };\n support: typeof formSupportContract;\n sizes: Record<\n OtpFieldSize,\n { slotSize: number; gap: number; textVariant: TextVariant }\n >;\n slot: {\n border: ColorReference;\n focusBorder: ColorReference;\n invalidBorder: ColorReference;\n filledBorder: ColorReference;\n radius: typeof fieldFrameContract.radius;\n borderWidth: number;\n content: ColorReference;\n };\n states: {\n focus: typeof focusIndicatorContract;\n disabledOpacity: number;\n };\n};\n\nexport const otpFieldBehavior = {\n controlled: [\"value\", \"defaultValue\", \"onValueChange\"],\n stateAxes: {\n availability: [\"enabled\", \"disabled\", \"readOnly\", \"busy\"],\n value: [\"empty\", \"filled\"],\n validation: [\"valid\", \"invalid\"],\n },\n web: {\n roles: [\"textbox\"],\n keyboard: [\"Tab\", \"ArrowLeft\", \"ArrowRight\", \"Home\", \"End\"],\n focus: \"native\",\n },\n native: {\n roles: [\"text\"],\n states: [\"disabled\", \"busy\"],\n actions: [\"focus\", \"setText\"],\n },\n scenarios: [\n \"one-accessible-name-and-value-for-the-whole-field-never-per-slot-announcement\",\n \"one-tab-stop-native-text-editing-owns-typing-backspacing-and-paste\",\n \"paste-anywhere-in-the-value-is-sanitized-to-digits-and-clamped-to-length\",\n \"non-digit-characters-are-stripped-not-rejected-outright\",\n \"resolveOtpFieldValue-truncates-typed-or-pasted-overflow-instead-of-throwing\",\n \"a-too-long-committed-descriptor-still-throws-as-malformed-state\",\n \"alphanumeric-otp-is-out-of-scope-until-a-real-product-need-exists\",\n ],\n} as const satisfies BehaviorContract;\n"]}
1
+ {"version":3,"file":"otp-field.js","sourceRoot":"","sources":["../src/otp-field.ts"],"names":[],"mappings":"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","sourcesContent":["import type { BehaviorContract } from \"./behaviors.js\";\nimport type { ColorReference } from \"./color-references.js\";\nimport {\n fieldFrameContract,\n focusIndicatorContract,\n formSupportContract,\n} from \"./component-contracts.js\";\nimport { control, opacity, spacing, type TextVariant } from \"./foundations.js\";\nimport { semanticColors } from \"./semantic-colors.js\";\n\n/**\n * Numeric-only, matching the domain the brief describes (인증번호). An\n * alphanumeric OTP is out of scope until a real product needs one — adding\n * a configurable character set now would mean guessing at a pattern nobody\n * has validated. See docs/otp-field.md.\n */\nexport type OtpFieldDescriptor = Readonly<{\n /** Number of visible slots. At least two — a single slot is not the multi-slot problem this component solves (Steps applies the same floor to its own step count for the same reason). */\n length: number;\n /** The one logical value, always dense — index i is filled iff i < value.length. Never sparse; see docs/otp-field.md. */\n value: string;\n}>;\n\nexport function validateOtpFieldDescriptor(descriptor: OtpFieldDescriptor): void {\n if (!Number.isInteger(descriptor.length) || descriptor.length < 2) {\n throw new RangeError(\"OtpField length must be an integer of at least two slots\");\n }\n if (typeof descriptor.value !== \"string\" || !/^\\d*$/.test(descriptor.value)) {\n throw new TypeError(\"OtpField value must be a string of digits only\");\n }\n if (descriptor.value.length > descriptor.length) {\n throw new RangeError(\"OtpField value must not be longer than length\");\n }\n}\n\n/** One entry per slot: the digit at that position, or \"\" for an unfilled slot. Always dense — no gaps. */\nexport function getOtpFieldSlotValues(\n descriptor: OtpFieldDescriptor,\n): readonly string[] {\n validateOtpFieldDescriptor(descriptor);\n return Array.from({ length: descriptor.length }, (_, index) => descriptor.value[index] ?? \"\");\n}\n\nexport type ResolvedOtpFieldDescriptor = OtpFieldDescriptor &\n Readonly<{\n slots: readonly string[];\n complete: boolean;\n }>;\n\nexport function resolveOtpFieldDescriptor(\n descriptor: OtpFieldDescriptor,\n): ResolvedOtpFieldDescriptor {\n validateOtpFieldDescriptor(descriptor);\n return {\n ...descriptor,\n slots: getOtpFieldSlotValues(descriptor),\n complete: descriptor.value.length === descriptor.length,\n };\n}\n\n/**\n * The single hard accessibility judgment this contract makes: OtpField is\n * ONE focusable, one accessible-name-and-value text control, not N separate\n * focusable slots. N separate real inputs is the well-documented\n * accessibility anti-pattern the brief names directly — a screen reader\n * announcing \"slot 3 of 6\" tells the user nothing about what they are\n * entering. The N visible boxes are a decorative rendering of one control's\n * characters (`getOtpFieldSlotValues`), the same way a styled `<input>` with\n * letter-spacing can look segmented while remaining one field. See\n * docs/otp-field.md.\n *\n * Because there is one real control, typing, backspacing, and pasting\n * (anywhere, including mid-string) are the platform's own native text\n * editing — insertion, deletion, and paste-over-a-selection are not\n * reimplemented here. The only judgment HJM owns is what happens to the\n * resulting raw string: keep digits only, never exceed `length`. This is\n * intentionally the one function this module needs for every edit path.\n */\nexport function resolveOtpFieldValue(length: number, rawText: string): string {\n if (!Number.isInteger(length) || length < 2) {\n throw new RangeError(\"OtpField length must be an integer of at least two slots\");\n }\n if (typeof rawText !== \"string\") {\n throw new TypeError(\"OtpField rawText must be a string\");\n }\n return rawText.replace(/\\D/g, \"\").slice(0, length);\n}\n\nexport type OtpFieldSize = \"medium\" | \"large\";\n\n/**\n * The `slot` boxes reuse Field's own border/focus/invalid colors\n * (`fieldFrameContract`) instead of inventing a new palette — each is a\n * small Field-frame look-alike, not a new visual language.\n */\nexport const otpFieldRecipe = {\n slots: [\"root\", \"input\", \"slot\", \"description\", \"error\"] as const,\n defaults: { size: \"medium\" },\n support: formSupportContract,\n sizes: {\n medium: {\n slotSize: control.minTouchTarget,\n gap: spacing.xs,\n textVariant: \"title\",\n },\n large: {\n slotSize: control.buttonHeight.large,\n gap: spacing.sm,\n textVariant: \"titleLarge\",\n },\n },\n slot: {\n border: fieldFrameContract.border,\n focusBorder: fieldFrameContract.focusBorder,\n invalidBorder: fieldFrameContract.invalidBorder,\n filledBorder: semanticColors.content.brand,\n radius: fieldFrameContract.radius,\n borderWidth: fieldFrameContract.borderWidth,\n content: semanticColors.content.primary,\n },\n states: {\n focus: focusIndicatorContract,\n disabledOpacity: opacity.disabled,\n },\n} as const satisfies {\n slots: readonly string[];\n defaults: { size: OtpFieldSize };\n support: typeof formSupportContract;\n sizes: Record<\n OtpFieldSize,\n { slotSize: number; gap: number; textVariant: TextVariant }\n >;\n slot: {\n border: ColorReference;\n focusBorder: ColorReference;\n invalidBorder: ColorReference;\n filledBorder: ColorReference;\n radius: typeof fieldFrameContract.radius;\n borderWidth: number;\n content: ColorReference;\n };\n states: {\n focus: typeof focusIndicatorContract;\n disabledOpacity: number;\n };\n};\n\nexport const otpFieldBehavior = {\n controlled: [\"value\", \"defaultValue\", \"onValueChange\"],\n stateAxes: {\n availability: [\"enabled\", \"disabled\", \"readOnly\", \"busy\"],\n value: [\"empty\", \"filled\"],\n validation: [\"valid\", \"invalid\"],\n },\n web: {\n roles: [\"textbox\"],\n keyboard: [\"Tab\", \"ArrowLeft\", \"ArrowRight\", \"Home\", \"End\"],\n focus: \"native\",\n },\n native: {\n roles: [\"text\"],\n states: [\"disabled\", \"busy\"],\n actions: [\"focus\", \"setText\"],\n },\n scenarios: [\n \"one-accessible-name-and-value-for-the-whole-field-never-per-slot-announcement\",\n \"one-tab-stop-native-text-editing-owns-typing-backspacing-and-paste\",\n \"paste-anywhere-in-the-value-is-sanitized-to-digits-and-clamped-to-length\",\n \"non-digit-characters-are-stripped-not-rejected-outright\",\n \"resolveOtpFieldValue-truncates-typed-or-pasted-overflow-instead-of-throwing\",\n \"a-too-long-committed-descriptor-still-throws-as-malformed-state\",\n \"alphanumeric-otp-is-out-of-scope-until-a-real-product-need-exists\",\n ],\n} as const satisfies BehaviorContract;\n\n/** Visual slots only; all presentations retain one real platform input. */\nexport type OtpFieldPresentation = \"boxes\" | \"underline\";\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"popover.d.ts","sourceRoot":"","sources":["../src/popover.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,gBAAgB,GAAG,KAAK,GAAG,QAAQ,GAAG,OAAO,GAAG,KAAK,CAAC;AAClE,MAAM,MAAM,YAAY,GAAG,OAAO,GAAG,QAAQ,GAAG,KAAK,CAAC;AAEtD;;;;;;;GAOG;AACH,MAAM,MAAM,oBAAoB,GAC5B,cAAc,GACd,iBAAiB,GACjB,eAAe,GACf,QAAQ,GACR,cAAc,CAAC;AAEnB;;;;;GAKG;AACH,MAAM,MAAM,uBAAuB,GAAG,SAAS,GAAG,oBAAoB,CAAC;AAEvE,MAAM,MAAM,wBAAwB,GAAG,QAAQ,CAAC;IAC9C,MAAM,EAAE,uBAAuB,CAAC;CACjC,CAAC,CAAC;AAEH,MAAM,MAAM,iBAAiB,GAAG,QAAQ,CAAC;IACvC,SAAS,CAAC,EAAE,gBAAgB,CAAC;IAC7B,KAAK,CAAC,EAAE,YAAY,CAAC;IACrB;;;OAGG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B,CAAC,CAAC;AAEH,MAAM,MAAM,yBAAyB,GAAG,QAAQ,CAAC;IAC/C,SAAS,EAAE,gBAAgB,CAAC;IAC5B,KAAK,EAAE,YAAY,CAAC;IACpB,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B,CAAC,CAAC;AAEH,eAAO,MAAM,yBAAyB;;;CAG6C,CAAC;AAEpF;;;;;;GAMG;AACH,MAAM,MAAM,oBAAoB,GAAG,QAAQ,CAAC;IAC1C,WAAW,EAAE,OAAO,CAAC;IACrB,cAAc,EAAE,OAAO,CAAC;IACxB,aAAa,EAAE,OAAO,CAAC;IACvB,eAAe,EAAE,OAAO,CAAC;CAC1B,CAAC,CAAC;AAEH;;;;;;;;GAQG;AACH,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,OAAO,CAAC;AAE9C,eAAO,MAAM,uBAAuB;qBACf,aAAa;;;;;CAK6C,CAAC;AAEhF,+CAA+C;AAC/C,eAAO,MAAM,iBAAiB;;;CAAqC,CAAC;AAEpE,MAAM,MAAM,0BAA0B,GAAG,QAAQ,CAAC;IAChD,IAAI,EAAE,OAAO,CAAC;IACd,WAAW,CAAC,EAAE,KAAK,CAAC;IACpB,YAAY,CAAC,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,wBAAwB,GAAG,IAAI,CAAC;CACtE,CAAC,CAAC;AAEH,MAAM,MAAM,4BAA4B,GAAG,QAAQ,CAAC;IAClD,IAAI,CAAC,EAAE,KAAK,CAAC;IACb,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,YAAY,CAAC,EAAE,CACb,IAAI,EAAE,OAAO,EACb,OAAO,EAAE,wBAAwB,KAC9B,IAAI,CAAC;CACX,CAAC,CAAC;AAEH,MAAM,MAAM,gBAAgB,GACxB,0BAA0B,GAC1B,4BAA4B,CAAC;AAEjC,6FAA6F;AAC7F,MAAM,MAAM,oBAAoB,GAAG,gBAAgB,CAAC,cAAc,CAAC,CAAC;AAuBpE,wBAAgB,yBAAyB,CAAC,UAAU,EAAE,iBAAiB,GAAG,IAAI,CA6B7E;AAED,wBAAgB,wBAAwB,CACtC,UAAU,EAAE,iBAAiB,GAC5B,yBAAyB,CAS3B;AAED,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,gBAAgB,GAAG,IAAI,CAgCtE;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,oBAAoB,EAC5B,MAAM,GAAE,oBAA8C,GACrD,OAAO,CAOT;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAkBzB,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,wBAAwB,qgBAW3B,CAAC"}
1
+ {"version":3,"file":"popover.d.ts","sourceRoot":"","sources":["../src/popover.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,gBAAgB,GAAG,KAAK,GAAG,QAAQ,GAAG,OAAO,GAAG,KAAK,CAAC;AAClE,MAAM,MAAM,YAAY,GAAG,OAAO,GAAG,QAAQ,GAAG,KAAK,CAAC;AAEtD;;;;;;;GAOG;AACH,MAAM,MAAM,oBAAoB,GAC5B,cAAc,GACd,iBAAiB,GACjB,eAAe,GACf,QAAQ,GACR,cAAc,CAAC;AAEnB;;;;;GAKG;AACH,MAAM,MAAM,uBAAuB,GAAG,SAAS,GAAG,oBAAoB,CAAC;AAEvE,MAAM,MAAM,wBAAwB,GAAG,QAAQ,CAAC;IAC9C,MAAM,EAAE,uBAAuB,CAAC;CACjC,CAAC,CAAC;AAEH,MAAM,MAAM,iBAAiB,GAAG,QAAQ,CAAC;IACvC,SAAS,CAAC,EAAE,gBAAgB,CAAC;IAC7B,KAAK,CAAC,EAAE,YAAY,CAAC;IACrB;;;OAGG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B,CAAC,CAAC;AAEH,MAAM,MAAM,yBAAyB,GAAG,QAAQ,CAAC;IAC/C,SAAS,EAAE,gBAAgB,CAAC;IAC5B,KAAK,EAAE,YAAY,CAAC;IACpB,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B,CAAC,CAAC;AAEH,eAAO,MAAM,yBAAyB;;;CAG6C,CAAC;AAEpF;;;;;;GAMG;AACH,MAAM,MAAM,oBAAoB,GAAG,QAAQ,CAAC;IAC1C,WAAW,EAAE,OAAO,CAAC;IACrB,cAAc,EAAE,OAAO,CAAC;IACxB,aAAa,EAAE,OAAO,CAAC;IACvB,eAAe,EAAE,OAAO,CAAC;CAC1B,CAAC,CAAC;AAEH;;;;;;;;GAQG;AACH,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,OAAO,CAAC;AAE9C,eAAO,MAAM,uBAAuB;qBACf,aAAa;;;;;CAK6C,CAAC;AAEhF,+CAA+C;AAC/C,eAAO,MAAM,iBAAiB;;;CAAqC,CAAC;AAEpE,MAAM,MAAM,0BAA0B,GAAG,QAAQ,CAAC;IAChD,IAAI,EAAE,OAAO,CAAC;IACd,WAAW,CAAC,EAAE,KAAK,CAAC;IACpB,YAAY,CAAC,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,wBAAwB,GAAG,IAAI,CAAC;CACtE,CAAC,CAAC;AAEH,MAAM,MAAM,4BAA4B,GAAG,QAAQ,CAAC;IAClD,IAAI,CAAC,EAAE,KAAK,CAAC;IACb,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,YAAY,CAAC,EAAE,CACb,IAAI,EAAE,OAAO,EACb,OAAO,EAAE,wBAAwB,KAC9B,IAAI,CAAC;CACX,CAAC,CAAC;AAEH,MAAM,MAAM,gBAAgB,GACxB,0BAA0B,GAC1B,4BAA4B,CAAC;AAEjC,6FAA6F;AAC7F,MAAM,MAAM,oBAAoB,GAAG,gBAAgB,CAAC,cAAc,CAAC,CAAC;AAOpE,wBAAgB,yBAAyB,CAAC,UAAU,EAAE,iBAAiB,GAAG,IAAI,CA6B7E;AAED,wBAAgB,wBAAwB,CACtC,UAAU,EAAE,iBAAiB,GAC5B,yBAAyB,CAS3B;AAED,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,gBAAgB,GAAG,IAAI,CAgCtE;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,oBAAoB,EAC5B,MAAM,GAAE,oBAA8C,GACrD,OAAO,CAOT;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAkBzB,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,wBAAwB,qgBAW3B,CAAC"}
package/dist/popover.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { isObject, rejectUnknownKeys } from "./internal/object-validation.js";
1
2
  import { floatingSurfaceContract } from "./component-contracts.js";
2
3
  import { motionPreset, spacing } from "./foundations.js";
3
4
  export const popoverDescriptorDefaults = {
@@ -17,21 +18,11 @@ const placements = new Set(["top", "bottom", "start", "end"]);
17
18
  const alignments = new Set(["start", "center", "end"]);
18
19
  const descriptorKeys = new Set(["placement", "align", "accessibilityLabel"]);
19
20
  const openStateKeys = new Set(["open", "defaultOpen", "onOpenChange"]);
20
- function isObject(value) {
21
- return value !== null && typeof value === "object" && !Array.isArray(value);
22
- }
23
- function rejectUnknownKeys(value, allowed, field) {
24
- for (const key of Object.keys(value)) {
25
- if (!allowed.has(key)) {
26
- throw new TypeError(`Unsupported Popover ${field} field: ${key}`);
27
- }
28
- }
29
- }
30
21
  export function validatePopoverDescriptor(descriptor) {
31
22
  if (!isObject(descriptor)) {
32
23
  throw new TypeError("Popover descriptor must be an object");
33
24
  }
34
- rejectUnknownKeys(descriptor, descriptorKeys, "descriptor");
25
+ rejectUnknownKeys(descriptor, descriptorKeys, "descriptor", "Popover");
35
26
  if (descriptor.placement !== undefined &&
36
27
  !placements.has(descriptor.placement)) {
37
28
  throw new TypeError(`Unsupported Popover placement: ${String(descriptor.placement)}`);
@@ -63,7 +54,7 @@ export function validatePopoverOpenState(state) {
63
54
  if (!isObject(state)) {
64
55
  throw new TypeError("Popover open state must be an object");
65
56
  }
66
- rejectUnknownKeys(state, openStateKeys, "open state");
57
+ rejectUnknownKeys(state, openStateKeys, "open state", "Popover");
67
58
  const runtime = state;
68
59
  const hasOpen = Object.prototype.hasOwnProperty.call(runtime, "open");
69
60
  const hasDefaultOpen = Object.prototype.hasOwnProperty.call(runtime, "defaultOpen");
@@ -1 +1 @@
1
- {"version":3,"file":"popover.js","sourceRoot":"","sources":["../src/popover.ts"],"names":[],"mappings":"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","sourcesContent":["import { floatingSurfaceContract } from \"./component-contracts.js\";\nimport { motionPreset, spacing } from \"./foundations.js\";\n\n/**\n * Popover is the third corner of a triangle with Tooltip and Menu — all three\n * are \"a floating surface anchored to a trigger.\" Tooltip is explicitly\n * plain-text and never receives focus (docs/tooltip.md: \"interactive\n * Popover로 확장하지 않는다\"). Menu is a collection of actionable items with\n * its own role/keyboard table (behaviorRegistry.menu). Popover is what is left:\n * arbitrary *interactive* content (a small form, rich text with a link, a\n * mixed layout) that is neither a single plain sentence nor an item list.\n * Focus entering the surface is the decisive, testable difference from\n * Tooltip — everything else here (dismiss reasons, non-modal posture) follows\n * from that one fact.\n */\nexport type PopoverPlacement = \"top\" | \"bottom\" | \"start\" | \"end\";\nexport type PopoverAlign = \"start\" | \"center\" | \"end\";\n\n/**\n * Popover is non-modal: it does not trap focus like Dialog/Sheet and does not\n * block the rest of the page. So its dismiss vocabulary is deliberately\n * narrower than SheetDismissReason — no \"back\" or \"swipe\" (this is a web-only\n * surface), but it adds \"outside-focus\" because, unlike a modal, Tab can\n * legitimately carry focus out of a non-modal surface and that departure is\n * itself a dismiss signal distinct from a pointer click outside.\n */\nexport type PopoverDismissReason =\n | \"close-action\"\n | \"outside-pointer\"\n | \"outside-focus\"\n | \"escape\"\n | \"programmatic\";\n\n/**\n * 여는 사유는 `\"trigger\"`다. Sheet·SidePanel·CommandPalette가 모두 이 이름을 쓰고,\n * `\"trigger-activation\"`은 `src/tooltip.ts`에서 **닫는** 사유(열려 있는 툴팁의\n * 트리거를 눌러 닫는다)로 이미 쓰이고 있다. 한 문자열이 여는 뜻과 닫는 뜻을 겸하면\n * 렌더러가 조용히 반대로 처리한다 — 컴파일러는 둘 다 유효한 문자열로만 본다.\n */\nexport type PopoverOpenChangeReason = \"trigger\" | PopoverDismissReason;\n\nexport type PopoverOpenChangeDetails = Readonly<{\n reason: PopoverOpenChangeReason;\n}>;\n\nexport type PopoverDescriptor = Readonly<{\n placement?: PopoverPlacement;\n align?: PopoverAlign;\n /**\n * Optional explicit accessible name. A renderer must connect its visible\n * heading with aria-labelledby; a heading alone does not name a dialog.\n */\n accessibilityLabel?: string;\n}>;\n\nexport type ResolvedPopoverDescriptor = Readonly<{\n placement: PopoverPlacement;\n align: PopoverAlign;\n accessibilityLabel?: string;\n}>;\n\nexport const popoverDescriptorDefaults = {\n placement: \"bottom\",\n align: \"start\",\n} as const satisfies Readonly<{ placement: PopoverPlacement; align: PopoverAlign }>;\n\n/**\n * A controlled owner's programmatic close always wins, exactly like\n * SheetDismissPolicy/canDismissSheet. Popover has no `busy` axis: unlike\n * Sheet/AlertDialog it is not modal, so there is no global \"block every\n * dismiss\" state to defend — a form inside the content that wants to ignore\n * Escape while submitting makes that call itself, at the content level.\n */\nexport type PopoverDismissPolicy = Readonly<{\n dismissible: boolean;\n outsideDismiss: boolean;\n escapeDismiss: boolean;\n focusOutDismiss: boolean;\n}>;\n\n/**\n * 무엇이 popover를 여는가. `press`가 기본이고 `hover`는 포인터의 추가 진입\n * 방식이다. hover를 켜도 press 경로를 유지해야 키보드·터치 사용자가 같은\n * 콘텐츠에 도달할 수 있다.\n *\n * 별도 HoverCard는 검토했지만 표면·초점·dismiss·충돌 회피 계약은 같고 여는\n * 방식만 하나 더하는 것이므로 컴포넌트를 나누지 않는다. hover는 지나가는 포인터에\n * 바로 반응하지 않도록 지연되며, click/키보드/터치 경로를 대체하지 않는다.\n */\nexport type PopoverOpenOn = \"press\" | \"hover\";\n\nexport const popoverBehaviorDefaults = {\n openOn: \"press\" as PopoverOpenOn,\n dismissible: true,\n outsideDismiss: true,\n escapeDismiss: true,\n focusOutDismiss: true,\n} as const satisfies PopoverDismissPolicy & Readonly<{ openOn: PopoverOpenOn }>;\n\n/** hover로 열 때의 지연. 지나가는 포인터마다 열리면 화면이 깜빡인다. */\nexport const popoverHoverDelay = { open: 300, close: 150 } as const;\n\nexport type ControlledPopoverOpenState = Readonly<{\n open: boolean;\n defaultOpen?: never;\n onOpenChange(open: boolean, details: PopoverOpenChangeDetails): void;\n}>;\n\nexport type UncontrolledPopoverOpenState = Readonly<{\n open?: never;\n defaultOpen?: boolean;\n onOpenChange?: (\n open: boolean,\n details: PopoverOpenChangeDetails,\n ) => void;\n}>;\n\nexport type PopoverOpenState =\n | ControlledPopoverOpenState\n | UncontrolledPopoverOpenState;\n\n/** Products own what page-change caused this; Popover only needs \"did it happen and how.\" */\nexport type PopoverChangeHandler = PopoverOpenState[\"onOpenChange\"];\n\nconst placements = new Set<PopoverPlacement>([\"top\", \"bottom\", \"start\", \"end\"]);\nconst alignments = new Set<PopoverAlign>([\"start\", \"center\", \"end\"]);\nconst descriptorKeys = new Set([\"placement\", \"align\", \"accessibilityLabel\"]);\nconst openStateKeys = new Set([\"open\", \"defaultOpen\", \"onOpenChange\"]);\n\nfunction isObject(value: unknown): value is Readonly<Record<string, unknown>> {\n return value !== null && typeof value === \"object\" && !Array.isArray(value);\n}\n\nfunction rejectUnknownKeys(\n value: Readonly<Record<string, unknown>>,\n allowed: ReadonlySet<string>,\n field: string,\n): void {\n for (const key of Object.keys(value)) {\n if (!allowed.has(key)) {\n throw new TypeError(`Unsupported Popover ${field} field: ${key}`);\n }\n }\n}\n\nexport function validatePopoverDescriptor(descriptor: PopoverDescriptor): void {\n if (!isObject(descriptor)) {\n throw new TypeError(\"Popover descriptor must be an object\");\n }\n rejectUnknownKeys(descriptor, descriptorKeys, \"descriptor\");\n if (\n descriptor.placement !== undefined &&\n !placements.has(descriptor.placement)\n ) {\n throw new TypeError(\n `Unsupported Popover placement: ${String(descriptor.placement)}`,\n );\n }\n if (descriptor.align !== undefined && !alignments.has(descriptor.align)) {\n throw new TypeError(`Unsupported Popover align: ${String(descriptor.align)}`);\n }\n if (descriptor.accessibilityLabel !== undefined) {\n if (\n typeof descriptor.accessibilityLabel !== \"string\" ||\n descriptor.accessibilityLabel.trim().length === 0\n ) {\n throw new TypeError(\"Popover accessibilityLabel must not be empty\");\n }\n if (descriptor.accessibilityLabel !== descriptor.accessibilityLabel.trim()) {\n throw new TypeError(\n \"Popover accessibilityLabel must not start or end with whitespace\",\n );\n }\n }\n}\n\nexport function resolvePopoverDescriptor(\n descriptor: PopoverDescriptor,\n): ResolvedPopoverDescriptor {\n validatePopoverDescriptor(descriptor);\n return {\n placement: descriptor.placement ?? popoverDescriptorDefaults.placement,\n align: descriptor.align ?? popoverDescriptorDefaults.align,\n ...(descriptor.accessibilityLabel !== undefined\n ? { accessibilityLabel: descriptor.accessibilityLabel }\n : {}),\n };\n}\n\nexport function validatePopoverOpenState(state: PopoverOpenState): void {\n if (!isObject(state)) {\n throw new TypeError(\"Popover open state must be an object\");\n }\n rejectUnknownKeys(state, openStateKeys, \"open state\");\n const runtime = state as Readonly<Record<string, unknown>>;\n const hasOpen = Object.prototype.hasOwnProperty.call(runtime, \"open\");\n const hasDefaultOpen = Object.prototype.hasOwnProperty.call(\n runtime,\n \"defaultOpen\",\n );\n if (hasOpen) {\n if (typeof runtime.open !== \"boolean\") {\n throw new TypeError(\"Popover open must be a boolean\");\n }\n if (hasDefaultOpen) {\n throw new TypeError(\"Controlled Popover must not provide defaultOpen\");\n }\n if (typeof runtime.onOpenChange !== \"function\") {\n throw new TypeError(\"Controlled Popover must provide onOpenChange\");\n }\n return;\n }\n if (hasDefaultOpen && typeof runtime.defaultOpen !== \"boolean\") {\n throw new TypeError(\"Popover defaultOpen must be a boolean\");\n }\n if (\n runtime.onOpenChange !== undefined &&\n typeof runtime.onOpenChange !== \"function\"\n ) {\n throw new TypeError(\"Popover onOpenChange must be a function\");\n }\n}\n\n/**\n * Resolves an attempted close without platform knowledge, mirroring\n * canDismissSheet. Programmatic close is always an owner override.\n */\nexport function canDismissPopover(\n reason: PopoverDismissReason,\n policy: PopoverDismissPolicy = popoverBehaviorDefaults,\n): boolean {\n if (reason === \"programmatic\") return true;\n if (!policy.dismissible) return false;\n if (reason === \"outside-pointer\") return policy.outsideDismiss;\n if (reason === \"outside-focus\") return policy.focusOutDismiss;\n if (reason === \"escape\") return policy.escapeDismiss;\n return true;\n}\n\n/**\n * Positioning boundary is identical to Tooltip's: HJM owns preferred\n * placement, spacing, and motion; DOM measurement, portal, flip/shift, and\n * RTL logical-to-physical translation stay in the product Web renderer's\n * private AnchoredOverlay (see docs/tooltip.md \"Positioning boundary\"). This\n * module never exposes that internal tool, so Popover cannot regress Tooltip's\n * \"no public collision/portal API\" boundary.\n */\nexport const popoverRecipe = {\n slots: [\"trigger\", \"content\", \"arrow\", \"closeAction\"] as const,\n surface: floatingSurfaceContract,\n arrow: { size: spacing.xxs, offset: spacing.xxs },\n sideOffset: spacing.xs,\n collisionPadding: spacing.xs,\n minWidth: 240,\n maxWidth: 360,\n transition: { enter: motionPreset.enter, exit: motionPreset.exit },\n} as const satisfies {\n slots: readonly string[];\n surface: typeof floatingSurfaceContract;\n arrow: { size: number; offset: number };\n sideOffset: number;\n collisionPadding: number;\n minWidth: number;\n maxWidth: number;\n transition: { enter: typeof motionPreset.enter; exit: typeof motionPreset.exit };\n};\n\n/**\n * Literal scenario names for behaviorRegistry.popover (lead wires into\n * src/behaviors.ts). Kept here, not there, so this module stays self-contained\n * per the authoring brief.\n */\nexport const popoverBehaviorScenarios = [\n \"focus-enters-surface-on-open\",\n \"escape-closes-and-restores-trigger-focus\",\n \"outside-pointer-close-does-not-cancel-the-original-interaction\",\n \"tabbing-past-last-focusable-child-closes-without-trapping\",\n \"optional-hover-opens-after-delay-and-survives-pointer-crossing\",\n \"hover-mode-retains-press-activation-for-touch-and-keyboard\",\n \"controlled-owner-programmatic-close-always-wins\",\n \"close-action-inside-content-closes-exactly-once\",\n \"trigger-while-open-does-not-reopen\",\n \"one-visible-popover-per-trigger\",\n] as const;\n"]}
1
+ {"version":3,"file":"popover.js","sourceRoot":"","sources":["../src/popover.ts"],"names":[],"mappings":"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","sourcesContent":["import { isObject, rejectUnknownKeys } from \"./internal/object-validation.js\";\nimport { floatingSurfaceContract } from \"./component-contracts.js\";\nimport { motionPreset, spacing } from \"./foundations.js\";\n\n/**\n * Popover is the third corner of a triangle with Tooltip and Menu — all three\n * are \"a floating surface anchored to a trigger.\" Tooltip is explicitly\n * plain-text and never receives focus (docs/tooltip.md: \"interactive\n * Popover로 확장하지 않는다\"). Menu is a collection of actionable items with\n * its own role/keyboard table (behaviorRegistry.menu). Popover is what is left:\n * arbitrary *interactive* content (a small form, rich text with a link, a\n * mixed layout) that is neither a single plain sentence nor an item list.\n * Focus entering the surface is the decisive, testable difference from\n * Tooltip — everything else here (dismiss reasons, non-modal posture) follows\n * from that one fact.\n */\nexport type PopoverPlacement = \"top\" | \"bottom\" | \"start\" | \"end\";\nexport type PopoverAlign = \"start\" | \"center\" | \"end\";\n\n/**\n * Popover is non-modal: it does not trap focus like Dialog/Sheet and does not\n * block the rest of the page. So its dismiss vocabulary is deliberately\n * narrower than SheetDismissReason — no \"back\" or \"swipe\" (this is a web-only\n * surface), but it adds \"outside-focus\" because, unlike a modal, Tab can\n * legitimately carry focus out of a non-modal surface and that departure is\n * itself a dismiss signal distinct from a pointer click outside.\n */\nexport type PopoverDismissReason =\n | \"close-action\"\n | \"outside-pointer\"\n | \"outside-focus\"\n | \"escape\"\n | \"programmatic\";\n\n/**\n * 여는 사유는 `\"trigger\"`다. Sheet·SidePanel·CommandPalette가 모두 이 이름을 쓰고,\n * `\"trigger-activation\"`은 `src/tooltip.ts`에서 **닫는** 사유(열려 있는 툴팁의\n * 트리거를 눌러 닫는다)로 이미 쓰이고 있다. 한 문자열이 여는 뜻과 닫는 뜻을 겸하면\n * 렌더러가 조용히 반대로 처리한다 — 컴파일러는 둘 다 유효한 문자열로만 본다.\n */\nexport type PopoverOpenChangeReason = \"trigger\" | PopoverDismissReason;\n\nexport type PopoverOpenChangeDetails = Readonly<{\n reason: PopoverOpenChangeReason;\n}>;\n\nexport type PopoverDescriptor = Readonly<{\n placement?: PopoverPlacement;\n align?: PopoverAlign;\n /**\n * Optional explicit accessible name. A renderer must connect its visible\n * heading with aria-labelledby; a heading alone does not name a dialog.\n */\n accessibilityLabel?: string;\n}>;\n\nexport type ResolvedPopoverDescriptor = Readonly<{\n placement: PopoverPlacement;\n align: PopoverAlign;\n accessibilityLabel?: string;\n}>;\n\nexport const popoverDescriptorDefaults = {\n placement: \"bottom\",\n align: \"start\",\n} as const satisfies Readonly<{ placement: PopoverPlacement; align: PopoverAlign }>;\n\n/**\n * A controlled owner's programmatic close always wins, exactly like\n * SheetDismissPolicy/canDismissSheet. Popover has no `busy` axis: unlike\n * Sheet/AlertDialog it is not modal, so there is no global \"block every\n * dismiss\" state to defend — a form inside the content that wants to ignore\n * Escape while submitting makes that call itself, at the content level.\n */\nexport type PopoverDismissPolicy = Readonly<{\n dismissible: boolean;\n outsideDismiss: boolean;\n escapeDismiss: boolean;\n focusOutDismiss: boolean;\n}>;\n\n/**\n * 무엇이 popover를 여는가. `press`가 기본이고 `hover`는 포인터의 추가 진입\n * 방식이다. hover를 켜도 press 경로를 유지해야 키보드·터치 사용자가 같은\n * 콘텐츠에 도달할 수 있다.\n *\n * 별도 HoverCard는 검토했지만 표면·초점·dismiss·충돌 회피 계약은 같고 여는\n * 방식만 하나 더하는 것이므로 컴포넌트를 나누지 않는다. hover는 지나가는 포인터에\n * 바로 반응하지 않도록 지연되며, click/키보드/터치 경로를 대체하지 않는다.\n */\nexport type PopoverOpenOn = \"press\" | \"hover\";\n\nexport const popoverBehaviorDefaults = {\n openOn: \"press\" as PopoverOpenOn,\n dismissible: true,\n outsideDismiss: true,\n escapeDismiss: true,\n focusOutDismiss: true,\n} as const satisfies PopoverDismissPolicy & Readonly<{ openOn: PopoverOpenOn }>;\n\n/** hover로 열 때의 지연. 지나가는 포인터마다 열리면 화면이 깜빡인다. */\nexport const popoverHoverDelay = { open: 300, close: 150 } as const;\n\nexport type ControlledPopoverOpenState = Readonly<{\n open: boolean;\n defaultOpen?: never;\n onOpenChange(open: boolean, details: PopoverOpenChangeDetails): void;\n}>;\n\nexport type UncontrolledPopoverOpenState = Readonly<{\n open?: never;\n defaultOpen?: boolean;\n onOpenChange?: (\n open: boolean,\n details: PopoverOpenChangeDetails,\n ) => void;\n}>;\n\nexport type PopoverOpenState =\n | ControlledPopoverOpenState\n | UncontrolledPopoverOpenState;\n\n/** Products own what page-change caused this; Popover only needs \"did it happen and how.\" */\nexport type PopoverChangeHandler = PopoverOpenState[\"onOpenChange\"];\n\nconst placements = new Set<PopoverPlacement>([\"top\", \"bottom\", \"start\", \"end\"]);\nconst alignments = new Set<PopoverAlign>([\"start\", \"center\", \"end\"]);\nconst descriptorKeys = new Set([\"placement\", \"align\", \"accessibilityLabel\"]);\nconst openStateKeys = new Set([\"open\", \"defaultOpen\", \"onOpenChange\"]);\n\nexport function validatePopoverDescriptor(descriptor: PopoverDescriptor): void {\n if (!isObject(descriptor)) {\n throw new TypeError(\"Popover descriptor must be an object\");\n }\n rejectUnknownKeys(descriptor, descriptorKeys, \"descriptor\", \"Popover\");\n if (\n descriptor.placement !== undefined &&\n !placements.has(descriptor.placement)\n ) {\n throw new TypeError(\n `Unsupported Popover placement: ${String(descriptor.placement)}`,\n );\n }\n if (descriptor.align !== undefined && !alignments.has(descriptor.align)) {\n throw new TypeError(`Unsupported Popover align: ${String(descriptor.align)}`);\n }\n if (descriptor.accessibilityLabel !== undefined) {\n if (\n typeof descriptor.accessibilityLabel !== \"string\" ||\n descriptor.accessibilityLabel.trim().length === 0\n ) {\n throw new TypeError(\"Popover accessibilityLabel must not be empty\");\n }\n if (descriptor.accessibilityLabel !== descriptor.accessibilityLabel.trim()) {\n throw new TypeError(\n \"Popover accessibilityLabel must not start or end with whitespace\",\n );\n }\n }\n}\n\nexport function resolvePopoverDescriptor(\n descriptor: PopoverDescriptor,\n): ResolvedPopoverDescriptor {\n validatePopoverDescriptor(descriptor);\n return {\n placement: descriptor.placement ?? popoverDescriptorDefaults.placement,\n align: descriptor.align ?? popoverDescriptorDefaults.align,\n ...(descriptor.accessibilityLabel !== undefined\n ? { accessibilityLabel: descriptor.accessibilityLabel }\n : {}),\n };\n}\n\nexport function validatePopoverOpenState(state: PopoverOpenState): void {\n if (!isObject(state)) {\n throw new TypeError(\"Popover open state must be an object\");\n }\n rejectUnknownKeys(state, openStateKeys, \"open state\", \"Popover\");\n const runtime = state as Readonly<Record<string, unknown>>;\n const hasOpen = Object.prototype.hasOwnProperty.call(runtime, \"open\");\n const hasDefaultOpen = Object.prototype.hasOwnProperty.call(\n runtime,\n \"defaultOpen\",\n );\n if (hasOpen) {\n if (typeof runtime.open !== \"boolean\") {\n throw new TypeError(\"Popover open must be a boolean\");\n }\n if (hasDefaultOpen) {\n throw new TypeError(\"Controlled Popover must not provide defaultOpen\");\n }\n if (typeof runtime.onOpenChange !== \"function\") {\n throw new TypeError(\"Controlled Popover must provide onOpenChange\");\n }\n return;\n }\n if (hasDefaultOpen && typeof runtime.defaultOpen !== \"boolean\") {\n throw new TypeError(\"Popover defaultOpen must be a boolean\");\n }\n if (\n runtime.onOpenChange !== undefined &&\n typeof runtime.onOpenChange !== \"function\"\n ) {\n throw new TypeError(\"Popover onOpenChange must be a function\");\n }\n}\n\n/**\n * Resolves an attempted close without platform knowledge, mirroring\n * canDismissSheet. Programmatic close is always an owner override.\n */\nexport function canDismissPopover(\n reason: PopoverDismissReason,\n policy: PopoverDismissPolicy = popoverBehaviorDefaults,\n): boolean {\n if (reason === \"programmatic\") return true;\n if (!policy.dismissible) return false;\n if (reason === \"outside-pointer\") return policy.outsideDismiss;\n if (reason === \"outside-focus\") return policy.focusOutDismiss;\n if (reason === \"escape\") return policy.escapeDismiss;\n return true;\n}\n\n/**\n * Positioning boundary is identical to Tooltip's: HJM owns preferred\n * placement, spacing, and motion; DOM measurement, portal, flip/shift, and\n * RTL logical-to-physical translation stay in the product Web renderer's\n * private AnchoredOverlay (see docs/tooltip.md \"Positioning boundary\"). This\n * module never exposes that internal tool, so Popover cannot regress Tooltip's\n * \"no public collision/portal API\" boundary.\n */\nexport const popoverRecipe = {\n slots: [\"trigger\", \"content\", \"arrow\", \"closeAction\"] as const,\n surface: floatingSurfaceContract,\n arrow: { size: spacing.xxs, offset: spacing.xxs },\n sideOffset: spacing.xs,\n collisionPadding: spacing.xs,\n minWidth: 240,\n maxWidth: 360,\n transition: { enter: motionPreset.enter, exit: motionPreset.exit },\n} as const satisfies {\n slots: readonly string[];\n surface: typeof floatingSurfaceContract;\n arrow: { size: number; offset: number };\n sideOffset: number;\n collisionPadding: number;\n minWidth: number;\n maxWidth: number;\n transition: { enter: typeof motionPreset.enter; exit: typeof motionPreset.exit };\n};\n\n/**\n * Literal scenario names for behaviorRegistry.popover (lead wires into\n * src/behaviors.ts). Kept here, not there, so this module stays self-contained\n * per the authoring brief.\n */\nexport const popoverBehaviorScenarios = [\n \"focus-enters-surface-on-open\",\n \"escape-closes-and-restores-trigger-focus\",\n \"outside-pointer-close-does-not-cancel-the-original-interaction\",\n \"tabbing-past-last-focusable-child-closes-without-trapping\",\n \"optional-hover-opens-after-delay-and-survives-pointer-crossing\",\n \"hover-mode-retains-press-activation-for-touch-and-keyboard\",\n \"controlled-owner-programmatic-close-always-wins\",\n \"close-action-inside-content-closes-exactly-once\",\n \"trigger-while-open-does-not-reopen\",\n \"one-visible-popover-per-trigger\",\n] as const;\n"]}
@@ -0,0 +1,10 @@
1
+ export type ReactionOption = Readonly<{
2
+ id: string;
3
+ emoji: string;
4
+ label: string;
5
+ count?: number;
6
+ disabled?: boolean;
7
+ }>;
8
+ export declare function validateReactions(options: readonly ReactionOption[], value: string | null): void;
9
+ export declare function nextReaction(options: readonly ReactionOption[], current: string | null, id: string): string | null;
10
+ //# sourceMappingURL=reactions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reactions.d.ts","sourceRoot":"","sources":["../src/reactions.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,cAAc,GAAG,QAAQ,CAAC;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,CAAC;AACxH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,SAAS,cAAc,EAAE,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAOhG;AACD,wBAAgB,YAAY,CAAC,OAAO,EAAE,SAAS,cAAc,EAAE,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAKlH"}
@@ -0,0 +1,20 @@
1
+ export function validateReactions(options, value) {
2
+ if (!options.length || new Set(options.map(option => option.id)).size !== options.length)
3
+ throw new TypeError("Reactions require unique options");
4
+ for (const option of options) {
5
+ if (!option.id.trim() || !option.emoji.trim() || !option.label.trim())
6
+ throw new TypeError("Reactions require identifiers, artwork and localized names");
7
+ if (option.count !== undefined && (!Number.isSafeInteger(option.count) || option.count < 0))
8
+ throw new RangeError("Reaction count must be a nonnegative integer");
9
+ }
10
+ if (value !== null && !options.some(option => option.id === value))
11
+ throw new TypeError("Selected reaction is missing");
12
+ }
13
+ export function nextReaction(options, current, id) {
14
+ validateReactions(options, current);
15
+ const option = options.find(item => item.id === id);
16
+ if (!option)
17
+ throw new TypeError("Unknown reaction");
18
+ return option.disabled ? current : current === id ? null : id;
19
+ }
20
+ //# sourceMappingURL=reactions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reactions.js","sourceRoot":"","sources":["../src/reactions.ts"],"names":[],"mappings":"AACA,MAAM,UAAU,iBAAiB,CAAC,OAAkC,EAAE,KAAoB;IACxF,IAAI,CAAC,OAAO,CAAC,MAAM,IAAI,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,OAAO,CAAC,MAAM;QAAE,MAAM,IAAI,SAAS,CAAC,kCAAkC,CAAC,CAAC;IAClJ,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE;YAAE,MAAM,IAAI,SAAS,CAAC,4DAA4D,CAAC,CAAC;QACzJ,IAAI,MAAM,CAAC,KAAK,KAAK,SAAS,IAAI,CAAC,CAAC,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,MAAM,CAAC,KAAK,GAAG,CAAC,CAAC;YAAE,MAAM,IAAI,UAAU,CAAC,8CAA8C,CAAC,CAAC;IACpK,CAAC;IACD,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,KAAK,KAAK,CAAC;QAAE,MAAM,IAAI,SAAS,CAAC,8BAA8B,CAAC,CAAC;AAC1H,CAAC;AACD,MAAM,UAAU,YAAY,CAAC,OAAkC,EAAE,OAAsB,EAAE,EAAU;IACjG,iBAAiB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IACpC,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;IACpD,IAAI,CAAC,MAAM;QAAE,MAAM,IAAI,SAAS,CAAC,kBAAkB,CAAC,CAAC;IACrD,OAAO,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;AAChE,CAAC","sourcesContent":["export type ReactionOption = Readonly<{ id: string; emoji: string; label: string; count?: number; disabled?: boolean }>;\nexport function validateReactions(options: readonly ReactionOption[], value: string | null): void {\n if (!options.length || new Set(options.map(option => option.id)).size !== options.length) throw new TypeError(\"Reactions require unique options\");\n for (const option of options) {\n if (!option.id.trim() || !option.emoji.trim() || !option.label.trim()) throw new TypeError(\"Reactions require identifiers, artwork and localized names\");\n if (option.count !== undefined && (!Number.isSafeInteger(option.count) || option.count < 0)) throw new RangeError(\"Reaction count must be a nonnegative integer\");\n }\n if (value !== null && !options.some(option => option.id === value)) throw new TypeError(\"Selected reaction is missing\");\n}\nexport function nextReaction(options: readonly ReactionOption[], current: string | null, id: string): string | null {\n validateReactions(options, current);\n const option = options.find(item => item.id === id);\n if (!option) throw new TypeError(\"Unknown reaction\");\n return option.disabled ? current : current === id ? null : id;\n}\n"]}
@@ -0,0 +1,8 @@
1
+ /** Logical forward offset. Horizontal RTL hosts normalize their own scrollLeft. */
2
+ export type ScrollMetrics = Readonly<{
3
+ offset: number;
4
+ contentSize: number;
5
+ viewportSize: number;
6
+ }>;
7
+ export declare function resolveScrollProgress({ offset, contentSize, viewportSize }: ScrollMetrics): number;
8
+ //# sourceMappingURL=scroll-progress.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scroll-progress.d.ts","sourceRoot":"","sources":["../src/scroll-progress.ts"],"names":[],"mappings":"AAAA,mFAAmF;AACnF,MAAM,MAAM,aAAa,GAAG,QAAQ,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AACpG,wBAAgB,qBAAqB,CAAC,EAAC,MAAM,EAAC,WAAW,EAAC,YAAY,EAAC,EAAC,aAAa,GAAE,MAAM,CAM5F"}
@@ -0,0 +1,10 @@
1
+ export function resolveScrollProgress({ offset, contentSize, viewportSize }) {
2
+ if (![offset, contentSize, viewportSize].every(Number.isFinite) || contentSize < 0 || viewportSize < 0)
3
+ throw new RangeError('Scroll metrics must be finite with nonnegative sizes');
4
+ // Unmeasured hosts are not complete; content that fits a measured viewport is.
5
+ if (viewportSize === 0)
6
+ return 0;
7
+ const extent = contentSize - viewportSize;
8
+ return extent <= 0 ? 1 : Math.min(1, Math.max(0, offset / extent));
9
+ }
10
+ //# sourceMappingURL=scroll-progress.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scroll-progress.js","sourceRoot":"","sources":["../src/scroll-progress.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,qBAAqB,CAAC,EAAC,MAAM,EAAC,WAAW,EAAC,YAAY,EAAe;IACnF,IAAI,CAAC,CAAC,MAAM,EAAC,WAAW,EAAC,YAAY,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,WAAW,GAAG,CAAC,IAAI,YAAY,GAAG,CAAC;QAAE,MAAM,IAAI,UAAU,CAAC,sDAAsD,CAAC,CAAC;IACnL,+EAA+E;IAC/E,IAAI,YAAY,KAAK,CAAC;QAAE,OAAO,CAAC,CAAC;IACjC,MAAM,MAAM,GAAC,WAAW,GAAC,YAAY,CAAC;IACtC,OAAO,MAAM,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAC,MAAM,GAAC,MAAM,CAAC,CAAC,CAAC;AACjE,CAAC","sourcesContent":["/** Logical forward offset. Horizontal RTL hosts normalize their own scrollLeft. */\nexport type ScrollMetrics = Readonly<{ offset: number; contentSize: number; viewportSize: number }>;\nexport function resolveScrollProgress({offset,contentSize,viewportSize}:ScrollMetrics):number {\n if (![offset,contentSize,viewportSize].every(Number.isFinite) || contentSize < 0 || viewportSize < 0) throw new RangeError('Scroll metrics must be finite with nonnegative sizes');\n // Unmeasured hosts are not complete; content that fits a measured viewport is.\n if (viewportSize === 0) return 0;\n const extent=contentSize-viewportSize;\n return extent <= 0 ? 1 : Math.min(1,Math.max(0,offset/extent));\n}\n"]}
@@ -0,0 +1,7 @@
1
+ import { type SortableItem } from './interaction-adapters.js';
2
+ export type TaskItem = SortableItem & Readonly<{
3
+ completed: boolean;
4
+ description?: string;
5
+ }>;
6
+ export declare function validateTasks(items: readonly TaskItem[]): void;
7
+ //# sourceMappingURL=task-list.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"task-list.d.ts","sourceRoot":"","sources":["../src/task-list.ts"],"names":[],"mappings":"AAAA,OAAM,EAAe,KAAK,YAAY,EAAC,MAAI,2BAA2B,CAAC;AACvE,MAAM,MAAM,QAAQ,GAAC,YAAY,GAAG,QAAQ,CAAC;IAAC,SAAS,EAAC,OAAO,CAAC;IAAA,WAAW,CAAC,EAAC,MAAM,CAAA;CAAC,CAAC,CAAC;AACtF,wBAAgB,aAAa,CAAC,KAAK,EAAC,SAAS,QAAQ,EAAE,GAAE,IAAI,CAAqI"}
@@ -0,0 +1,4 @@
1
+ import { validateItems } from './interaction-adapters.js';
2
+ export function validateTasks(items) { validateItems(items); if (items.some(item => typeof item.completed !== 'boolean'))
3
+ throw new TypeError('Task completion must be boolean'); }
4
+ //# sourceMappingURL=task-list.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"task-list.js","sourceRoot":"","sources":["../src/task-list.ts"],"names":[],"mappings":"AAAA,OAAM,EAAC,aAAa,EAAmB,MAAI,2BAA2B,CAAC;AAEvE,MAAM,UAAU,aAAa,CAAC,KAAyB,IAAO,aAAa,CAAC,KAAK,CAAC,CAAC,CAAA,IAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAA,EAAE,CAAA,OAAO,IAAI,CAAC,SAAS,KAAG,SAAS,CAAC;IAAC,MAAM,IAAI,SAAS,CAAC,iCAAiC,CAAC,CAAC,CAAA,CAAC","sourcesContent":["import{validateItems,type SortableItem}from'./interaction-adapters.js';\nexport type TaskItem=SortableItem & Readonly<{completed:boolean;description?:string}>;\nexport function validateTasks(items:readonly TaskItem[]):void{validateItems(items);if(items.some(item=>typeof item.completed!=='boolean'))throw new TypeError('Task completion must be boolean');}\n"]}
@@ -0,0 +1,14 @@
1
+ import { type ResolvedTheme, type ThemeColors } from "./colors.js";
2
+ export type StudioPalette = Partial<Record<ResolvedTheme, Partial<ThemeColors>>>;
3
+ export type StudioColorRole = "primary" | "onPrimary" | "contentBrand";
4
+ export declare function applyStudioColor(palette: StudioPalette, theme: ResolvedTheme, role: StudioColorRole, color: string): StudioPalette;
5
+ export declare function studioReport(palette: StudioPalette, theme: ResolvedTheme): {
6
+ ratio: number;
7
+ pass: boolean;
8
+ foreground: keyof ThemeColors;
9
+ background: keyof ThemeColors;
10
+ minimum: number;
11
+ kind: "text" | "non-text";
12
+ }[];
13
+ export declare function exportStudioPalette(palette: StudioPalette): string;
14
+ //# sourceMappingURL=theme-studio.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"theme-studio.d.ts","sourceRoot":"","sources":["../src/theme-studio.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,KAAK,aAAa,EAAE,KAAK,WAAW,EAAE,MAAM,aAAa,CAAC;AAE3E,MAAM,MAAM,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC,aAAa,EAAE,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;AACjF,MAAM,MAAM,eAAe,GAAG,SAAS,GAAG,WAAW,GAAG,cAAc,CAAC;AACvE,wBAAgB,gBAAgB,CAAC,OAAO,EAAC,aAAa,EAAE,KAAK,EAAC,aAAa,EAAE,IAAI,EAAC,eAAe,EAAE,KAAK,EAAC,MAAM,GAAE,aAAa,CAG7H;AACD,wBAAgB,YAAY,CAAC,OAAO,EAAC,aAAa,EAAC,KAAK,EAAC,aAAa;;;;;;;IAGrE;AACD,wBAAgB,mBAAmB,CAAC,OAAO,EAAC,aAAa,UAGxD"}
@@ -0,0 +1,16 @@
1
+ import { THEMES } from "./colors.js";
2
+ import { contrastRatio, paletteContrastRules } from "./palette-contrast.js";
3
+ export function applyStudioColor(palette, theme, role, color) {
4
+ if (!/^#[0-9a-f]{6}$/i.test(color.trim()))
5
+ throw new TypeError("Expected a six-digit hex color");
6
+ return { ...palette, [theme]: { ...palette[theme], [role]: color.trim().toLowerCase() } };
7
+ }
8
+ export function studioReport(palette, theme) {
9
+ const resolved = { ...THEMES[theme], ...palette[theme] };
10
+ return paletteContrastRules.map(rule => ({ ...rule, ratio: contrastRatio(resolved[rule.foreground], resolved[rule.background]), pass: contrastRatio(resolved[rule.foreground], resolved[rule.background]) >= rule.minimum }));
11
+ }
12
+ export function exportStudioPalette(palette) {
13
+ // Export the actual provider overrides, not invented derived hues or product defaults.
14
+ return JSON.stringify({ brandPalette: palette }, null, 2);
15
+ }
16
+ //# sourceMappingURL=theme-studio.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"theme-studio.js","sourceRoot":"","sources":["../src/theme-studio.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAwC,MAAM,aAAa,CAAC;AAC3E,OAAO,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAG5E,MAAM,UAAU,gBAAgB,CAAC,OAAqB,EAAE,KAAmB,EAAE,IAAoB,EAAE,KAAY;IAC9G,IAAG,CAAC,iBAAiB,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;QAAC,MAAM,IAAI,SAAS,CAAC,gCAAgC,CAAC,CAAC;IAC/F,OAAO,EAAC,GAAG,OAAO,EAAC,CAAC,KAAK,CAAC,EAAC,EAAC,GAAG,OAAO,CAAC,KAAK,CAAC,EAAC,CAAC,IAAI,CAAC,EAAC,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,EAAC,EAAC,CAAC;AACnF,CAAC;AACD,MAAM,UAAU,YAAY,CAAC,OAAqB,EAAC,KAAmB;IACrE,MAAM,QAAQ,GAAC,EAAC,GAAG,MAAM,CAAC,KAAK,CAAC,EAAC,GAAG,OAAO,CAAC,KAAK,CAAC,EAAC,CAAC;IACpD,OAAO,oBAAoB,CAAC,GAAG,CAAC,IAAI,CAAA,EAAE,CAAA,CAAC,EAAC,GAAG,IAAI,EAAC,KAAK,EAAC,aAAa,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,EAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,EAAC,IAAI,EAAC,aAAa,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,EAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,IAAE,IAAI,CAAC,OAAO,EAAC,CAAC,CAAC,CAAC;AACnN,CAAC;AACD,MAAM,UAAU,mBAAmB,CAAC,OAAqB;IACxD,uFAAuF;IACvF,OAAO,IAAI,CAAC,SAAS,CAAC,EAAC,YAAY,EAAC,OAAO,EAAC,EAAC,IAAI,EAAC,CAAC,CAAC,CAAC;AACtD,CAAC","sourcesContent":["import { THEMES, type ResolvedTheme, type ThemeColors } from \"./colors.js\";\nimport { contrastRatio, paletteContrastRules } from \"./palette-contrast.js\";\nexport type StudioPalette = Partial<Record<ResolvedTheme, Partial<ThemeColors>>>;\nexport type StudioColorRole = \"primary\" | \"onPrimary\" | \"contentBrand\";\nexport function applyStudioColor(palette:StudioPalette, theme:ResolvedTheme, role:StudioColorRole, color:string):StudioPalette {\n if(!/^#[0-9a-f]{6}$/i.test(color.trim()))throw new TypeError(\"Expected a six-digit hex color\");\n return {...palette,[theme]:{...palette[theme],[role]:color.trim().toLowerCase()}};\n}\nexport function studioReport(palette:StudioPalette,theme:ResolvedTheme){\n const resolved={...THEMES[theme],...palette[theme]};\n return paletteContrastRules.map(rule=>({...rule,ratio:contrastRatio(resolved[rule.foreground],resolved[rule.background]),pass:contrastRatio(resolved[rule.foreground],resolved[rule.background])>=rule.minimum}));\n}\nexport function exportStudioPalette(palette:StudioPalette){\n // Export the actual provider overrides, not invented derived hues or product defaults.\n return JSON.stringify({brandPalette:palette},null,2);\n}\n"]}
@@ -1,9 +1,11 @@
1
1
  import type { OrbState, OrbSize, OrbFrame } from "./internal/thinking-orb/types.js";
2
2
  export type { OrbState, OrbSize, OrbFrame };
3
3
  export declare const thinkingOrbStates: readonly ["working", "searching", "solving", "listening", "connecting", "weaving", "composing", "breathing", "shaping"];
4
+ export type ThinkingOrbAppearance = "state" | "fluid" | "matrix";
4
5
  export type ThinkingOrbOptions = Readonly<{
5
6
  /** Actual operation phase, supplied by the host; the orb never simulates progress. */
6
7
  state?: OrbState;
8
+ appearance?: ThinkingOrbAppearance;
7
9
  size?: OrbSize;
8
10
  /** Localized description of the current operation. */
9
11
  label: string;
@@ -13,9 +15,9 @@ export type ThinkingOrbOptions = Readonly<{
13
15
  active?: boolean;
14
16
  }>;
15
17
  export { thinkingOrbRecipe } from "./thinking-orb-recipe.js";
16
- export declare function validateThinkingOrb({ state, size, speed, label }: ThinkingOrbOptions): void;
18
+ export declare function validateThinkingOrb({ state, size, speed, label, appearance }: ThinkingOrbOptions): void;
17
19
  /** Theme-free, deterministic geometry; no DOM/React/native imports. */
18
- export declare function buildThinkingOrbFrame(state: OrbState, size: OrbSize, time: number): OrbFrame;
20
+ export declare function buildThinkingOrbFrame(state: OrbState, size: OrbSize, time: number, appearance?: ThinkingOrbAppearance): OrbFrame;
19
21
  /** A local elapsed clock freezes exactly, instead of jumping to wall time after resume. */
20
22
  export declare function createThinkingOrbClock(): {
21
23
  resetDelta(): void;
@@ -1 +1 @@
1
- {"version":3,"file":"thinking-orb.d.ts","sourceRoot":"","sources":["../src/thinking-orb.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,kCAAkC,CAAC;AACpF,YAAY,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC;AAE5C,eAAO,MAAM,iBAAiB,yHAA0H,CAAC;AACzJ,MAAM,MAAM,kBAAkB,GAAG,QAAQ,CAAC;IACxC,sFAAsF;IACtF,KAAK,CAAC,EAAE,QAAQ,CAAC;IACjB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,sDAAsD;IACtD,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,uFAAuF;IACvF,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB,CAAC,CAAC;AACH,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAG7D,wBAAgB,mBAAmB,CAAC,EAAE,KAAiB,EAAE,IAAS,EAAE,KAAS,EAAE,KAAK,EAAE,EAAE,kBAAkB,GAAG,IAAI,CAKhH;AAED,uEAAuE;AACvE,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,QAAQ,CAK5F;AAED,2FAA2F;AAC3F,wBAAgB,sBAAsB;;gBAKtB,MAAM,SAAS,MAAM;;EAQpC"}
1
+ {"version":3,"file":"thinking-orb.d.ts","sourceRoot":"","sources":["../src/thinking-orb.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,kCAAkC,CAAC;AACpF,YAAY,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC;AAE5C,eAAO,MAAM,iBAAiB,yHAA0H,CAAC;AACzJ,MAAM,MAAM,qBAAqB,GAAG,OAAO,GAAG,OAAO,GAAG,QAAQ,CAAC;AACjE,MAAM,MAAM,kBAAkB,GAAG,QAAQ,CAAC;IACxC,sFAAsF;IACtF,KAAK,CAAC,EAAE,QAAQ,CAAC;IACjB,UAAU,CAAC,EAAE,qBAAqB,CAAC;IACnC,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,sDAAsD;IACtD,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,uFAAuF;IACvF,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB,CAAC,CAAC;AACH,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAG7D,wBAAgB,mBAAmB,CAAC,EAAE,KAAiB,EAAE,IAAS,EAAE,KAAS,EAAE,KAAK,EAAE,UAAoB,EAAE,EAAE,kBAAkB,GAAG,IAAI,CAMtI;AAED,uEAAuE;AACvE,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,GAAE,qBAA+B,GAAG,QAAQ,CAMzI;AAED,2FAA2F;AAC3F,wBAAgB,sBAAsB;;gBAKtB,MAAM,SAAS,MAAM;;EAQpC"}