@hjmds/react 1.30.0 → 1.32.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 (102) hide show
  1. package/dist/auth-screen.d.ts +18 -3
  2. package/dist/auth-screen.d.ts.map +1 -1
  3. package/dist/auth-screen.js +22 -6
  4. package/dist/auth-screen.js.map +1 -1
  5. package/dist/bottom-cta.d.ts +6 -1
  6. package/dist/bottom-cta.d.ts.map +1 -1
  7. package/dist/bottom-cta.js +1 -1
  8. package/dist/bottom-cta.js.map +1 -1
  9. package/dist/bottom-navigation.d.ts +10 -0
  10. package/dist/bottom-navigation.d.ts.map +1 -1
  11. package/dist/bottom-navigation.js +80 -8
  12. package/dist/bottom-navigation.js.map +1 -1
  13. package/dist/carousel.d.ts +29 -1
  14. package/dist/carousel.d.ts.map +1 -1
  15. package/dist/carousel.js +27 -3
  16. package/dist/carousel.js.map +1 -1
  17. package/dist/display.d.ts +8 -2
  18. package/dist/display.d.ts.map +1 -1
  19. package/dist/display.js +12 -7
  20. package/dist/display.js.map +1 -1
  21. package/dist/evidence.d.ts +1 -1
  22. package/dist/evidence.js +1 -1
  23. package/dist/evidence.js.map +1 -1
  24. package/dist/forms.d.ts.map +1 -1
  25. package/dist/forms.js +2 -1
  26. package/dist/forms.js.map +1 -1
  27. package/dist/image-choice.d.ts +20 -2
  28. package/dist/image-choice.d.ts.map +1 -1
  29. package/dist/image-choice.js +60 -7
  30. package/dist/image-choice.js.map +1 -1
  31. package/dist/index.d.ts +3 -3
  32. package/dist/index.d.ts.map +1 -1
  33. package/dist/index.js +3 -3
  34. package/dist/index.js.map +1 -1
  35. package/dist/internal/field-error.d.ts +19 -0
  36. package/dist/internal/field-error.d.ts.map +1 -0
  37. package/dist/internal/field-error.js +19 -0
  38. package/dist/internal/field-error.js.map +1 -0
  39. package/dist/internal/initial-focus.d.ts.map +1 -1
  40. package/dist/internal/initial-focus.js +49 -7
  41. package/dist/internal/initial-focus.js.map +1 -1
  42. package/dist/internal/media-album.d.ts +70 -0
  43. package/dist/internal/media-album.d.ts.map +1 -0
  44. package/dist/internal/media-album.js +52 -0
  45. package/dist/internal/media-album.js.map +1 -0
  46. package/dist/internal/message-reactions.d.ts +39 -2
  47. package/dist/internal/message-reactions.d.ts.map +1 -1
  48. package/dist/internal/message-reactions.js +31 -6
  49. package/dist/internal/message-reactions.js.map +1 -1
  50. package/dist/layout.d.ts +19 -3
  51. package/dist/layout.d.ts.map +1 -1
  52. package/dist/layout.js +10 -3
  53. package/dist/layout.js.map +1 -1
  54. package/dist/navigation.d.ts +3 -1
  55. package/dist/navigation.d.ts.map +1 -1
  56. package/dist/navigation.js +4 -2
  57. package/dist/navigation.js.map +1 -1
  58. package/dist/number-field.d.ts.map +1 -1
  59. package/dist/number-field.js +2 -1
  60. package/dist/number-field.js.map +1 -1
  61. package/dist/overlays.d.ts +65 -0
  62. package/dist/overlays.d.ts.map +1 -1
  63. package/dist/overlays.js +36 -3
  64. package/dist/overlays.js.map +1 -1
  65. package/dist/pagination.d.ts +13 -11
  66. package/dist/pagination.d.ts.map +1 -1
  67. package/dist/pagination.js +12 -5
  68. package/dist/pagination.js.map +1 -1
  69. package/dist/public-exports.generated.d.ts +8 -0
  70. package/dist/public-exports.generated.d.ts.map +1 -1
  71. package/dist/public-exports.generated.js +24 -0
  72. package/dist/public-exports.generated.js.map +1 -1
  73. package/dist/screen-flows.d.ts +118 -14
  74. package/dist/screen-flows.d.ts.map +1 -1
  75. package/dist/screen-flows.js +95 -23
  76. package/dist/screen-flows.js.map +1 -1
  77. package/dist/screens.d.ts +69 -10
  78. package/dist/screens.d.ts.map +1 -1
  79. package/dist/screens.js +77 -15
  80. package/dist/screens.js.map +1 -1
  81. package/dist/select.d.ts.map +1 -1
  82. package/dist/select.js +2 -1
  83. package/dist/select.js.map +1 -1
  84. package/dist/selection.d.ts.map +1 -1
  85. package/dist/selection.js +3 -2
  86. package/dist/selection.js.map +1 -1
  87. package/dist/steps.d.ts +11 -1
  88. package/dist/steps.d.ts.map +1 -1
  89. package/dist/steps.js +11 -6
  90. package/dist/steps.js.map +1 -1
  91. package/dist/styles.css +181 -22
  92. package/dist/styles.layered.css +181 -22
  93. package/dist/supplemental-display.d.ts.map +1 -1
  94. package/dist/supplemental-display.js +2 -48
  95. package/dist/supplemental-display.js.map +1 -1
  96. package/dist/theme.d.ts.map +1 -1
  97. package/dist/theme.js +1 -0
  98. package/dist/theme.js.map +1 -1
  99. package/dist/toast.d.ts.map +1 -1
  100. package/dist/toast.js +1 -1
  101. package/dist/toast.js.map +1 -1
  102. package/package.json +3 -3
@@ -373,7 +373,7 @@
373
373
  the support text fades, so a custom Field control dims without needing a class. A component
374
374
  recipe value (Select, NumberField, OtpField, SearchField, PasswordField) arrives as an
375
375
  inline --hjm-field-disabled-opacity on the root. */
376
- .hjm-field[data-state="disabled"] > :not(.hjm-field__description):not(.hjm-field__error) { opacity: var(--hjm-field-disabled-opacity); }
376
+ .hjm-field[data-state="disabled"] > :not(.hjm-field__description):not(.hjm-field__error):not([data-hjm-field-error]) { opacity: var(--hjm-field-disabled-opacity); }
377
377
  .hjm-field__input {
378
378
  inline-size: 100%;
379
379
  min-inline-size: 0;
@@ -525,6 +525,13 @@
525
525
  border-radius: var(--hjm-radius-xl);
526
526
  box-shadow: var(--hjm-shadow-floating);
527
527
  }
528
+ /* configuration.shape (bottomNavigationRecipe.shapes): the renderer sets the frame radius token and inner padding. */
529
+ .hjm-bottom-navigation[data-presentation="floating"]:not([data-shape="standard"]) .hjm-bottom-navigation__surface {
530
+ border-radius: var(--hjm-bottom-navigation-shape-radius);
531
+ }
532
+ .hjm-bottom-navigation[data-presentation="floating"]:not([data-shape="standard"]) .hjm-bottom-navigation__list {
533
+ padding: var(--hjm-bottom-navigation-shape-padding);
534
+ }
528
535
  .hjm-bottom-navigation__list {
529
536
  display: grid;
530
537
  grid-template-columns: repeat(var(--hjm-bottom-navigation-columns), minmax(var(--hjm-bottom-navigation-item-min-width), 1fr));
@@ -574,6 +581,14 @@
574
581
  }
575
582
  .hjm-bottom-navigation__indicator > :first-child { transition: transform 160ms ease; }
576
583
  .hjm-bottom-navigation__indicator[data-state="selected"] > :first-child { transform: scale(1.06); }
584
+ /* iconEmphasis "lift" (bottomNavigationRecipe.icon.liftEmphasis): the selected icon rises one step above the shared
585
+ scale and idle icons dim, the non-color cue for full-color artwork. The badge is a later sibling and stays opaque. */
586
+ .hjm-bottom-navigation[data-icon-emphasis="lift"] .hjm-bottom-navigation__indicator[data-state="selected"] > :first-child {
587
+ transform: translateY(var(--hjm-bottom-navigation-lift-offset)) scale(1.06);
588
+ }
589
+ .hjm-bottom-navigation[data-icon-emphasis="lift"] li:not([data-prominent="true"]) .hjm-bottom-navigation__indicator[data-state="idle"] > :first-child {
590
+ opacity: var(--hjm-bottom-navigation-lift-idle-opacity);
591
+ }
577
592
  /* Icon-only items center the indicator in the density's minimum height instead of leaving an empty label row. */
578
593
  .hjm-bottom-navigation[data-labels="hidden"] .hjm-bottom-navigation__item { justify-content: center; }
579
594
  .hjm-bottom-navigation__label { font-size: var(--hjm-type-caption-size); line-height: var(--hjm-type-caption-line-height); font-weight: var(--hjm-text-emphasis-medium); }
@@ -601,6 +616,18 @@
601
616
  inset-block-start: 50%;
602
617
  translate: -50% -50%;
603
618
  }
619
+ /* Prominent center destination: bottomNavigationRecipe.prominentDestination, lifted so its label stays on the
620
+ other labels' line. The circle keeps brand fill in both states; the label carries selection. */
621
+ .hjm-bottom-navigation li[data-prominent="true"] .hjm-bottom-navigation__indicator {
622
+ inline-size: var(--hjm-bottom-navigation-prominent-diameter);
623
+ block-size: var(--hjm-bottom-navigation-prominent-diameter);
624
+ margin-block-start: calc(-1 * var(--hjm-bottom-navigation-prominent-lift));
625
+ border-radius: var(--hjm-radius-full);
626
+ color: var(--hjm-color-on-primary);
627
+ background: var(--hjm-color-primary);
628
+ box-shadow: var(--hjm-shadow-floating);
629
+ }
630
+ .hjm-bottom-navigation li[data-prominent="true"] .hjm-bottom-navigation__indicator > :first-child { transform: none; }
604
631
 
605
632
  .hjm-number-field__control {
606
633
  padding-inline: 0;
@@ -1720,6 +1747,22 @@ button.hjm-list-row, a.hjm-list-row { cursor: pointer; }
1720
1747
  AuthScreenLayout safeAreaBottom (2026-10-17 1.28 adoption: products wrapped the layout in their own inset). */
1721
1748
  padding-block-end: max(var(--hjm-auth-screen-padding-block), env(safe-area-inset-bottom, 0px));
1722
1749
  }
1750
+ /* With title/exit the layout owns the ScreenLayout centered header band: full-bleed over the inline padding, at the
1751
+ shared screen gutter, with the former top padding moved below it (2026-10-18: products kept a TopBar above). */
1752
+ .hjm-auth-screen[data-header] { padding-block-start: 0; }
1753
+ .hjm-auth-screen__header {
1754
+ display: grid;
1755
+ grid-template-columns: 1fr minmax(0, auto) 1fr;
1756
+ align-items: center;
1757
+ box-sizing: border-box;
1758
+ min-block-size: var(--hjm-auth-screen-header-min-height);
1759
+ margin-inline: calc(var(--hjm-auth-screen-padding-inline) * -1);
1760
+ margin-block-end: var(--hjm-auth-screen-padding-block);
1761
+ padding-inline: var(--hjm-auth-screen-header-padding-inline);
1762
+ padding-block: var(--hjm-auth-screen-header-padding-block);
1763
+ }
1764
+ .hjm-auth-screen__header-title { min-inline-size: 0; text-align: center; overflow-wrap: anywhere; }
1765
+ .hjm-auth-screen__header-title > * { margin: 0; }
1723
1766
  .hjm-auth-screen__block {
1724
1767
  display: flex;
1725
1768
  flex: 1;
@@ -1771,17 +1814,18 @@ button.hjm-list-row, a.hjm-list-row { cursor: pointer; }
1771
1814
  flex-wrap: wrap;
1772
1815
  justify-content: center;
1773
1816
  align-items: center;
1774
- column-gap: var(--hjm-auth-screen-link-gap);
1775
1817
  }
1776
- /* 2026-10-17 "간격 줄여": 보이는 간격은 gap + 구분점뿐이다. 44 터치 높이는 배경 없는 min-block-size,
1777
- 가로 터치 폭은 보이지 않는 가상 요소가 구분점 앞까지 넓힌다 — 버튼 안쪽 여백으로 만들면 글자 사이가 다시 벌어진다. */
1818
+ /* 2026-10-17 "간격 줄여": 보이는 간격은 linkGap + 구분점뿐이다. 44 터치 높이는 배경 없는 min-block-size다.
1819
+ 2026-10-18 링크 사이 간격을 flex column-gap에서 링크의 inline 여백으로 옮겼다. 보이는 간격은 같고(column-gap 0),
1820
+ 가로 터치 폭이 그 여백만큼 링크 상자 안에 든다. 예전 가상 요소는 상자 밖으로 linkGap만큼 뻗어, 긴 링크가 푸터 폭을
1821
+ 다 쓰면 푸터의 스크롤 폭을 넓혔다(웹 scenario-matrix auth-screen long-copy 288 > 282). 여백을 gap과 함께 두면
1822
+ 글자 사이가 두 배로 벌어지므로 gap은 두지 않는다. */
1778
1823
  .hjm-auth-screen__link {
1779
- position: relative;
1780
1824
  display: inline-flex;
1781
1825
  align-items: center;
1782
1826
  min-block-size: var(--hjm-auth-screen-link-target);
1783
1827
  margin: 0;
1784
- padding: 0;
1828
+ padding: 0 var(--hjm-auth-screen-link-gap);
1785
1829
  border: 0;
1786
1830
  background: none;
1787
1831
  font-family: var(--hjm-font-family-ui, inherit);
@@ -1789,12 +1833,6 @@ button.hjm-list-row, a.hjm-list-row { cursor: pointer; }
1789
1833
  text-underline-offset: 0.18em;
1790
1834
  cursor: pointer;
1791
1835
  }
1792
- .hjm-auth-screen__link::after {
1793
- content: "";
1794
- position: absolute;
1795
- inset-block: 0;
1796
- inset-inline: calc(var(--hjm-auth-screen-link-gap) * -1);
1797
- }
1798
1836
  .hjm-auth-screen__link:focus-visible {
1799
1837
  outline: var(--hjm-focus-width) solid var(--hjm-color-focus);
1800
1838
  outline-offset: var(--hjm-focus-offset);
@@ -2192,6 +2230,46 @@ button.hjm-list-row, a.hjm-list-row { cursor: pointer; }
2192
2230
  background: var(--hjm-backdrop-modal);
2193
2231
  overscroll-behavior: contain;
2194
2232
  }
2233
+ /* Dialog overlayLayer: viewport-sized, decorative, above the card (later sibling) and never a pointer target. */
2234
+ .hjm-dialog__overlay-layer {
2235
+ position: absolute;
2236
+ inset: 0;
2237
+ pointer-events: none;
2238
+ }
2239
+ /* ImmersiveOverlay: an edge-to-edge stage and control bar with no scrim, card or gutter. */
2240
+ .hjm-overlay.hjm-immersive-positioner {
2241
+ align-items: stretch;
2242
+ padding: 0;
2243
+ background: var(--hjm-immersive-background);
2244
+ }
2245
+ .hjm-immersive {
2246
+ display: flex;
2247
+ flex-direction: column;
2248
+ inline-size: 100%;
2249
+ block-size: 100%;
2250
+ color: var(--hjm-color-text);
2251
+ background: var(--hjm-immersive-background);
2252
+ outline: none;
2253
+ }
2254
+ .hjm-immersive__stage {
2255
+ position: relative;
2256
+ flex: 1 1 auto;
2257
+ min-block-size: 0;
2258
+ overflow: hidden;
2259
+ }
2260
+ .hjm-immersive__controls {
2261
+ display: flex;
2262
+ flex-direction: column;
2263
+ gap: var(--hjm-immersive-gap);
2264
+ padding: var(--hjm-immersive-padding);
2265
+ padding-inline: max(var(--hjm-immersive-padding), env(safe-area-inset-left)) max(var(--hjm-immersive-padding), env(safe-area-inset-right));
2266
+ padding-block-end: max(var(--hjm-immersive-padding), env(safe-area-inset-bottom));
2267
+ }
2268
+ .hjm-immersive__actions {
2269
+ display: flex;
2270
+ align-items: center;
2271
+ gap: var(--hjm-immersive-action-gap);
2272
+ }
2195
2273
  .hjm-dialog,
2196
2274
  .hjm-alert-dialog,
2197
2275
  .hjm-sheet {
@@ -2208,6 +2286,8 @@ button.hjm-list-row, a.hjm-list-row { cursor: pointer; }
2208
2286
  .hjm-dialog { inline-size: min(36rem, 100%); }
2209
2287
  .hjm-dialog[data-size="small"] { inline-size: min(28rem, 100%); }
2210
2288
  .hjm-dialog[data-size="large"] { inline-size: min(48rem, 100%); }
2289
+ /* Dialog scrollEnabled={false}: the card keeps its scroll offset while a gesture in the body owns the pointer. */
2290
+ .hjm-dialog[data-scroll="locked"] { overflow: hidden; overscroll-behavior: contain; touch-action: none; }
2211
2291
  .hjm-alert-dialog[data-size="small"] { inline-size: min(28rem, 100%); }
2212
2292
  .hjm-alert-dialog[data-size="large"] { inline-size: min(48rem, 100%); }
2213
2293
  .hjm-dialog__header,
@@ -2725,6 +2805,8 @@ button.hjm-list-row, a.hjm-list-row { cursor: pointer; }
2725
2805
  .hjm-pagination__item[data-state="current"] { border-color: var(--hjm-color-content-brand); color: var(--hjm-color-content-brand); font-weight: var(--hjm-text-emphasis-strong); }
2726
2806
  .hjm-pagination__item[aria-disabled="true"] { opacity: 0.5; cursor: not-allowed; }
2727
2807
  .hjm-pagination__ellipsis { color: var(--hjm-color-text-muted); }
2808
+ /* Open-ended current page label (paginationRecipe.pageLabel): text, not a button, on the steps' 44px row. */
2809
+ .hjm-pagination__page-label { min-block-size: var(--hjm-control-min-touch-target); display: grid; place-items: center; padding-inline: var(--hjm-space-xs); color: var(--hjm-color-text-body); overflow-wrap: anywhere; }
2728
2810
  .hjm-load-more { display: grid; justify-items: center; gap: var(--hjm-space-sm); padding-block: var(--hjm-space-lg); text-align: center; }
2729
2811
  .hjm-load-more[data-density="compact"] { gap: var(--hjm-space-xs); padding-block: var(--hjm-space-sm); }
2730
2812
  .hjm-load-more__sentinel { inline-size: 1px; block-size: 1px; }
@@ -2749,6 +2831,9 @@ button.hjm-list-row, a.hjm-list-row { cursor: pointer; }
2749
2831
  .hjm-steps__step[data-status="pending"] .hjm-steps__label { color: var(--hjm-color-text-muted); }
2750
2832
  .hjm-steps__step[data-status="error"] .hjm-steps__label { color: var(--hjm-color-danger); }
2751
2833
  .hjm-steps__description { color: var(--hjm-color-text-muted); font-size: var(--hjm-type-caption-size); overflow-wrap: anywhere; }
2834
+ /* A step before the cursor is one button over marker and label (Steps onStepPress); the cell keeps its static layout. */
2835
+ .hjm-steps__press { display: grid; align-content: start; gap: var(--hjm-space-xs); min-inline-size: 0; min-block-size: var(--hjm-steps-press-target); margin: 0; padding: 0; border: 0; background: none; color: inherit; font: inherit; text-align: start; cursor: pointer; }
2836
+ .hjm-steps__press:focus-visible { outline: var(--hjm-focus-width) solid var(--hjm-color-focus); outline-offset: var(--hjm-focus-offset); }
2752
2837
 
2753
2838
  .hjm-file-picker { display: grid; gap: var(--hjm-space-xs); }
2754
2839
  .hjm-file-picker__label { color: var(--hjm-color-text); font-weight: var(--hjm-text-emphasis-medium); }
@@ -2797,14 +2882,14 @@ button.hjm-list-row, a.hjm-list-row { cursor: pointer; }
2797
2882
  /* Cards stay narrow on desktop too; keep close/action rows explicit (docs/toast.md). The card owns its width cap so a
2798
2883
  controlled Toast outside the viewport keeps it too (it stretched to 1200px in the layout story, 2026-10-17 review).
2799
2884
  1.10.0 layout: [tone badge][title + description][close] / action pill on its own row, end-aligned.
2800
- The 2px tone strip is retired — the tinted badge carries tone (toastRecipe.toneMark width 0). */
2885
+ There is no edge stripe: the tinted badge (or product media) carries tone. 1.10.0 retired the 2px strip and 1.32.0
2886
+ removed its always-hidden element, so no product rule is needed to hide it (docs/toast.md). */
2801
2887
  .hjm-toast { position: relative; min-inline-size: 0; max-inline-size: min(26.25rem, 100%); min-block-size: 3.5rem; display: grid; grid-template-columns: auto minmax(0, 1fr) auto; align-items: start; column-gap: var(--hjm-space-sm); row-gap: var(--hjm-space-xs); padding: var(--hjm-toast-padding-block) var(--hjm-toast-padding-inline); overflow: hidden; border: var(--hjm-toast-border-width) solid var(--hjm-toast-border); border-radius: var(--hjm-toast-radius); color: var(--hjm-color-text); background: var(--hjm-toast-background); box-shadow: var(--hjm-toast-shadow); pointer-events: auto; }
2802
2888
  /* Whole-card activation is a sibling surface; explicit controls stay above it. */
2803
2889
  .hjm-toast__press { position: absolute; inset: 0; z-index: 1; border: 0; border-radius: inherit; padding: 0; background: transparent; cursor: pointer; }
2804
2890
  .hjm-toast__press:focus-visible { outline: 2px solid var(--hjm-color-content-brand); outline-offset: -2px; }
2805
2891
  .hjm-toast:has(> .hjm-toast__press:active) { opacity: var(--hjm-toast-pressed-opacity); }
2806
2892
  .hjm-toast:has(> .hjm-toast__press) > :is(.hjm-toast__action, .hjm-toast__close) { position: relative; z-index: 2; }
2807
- .hjm-toast__tone-mark { display: none; }
2808
2893
  .hjm-toast__icon { grid-column: 1; grid-row: 1; align-self: start; display: grid; place-items: center; inline-size: var(--hjm-toast-badge-size); block-size: var(--hjm-toast-badge-size); border-radius: 50%; color: var(--hjm-toast-accent-neutral); background: var(--hjm-toast-badge-neutral); }
2809
2894
  .hjm-toast[data-tone="info"] .hjm-toast__icon { color: var(--hjm-toast-accent-info); background: var(--hjm-toast-badge-info); }
2810
2895
  .hjm-toast[data-tone="success"] .hjm-toast__icon { color: var(--hjm-toast-accent-success); background: var(--hjm-toast-badge-success); }
@@ -2935,10 +3020,12 @@ button.hjm-list-row, a.hjm-list-row { cursor: pointer; }
2935
3020
  .hjm-carousel__rotation { justify-self: start; }
2936
3021
  .hjm-carousel__controls, .hjm-carousel__dots { display: flex; align-items: center; justify-content: center; flex-wrap: wrap; gap: var(--hjm-space-xs); }
2937
3022
  .hjm-carousel__controls { flex-wrap: nowrap; } .hjm-carousel__dots { flex-shrink: 1; min-inline-size: 0; }
2938
- .hjm-carousel__dot { display: grid; place-items: center; min-inline-size: var(--hjm-control-min-touch-target); min-block-size: var(--hjm-control-min-touch-target); border: 0; border-radius: var(--hjm-radius-full); background: transparent; cursor: pointer; }
2939
- .hjm-carousel__dot > span { inline-size: var(--hjm-space-xs); block-size: var(--hjm-space-xs); border-radius: var(--hjm-radius-full); background: var(--hjm-color-text-weak); } /* carouselRecipe.dot.color.inactive (border.strong), as Native */
2940
- .hjm-carousel__dot[data-current="true"] > span { background: var(--hjm-color-content-brand); }
2941
- .hjm-carousel__dot:focus-visible { outline: 2px solid var(--hjm-color-content-brand); outline-offset: 2px; }
3023
+ /* PageIndicator is the same dot row for a product-owned pager (carouselRecipe.dot). */
3024
+ .hjm-page-indicator { display: flex; align-items: center; justify-content: center; flex-wrap: wrap; gap: var(--hjm-space-xs); min-inline-size: 0; }
3025
+ .hjm-carousel__dot, .hjm-page-indicator__dot { display: grid; place-items: center; min-inline-size: var(--hjm-control-min-touch-target); min-block-size: var(--hjm-control-min-touch-target); border: 0; border-radius: var(--hjm-radius-full); background: transparent; cursor: pointer; }
3026
+ .hjm-carousel__dot > span, .hjm-page-indicator__dot > span { inline-size: var(--hjm-space-xs); block-size: var(--hjm-space-xs); border-radius: var(--hjm-radius-full); background: var(--hjm-color-text-weak); } /* carouselRecipe.dot.color.inactive (border.strong), as Native */
3027
+ .hjm-carousel__dot[data-current="true"] > span, .hjm-page-indicator__dot[data-current="true"] > span { background: var(--hjm-color-content-brand); }
3028
+ .hjm-carousel__dot:focus-visible, .hjm-page-indicator__dot:focus-visible { outline: 2px solid var(--hjm-color-content-brand); outline-offset: 2px; }
2942
3029
 
2943
3030
  /* The viewport action follows the content in DOM order. Its measured clearance
2944
3031
  belongs on the scroll content, not on the fixed button (docs/floating-action-button.md). */
@@ -3114,6 +3201,16 @@ button.hjm-list-row, a.hjm-list-row { cursor: pointer; }
3114
3201
  .hjm-tabs:is([data-appearance="gooey"], [data-appearance="slide"]) .hjm-tabs__list { position: relative; }
3115
3202
  .hjm-tabs:is([data-appearance="gooey"], [data-appearance="slide"]) .hjm-tabs__tab[data-state="selected"]::after { display: none; }
3116
3203
  .hjm-tabs__indicator { position: absolute; bottom: 0; height: 2px; border-radius: var(--hjm-radius-full); background: var(--hjm-color-content-brand); pointer-events: none; }
3204
+ /* indicator="filled" (tabsRecipe.indicators.filled): a surface-accent pill behind the selected tab, no list divider.
3205
+ The moving pill spans the tab height and sits under the labels. */
3206
+ .hjm-tabs[data-indicator="filled"] .hjm-tabs__list { border: 0; }
3207
+ .hjm-tabs[data-indicator="filled"] .hjm-tabs__tab { border-radius: var(--hjm-radius-full); }
3208
+ .hjm-tabs[data-indicator="filled"] .hjm-tabs__tab[data-state="selected"] { color: var(--hjm-color-content-brand); }
3209
+ .hjm-tabs[data-indicator="filled"] .hjm-tabs__tab[data-state="selected"]::after { display: none; }
3210
+ .hjm-tabs[data-indicator="filled"]:not([data-indicator-motion="moving"]) .hjm-tabs__tab[data-state="selected"] { background: var(--hjm-color-surface-accent); }
3211
+ .hjm-tabs[data-indicator="filled"] .hjm-tabs__indicator { top: 0; bottom: 0; height: auto; border-radius: var(--hjm-radius-full); background: var(--hjm-color-surface-accent); z-index: 0; }
3212
+ .hjm-tabs[data-indicator="filled"] .hjm-tabs__list { position: relative; }
3213
+ .hjm-tabs[data-indicator="filled"] .hjm-tabs__tab { z-index: 1; }
3117
3214
  .hjm-tabs__gooey { height: 6px; }
3118
3215
 
3119
3216
  /* Capsule destinations retain route/link semantics. At larger text sizes we show
@@ -3168,6 +3265,7 @@ button.hjm-list-row, a.hjm-list-row { cursor: pointer; }
3168
3265
  .hjm-screen__header { display: flex; flex-wrap: wrap; align-items: center; gap: var(--hjm-screen-item-gap, var(--hjm-space-sm)); padding: var(--hjm-screen-padding); flex: 0 0 auto; }
3169
3266
  .hjm-screen__heading { flex: 1 1 calc(var(--hjm-screen-header-min) * var(--hjm-text-scale, 1)); min-inline-size: 0; overflow-wrap: anywhere; }
3170
3267
  .hjm-screen__heading > * { margin: 0; }
3268
+ .hjm-screen__title-leading { display: inline-flex; flex-shrink: 0; align-items: center; justify-content: center; }
3171
3269
  .hjm-screen__notice { padding-inline: var(--hjm-screen-padding); flex: 0 0 auto; }
3172
3270
  /* --hjm-screen-body-inline is the body's inline padding and the distance a bleeding CollectionRail crosses (Native
3173
3271
  ScreenBodyInsetContext); inset variants change this one value instead of the padding itself. */
@@ -3175,8 +3273,15 @@ button.hjm-list-row, a.hjm-list-row { cursor: pointer; }
3175
3273
  /* contentInset="body-edge": header, notice and footer keep the gutter; full-width list rows own their inline inset
3176
3274
  (review S5#9: body 16 + row 16 put DM avatars ~32 from the edge). "none" keeps its host-owns-all meaning. */
3177
3275
  .hjm-screen[data-content-inset="body-edge"] > .hjm-screen__body { --hjm-screen-body-inline: 0px; }
3276
+ /* contentInset="body-bleed": the same gutters stay on header, notice and footer; a map or canvas body has none on any
3277
+ side. As the last region it still clears the fixed BottomNavigation, without the gutter (Native twin). */
3278
+ .hjm-screen[data-content-inset="body-bleed"] > .hjm-screen__body { --hjm-screen-body-inline: 0px; padding-block: 0; }
3279
+ .hjm-screen[data-content-inset="body-bleed"] > .hjm-screen__body:last-child { padding-block-end: var(--hjm-bottom-navigation-inset, 0px); }
3280
+ /* Both hand the body gutter to product content; the shared state group has no inset of its own, so it keeps the gutter. */
3281
+ .hjm-screen[data-content-inset="body-edge"] > .hjm-screen__body > .hjm-screen__state,
3282
+ .hjm-screen[data-content-inset="body-bleed"] > .hjm-screen__body > .hjm-screen__state { padding-inline: var(--hjm-screen-padding); }
3178
3283
  /* Overlay content is not in the screen body, even when rendered inside it: a bleeding rail there stays in its box. */
3179
- .hjm-sheet, .hjm-dialog, .hjm-alert-dialog, .hjm-popover { --hjm-screen-body-inline: 0px; }
3284
+ .hjm-sheet, .hjm-dialog, .hjm-alert-dialog, .hjm-popover { --hjm-screen-body-inline: 0px; --hjm-bottom-navigation-inset: 0px; }
3180
3285
  /* contentInset="none" hands every inset to the host: no footer rule, as on Native (BottomCTA then draws its own bar). */
3181
3286
  .hjm-screen[data-content-inset="none"] > .hjm-screen__footer { border-block-start: 0; }
3182
3287
  .hjm-screen__body[data-scroll="screen"] { overflow-y: auto; }
@@ -3185,7 +3290,11 @@ button.hjm-list-row, a.hjm-list-row { cursor: pointer; }
3185
3290
  .hjm-screen__centered-content { margin-block: auto; flex-shrink: 0; inline-size: 100%; }
3186
3291
  .hjm-screen__body[data-replacement="true"] { display: flex; flex-direction: column; }
3187
3292
  .hjm-screen__state { margin-block: auto; flex-shrink: 0; display: flex; flex-direction: column; align-items: center; gap: var(--hjm-screen-state-gap, var(--hjm-space-md)); padding-block: var(--hjm-screen-gap); text-align: center; }
3188
- .hjm-screen__footer { flex: 0 0 auto; padding: var(--hjm-screen-padding); padding-block-end: max(var(--hjm-screen-padding), env(safe-area-inset-bottom)); border-block-start: 1px solid var(--hjm-color-border); }
3293
+ .hjm-screen__footer { flex: 0 0 auto; padding: var(--hjm-screen-padding); padding-block-end: max(var(--hjm-screen-padding), env(safe-area-inset-bottom), calc(var(--hjm-screen-padding) + var(--hjm-bottom-navigation-inset, 0px))); border-block-start: 1px solid var(--hjm-color-border); }
3294
+ /* --hjm-bottom-navigation-inset (BottomNavigationInsetProvider) is the viewport bottom the fixed bar covers. The last
3295
+ region keeps its gutter above the bar; without a provider the value is 0 and the padding is unchanged. This is the
3296
+ only place the inset is applied: a scroll="content" list inside must not add it again. */
3297
+ .hjm-screen__body:last-child { padding-block-end: calc(var(--hjm-screen-padding) + var(--hjm-bottom-navigation-inset, 0px)); }
3189
3298
  /* SearchScreen filtersOverflow=scroll; why: screen-flows.tsx. Block padding keeps focus rings unclipped.
3190
3299
  --hjm-search-filters-bleed = screen padding + hostGutter (1.13.1), set inline by SearchScreen. */
3191
3300
  .hjm-search-screen__filters { --f: calc(var(--hjm-focus-width) + var(--hjm-focus-offset)); --b: var(--hjm-search-filters-bleed, var(--hjm-screen-padding)); overflow-x: auto; margin: calc(-1 * var(--f)) calc(-1 * var(--b)); padding: var(--f) var(--b); scroll-padding-inline: var(--b); scrollbar-width: none; }
@@ -3233,6 +3342,19 @@ button.hjm-list-row, a.hjm-list-row { cursor: pointer; }
3233
3342
  [dir="rtl"] .hjm-chat-message[data-tail] .hjm-chat-message__bubble::before { transform: scaleX(-1); }
3234
3343
 
3235
3344
  .hjm-chat-message__meta { display: flex; flex-shrink: 0; align-items: center; gap: var(--hjm-space-xs); }
3345
+ /* Reaction summary pill (sizes inline from chatMessageRecipe.reactionSummary); own reaction shows the brand border. */
3346
+ .hjm-chat-message__reaction-summary { display: inline-flex; align-items: center; box-sizing: border-box; border: 1px solid var(--hjm-color-border); border-radius: var(--hjm-radius-full); background: var(--hjm-color-surface); color: var(--hjm-color-text); font: inherit; line-height: 1; cursor: pointer; }
3347
+ .hjm-chat-message__reaction-summary[data-selected] { border-color: var(--hjm-color-content-brand); }
3348
+ .hjm-chat-message__reaction-summary:hover:not(:disabled) { background: var(--hjm-color-surface-alt); }
3349
+ .hjm-chat-message__reaction-summary:focus-visible { outline: 2px solid var(--hjm-color-focus, currentColor); outline-offset: 2px; }
3350
+ .hjm-chat-message__reaction-summary:disabled { opacity: 0.5; cursor: default; }
3351
+ /* Read-only counts (summary.readOnly): same slot, plain text, no pill surface or pointer affordance. */
3352
+ .hjm-chat-message__reaction-counts { display: inline-flex; align-items: center; line-height: 1; }
3353
+ /* Typing dots (typingIndicatorRecipe via custom properties): staggered pulse, static under reduced motion. */
3354
+ .hjm-typing-indicator__dot { inline-size: var(--hjm-typing-dot); block-size: var(--hjm-typing-dot); border-radius: 50%; background: var(--hjm-color-text-muted); animation: hjm-typing-pulse var(--hjm-typing-cycle) ease-in-out infinite both; }
3355
+ .hjm-typing-indicator[data-reduced-motion] .hjm-typing-indicator__dot { animation: none; }
3356
+ @media (prefers-reduced-motion: reduce) { .hjm-typing-indicator__dot { animation: none; } }
3357
+ @keyframes hjm-typing-pulse { 0%, 100% { opacity: var(--hjm-typing-rest); } 50% { opacity: 1; } }
3236
3358
  /* A quoted reply heads the bubble and is divided from the answer. */
3237
3359
  .hjm-chat-message__reply { border-block-end: 1px solid var(--hjm-color-border); padding-block-end: var(--hjm-space-xs); margin-block-end: var(--hjm-space-xs); display: flex; flex-direction: column; gap: 2px; min-inline-size: 0; }
3238
3360
  .hjm-chat-message__quote { inline-size: 100%; border-inline: 0; border-block-start: 0; background: none; padding-inline: 0; padding-block-start: 0; color: inherit; font: inherit; text-align: start; cursor: pointer; }
@@ -3243,6 +3365,17 @@ button.hjm-list-row, a.hjm-list-row { cursor: pointer; }
3243
3365
  .hjm-chat-message__media-item > img { display: block; inline-size: 100%; block-size: 100%; object-fit: cover; }
3244
3366
  button.hjm-chat-message__media-item { cursor: pointer; }
3245
3367
  button.hjm-chat-message__media-item:focus-visible { outline: 2px solid var(--hjm-color-focus, currentColor); outline-offset: -2px; }
3368
+ /* Paged media album (2026-10-18, mediaAlbumRecipe): one mounted page in the host's media width, counter row below. */
3369
+ .hjm-media-album { display: flex; flex-direction: column; max-inline-size: 100%; }
3370
+ .hjm-media-album__page { position: relative; display: block; inline-size: 100%; overflow: hidden; padding: 0; border: 0; background: var(--hjm-color-surface-alt); }
3371
+ /* The page wrapper fills the frame in every state; the open action is a sibling overlay so a page status inside stays reachable. */
3372
+ .hjm-media-album__content { inline-size: 100%; block-size: 100%; }
3373
+ .hjm-media-album__content > img { display: block; inline-size: 100%; block-size: 100%; object-fit: cover; }
3374
+ .hjm-media-album__open { position: absolute; inset: 0; z-index: 1; padding: 0; border: 0; border-radius: inherit; background: transparent; cursor: pointer; }
3375
+ .hjm-media-album__open:focus-visible { outline: 2px solid var(--hjm-color-focus, currentColor); outline-offset: -2px; }
3376
+ /* Loading / failed page (MediaAlbumPageStatus): one block centered in the frame (VQ-09); gap and padding inline from mediaAlbumRecipe.pageStatus. */
3377
+ .hjm-media-album__status { box-sizing: border-box; display: flex; flex-direction: column; align-items: center; justify-content: center; inline-size: 100%; block-size: 100%; text-align: center; }
3378
+ .hjm-media-album__controls { display: flex; align-items: center; justify-content: space-between; }
3246
3379
  .hjm-chat-message__bubble[data-photo-only] { background: none; padding: 0; }
3247
3380
  .hjm-chat-message__bubble[data-photo-only]::before { display: none; }
3248
3381
  /* Only the shared default gutter narrows to the timeline gutter; "none" and "body-edge" keep their own meaning. */
@@ -3255,8 +3388,21 @@ button.hjm-chat-message__media-item:focus-visible { outline: 2px solid var(--hjm
3255
3388
  .hjm-image-choice { display: flex; flex-direction: column; gap: var(--hjm-space-xs); }
3256
3389
  .hjm-image-choice__label { font-weight: var(--hjm-text-emphasis-medium); }
3257
3390
  .hjm-image-choice__tiles { display: flex; flex-wrap: wrap; gap: var(--hjm-image-choice-gap); }
3258
- .hjm-image-choice__tile { position: relative; inline-size: calc(var(--hjm-image-choice-size) + (var(--hjm-image-choice-ring) + var(--hjm-image-choice-offset)) * 2); aspect-ratio: 1; padding: var(--hjm-image-choice-offset); border: var(--hjm-image-choice-ring) solid transparent; border-radius: calc(var(--hjm-image-choice-radius) + var(--hjm-image-choice-ring) + var(--hjm-image-choice-offset)); background: none; cursor: pointer; }
3259
- .hjm-image-choice__tile[data-selected] { border-color: var(--hjm-color-content-brand); }
3391
+ /* The button is a column (ring frame, optional item label) so the label shares the tap target; the ring is drawn on
3392
+ the inner frame (2026-10-18 showItemLabels). */
3393
+ .hjm-image-choice__tile { display: flex; flex-direction: column; gap: var(--hjm-image-choice-item-label-gap); inline-size: calc(var(--hjm-image-choice-size) + (var(--hjm-image-choice-ring) + var(--hjm-image-choice-offset)) * 2); padding: 0; border: 0; border-radius: calc(var(--hjm-image-choice-radius) + var(--hjm-image-choice-ring) + var(--hjm-image-choice-offset)); background: none; color: inherit; cursor: pointer; }
3394
+ .hjm-image-choice__ring { position: relative; display: block; inline-size: 100%; aspect-ratio: 1; padding: var(--hjm-image-choice-offset); border: var(--hjm-image-choice-ring) solid transparent; border-radius: inherit; }
3395
+ .hjm-image-choice__tile[data-selected] .hjm-image-choice__ring { border-color: var(--hjm-color-content-brand); }
3396
+ .hjm-image-choice__item-label { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; text-align: center; }
3397
+ /* Caption block (label lines + optional description line) has the same height in every tile of a group
3398
+ (resolveImageChoiceCaptionLines), so wrapped rows stay even and virtualized rows share one stride. */
3399
+ .hjm-image-choice__caption { display: flex; flex-direction: column; min-inline-size: 0; block-size: calc(var(--hjm-type-caption-line-height) * var(--hjm-image-choice-caption-lines)); }
3400
+ /* Two-line labels keep words whole (keep-all) and clamp; a single over-long word still breaks rather than overflowing. */
3401
+ .hjm-image-choice__item-label[data-lines="2"] { display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; line-clamp: 2; white-space: normal; word-break: keep-all; overflow-wrap: anywhere; }
3402
+ .hjm-image-choice__item-description { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; text-align: center; }
3403
+ /* virtualized: the group is its own fixed-height scroller; the inset keeps the tile focus outline inside the clip. */
3404
+ .hjm-image-choice__viewport { position: relative; box-sizing: border-box; overflow-y: auto; padding: var(--hjm-image-choice-viewport-inset); }
3405
+ .hjm-image-choice__row { position: absolute; inset-inline: 0; display: flex; gap: var(--hjm-image-choice-gap); }
3260
3406
  .hjm-image-choice__tile:focus-visible { outline: 2px solid var(--hjm-color-focus, currentColor); outline-offset: 2px; }
3261
3407
  .hjm-image-choice__tile:disabled { opacity: 0.5; cursor: default; }
3262
3408
  .hjm-image-choice__image { display: block; inline-size: 100%; block-size: 100%; overflow: hidden; border-radius: var(--hjm-image-choice-radius); background: var(--hjm-color-surface); }
@@ -3304,6 +3450,8 @@ button.hjm-chat-message__media-item:focus-visible { outline: 2px solid var(--hjm
3304
3450
  .hjm-comment-row__reactions:focus-visible { outline: 2px solid var(--hjm-color-focus, currentColor); outline-offset: 2px; }
3305
3451
  .hjm-comment-row__media { align-self: flex-start; overflow: hidden; margin-block-start: 4px; }
3306
3452
  .hjm-comment-row__media > img { display: block; inline-size: 100%; block-size: auto; }
3453
+ .hjm-comment-row__album { align-self: flex-start; margin-block-start: 4px; }
3454
+ .hjm-comment-row__panel { min-inline-size: 0; }
3307
3455
  /* commentThreadRecipe.actionAnchor (2026-10-17 measured audit): the 44 targets centre on the identity's first line
3308
3456
  (--hjm-comment-anchor-line, set per row), so like/more glyphs share the author line's centre instead of sitting
3309
3457
  12px below it. When HJM's own like/more is the last control (data-edge), the whole column takes the IconButton edge
@@ -3417,6 +3565,17 @@ button.hjm-chat-message__media-item:focus-visible { outline: 2px solid var(--hjm
3417
3565
  .hjm-card[data-interactive="true"] { font: inherit; color: inherit; text-align: inherit; cursor: pointer; min-inline-size: var(--hjm-control-min-touch-target); min-block-size: var(--hjm-control-min-touch-target); }
3418
3566
  .hjm-card[data-interactive="true"]:active:not(:disabled) { opacity: var(--hjm-card-pressed-opacity); }
3419
3567
  .hjm-card[data-interactive="true"]:disabled { opacity: var(--hjm-card-disabled-opacity); cursor: default; }
3568
+ /* Whole-card activation beside actions: the article keeps its semantics, a transparent button covers it, and only the
3569
+ action controls rise above that button, so the gaps around them still open the card. */
3570
+ .hjm-card[data-activation="overlay"] { position: relative; }
3571
+ .hjm-card__activator { position: absolute; inset: 0; z-index: 0; margin: 0; padding: 0; border: 0; border-radius: inherit; background: transparent; cursor: pointer; }
3572
+ .hjm-card__activator:disabled { cursor: default; }
3573
+ .hjm-card[data-activation="overlay"] > .hjm-card__actions { position: relative; z-index: 1; pointer-events: none; }
3574
+ .hjm-card[data-activation="overlay"] > .hjm-card__actions > * { pointer-events: auto; }
3575
+ /* Press/disabled feedback belongs to the card target (media and body); action controls keep their own states. */
3576
+ .hjm-card[data-activation="overlay"]:has(> .hjm-card__activator:active:not(:disabled)) > :is(.hjm-card__media, .hjm-card__body) { opacity: var(--hjm-card-pressed-opacity); }
3577
+ .hjm-card[data-activation="overlay"]:has(> .hjm-card__activator:disabled) > :is(.hjm-card__media, .hjm-card__body) { opacity: var(--hjm-card-disabled-opacity); }
3578
+ .hjm-card[data-activation="overlay"]:has(> .hjm-card__activator:focus-visible) { outline: var(--hjm-focus-width) solid var(--hjm-color-focus); outline-offset: var(--hjm-focus-offset); }
3420
3579
 
3421
3580
  /* Full destination cards keep all names and widths stable; colors remain product semantic roles. */
3422
3581
  .hjm-bottom-navigation[data-selection="tile"] .hjm-bottom-navigation__surface { background: var(--hjm-color-surface-accent); }
@@ -1 +1 @@
1
- {"version":3,"file":"supplemental-display.d.ts","sourceRoot":"","sources":["../src/supplemental-display.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"supplemental-display.d.ts","sourceRoot":"","sources":["../src/supplemental-display.tsx"],"names":[],"mappings":"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"}
@@ -1,56 +1,10 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
- import { getIconTransform, resolveIconDescriptor, } from "@hjmds/design-contracts/components/icon";
2
+ import { getIconTransform, resolveIconDescriptor, semanticIconPaths, } from "@hjmds/design-contracts/components/icon";
3
3
  import { imageRecipe, resolveImageAspectRatio, resolveImageDescriptor, resolveImageFallbackAccessibilityLabel, } from "@hjmds/design-contracts/components/image";
4
4
  import { counterBadgeRecipe, formatCounterBadgeCount, iconRecipe, } from "@hjmds/design-contracts/recipes";
5
5
  import { forwardRef, useState, useMemo, useRef, useLayoutEffect, } from "react";
6
6
  import { classNames } from "./internal.js";
7
7
  import { useOptionalHjmTheme } from "./provider.js";
8
- /** Internal, dependency-free semantic glyph registry. All marks share one 24px stroke grid. */
9
- const iconPaths = {
10
- add: "M12 5v14M5 12h14",
11
- ai: "M12 2l1.2 4.1L17 8l-3.8 1.9L12 14l-1.2-4.1L7 8l3.8-1.9L12 2ZM19 14l.7 2.3L22 17.5l-2.3 1.2L19 21l-.7-2.3-2.3-1.2 2.3-1.2L19 14Z",
12
- alert: "M12 3 2.7 20h18.6L12 3Zm0 6v4m0 3h.01",
13
- back: "M15 18 9 12l6-6M9 12h10",
14
- calendar: "M5 4h14a2 2 0 0 1 2 2v13a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2Zm2-2v4m10-4v4M3 9h18",
15
- check: "m5 12 4 4L19 6",
16
- chevronDown: "m6 9 6 6 6-6",
17
- chevronEnd: "m9 6 6 6-6 6",
18
- chevronStart: "m15 6-6 6 6 6",
19
- chevronUp: "m6 15 6-6 6 6",
20
- close: "M6 6l12 12M18 6 6 18",
21
- compare: "M8 7h11m0 0-3-3m3 3-3 3M16 17H5m0 0 3-3m-3 3 3 3",
22
- copy: "M8 8h11a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2H10a2 2 0 0 1-2-2V8Zm8 0V5a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2v9a2 2 0 0 0 2 2h3",
23
- delete: "M4 7h16M9 7V4h6v3m3 0-1 14H7L6 7m4 4v6m4-6v6",
24
- download: "M12 3v12m0 0 5-5m-5 5-5-5M4 19v2h16v-2",
25
- edit: "m4 16-1 5 5-1L19 9l-4-4L4 16Zm9-9 4 4",
26
- error: "M12 22a10 10 0 1 0 0-20 10 10 0 0 0 0 20Zm0-14v5m0 3h.01",
27
- favorite: "M20.8 4.6a5.5 5.5 0 0 0-7.8 0L12 5.7l-1.1-1.1a5.5 5.5 0 0 0-7.8 7.8L12 21l8.8-8.6a5.5 5.5 0 0 0 0-7.8Z",
28
- filter: "M3 5h18l-7 8v6l-4 2v-8L3 5Z",
29
- forward: "m9 6 6 6-6 6m6-6H5",
30
- help: "M12 22a10 10 0 1 0 0-20 10 10 0 0 0 0 20Zm-3-13a3 3 0 1 1 4.7 2.5c-1 .7-1.7 1.2-1.7 2.5m0 3h.01",
31
- home: "m3 11 9-8 9 8v10h-6v-6H9v6H3V11Z",
32
- info: "M12 22a10 10 0 1 0 0-20 10 10 0 0 0 0 20Zm0-11v6m0-10h.01",
33
- lock: "M6 10h12v11H6V10Zm3 0V7a3 3 0 0 1 6 0v3",
34
- menu: "M4 6h16M4 12h16M4 18h16",
35
- more: "M5 12h.01M12 12h.01M19 12h.01",
36
- notifications: "M18 8a6 6 0 0 0-12 0c0 7-3 7-3 9h18c0-2-3-2-3-9Zm-8 12h4",
37
- pause: "M8 5v14m8-14v14",
38
- play: "m8 5 11 7-11 7V5Z",
39
- refresh: "M20 7v5h-5M4 17v-5h5m10.5-3A8 8 0 0 0 6 6l-2 2m.5 7A8 8 0 0 0 18 18l2-2",
40
- search: "m21 21-4.4-4.4M19 11a8 8 0 1 1-16 0 8 8 0 0 1 16 0Z",
41
- settings: "M12 15.5a3.5 3.5 0 1 0 0-7 3.5 3.5 0 0 0 0 7Zm7.4-3.5 2-1.5-2-3.5-2.4 1a8 8 0 0 0-2-1.2L14.7 4h-4l-.4 2.8A8 8 0 0 0 8 8L5.6 7l-2 3.5 2 1.5a8 8 0 0 0 0 2l-2 1.5 2 3.5L8 18a8 8 0 0 0 2.3 1.2l.4 2.8h4l.3-2.8A8 8 0 0 0 17 18l2.4 1 2-3.5-2-1.5a8 8 0 0 0 0-2Z",
42
- share: "M18 8a3 3 0 1 0 0-6 3 3 0 0 0 0 6ZM6 15a3 3 0 1 0 0-6 3 3 0 0 0 0 6Zm12 9a3 3 0 1 0 0-6 3 3 0 0 0 0 6ZM8.6 16.5l6.8 4M15.4 6.5l-6.8 4",
43
- success: "M12 22a10 10 0 1 0 0-20 10 10 0 0 0 0 20Zm-5-10 3 3 7-7",
44
- trendDown: "M3 7l7 7 4-4 7 7m0 0v-6m0 6h-6",
45
- trendFlat: "M4 12h16m0 0-4-4m4 4-4 4",
46
- trendUp: "M3 17l7-7 4 4 7-7m0 0v6m0-6h-6",
47
- upload: "M12 21V9m0 0-5 5m5-5 5 5M4 5V3h16v2",
48
- user: "M12 12a4 4 0 1 0 0-8 4 4 0 0 0 0 8Zm-8 9a8 8 0 0 1 16 0",
49
- users: "M9 11a4 4 0 1 0 0-8 4 4 0 0 0 0 8Zm-7 10a7 7 0 0 1 14 0m1-16a4 4 0 0 1 0 7m0 3a6 6 0 0 1 5 6",
50
- visibility: "M2 12s4-7 10-7 10 7 10 7-4 7-10 7S2 12 2 12Zm10 3a3 3 0 1 0 0-6 3 3 0 0 0 0 6Z",
51
- visibilityOff: "m3 3 18 18M10.6 5.2A9 9 0 0 1 12 5c6 0 10 7 10 7a17 17 0 0 1-2.1 3M6.6 6.6C3.8 8.5 2 12 2 12s4 7 10 7a9 9 0 0 0 3.4-.7M9.9 9.9a3 3 0 0 0 4.2 4.2",
52
- warning: "M12 3 2.7 20h18.6L12 3Zm0 6v4m0 3h.01",
53
- };
54
8
  export const Icon = forwardRef(function Icon({ name, size, tone, weight, directionality, decorative, accessibilityLabel, renderGlyph, className, style, layoutStyle, ...props }, ref) {
55
9
  const descriptor = resolveIconDescriptor({
56
10
  name,
@@ -64,7 +18,7 @@ export const Icon = forwardRef(function Icon({ name, size, tone, weight, directi
64
18
  const theme = useOptionalHjmTheme();
65
19
  const transform = getIconTransform(descriptor.directionality, theme?.environment.direction ?? "ltr");
66
20
  const dimension = iconRecipe.sizes[descriptor.size];
67
- return (_jsx("svg", { ...props, ref: ref, viewBox: "0 0 24 24", fill: "none", xmlns: "http://www.w3.org/2000/svg", className: classNames("hjm-icon", className), "data-name": descriptor.name, "data-size": descriptor.size, "data-tone": descriptor.tone, "data-weight": descriptor.weight, "data-transform": transform, width: dimension, height: dimension, stroke: "currentColor", strokeWidth: iconRecipe.weights[descriptor.weight], strokeLinecap: "round", strokeLinejoin: "round", role: descriptor.decorative ? undefined : "img", "aria-hidden": descriptor.decorative || undefined, "aria-label": descriptor.decorative ? undefined : descriptor.accessibilityLabel, focusable: "false", style: { ...style, ...layoutStyle }, children: renderGlyph?.({ name: descriptor.name, size: 24, color: "currentColor", strokeWidth: iconRecipe.weights[descriptor.weight] }) ?? _jsx("path", { d: iconPaths[descriptor.name] }) }));
21
+ return (_jsx("svg", { ...props, ref: ref, viewBox: "0 0 24 24", fill: "none", xmlns: "http://www.w3.org/2000/svg", className: classNames("hjm-icon", className), "data-name": descriptor.name, "data-size": descriptor.size, "data-tone": descriptor.tone, "data-weight": descriptor.weight, "data-transform": transform, width: dimension, height: dimension, stroke: "currentColor", strokeWidth: iconRecipe.weights[descriptor.weight], strokeLinecap: "round", strokeLinejoin: "round", role: descriptor.decorative ? undefined : "img", "aria-hidden": descriptor.decorative || undefined, "aria-label": descriptor.decorative ? undefined : descriptor.accessibilityLabel, focusable: "false", style: { ...style, ...layoutStyle }, children: renderGlyph?.({ name: descriptor.name, size: 24, color: "currentColor", strokeWidth: iconRecipe.weights[descriptor.weight] }) ?? _jsx("path", { d: semanticIconPaths[descriptor.name] }) }));
68
22
  });
69
23
  /** Intrinsic-size image with canonical alt semantics and an accessible fallback. */
70
24
  export const Image = forwardRef(function Image({ src, width, height, fit, decorative, accessibilityLabel, imageProps, renderImage, fallback, imageRef, onLoad, onError, onLoadStatusChange, className, style, layoutStyle, ...props }, ref) {
@@ -1 +1 @@
1
- {"version":3,"file":"supplemental-display.js","sourceRoot":"","sources":["../src/supplemental-display.tsx"],"names":[],"mappings":";AAAA,OAAO,EACL,gBAAgB,EAChB,qBAAqB,GAGtB,MAAM,yCAAyC,CAAC;AACjD,OAAO,EACL,WAAW,EACX,uBAAuB,EACvB,sBAAsB,EACtB,sCAAsC,GAGvC,MAAM,0CAA0C,CAAC;AAClD,OAAO,EACL,kBAAkB,EAClB,uBAAuB,EACvB,UAAU,GAIX,MAAM,iCAAiC,CAAC;AACzC,OAAO,EACL,UAAU,EACV,QAAQ,EACR,OAAO,EACP,MAAM,EACN,eAAe,GAShB,MAAM,OAAO,CAAC;AACf,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAGpD,+FAA+F;AAC/F,MAAM,SAAS,GAAG;IAChB,GAAG,EAAE,kBAAkB;IACvB,EAAE,EAAE,iIAAiI;IACrI,KAAK,EAAE,uCAAuC;IAC9C,IAAI,EAAE,yBAAyB;IAC/B,QAAQ,EAAE,6FAA6F;IACvG,KAAK,EAAE,gBAAgB;IACvB,WAAW,EAAE,cAAc;IAC3B,UAAU,EAAE,cAAc;IAC1B,YAAY,EAAE,eAAe;IAC7B,SAAS,EAAE,eAAe;IAC1B,KAAK,EAAE,sBAAsB;IAC7B,OAAO,EAAE,kDAAkD;IAC3D,IAAI,EAAE,iHAAiH;IACvH,MAAM,EAAE,8CAA8C;IACtD,QAAQ,EAAE,wCAAwC;IAClD,IAAI,EAAE,uCAAuC;IAC7C,KAAK,EAAE,0DAA0D;IACjE,QAAQ,EAAE,wGAAwG;IAClH,MAAM,EAAE,6BAA6B;IACrC,OAAO,EAAE,oBAAoB;IAC7B,IAAI,EAAE,iGAAiG;IACvG,IAAI,EAAE,kCAAkC;IACxC,IAAI,EAAE,2DAA2D;IACjE,IAAI,EAAE,yCAAyC;IAC/C,IAAI,EAAE,yBAAyB;IAC/B,IAAI,EAAE,+BAA+B;IACrC,aAAa,EAAE,0DAA0D;IACzE,KAAK,EAAE,iBAAiB;IACxB,IAAI,EAAE,mBAAmB;IACzB,OAAO,EAAE,yEAAyE;IAClF,MAAM,EAAE,qDAAqD;IAC7D,QAAQ,EAAE,+PAA+P;IACzQ,KAAK,EAAE,uIAAuI;IAC9I,OAAO,EAAE,yDAAyD;IAClE,SAAS,EAAE,gCAAgC;IAC3C,SAAS,EAAE,0BAA0B;IACrC,OAAO,EAAE,gCAAgC;IACzC,MAAM,EAAE,qCAAqC;IAC7C,IAAI,EAAE,yDAAyD;IAC/D,KAAK,EAAE,8FAA8F;IACrG,UAAU,EAAE,gFAAgF;IAC5F,aAAa,EAAE,kJAAkJ;IACjK,OAAO,EAAE,uCAAuC;CACG,CAAC;AAYtD,MAAM,CAAC,MAAM,IAAI,GAAG,UAAU,CAA2B,SAAS,IAAI,CACpE,EACE,IAAI,EACJ,IAAI,EACJ,IAAI,EACJ,MAAM,EACN,cAAc,EACd,UAAU,EACV,kBAAkB,EAClB,WAAW,EACX,SAAS,EACT,KAAK,EACL,WAAW,EACX,GAAG,KAAK,EACT,EACD,GAAG;IAEH,MAAM,UAAU,GAAG,qBAAqB,CAAC;QACvC,IAAI;QACJ,GAAG,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC;QACvC,GAAG,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC;QACvC,GAAG,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC;QAC3C,GAAG,CAAC,cAAc,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,CAAC;QAC3D,GAAG,CAAC,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC;QACnD,GAAG,CAAC,kBAAkB,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,kBAAkB,EAAE,CAAC;KAClD,CAAC,CAAC;IACrB,MAAM,KAAK,GAAG,mBAAmB,EAAE,CAAC;IACpC,MAAM,SAAS,GAAG,gBAAgB,CAChC,UAAU,CAAC,cAAc,EACzB,KAAK,EAAE,WAAW,CAAC,SAAS,IAAI,KAAK,CACtC,CAAC;IACF,MAAM,SAAS,GAAG,UAAU,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;IACpD,OAAO,CACL,iBACM,KAAK,EACT,GAAG,EAAE,GAAG,EACR,OAAO,EAAC,WAAW,EACnB,IAAI,EAAC,MAAM,EACX,KAAK,EAAC,4BAA4B,EAClC,SAAS,EAAE,UAAU,CAAC,UAAU,EAAE,SAAS,CAAC,eACjC,UAAU,CAAC,IAAI,eACf,UAAU,CAAC,IAAI,eACf,UAAU,CAAC,IAAI,iBACb,UAAU,CAAC,MAAM,oBACd,SAAS,EACzB,KAAK,EAAE,SAAS,EAChB,MAAM,EAAE,SAAS,EACjB,MAAM,EAAC,cAAc,EACrB,WAAW,EAAE,UAAU,CAAC,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC,EAClD,aAAa,EAAC,OAAO,EACrB,cAAc,EAAC,OAAO,EACtB,IAAI,EAAE,UAAU,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,iBAClC,UAAU,CAAC,UAAU,IAAI,SAAS,gBACnC,UAAU,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,UAAU,CAAC,kBAAkB,EAC7E,SAAS,EAAC,OAAO,EACjB,KAAK,EAAE,EAAE,GAAG,KAAK,EAAE,GAAG,WAAW,EAAE,YAElC,WAAW,EAAE,CAAC,EAAE,IAAI,EAAE,UAAU,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,UAAU,CAAC,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,eAAM,CAAC,EAAE,SAAS,CAAC,UAAU,CAAC,IAAI,CAAC,GAAI,GACrK,CACP,CAAC;AACJ,CAAC,CAAC,CAAC;AAsEH,oFAAoF;AACpF,MAAM,CAAC,MAAM,KAAK,GAAG,UAAU,CAA8B,SAAS,KAAK,CACzE,EACE,GAAG,EACH,KAAK,EACL,MAAM,EACN,GAAG,EACH,UAAU,EACV,kBAAkB,EAClB,UAAU,EACV,WAAW,EACX,QAAQ,EACR,QAAQ,EACR,MAAM,EACN,OAAO,EACP,kBAAkB,EAClB,SAAS,EACT,KAAK,EACL,WAAW,EACX,GAAG,KAAK,EACT,EACD,GAAG;IAEH,MAAM,UAAU,GAAG,sBAAsB,CAAC;QACxC,GAAG;QACH,KAAK;QACL,MAAM;QACN,GAAG,CAAC,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC;QACrC,GAAG,CAAC,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC;QACnD,GAAG,CAAC,kBAAkB,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,kBAAkB,EAAE,CAAC;KACjD,CAAC,CAAC;IACtB,6EAA6E;IAC7E,oFAAoF;IACpF,8EAA8E;IAC9E,qEAAqE;IACrE,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,EAAE,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,UAAU,EAAE,cAAc,CAAC,CAAC,CAAC;IACrJ,MAAM,gBAAgB,GAAG,MAAM,CAAgB,UAAU,CAAC,CAAC;IAC3D,eAAe,CAAC,GAAG,EAAE;QACnB,gBAAgB,CAAC,OAAO,GAAG,UAAU,CAAC;QACtC,OAAO,GAAG,EAAE,GAAG,gBAAgB,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;IACpD,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC;IACjB,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAa,EAAE,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC;IAClF,MAAM,MAAM,GAAG,KAAK,CAAC,UAAU,KAAK,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC;IAC1E,MAAM,EACJ,SAAS,EAAE,cAAc,EACzB,KAAK,EAAE,UAAU,EACjB,GAAG,cAAc,EAClB,GAAG,UAAU,IAAI,EAAE,CAAC;IAErB,MAAM,UAAU,GAAwC,CAAC,KAAK,EAAE,EAAE;QAChE,IAAI,gBAAgB,CAAC,OAAO,KAAK,UAAU;YAAE,OAAO;QACpD,QAAQ,CAAC,EAAE,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC;QAC3C,kBAAkB,EAAE,CAAC,QAAQ,CAAC,CAAC;QAC/B,MAAM,EAAE,CAAC,KAAK,CAAC,CAAC;IAClB,CAAC,CAAC;IACF,MAAM,WAAW,GAAwC,CAAC,KAAK,EAAE,EAAE;QACjE,IAAI,gBAAgB,CAAC,OAAO,KAAK,UAAU;YAAE,OAAO;QACpD,QAAQ,CAAC,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC;QAC1C,kBAAkB,EAAE,CAAC,OAAO,CAAC,CAAC;QAC9B,OAAO,EAAE,CAAC,KAAK,CAAC,CAAC;IACnB,CAAC,CAAC;IACF,MAAM,YAAY,GAAsB;QACtC,GAAG,cAAc;QACjB,GAAG,EAAE,UAAU,CAAC,GAAG;QACnB,GAAG,EAAE,UAAU,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,kBAAkB;QAC/D,KAAK,EAAE,UAAU,CAAC,KAAK;QACvB,MAAM,EAAE,UAAU,CAAC,MAAM;QACzB,SAAS,EAAE,UAAU,CAAC,kBAAkB,EAAE,cAAc,CAAC;YACvD,kBAAkB;QACpB,KAAK,EAAE,EAAE,GAAG,UAAU,EAAE,SAAS,EAAE,UAAU,CAAC,GAAG,EAAE;QACnD,GAAG,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACzD,MAAM,EAAE,UAAU;QAClB,OAAO,EAAE,WAAW;QACpB,GAAG,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,QAAQ,EAAE,CAAC;KACrD,CAAC;IAEF,IAAI,MAAiB,CAAC;IACtB,IAAI,MAAM,KAAK,OAAO,EAAE,CAAC;QACvB,MAAM,aAAa,GAAG,sCAAsC,CAAC,UAAU,CAAC,CAAC;QACzE,MAAM,GAAG,CACP,eACE,SAAS,EAAC,qBAAqB,EAC/B,IAAI,EAAE,UAAU,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,gBACnC,aAAa,iBACZ,UAAU,CAAC,UAAU,IAAI,SAAS,YAE/C,eAAM,SAAS,EAAC,0BAA0B,iBAAa,MAAM,YAC1D,QAAQ,IAAI,CACX,KAAC,IAAI,IACH,IAAI,EAAE,WAAW,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,EACpC,IAAI,EAAE,WAAW,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,EACpC,UAAU,SACV,CACH,GACI,GACF,CACR,CAAC;IACJ,CAAC;SAAM,IAAI,WAAW,KAAK,SAAS,EAAE,CAAC;QACrC,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,GAAG,gBAAgB,EAAE,GAAG,YAAY,CAAC;QAC5D,MAAM,GAAG,iBAAS,gBAAgB,EAAE,GAAG,EAAE,QAAQ,GAAI,CAAC;IACxD,CAAC;SAAM,CAAC;QACN,MAAM,GAAG,WAAW,CAAC,YAAY,CAAC,CAAC;IACrC,CAAC;IAED,OAAO,CACL,kBACM,KAAK,EACT,GAAG,EAAE,GAAG,EACR,SAAS,EAAE,UAAU,CAAC,WAAW,EAAE,SAAS,CAAC,cACnC,UAAU,CAAC,GAAG,iBACX,MAAM,EACnB,KAAK,EAAE;YACL,UAAU,EAAE,UAAU,CAAC,KAAK;YAC5B,GAAG,KAAK;YACR,GAAG,WAAW;YACd,WAAW,EAAE,uBAAuB,CAClC,UAAU,CAAC,KAAK,EAChB,UAAU,CAAC,MAAM,CAClB;SACF,YAEA,MAAM,GACF,CACR,CAAC;AACJ,CAAC,CAAC,CAAC;AAoBH,MAAM,CAAC,MAAM,YAAY,GAAG,UAAU,CACpC,SAAS,YAAY,CACnB,EACE,KAAK,EACL,GAAG,GAAG,kBAAkB,CAAC,QAAQ,CAAC,GAAG,EACrC,IAAI,GAAG,kBAAkB,CAAC,QAAQ,CAAC,IAAI,EACvC,IAAI,GAAG,kBAAkB,CAAC,QAAQ,CAAC,IAAI,EACvC,OAAO,GAAG,kBAAkB,CAAC,QAAQ,CAAC,OAAO,EAC7C,GAAG,GAAG,KAAK,EACX,kBAAkB,EAClB,SAAS,EACT,WAAW,EACX,KAAK,EACL,GAAG,KAAK,EACT,EACD,GAAG;IAEH,MAAM,KAAK,GAAG,uBAAuB,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IAClD,IAAI,kBAAkB,KAAK,SAAS,IAAI,kBAAkB,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC/E,MAAM,IAAI,SAAS,CAAC,mDAAmD,CAAC,CAAC;IAC3E,CAAC;IACD,IAAI,GAAG,IAAI,kBAAkB,KAAK,SAAS,EAAE,CAAC;QAC5C,2DAA2D;QAC3D,MAAM,IAAI,SAAS,CAAC,iDAAiD,CAAC,CAAC;IACzE,CAAC;IACD,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IAChC,OAAO,CACL,kBACM,KAAK,EACT,GAAG,EAAE,GAAG,EACR,SAAS,EAAE,UAAU,CAAC,mBAAmB,EAAE,SAAS,CAAC,eAC1C,IAAI,eACJ,IAAI,kBACD,OAAO,cACX,GAAG,IAAI,SAAS,EAC1B,KAAK,EAAE,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,KAAK,EAAE,GAAG,WAAW,EAAE,wBAAwB,EAAE,GAAG,kBAAkB,CAAC,OAAO,IAAI,EAAkB,CAAC,CAAC,CAAC,EAAE,GAAG,KAAK,EAAE,GAAG,WAAW,EAAE,iBACxI,kBAAkB,KAAK,SAAS,IAAI,SAAS;QAC1D,8EAA8E;QAC9E,IAAI,EAAE,kBAAkB,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,gBAC9C,kBAAkB,YAE7B,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,GACd,CACR,CAAC;AACJ,CAAC,CACF,CAAC","sourcesContent":["import {\n getIconTransform,\n resolveIconDescriptor,\n type IconDescriptor,\n type SemanticIconName,\n} from \"@hjmds/design-contracts/components/icon\";\nimport {\n imageRecipe,\n resolveImageAspectRatio,\n resolveImageDescriptor,\n resolveImageFallbackAccessibilityLabel,\n type ImageDescriptor,\n type ImageLoadStatus,\n} from \"@hjmds/design-contracts/components/image\";\nimport {\n counterBadgeRecipe,\n formatCounterBadgeCount,\n iconRecipe,\n type CounterBadgeSize,\n type CounterBadgeTone,\n type CounterBadgeVariant,\n} from \"@hjmds/design-contracts/recipes\";\nimport {\n forwardRef,\n useState,\n useMemo,\n useRef,\n useLayoutEffect,\n type CSSProperties,\n type HTMLAttributes,\n type ImgHTMLAttributes,\n type ReactElement,\n type ReactEventHandler,\n type ReactNode,\n type Ref,\n type SVGAttributes,\n} from \"react\";\nimport { classNames } from \"./internal.js\";\nimport { useOptionalHjmTheme } from \"./provider.js\";\nimport type { HjmCompositionStyleProp } from \"./composition-style.js\";\n\n/** Internal, dependency-free semantic glyph registry. All marks share one 24px stroke grid. */\nconst iconPaths = {\n add: \"M12 5v14M5 12h14\",\n ai: \"M12 2l1.2 4.1L17 8l-3.8 1.9L12 14l-1.2-4.1L7 8l3.8-1.9L12 2ZM19 14l.7 2.3L22 17.5l-2.3 1.2L19 21l-.7-2.3-2.3-1.2 2.3-1.2L19 14Z\",\n alert: \"M12 3 2.7 20h18.6L12 3Zm0 6v4m0 3h.01\",\n back: \"M15 18 9 12l6-6M9 12h10\",\n calendar: \"M5 4h14a2 2 0 0 1 2 2v13a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2Zm2-2v4m10-4v4M3 9h18\",\n check: \"m5 12 4 4L19 6\",\n chevronDown: \"m6 9 6 6 6-6\",\n chevronEnd: \"m9 6 6 6-6 6\",\n chevronStart: \"m15 6-6 6 6 6\",\n chevronUp: \"m6 15 6-6 6 6\",\n close: \"M6 6l12 12M18 6 6 18\",\n compare: \"M8 7h11m0 0-3-3m3 3-3 3M16 17H5m0 0 3-3m-3 3 3 3\",\n copy: \"M8 8h11a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2H10a2 2 0 0 1-2-2V8Zm8 0V5a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2v9a2 2 0 0 0 2 2h3\",\n delete: \"M4 7h16M9 7V4h6v3m3 0-1 14H7L6 7m4 4v6m4-6v6\",\n download: \"M12 3v12m0 0 5-5m-5 5-5-5M4 19v2h16v-2\",\n edit: \"m4 16-1 5 5-1L19 9l-4-4L4 16Zm9-9 4 4\",\n error: \"M12 22a10 10 0 1 0 0-20 10 10 0 0 0 0 20Zm0-14v5m0 3h.01\",\n favorite: \"M20.8 4.6a5.5 5.5 0 0 0-7.8 0L12 5.7l-1.1-1.1a5.5 5.5 0 0 0-7.8 7.8L12 21l8.8-8.6a5.5 5.5 0 0 0 0-7.8Z\",\n filter: \"M3 5h18l-7 8v6l-4 2v-8L3 5Z\",\n forward: \"m9 6 6 6-6 6m6-6H5\",\n help: \"M12 22a10 10 0 1 0 0-20 10 10 0 0 0 0 20Zm-3-13a3 3 0 1 1 4.7 2.5c-1 .7-1.7 1.2-1.7 2.5m0 3h.01\",\n home: \"m3 11 9-8 9 8v10h-6v-6H9v6H3V11Z\",\n info: \"M12 22a10 10 0 1 0 0-20 10 10 0 0 0 0 20Zm0-11v6m0-10h.01\",\n lock: \"M6 10h12v11H6V10Zm3 0V7a3 3 0 0 1 6 0v3\",\n menu: \"M4 6h16M4 12h16M4 18h16\",\n more: \"M5 12h.01M12 12h.01M19 12h.01\",\n notifications: \"M18 8a6 6 0 0 0-12 0c0 7-3 7-3 9h18c0-2-3-2-3-9Zm-8 12h4\",\n pause: \"M8 5v14m8-14v14\",\n play: \"m8 5 11 7-11 7V5Z\",\n refresh: \"M20 7v5h-5M4 17v-5h5m10.5-3A8 8 0 0 0 6 6l-2 2m.5 7A8 8 0 0 0 18 18l2-2\",\n search: \"m21 21-4.4-4.4M19 11a8 8 0 1 1-16 0 8 8 0 0 1 16 0Z\",\n settings: \"M12 15.5a3.5 3.5 0 1 0 0-7 3.5 3.5 0 0 0 0 7Zm7.4-3.5 2-1.5-2-3.5-2.4 1a8 8 0 0 0-2-1.2L14.7 4h-4l-.4 2.8A8 8 0 0 0 8 8L5.6 7l-2 3.5 2 1.5a8 8 0 0 0 0 2l-2 1.5 2 3.5L8 18a8 8 0 0 0 2.3 1.2l.4 2.8h4l.3-2.8A8 8 0 0 0 17 18l2.4 1 2-3.5-2-1.5a8 8 0 0 0 0-2Z\",\n share: \"M18 8a3 3 0 1 0 0-6 3 3 0 0 0 0 6ZM6 15a3 3 0 1 0 0-6 3 3 0 0 0 0 6Zm12 9a3 3 0 1 0 0-6 3 3 0 0 0 0 6ZM8.6 16.5l6.8 4M15.4 6.5l-6.8 4\",\n success: \"M12 22a10 10 0 1 0 0-20 10 10 0 0 0 0 20Zm-5-10 3 3 7-7\",\n trendDown: \"M3 7l7 7 4-4 7 7m0 0v-6m0 6h-6\",\n trendFlat: \"M4 12h16m0 0-4-4m4 4-4 4\",\n trendUp: \"M3 17l7-7 4 4 7-7m0 0v6m0-6h-6\",\n upload: \"M12 21V9m0 0-5 5m5-5 5 5M4 5V3h16v2\",\n user: \"M12 12a4 4 0 1 0 0-8 4 4 0 0 0 0 8Zm-8 9a8 8 0 0 1 16 0\",\n users: \"M9 11a4 4 0 1 0 0-8 4 4 0 0 0 0 8Zm-7 10a7 7 0 0 1 14 0m1-16a4 4 0 0 1 0 7m0 3a6 6 0 0 1 5 6\",\n visibility: \"M2 12s4-7 10-7 10 7 10 7-4 7-10 7S2 12 2 12Zm10 3a3 3 0 1 0 0-6 3 3 0 0 0 0 6Z\",\n visibilityOff: \"m3 3 18 18M10.6 5.2A9 9 0 0 1 12 5c6 0 10 7 10 7a17 17 0 0 1-2.1 3M6.6 6.6C3.8 8.5 2 12 2 12s4 7 10 7a9 9 0 0 0 3.4-.7M9.9 9.9a3 3 0 0 0 4.2 4.2\",\n warning: \"M12 3 2.7 20h18.6L12 3Zm0 6v4m0 3h.01\",\n} as const satisfies Record<SemanticIconName, string>;\n\nexport type IconProps = Omit<\n SVGAttributes<SVGSVGElement>,\n \"children\" | \"color\"\n> & IconDescriptor & Readonly<{\n /** Optional glyph inside the existing 24-unit SVG frame; HJM owns semantics. */\n renderGlyph?: (props: Readonly<{ name: SemanticIconName; size: number; color: string; strokeWidth: number }>) => ReactNode;\n /** Canonical layout-only placement on the root element. Controlled visual keys are excluded. */\n layoutStyle?: HjmCompositionStyleProp;\n}>;\n\nexport const Icon = forwardRef<SVGSVGElement, IconProps>(function Icon(\n {\n name,\n size,\n tone,\n weight,\n directionality,\n decorative,\n accessibilityLabel,\n renderGlyph,\n className,\n style,\n layoutStyle,\n ...props\n },\n ref,\n) {\n const descriptor = resolveIconDescriptor({\n name,\n ...(size === undefined ? {} : { size }),\n ...(tone === undefined ? {} : { tone }),\n ...(weight === undefined ? {} : { weight }),\n ...(directionality === undefined ? {} : { directionality }),\n ...(decorative === undefined ? {} : { decorative }),\n ...(accessibilityLabel === undefined ? {} : { accessibilityLabel }),\n } as IconDescriptor);\n const theme = useOptionalHjmTheme();\n const transform = getIconTransform(\n descriptor.directionality,\n theme?.environment.direction ?? \"ltr\",\n );\n const dimension = iconRecipe.sizes[descriptor.size];\n return (\n <svg\n {...props}\n ref={ref}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n className={classNames(\"hjm-icon\", className)}\n data-name={descriptor.name}\n data-size={descriptor.size}\n data-tone={descriptor.tone}\n data-weight={descriptor.weight}\n data-transform={transform}\n width={dimension}\n height={dimension}\n stroke=\"currentColor\"\n strokeWidth={iconRecipe.weights[descriptor.weight]}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n role={descriptor.decorative ? undefined : \"img\"}\n aria-hidden={descriptor.decorative || undefined}\n aria-label={descriptor.decorative ? undefined : descriptor.accessibilityLabel}\n focusable=\"false\"\n style={{ ...style, ...layoutStyle }}\n >\n {renderGlyph?.({ name: descriptor.name, size: 24, color: \"currentColor\", strokeWidth: iconRecipe.weights[descriptor.weight] }) ?? <path d={iconPaths[descriptor.name]} />}\n </svg>\n );\n});\n\ntype ImageElementProps = Omit<\n ImgHTMLAttributes<HTMLImageElement>,\n | \"alt\"\n | \"aria-hidden\"\n | \"aria-label\"\n | \"children\"\n | \"className\"\n | \"height\"\n | \"onError\"\n | \"onLoad\"\n | \"role\"\n | \"src\"\n | \"style\"\n | \"width\"\n>;\n\n/** Canonical props handed to a framework adapter such as `next/image`. */\nexport type ImageAdapterProps = ImageElementProps &\n Readonly<{\n src: string;\n alt: string;\n width: number;\n height: number;\n className?: string;\n style: CSSProperties;\n \"aria-hidden\"?: true;\n onLoad: ReactEventHandler<HTMLImageElement>;\n onError: ReactEventHandler<HTMLImageElement>;\n ref?: Ref<HTMLImageElement>;\n }>;\n\ntype ImageRootProps = Omit<\n HTMLAttributes<HTMLSpanElement>,\n | \"aria-hidden\"\n | \"aria-label\"\n | \"aria-labelledby\"\n | \"children\"\n | \"onError\"\n | \"onLoad\"\n | \"role\"\n>;\n\nexport type ImageProps = ImageRootProps &\n ImageDescriptor &\n Readonly<{\n /** Additional native `<img>` props shared with the framework adapter. */\n imageProps?: ImageElementProps &\n Readonly<{ className?: string; style?: CSSProperties }>;\n /**\n * Receives the complete accessible image contract. The adapter must pass\n * these props to its underlying image element so HJM can observe failure.\n */\n renderImage?: (props: ImageAdapterProps) => ReactElement;\n /** Visual content only; HJM keeps the fallback's accessible name. */\n fallback?: ReactNode;\n imageRef?: Ref<HTMLImageElement>;\n onLoad?: ReactEventHandler<HTMLImageElement>;\n onError?: ReactEventHandler<HTMLImageElement>;\n onLoadStatusChange?: (status: Extract<ImageLoadStatus, \"loaded\" | \"error\">) => void;\n /** Canonical layout-only placement on the root frame; the aspect ratio stays descriptor-owned. */\n layoutStyle?: HjmCompositionStyleProp;\n }>;\n\ntype ImageState = Readonly<{\n generation: object;\n status: Extract<ImageLoadStatus, \"loading\" | \"loaded\" | \"error\">;\n}>;\n\n/** Intrinsic-size image with canonical alt semantics and an accessible fallback. */\nexport const Image = forwardRef<HTMLSpanElement, ImageProps>(function Image(\n {\n src,\n width,\n height,\n fit,\n decorative,\n accessibilityLabel,\n imageProps,\n renderImage,\n fallback,\n imageRef,\n onLoad,\n onError,\n onLoadStatusChange,\n className,\n style,\n layoutStyle,\n ...props\n },\n ref,\n) {\n const descriptor = resolveImageDescriptor({\n src,\n width,\n height,\n ...(fit === undefined ? {} : { fit }),\n ...(decorative === undefined ? {} : { decorative }),\n ...(accessibilityLabel === undefined ? {} : { accessibilityLabel }),\n } as ImageDescriptor);\n // A→B→A is a new request even when the URL repeats. Retire adapter callbacks\n // at commit/unmount so old network events cannot update state or product observers.\n // Responsive source candidates and request policy are part of image identity;\n // a new srcSet must recover even when its fallback src is unchanged.\n const generation = useMemo(() => ({}), [descriptor.src, imageProps?.srcSet, imageProps?.sizes, imageProps?.crossOrigin, imageProps?.referrerPolicy]);\n const activeGeneration = useRef<object | null>(generation);\n useLayoutEffect(() => {\n activeGeneration.current = generation;\n return () => { activeGeneration.current = null; };\n }, [generation]);\n const [state, setState] = useState<ImageState>({ generation, status: \"loading\" });\n const status = state.generation === generation ? state.status : \"loading\";\n const {\n className: imageClassName,\n style: imageStyle,\n ...restImageProps\n } = imageProps ?? {};\n\n const handleLoad: ReactEventHandler<HTMLImageElement> = (event) => {\n if (activeGeneration.current !== generation) return;\n setState({ generation, status: \"loaded\" });\n onLoadStatusChange?.(\"loaded\");\n onLoad?.(event);\n };\n const handleError: ReactEventHandler<HTMLImageElement> = (event) => {\n if (activeGeneration.current !== generation) return;\n setState({ generation, status: \"error\" });\n onLoadStatusChange?.(\"error\");\n onError?.(event);\n };\n const adapterProps: ImageAdapterProps = {\n ...restImageProps,\n src: descriptor.src,\n alt: descriptor.decorative ? \"\" : descriptor.accessibilityLabel,\n width: descriptor.width,\n height: descriptor.height,\n className: classNames(\"hjm-image__asset\", imageClassName) ??\n \"hjm-image__asset\",\n style: { ...imageStyle, objectFit: descriptor.fit },\n ...(descriptor.decorative ? { \"aria-hidden\": true } : {}),\n onLoad: handleLoad,\n onError: handleError,\n ...(imageRef === undefined ? {} : { ref: imageRef }),\n };\n\n let visual: ReactNode;\n if (status === \"error\") {\n const fallbackLabel = resolveImageFallbackAccessibilityLabel(descriptor);\n visual = (\n <span\n className=\"hjm-image__fallback\"\n role={descriptor.decorative ? undefined : \"img\"}\n aria-label={fallbackLabel}\n aria-hidden={descriptor.decorative || undefined}\n >\n <span className=\"hjm-image__fallback-icon\" aria-hidden=\"true\">\n {fallback ?? (\n <Icon\n name={imageRecipe.fallback.icon.name}\n tone={imageRecipe.fallback.icon.tone}\n decorative\n />\n )}\n </span>\n </span>\n );\n } else if (renderImage === undefined) {\n const { ref: assetRef, ...nativeImageProps } = adapterProps;\n visual = <img {...nativeImageProps} ref={assetRef} />;\n } else {\n visual = renderImage(adapterProps);\n }\n\n return (\n <span\n {...props}\n ref={ref}\n className={classNames(\"hjm-image\", className)}\n data-fit={descriptor.fit}\n data-status={status}\n style={{\n inlineSize: descriptor.width,\n ...style,\n ...layoutStyle,\n aspectRatio: resolveImageAspectRatio(\n descriptor.width,\n descriptor.height,\n ),\n }}\n >\n {visual}\n </span>\n );\n});\n\nexport type CounterBadgeProps = Omit<HTMLAttributes<HTMLSpanElement>, \"children\"> &\n Readonly<{\n count: number;\n max?: number;\n tone?: CounterBadgeTone;\n size?: CounterBadgeSize;\n variant?: CounterBadgeVariant;\n /**\n * Says \"there is something new\" without a number. Use it where the count is\n * unknown or not worth reading; inventing a number would be worse than\n * saying none. The accessible name then carries the whole meaning.\n */\n dot?: boolean;\n accessibilityLabel?: string;\n /** Canonical layout-only placement. Controlled visual keys are excluded. */\n layoutStyle?: HjmCompositionStyleProp;\n}>;\n\nexport const CounterBadge = forwardRef<HTMLSpanElement, CounterBadgeProps>(\n function CounterBadge(\n {\n count,\n max = counterBadgeRecipe.defaults.max,\n tone = counterBadgeRecipe.defaults.tone,\n size = counterBadgeRecipe.defaults.size,\n variant = counterBadgeRecipe.defaults.variant,\n dot = false,\n accessibilityLabel,\n className,\n layoutStyle,\n style,\n ...props\n },\n ref,\n ) {\n const label = formatCounterBadgeCount(count, max);\n if (accessibilityLabel !== undefined && accessibilityLabel.trim().length === 0) {\n throw new TypeError(\"CounterBadge accessibilityLabel must not be empty\");\n }\n if (dot && accessibilityLabel === undefined) {\n // A dot with no name is a decoration that nobody can read.\n throw new TypeError(\"CounterBadge dot requires an accessibilityLabel\");\n }\n if (label === null) return null;\n return (\n <span\n {...props}\n ref={ref}\n className={classNames(\"hjm-counter-badge\", className)}\n data-tone={tone}\n data-size={size}\n data-variant={variant}\n data-dot={dot || undefined}\n style={dot ? { ...style, ...layoutStyle, \"--hjm-counter-dot-size\": `${counterBadgeRecipe.dotSize}px` } as typeof style : { ...style, ...layoutStyle }}\n aria-hidden={accessibilityLabel === undefined || undefined}\n // A named count needs a semantic role; generic spans cannot carry aria-label.\n role={accessibilityLabel === undefined ? undefined : \"img\"}\n aria-label={accessibilityLabel}\n >\n {dot ? null : label}\n </span>\n );\n },\n);\n"]}
1
+ {"version":3,"file":"supplemental-display.js","sourceRoot":"","sources":["../src/supplemental-display.tsx"],"names":[],"mappings":";AAAA,OAAO,EACL,gBAAgB,EAChB,qBAAqB,EACrB,iBAAiB,GAGlB,MAAM,yCAAyC,CAAC;AACjD,OAAO,EACL,WAAW,EACX,uBAAuB,EACvB,sBAAsB,EACtB,sCAAsC,GAGvC,MAAM,0CAA0C,CAAC;AAClD,OAAO,EACL,kBAAkB,EAClB,uBAAuB,EACvB,UAAU,GAIX,MAAM,iCAAiC,CAAC;AACzC,OAAO,EACL,UAAU,EACV,QAAQ,EACR,OAAO,EACP,MAAM,EACN,eAAe,GAShB,MAAM,OAAO,CAAC;AACf,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAcpD,MAAM,CAAC,MAAM,IAAI,GAAG,UAAU,CAA2B,SAAS,IAAI,CACpE,EACE,IAAI,EACJ,IAAI,EACJ,IAAI,EACJ,MAAM,EACN,cAAc,EACd,UAAU,EACV,kBAAkB,EAClB,WAAW,EACX,SAAS,EACT,KAAK,EACL,WAAW,EACX,GAAG,KAAK,EACT,EACD,GAAG;IAEH,MAAM,UAAU,GAAG,qBAAqB,CAAC;QACvC,IAAI;QACJ,GAAG,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC;QACvC,GAAG,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC;QACvC,GAAG,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC;QAC3C,GAAG,CAAC,cAAc,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,CAAC;QAC3D,GAAG,CAAC,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC;QACnD,GAAG,CAAC,kBAAkB,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,kBAAkB,EAAE,CAAC;KAClD,CAAC,CAAC;IACrB,MAAM,KAAK,GAAG,mBAAmB,EAAE,CAAC;IACpC,MAAM,SAAS,GAAG,gBAAgB,CAChC,UAAU,CAAC,cAAc,EACzB,KAAK,EAAE,WAAW,CAAC,SAAS,IAAI,KAAK,CACtC,CAAC;IACF,MAAM,SAAS,GAAG,UAAU,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;IACpD,OAAO,CACL,iBACM,KAAK,EACT,GAAG,EAAE,GAAG,EACR,OAAO,EAAC,WAAW,EACnB,IAAI,EAAC,MAAM,EACX,KAAK,EAAC,4BAA4B,EAClC,SAAS,EAAE,UAAU,CAAC,UAAU,EAAE,SAAS,CAAC,eACjC,UAAU,CAAC,IAAI,eACf,UAAU,CAAC,IAAI,eACf,UAAU,CAAC,IAAI,iBACb,UAAU,CAAC,MAAM,oBACd,SAAS,EACzB,KAAK,EAAE,SAAS,EAChB,MAAM,EAAE,SAAS,EACjB,MAAM,EAAC,cAAc,EACrB,WAAW,EAAE,UAAU,CAAC,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC,EAClD,aAAa,EAAC,OAAO,EACrB,cAAc,EAAC,OAAO,EACtB,IAAI,EAAE,UAAU,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,iBAClC,UAAU,CAAC,UAAU,IAAI,SAAS,gBACnC,UAAU,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,UAAU,CAAC,kBAAkB,EAC7E,SAAS,EAAC,OAAO,EACjB,KAAK,EAAE,EAAE,GAAG,KAAK,EAAE,GAAG,WAAW,EAAE,YAElC,WAAW,EAAE,CAAC,EAAE,IAAI,EAAE,UAAU,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,UAAU,CAAC,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,eAAM,CAAC,EAAE,iBAAiB,CAAC,UAAU,CAAC,IAAI,CAAC,GAAI,GAC7K,CACP,CAAC;AACJ,CAAC,CAAC,CAAC;AAsEH,oFAAoF;AACpF,MAAM,CAAC,MAAM,KAAK,GAAG,UAAU,CAA8B,SAAS,KAAK,CACzE,EACE,GAAG,EACH,KAAK,EACL,MAAM,EACN,GAAG,EACH,UAAU,EACV,kBAAkB,EAClB,UAAU,EACV,WAAW,EACX,QAAQ,EACR,QAAQ,EACR,MAAM,EACN,OAAO,EACP,kBAAkB,EAClB,SAAS,EACT,KAAK,EACL,WAAW,EACX,GAAG,KAAK,EACT,EACD,GAAG;IAEH,MAAM,UAAU,GAAG,sBAAsB,CAAC;QACxC,GAAG;QACH,KAAK;QACL,MAAM;QACN,GAAG,CAAC,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC;QACrC,GAAG,CAAC,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC;QACnD,GAAG,CAAC,kBAAkB,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,kBAAkB,EAAE,CAAC;KACjD,CAAC,CAAC;IACtB,6EAA6E;IAC7E,oFAAoF;IACpF,8EAA8E;IAC9E,qEAAqE;IACrE,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,EAAE,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,UAAU,EAAE,cAAc,CAAC,CAAC,CAAC;IACrJ,MAAM,gBAAgB,GAAG,MAAM,CAAgB,UAAU,CAAC,CAAC;IAC3D,eAAe,CAAC,GAAG,EAAE;QACnB,gBAAgB,CAAC,OAAO,GAAG,UAAU,CAAC;QACtC,OAAO,GAAG,EAAE,GAAG,gBAAgB,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;IACpD,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC;IACjB,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAa,EAAE,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC;IAClF,MAAM,MAAM,GAAG,KAAK,CAAC,UAAU,KAAK,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC;IAC1E,MAAM,EACJ,SAAS,EAAE,cAAc,EACzB,KAAK,EAAE,UAAU,EACjB,GAAG,cAAc,EAClB,GAAG,UAAU,IAAI,EAAE,CAAC;IAErB,MAAM,UAAU,GAAwC,CAAC,KAAK,EAAE,EAAE;QAChE,IAAI,gBAAgB,CAAC,OAAO,KAAK,UAAU;YAAE,OAAO;QACpD,QAAQ,CAAC,EAAE,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC;QAC3C,kBAAkB,EAAE,CAAC,QAAQ,CAAC,CAAC;QAC/B,MAAM,EAAE,CAAC,KAAK,CAAC,CAAC;IAClB,CAAC,CAAC;IACF,MAAM,WAAW,GAAwC,CAAC,KAAK,EAAE,EAAE;QACjE,IAAI,gBAAgB,CAAC,OAAO,KAAK,UAAU;YAAE,OAAO;QACpD,QAAQ,CAAC,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC;QAC1C,kBAAkB,EAAE,CAAC,OAAO,CAAC,CAAC;QAC9B,OAAO,EAAE,CAAC,KAAK,CAAC,CAAC;IACnB,CAAC,CAAC;IACF,MAAM,YAAY,GAAsB;QACtC,GAAG,cAAc;QACjB,GAAG,EAAE,UAAU,CAAC,GAAG;QACnB,GAAG,EAAE,UAAU,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,kBAAkB;QAC/D,KAAK,EAAE,UAAU,CAAC,KAAK;QACvB,MAAM,EAAE,UAAU,CAAC,MAAM;QACzB,SAAS,EAAE,UAAU,CAAC,kBAAkB,EAAE,cAAc,CAAC;YACvD,kBAAkB;QACpB,KAAK,EAAE,EAAE,GAAG,UAAU,EAAE,SAAS,EAAE,UAAU,CAAC,GAAG,EAAE;QACnD,GAAG,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACzD,MAAM,EAAE,UAAU;QAClB,OAAO,EAAE,WAAW;QACpB,GAAG,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,QAAQ,EAAE,CAAC;KACrD,CAAC;IAEF,IAAI,MAAiB,CAAC;IACtB,IAAI,MAAM,KAAK,OAAO,EAAE,CAAC;QACvB,MAAM,aAAa,GAAG,sCAAsC,CAAC,UAAU,CAAC,CAAC;QACzE,MAAM,GAAG,CACP,eACE,SAAS,EAAC,qBAAqB,EAC/B,IAAI,EAAE,UAAU,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,gBACnC,aAAa,iBACZ,UAAU,CAAC,UAAU,IAAI,SAAS,YAE/C,eAAM,SAAS,EAAC,0BAA0B,iBAAa,MAAM,YAC1D,QAAQ,IAAI,CACX,KAAC,IAAI,IACH,IAAI,EAAE,WAAW,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,EACpC,IAAI,EAAE,WAAW,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,EACpC,UAAU,SACV,CACH,GACI,GACF,CACR,CAAC;IACJ,CAAC;SAAM,IAAI,WAAW,KAAK,SAAS,EAAE,CAAC;QACrC,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,GAAG,gBAAgB,EAAE,GAAG,YAAY,CAAC;QAC5D,MAAM,GAAG,iBAAS,gBAAgB,EAAE,GAAG,EAAE,QAAQ,GAAI,CAAC;IACxD,CAAC;SAAM,CAAC;QACN,MAAM,GAAG,WAAW,CAAC,YAAY,CAAC,CAAC;IACrC,CAAC;IAED,OAAO,CACL,kBACM,KAAK,EACT,GAAG,EAAE,GAAG,EACR,SAAS,EAAE,UAAU,CAAC,WAAW,EAAE,SAAS,CAAC,cACnC,UAAU,CAAC,GAAG,iBACX,MAAM,EACnB,KAAK,EAAE;YACL,UAAU,EAAE,UAAU,CAAC,KAAK;YAC5B,GAAG,KAAK;YACR,GAAG,WAAW;YACd,WAAW,EAAE,uBAAuB,CAClC,UAAU,CAAC,KAAK,EAChB,UAAU,CAAC,MAAM,CAClB;SACF,YAEA,MAAM,GACF,CACR,CAAC;AACJ,CAAC,CAAC,CAAC;AAoBH,MAAM,CAAC,MAAM,YAAY,GAAG,UAAU,CACpC,SAAS,YAAY,CACnB,EACE,KAAK,EACL,GAAG,GAAG,kBAAkB,CAAC,QAAQ,CAAC,GAAG,EACrC,IAAI,GAAG,kBAAkB,CAAC,QAAQ,CAAC,IAAI,EACvC,IAAI,GAAG,kBAAkB,CAAC,QAAQ,CAAC,IAAI,EACvC,OAAO,GAAG,kBAAkB,CAAC,QAAQ,CAAC,OAAO,EAC7C,GAAG,GAAG,KAAK,EACX,kBAAkB,EAClB,SAAS,EACT,WAAW,EACX,KAAK,EACL,GAAG,KAAK,EACT,EACD,GAAG;IAEH,MAAM,KAAK,GAAG,uBAAuB,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IAClD,IAAI,kBAAkB,KAAK,SAAS,IAAI,kBAAkB,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC/E,MAAM,IAAI,SAAS,CAAC,mDAAmD,CAAC,CAAC;IAC3E,CAAC;IACD,IAAI,GAAG,IAAI,kBAAkB,KAAK,SAAS,EAAE,CAAC;QAC5C,2DAA2D;QAC3D,MAAM,IAAI,SAAS,CAAC,iDAAiD,CAAC,CAAC;IACzE,CAAC;IACD,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IAChC,OAAO,CACL,kBACM,KAAK,EACT,GAAG,EAAE,GAAG,EACR,SAAS,EAAE,UAAU,CAAC,mBAAmB,EAAE,SAAS,CAAC,eAC1C,IAAI,eACJ,IAAI,kBACD,OAAO,cACX,GAAG,IAAI,SAAS,EAC1B,KAAK,EAAE,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,KAAK,EAAE,GAAG,WAAW,EAAE,wBAAwB,EAAE,GAAG,kBAAkB,CAAC,OAAO,IAAI,EAAkB,CAAC,CAAC,CAAC,EAAE,GAAG,KAAK,EAAE,GAAG,WAAW,EAAE,iBACxI,kBAAkB,KAAK,SAAS,IAAI,SAAS;QAC1D,8EAA8E;QAC9E,IAAI,EAAE,kBAAkB,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,gBAC9C,kBAAkB,YAE7B,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,GACd,CACR,CAAC;AACJ,CAAC,CACF,CAAC","sourcesContent":["import {\n getIconTransform,\n resolveIconDescriptor,\n semanticIconPaths,\n type IconDescriptor,\n type SemanticIconName,\n} from \"@hjmds/design-contracts/components/icon\";\nimport {\n imageRecipe,\n resolveImageAspectRatio,\n resolveImageDescriptor,\n resolveImageFallbackAccessibilityLabel,\n type ImageDescriptor,\n type ImageLoadStatus,\n} from \"@hjmds/design-contracts/components/image\";\nimport {\n counterBadgeRecipe,\n formatCounterBadgeCount,\n iconRecipe,\n type CounterBadgeSize,\n type CounterBadgeTone,\n type CounterBadgeVariant,\n} from \"@hjmds/design-contracts/recipes\";\nimport {\n forwardRef,\n useState,\n useMemo,\n useRef,\n useLayoutEffect,\n type CSSProperties,\n type HTMLAttributes,\n type ImgHTMLAttributes,\n type ReactElement,\n type ReactEventHandler,\n type ReactNode,\n type Ref,\n type SVGAttributes,\n} from \"react\";\nimport { classNames } from \"./internal.js\";\nimport { useOptionalHjmTheme } from \"./provider.js\";\nimport type { HjmCompositionStyleProp } from \"./composition-style.js\";\n\n\nexport type IconProps = Omit<\n SVGAttributes<SVGSVGElement>,\n \"children\" | \"color\"\n> & IconDescriptor & Readonly<{\n /** Optional glyph inside the existing 24-unit SVG frame; HJM owns semantics. */\n renderGlyph?: (props: Readonly<{ name: SemanticIconName; size: number; color: string; strokeWidth: number }>) => ReactNode;\n /** Canonical layout-only placement on the root element. Controlled visual keys are excluded. */\n layoutStyle?: HjmCompositionStyleProp;\n}>;\n\nexport const Icon = forwardRef<SVGSVGElement, IconProps>(function Icon(\n {\n name,\n size,\n tone,\n weight,\n directionality,\n decorative,\n accessibilityLabel,\n renderGlyph,\n className,\n style,\n layoutStyle,\n ...props\n },\n ref,\n) {\n const descriptor = resolveIconDescriptor({\n name,\n ...(size === undefined ? {} : { size }),\n ...(tone === undefined ? {} : { tone }),\n ...(weight === undefined ? {} : { weight }),\n ...(directionality === undefined ? {} : { directionality }),\n ...(decorative === undefined ? {} : { decorative }),\n ...(accessibilityLabel === undefined ? {} : { accessibilityLabel }),\n } as IconDescriptor);\n const theme = useOptionalHjmTheme();\n const transform = getIconTransform(\n descriptor.directionality,\n theme?.environment.direction ?? \"ltr\",\n );\n const dimension = iconRecipe.sizes[descriptor.size];\n return (\n <svg\n {...props}\n ref={ref}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n className={classNames(\"hjm-icon\", className)}\n data-name={descriptor.name}\n data-size={descriptor.size}\n data-tone={descriptor.tone}\n data-weight={descriptor.weight}\n data-transform={transform}\n width={dimension}\n height={dimension}\n stroke=\"currentColor\"\n strokeWidth={iconRecipe.weights[descriptor.weight]}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n role={descriptor.decorative ? undefined : \"img\"}\n aria-hidden={descriptor.decorative || undefined}\n aria-label={descriptor.decorative ? undefined : descriptor.accessibilityLabel}\n focusable=\"false\"\n style={{ ...style, ...layoutStyle }}\n >\n {renderGlyph?.({ name: descriptor.name, size: 24, color: \"currentColor\", strokeWidth: iconRecipe.weights[descriptor.weight] }) ?? <path d={semanticIconPaths[descriptor.name]} />}\n </svg>\n );\n});\n\ntype ImageElementProps = Omit<\n ImgHTMLAttributes<HTMLImageElement>,\n | \"alt\"\n | \"aria-hidden\"\n | \"aria-label\"\n | \"children\"\n | \"className\"\n | \"height\"\n | \"onError\"\n | \"onLoad\"\n | \"role\"\n | \"src\"\n | \"style\"\n | \"width\"\n>;\n\n/** Canonical props handed to a framework adapter such as `next/image`. */\nexport type ImageAdapterProps = ImageElementProps &\n Readonly<{\n src: string;\n alt: string;\n width: number;\n height: number;\n className?: string;\n style: CSSProperties;\n \"aria-hidden\"?: true;\n onLoad: ReactEventHandler<HTMLImageElement>;\n onError: ReactEventHandler<HTMLImageElement>;\n ref?: Ref<HTMLImageElement>;\n }>;\n\ntype ImageRootProps = Omit<\n HTMLAttributes<HTMLSpanElement>,\n | \"aria-hidden\"\n | \"aria-label\"\n | \"aria-labelledby\"\n | \"children\"\n | \"onError\"\n | \"onLoad\"\n | \"role\"\n>;\n\nexport type ImageProps = ImageRootProps &\n ImageDescriptor &\n Readonly<{\n /** Additional native `<img>` props shared with the framework adapter. */\n imageProps?: ImageElementProps &\n Readonly<{ className?: string; style?: CSSProperties }>;\n /**\n * Receives the complete accessible image contract. The adapter must pass\n * these props to its underlying image element so HJM can observe failure.\n */\n renderImage?: (props: ImageAdapterProps) => ReactElement;\n /** Visual content only; HJM keeps the fallback's accessible name. */\n fallback?: ReactNode;\n imageRef?: Ref<HTMLImageElement>;\n onLoad?: ReactEventHandler<HTMLImageElement>;\n onError?: ReactEventHandler<HTMLImageElement>;\n onLoadStatusChange?: (status: Extract<ImageLoadStatus, \"loaded\" | \"error\">) => void;\n /** Canonical layout-only placement on the root frame; the aspect ratio stays descriptor-owned. */\n layoutStyle?: HjmCompositionStyleProp;\n }>;\n\ntype ImageState = Readonly<{\n generation: object;\n status: Extract<ImageLoadStatus, \"loading\" | \"loaded\" | \"error\">;\n}>;\n\n/** Intrinsic-size image with canonical alt semantics and an accessible fallback. */\nexport const Image = forwardRef<HTMLSpanElement, ImageProps>(function Image(\n {\n src,\n width,\n height,\n fit,\n decorative,\n accessibilityLabel,\n imageProps,\n renderImage,\n fallback,\n imageRef,\n onLoad,\n onError,\n onLoadStatusChange,\n className,\n style,\n layoutStyle,\n ...props\n },\n ref,\n) {\n const descriptor = resolveImageDescriptor({\n src,\n width,\n height,\n ...(fit === undefined ? {} : { fit }),\n ...(decorative === undefined ? {} : { decorative }),\n ...(accessibilityLabel === undefined ? {} : { accessibilityLabel }),\n } as ImageDescriptor);\n // A→B→A is a new request even when the URL repeats. Retire adapter callbacks\n // at commit/unmount so old network events cannot update state or product observers.\n // Responsive source candidates and request policy are part of image identity;\n // a new srcSet must recover even when its fallback src is unchanged.\n const generation = useMemo(() => ({}), [descriptor.src, imageProps?.srcSet, imageProps?.sizes, imageProps?.crossOrigin, imageProps?.referrerPolicy]);\n const activeGeneration = useRef<object | null>(generation);\n useLayoutEffect(() => {\n activeGeneration.current = generation;\n return () => { activeGeneration.current = null; };\n }, [generation]);\n const [state, setState] = useState<ImageState>({ generation, status: \"loading\" });\n const status = state.generation === generation ? state.status : \"loading\";\n const {\n className: imageClassName,\n style: imageStyle,\n ...restImageProps\n } = imageProps ?? {};\n\n const handleLoad: ReactEventHandler<HTMLImageElement> = (event) => {\n if (activeGeneration.current !== generation) return;\n setState({ generation, status: \"loaded\" });\n onLoadStatusChange?.(\"loaded\");\n onLoad?.(event);\n };\n const handleError: ReactEventHandler<HTMLImageElement> = (event) => {\n if (activeGeneration.current !== generation) return;\n setState({ generation, status: \"error\" });\n onLoadStatusChange?.(\"error\");\n onError?.(event);\n };\n const adapterProps: ImageAdapterProps = {\n ...restImageProps,\n src: descriptor.src,\n alt: descriptor.decorative ? \"\" : descriptor.accessibilityLabel,\n width: descriptor.width,\n height: descriptor.height,\n className: classNames(\"hjm-image__asset\", imageClassName) ??\n \"hjm-image__asset\",\n style: { ...imageStyle, objectFit: descriptor.fit },\n ...(descriptor.decorative ? { \"aria-hidden\": true } : {}),\n onLoad: handleLoad,\n onError: handleError,\n ...(imageRef === undefined ? {} : { ref: imageRef }),\n };\n\n let visual: ReactNode;\n if (status === \"error\") {\n const fallbackLabel = resolveImageFallbackAccessibilityLabel(descriptor);\n visual = (\n <span\n className=\"hjm-image__fallback\"\n role={descriptor.decorative ? undefined : \"img\"}\n aria-label={fallbackLabel}\n aria-hidden={descriptor.decorative || undefined}\n >\n <span className=\"hjm-image__fallback-icon\" aria-hidden=\"true\">\n {fallback ?? (\n <Icon\n name={imageRecipe.fallback.icon.name}\n tone={imageRecipe.fallback.icon.tone}\n decorative\n />\n )}\n </span>\n </span>\n );\n } else if (renderImage === undefined) {\n const { ref: assetRef, ...nativeImageProps } = adapterProps;\n visual = <img {...nativeImageProps} ref={assetRef} />;\n } else {\n visual = renderImage(adapterProps);\n }\n\n return (\n <span\n {...props}\n ref={ref}\n className={classNames(\"hjm-image\", className)}\n data-fit={descriptor.fit}\n data-status={status}\n style={{\n inlineSize: descriptor.width,\n ...style,\n ...layoutStyle,\n aspectRatio: resolveImageAspectRatio(\n descriptor.width,\n descriptor.height,\n ),\n }}\n >\n {visual}\n </span>\n );\n});\n\nexport type CounterBadgeProps = Omit<HTMLAttributes<HTMLSpanElement>, \"children\"> &\n Readonly<{\n count: number;\n max?: number;\n tone?: CounterBadgeTone;\n size?: CounterBadgeSize;\n variant?: CounterBadgeVariant;\n /**\n * Says \"there is something new\" without a number. Use it where the count is\n * unknown or not worth reading; inventing a number would be worse than\n * saying none. The accessible name then carries the whole meaning.\n */\n dot?: boolean;\n accessibilityLabel?: string;\n /** Canonical layout-only placement. Controlled visual keys are excluded. */\n layoutStyle?: HjmCompositionStyleProp;\n}>;\n\nexport const CounterBadge = forwardRef<HTMLSpanElement, CounterBadgeProps>(\n function CounterBadge(\n {\n count,\n max = counterBadgeRecipe.defaults.max,\n tone = counterBadgeRecipe.defaults.tone,\n size = counterBadgeRecipe.defaults.size,\n variant = counterBadgeRecipe.defaults.variant,\n dot = false,\n accessibilityLabel,\n className,\n layoutStyle,\n style,\n ...props\n },\n ref,\n ) {\n const label = formatCounterBadgeCount(count, max);\n if (accessibilityLabel !== undefined && accessibilityLabel.trim().length === 0) {\n throw new TypeError(\"CounterBadge accessibilityLabel must not be empty\");\n }\n if (dot && accessibilityLabel === undefined) {\n // A dot with no name is a decoration that nobody can read.\n throw new TypeError(\"CounterBadge dot requires an accessibilityLabel\");\n }\n if (label === null) return null;\n return (\n <span\n {...props}\n ref={ref}\n className={classNames(\"hjm-counter-badge\", className)}\n data-tone={tone}\n data-size={size}\n data-variant={variant}\n data-dot={dot || undefined}\n style={dot ? { ...style, ...layoutStyle, \"--hjm-counter-dot-size\": `${counterBadgeRecipe.dotSize}px` } as typeof style : { ...style, ...layoutStyle }}\n aria-hidden={accessibilityLabel === undefined || undefined}\n // A named count needs a semantic role; generic spans cannot carry aria-label.\n role={accessibilityLabel === undefined ? undefined : \"img\"}\n aria-label={accessibilityLabel}\n >\n {dot ? null : label}\n </span>\n );\n },\n);\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"theme.d.ts","sourceRoot":"","sources":["../src/theme.ts"],"names":[],"mappings":"AAkBA,OAAO,EAEL,KAAK,yBAAyB,EAC/B,MAAM,2DAA2D,CAAC;AAoBnE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAE3C,MAAM,MAAM,aAAa,GAAG,aAAa,GACvC,MAAM,CAAC,SAAS,MAAM,EAAE,EAAE,MAAM,GAAG,MAAM,CAAC,CAAC;AAmB7C,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,yBAAyB,GAC/B,aAAa,CAoOf"}
1
+ {"version":3,"file":"theme.d.ts","sourceRoot":"","sources":["../src/theme.ts"],"names":[],"mappings":"AAkBA,OAAO,EAEL,KAAK,yBAAyB,EAC/B,MAAM,2DAA2D,CAAC;AAoBnE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAE3C,MAAM,MAAM,aAAa,GAAG,aAAa,GACvC,MAAM,CAAC,SAAS,MAAM,EAAE,EAAE,MAAM,GAAG,MAAM,CAAC,CAAC;AAmB7C,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,yBAAyB,GAC/B,aAAa,CAqOf"}
package/dist/theme.js CHANGED
@@ -157,6 +157,7 @@ export function createHjmThemeStyle(value) {
157
157
  // dialogs, sheets and toasts cannot retain neutral shadows after a theme switch.
158
158
  style[`--hjm-${name}-shadow`] = shadowCss(profileTokens?.shadow.floating ?? chrome.shadow);
159
159
  }
160
+ style["--hjm-immersive-background"] = resolveColorReference(dialogRecipe.immersive.background, palette);
160
161
  style["--hjm-sheet-max-height"] = `${sheetRecipe.content.maxHeightRatio * 100}dvh`;
161
162
  style["--hjm-sheet-max-width"] = `${sheetRecipe.web.maxWidth}px`;
162
163
  style["--hjm-sheet-handle-width"] = `${sheetRecipe.handle.width}px`;