@hjmds/react 1.35.0 → 1.36.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.
package/dist/styles.css CHANGED
@@ -1061,6 +1061,9 @@ button.hjm-list-row, a.hjm-list-row { cursor: pointer; }
1061
1061
  the avatar box in product styles. */
1062
1062
  .hjm-list-row__leading { display: flex; align-items: center; justify-content: center; inline-size: var(--hjm-list-row-leading-size); block-size: var(--hjm-list-row-leading-size); overflow: hidden; }
1063
1063
  .hjm-list-row__leading[data-shape="circle"] { border-radius: var(--hjm-radius-full); }
1064
+ /* Photo source peers share ListRow geometry; only their decorative brand plate is specialized. */
1065
+ .hjm-photo-source__icon { display: grid; place-items: center; inline-size: 100%; block-size: 100%; border-radius: var(--hjm-radius-md); }
1066
+ .hjm-photo-source__icon svg { inline-size: 24px; block-size: 24px; }
1064
1067
  .hjm-list-row__content { flex: 1 1 auto; min-inline-size: 0; display: grid; gap: var(--hjm-space-xxs); }
1065
1068
  /* listRowRecipe title bodyLarge / description body (2026-10-17: Web inherited 14 for both while Native used the recipe). */
1066
1069
  .hjm-list-row__title { color: var(--hjm-color-text-body); font-size: var(--hjm-type-body-large-size); line-height: var(--hjm-type-body-large-line-height); font-weight: var(--hjm-type-title-weight); overflow-wrap: anywhere; }
@@ -2383,7 +2386,8 @@ button.hjm-list-row, a.hjm-list-row { cursor: pointer; }
2383
2386
  display: flex;
2384
2387
  flex-wrap: wrap;
2385
2388
  justify-content: flex-end;
2386
- gap: var(--hjm-space-sm);
2389
+ /* Match actionGroupRecipe: 8px in either direction (2026-10-20 user request). */
2390
+ gap: var(--hjm-space-xs);
2387
2391
  padding: 0 var(--hjm-space-lg) var(--hjm-space-lg);
2388
2392
  }
2389
2393
  .hjm-dialog__close {
@@ -2675,6 +2679,27 @@ button.hjm-list-row, a.hjm-list-row { cursor: pointer; }
2675
2679
  .hjm-menu__leading,
2676
2680
  .hjm-menu__trailing { flex: 0 0 auto; color: var(--hjm-color-text-muted); }
2677
2681
 
2682
+ /* Three Menu presentations share items and focus semantics; modal chrome never belongs to a consumer. */
2683
+ .hjm-menu-positioner[data-presentation="bottom"] { align-items: end; padding-block-end: max(var(--hjm-space-md), env(safe-area-inset-bottom)); }
2684
+ .hjm-menu__content[data-presentation="grouped"],
2685
+ .hjm-menu__content[data-presentation="bottom"] {
2686
+ position: relative; inset: auto; display: flex; flex-direction: column; gap: var(--hjm-space-xs);
2687
+ inline-size: min(18rem, 100%); min-inline-size: 0; max-inline-size: 100%;
2688
+ max-block-size: calc(100dvh - 2 * var(--hjm-space-md)); padding: var(--hjm-space-sm);
2689
+ border-radius: var(--hjm-radius-lg);
2690
+ }
2691
+ .hjm-menu__content[data-presentation="bottom"] { inline-size: min(26.25rem, 100%); padding: 0; border: 0; background: transparent; box-shadow: none; }
2692
+ .hjm-menu__content[data-presentation="bottom"] .hjm-menu__viewport { background: var(--hjm-color-bg); }
2693
+ .hjm-menu__content[data-presentation="grouped"] .hjm-menu__viewport,
2694
+ .hjm-menu__content[data-presentation="bottom"] .hjm-menu__viewport { min-block-size: 0; overflow: auto; border-radius: var(--hjm-radius-md); }
2695
+ .hjm-menu__content[data-presentation="grouped"] .hjm-menu__viewport { background: var(--hjm-color-surface); }
2696
+ .hjm-menu__content[data-presentation="anchored"] .hjm-menu__item + .hjm-menu__item,
2697
+ .hjm-menu__content[data-presentation="grouped"] .hjm-menu__item + .hjm-menu__item,
2698
+ .hjm-menu__content[data-presentation="bottom"] .hjm-menu__item + .hjm-menu__item { border-block-start: 1px solid var(--hjm-color-border); border-radius: 0; }
2699
+ .hjm-menu__content[data-presentation="grouped"][data-density="comfortable"] .hjm-menu__item { min-block-size: 3.25rem; }
2700
+ .hjm-menu__content[data-presentation="grouped"] > .hjm-button,
2701
+ .hjm-menu__content[data-presentation="bottom"] > .hjm-button { flex-shrink: 0; inline-size: 100%; }
2702
+
2678
2703
  /* Advanced forms --------------------------------------------------------- */
2679
2704
  .hjm-select__native { appearance: none; padding-inline-end: calc(var(--hjm-space-lg) + var(--hjm-space-sm)); cursor: pointer; }
2680
2705
  .hjm-select__anchor { position: relative; min-inline-size: 0; }
@@ -3397,13 +3422,13 @@ button.hjm-list-row, a.hjm-list-row { cursor: pointer; }
3397
3422
  .hjm-chat-message[data-direction="outgoing"] .hjm-chat-message__body { flex-direction: row-reverse; }
3398
3423
  .hjm-chat-message__bubble { border-radius: 14px; background: var(--hjm-color-surface); padding: 6px 10px; min-inline-size: 0; overflow-wrap: anywhere; white-space: pre-wrap; }
3399
3424
  .hjm-chat-message[data-direction="outgoing"] .hjm-chat-message__bubble { background: var(--hjm-color-surface-accent); }
3400
- /* A flat-topped tip in the bubble surface continues the run's first top edge; that corner tightens to meet it. */
3425
+ /* Tighten the first corner to join the overlapping rounded tip. */
3401
3426
  .hjm-chat-message[data-tail] .hjm-chat-message__bubble { position: relative; border-start-start-radius: 4px; }
3402
- .hjm-chat-message[data-tail] .hjm-chat-message__bubble::before { content: ""; position: absolute; top: 0; inset-inline-start: -6px; width: 7px; height: 10px; background: var(--hjm-color-surface); clip-path: polygon(0 0, 100% 0, 100% 100%); pointer-events: none; }
3427
+ /* The reference tip follows the top edge; its curved underside joins the bubble (2026-10-20). */
3428
+ .hjm-chat-message[data-tail] .hjm-chat-message__bubble::before { content: ""; position: absolute; top: 0; inset-inline-start: -6px; width: 11px; height: 10px; border-start-start-radius: 1px; border-end-start-radius: 10px; background: var(--hjm-color-surface); pointer-events: none; }
3403
3429
  .hjm-chat-message[data-tail][data-direction="outgoing"] .hjm-chat-message__bubble { border-start-start-radius: 14px; border-start-end-radius: 4px; }
3404
- .hjm-chat-message[data-tail][data-direction="outgoing"] .hjm-chat-message__bubble::before { inset-inline-start: auto; inset-inline-end: -6px; background: var(--hjm-color-surface-accent); clip-path: polygon(0 0, 100% 0, 0 100%); }
3405
- /* clip-path is physical; mirror the tip for right-to-left layouts. */
3406
- [dir="rtl"] .hjm-chat-message[data-tail] .hjm-chat-message__bubble::before { transform: scaleX(-1); }
3430
+ .hjm-chat-message[data-tail][data-direction="outgoing"] .hjm-chat-message__bubble::before { inset-inline-start: auto; inset-inline-end: -6px; border-start-start-radius: 0; border-end-start-radius: 0; border-start-end-radius: 1px; border-end-end-radius: 10px; background: var(--hjm-color-surface-accent); }
3431
+ /* Logical corner radii and insets mirror the curved tail in RTL. */
3407
3432
 
3408
3433
  .hjm-chat-message__meta { display: flex; flex-shrink: 0; align-items: center; gap: var(--hjm-space-xs); }
3409
3434
  /* Reaction summary pill (sizes inline from chatMessageRecipe.reactionSummary); own reaction shows the brand border. */
@@ -3592,11 +3617,12 @@ button.hjm-chat-message__media-item:focus-visible { outline: 2px solid var(--hjm
3592
3617
  /* Keep the inset pill behind the whole line at large text (40px text / 28px fill was observed). Native already includes this inset as vertical padding. */
3593
3618
  .hjm-segmented[data-presentation="pills"] .hjm-segmented__items { flex-wrap:wrap; gap:var(--hjm-space-xs); overflow:visible; padding:0; border:0; border-radius:0; background:transparent; }
3594
3619
  .hjm-segmented[data-presentation="pills"] .hjm-segmented__item { padding-block:var(--hjm-space-xxs); position:relative; flex:0 1 auto; min-inline-size:0; min-block-size:max(var(--hjm-control-min-touch-target), calc(var(--hjm-segmented-height) + 2 * var(--hjm-space-xxs))); border:0; border-radius:var(--hjm-radius-full); background:transparent; box-shadow:none; padding-inline:var(--hjm-space-md); color:var(--hjm-color-text-muted); }
3595
- .hjm-segmented[data-presentation="pills"] .hjm-segmented__item::before { content:""; position:absolute; inset:var(--hjm-space-xxs) 0; border-radius:var(--hjm-radius-full); background:var(--hjm-color-surface-alt); }
3620
+ /* Outline the inset surface, preserving the pill's layout and touch target on colored scenes. */
3621
+ .hjm-segmented[data-presentation="pills"] .hjm-segmented__item::before { content:""; position:absolute; inset:var(--hjm-space-xxs) 0; border-radius:var(--hjm-radius-full); background:var(--hjm-color-bg); border:1px solid var(--hjm-color-border-control); }
3596
3622
  .hjm-segmented[data-presentation="pills"][data-size="small"] .hjm-segmented__item { padding-inline:var(--hjm-space-sm); }
3597
3623
  .hjm-segmented[data-presentation="pills"] .hjm-segmented__item > span { position:relative; overflow-wrap:anywhere; }
3598
3624
  .hjm-segmented[data-presentation="pills"] .hjm-segmented__item[data-state="checked"] { color:var(--hjm-color-bg); font-weight:var(--hjm-font-weight-semibold); }
3599
- .hjm-segmented[data-presentation="pills"] .hjm-segmented__item[data-state="checked"]::before { background:var(--hjm-color-text-body); }
3625
+ .hjm-segmented[data-presentation="pills"] .hjm-segmented__item[data-state="checked"]::before { background:var(--hjm-color-text-body); border-color:var(--hjm-color-text-body); }
3600
3626
  .hjm-segmented[data-presentation="pills"] .hjm-segmented__item:focus-within { outline:2px solid var(--hjm-color-focus); outline-offset:2px; }
3601
3627
 
3602
3628
  /* Reference rating: real radios preserve browser keyboard and form behavior. */
@@ -1062,6 +1062,9 @@ button.hjm-list-row, a.hjm-list-row { cursor: pointer; }
1062
1062
  the avatar box in product styles. */
1063
1063
  .hjm-list-row__leading { display: flex; align-items: center; justify-content: center; inline-size: var(--hjm-list-row-leading-size); block-size: var(--hjm-list-row-leading-size); overflow: hidden; }
1064
1064
  .hjm-list-row__leading[data-shape="circle"] { border-radius: var(--hjm-radius-full); }
1065
+ /* Photo source peers share ListRow geometry; only their decorative brand plate is specialized. */
1066
+ .hjm-photo-source__icon { display: grid; place-items: center; inline-size: 100%; block-size: 100%; border-radius: var(--hjm-radius-md); }
1067
+ .hjm-photo-source__icon svg { inline-size: 24px; block-size: 24px; }
1065
1068
  .hjm-list-row__content { flex: 1 1 auto; min-inline-size: 0; display: grid; gap: var(--hjm-space-xxs); }
1066
1069
  /* listRowRecipe title bodyLarge / description body (2026-10-17: Web inherited 14 for both while Native used the recipe). */
1067
1070
  .hjm-list-row__title { color: var(--hjm-color-text-body); font-size: var(--hjm-type-body-large-size); line-height: var(--hjm-type-body-large-line-height); font-weight: var(--hjm-type-title-weight); overflow-wrap: anywhere; }
@@ -2384,7 +2387,8 @@ button.hjm-list-row, a.hjm-list-row { cursor: pointer; }
2384
2387
  display: flex;
2385
2388
  flex-wrap: wrap;
2386
2389
  justify-content: flex-end;
2387
- gap: var(--hjm-space-sm);
2390
+ /* Match actionGroupRecipe: 8px in either direction (2026-10-20 user request). */
2391
+ gap: var(--hjm-space-xs);
2388
2392
  padding: 0 var(--hjm-space-lg) var(--hjm-space-lg);
2389
2393
  }
2390
2394
  .hjm-dialog__close {
@@ -2676,6 +2680,27 @@ button.hjm-list-row, a.hjm-list-row { cursor: pointer; }
2676
2680
  .hjm-menu__leading,
2677
2681
  .hjm-menu__trailing { flex: 0 0 auto; color: var(--hjm-color-text-muted); }
2678
2682
 
2683
+ /* Three Menu presentations share items and focus semantics; modal chrome never belongs to a consumer. */
2684
+ .hjm-menu-positioner[data-presentation="bottom"] { align-items: end; padding-block-end: max(var(--hjm-space-md), env(safe-area-inset-bottom)); }
2685
+ .hjm-menu__content[data-presentation="grouped"],
2686
+ .hjm-menu__content[data-presentation="bottom"] {
2687
+ position: relative; inset: auto; display: flex; flex-direction: column; gap: var(--hjm-space-xs);
2688
+ inline-size: min(18rem, 100%); min-inline-size: 0; max-inline-size: 100%;
2689
+ max-block-size: calc(100dvh - 2 * var(--hjm-space-md)); padding: var(--hjm-space-sm);
2690
+ border-radius: var(--hjm-radius-lg);
2691
+ }
2692
+ .hjm-menu__content[data-presentation="bottom"] { inline-size: min(26.25rem, 100%); padding: 0; border: 0; background: transparent; box-shadow: none; }
2693
+ .hjm-menu__content[data-presentation="bottom"] .hjm-menu__viewport { background: var(--hjm-color-bg); }
2694
+ .hjm-menu__content[data-presentation="grouped"] .hjm-menu__viewport,
2695
+ .hjm-menu__content[data-presentation="bottom"] .hjm-menu__viewport { min-block-size: 0; overflow: auto; border-radius: var(--hjm-radius-md); }
2696
+ .hjm-menu__content[data-presentation="grouped"] .hjm-menu__viewport { background: var(--hjm-color-surface); }
2697
+ .hjm-menu__content[data-presentation="anchored"] .hjm-menu__item + .hjm-menu__item,
2698
+ .hjm-menu__content[data-presentation="grouped"] .hjm-menu__item + .hjm-menu__item,
2699
+ .hjm-menu__content[data-presentation="bottom"] .hjm-menu__item + .hjm-menu__item { border-block-start: 1px solid var(--hjm-color-border); border-radius: 0; }
2700
+ .hjm-menu__content[data-presentation="grouped"][data-density="comfortable"] .hjm-menu__item { min-block-size: 3.25rem; }
2701
+ .hjm-menu__content[data-presentation="grouped"] > .hjm-button,
2702
+ .hjm-menu__content[data-presentation="bottom"] > .hjm-button { flex-shrink: 0; inline-size: 100%; }
2703
+
2679
2704
  /* Advanced forms --------------------------------------------------------- */
2680
2705
  .hjm-select__native { appearance: none; padding-inline-end: calc(var(--hjm-space-lg) + var(--hjm-space-sm)); cursor: pointer; }
2681
2706
  .hjm-select__anchor { position: relative; min-inline-size: 0; }
@@ -3398,13 +3423,13 @@ button.hjm-list-row, a.hjm-list-row { cursor: pointer; }
3398
3423
  .hjm-chat-message[data-direction="outgoing"] .hjm-chat-message__body { flex-direction: row-reverse; }
3399
3424
  .hjm-chat-message__bubble { border-radius: 14px; background: var(--hjm-color-surface); padding: 6px 10px; min-inline-size: 0; overflow-wrap: anywhere; white-space: pre-wrap; }
3400
3425
  .hjm-chat-message[data-direction="outgoing"] .hjm-chat-message__bubble { background: var(--hjm-color-surface-accent); }
3401
- /* A flat-topped tip in the bubble surface continues the run's first top edge; that corner tightens to meet it. */
3426
+ /* Tighten the first corner to join the overlapping rounded tip. */
3402
3427
  .hjm-chat-message[data-tail] .hjm-chat-message__bubble { position: relative; border-start-start-radius: 4px; }
3403
- .hjm-chat-message[data-tail] .hjm-chat-message__bubble::before { content: ""; position: absolute; top: 0; inset-inline-start: -6px; width: 7px; height: 10px; background: var(--hjm-color-surface); clip-path: polygon(0 0, 100% 0, 100% 100%); pointer-events: none; }
3428
+ /* The reference tip follows the top edge; its curved underside joins the bubble (2026-10-20). */
3429
+ .hjm-chat-message[data-tail] .hjm-chat-message__bubble::before { content: ""; position: absolute; top: 0; inset-inline-start: -6px; width: 11px; height: 10px; border-start-start-radius: 1px; border-end-start-radius: 10px; background: var(--hjm-color-surface); pointer-events: none; }
3404
3430
  .hjm-chat-message[data-tail][data-direction="outgoing"] .hjm-chat-message__bubble { border-start-start-radius: 14px; border-start-end-radius: 4px; }
3405
- .hjm-chat-message[data-tail][data-direction="outgoing"] .hjm-chat-message__bubble::before { inset-inline-start: auto; inset-inline-end: -6px; background: var(--hjm-color-surface-accent); clip-path: polygon(0 0, 100% 0, 0 100%); }
3406
- /* clip-path is physical; mirror the tip for right-to-left layouts. */
3407
- [dir="rtl"] .hjm-chat-message[data-tail] .hjm-chat-message__bubble::before { transform: scaleX(-1); }
3431
+ .hjm-chat-message[data-tail][data-direction="outgoing"] .hjm-chat-message__bubble::before { inset-inline-start: auto; inset-inline-end: -6px; border-start-start-radius: 0; border-end-start-radius: 0; border-start-end-radius: 1px; border-end-end-radius: 10px; background: var(--hjm-color-surface-accent); }
3432
+ /* Logical corner radii and insets mirror the curved tail in RTL. */
3408
3433
 
3409
3434
  .hjm-chat-message__meta { display: flex; flex-shrink: 0; align-items: center; gap: var(--hjm-space-xs); }
3410
3435
  /* Reaction summary pill (sizes inline from chatMessageRecipe.reactionSummary); own reaction shows the brand border. */
@@ -3593,11 +3618,12 @@ button.hjm-chat-message__media-item:focus-visible { outline: 2px solid var(--hjm
3593
3618
  /* Keep the inset pill behind the whole line at large text (40px text / 28px fill was observed). Native already includes this inset as vertical padding. */
3594
3619
  .hjm-segmented[data-presentation="pills"] .hjm-segmented__items { flex-wrap:wrap; gap:var(--hjm-space-xs); overflow:visible; padding:0; border:0; border-radius:0; background:transparent; }
3595
3620
  .hjm-segmented[data-presentation="pills"] .hjm-segmented__item { padding-block:var(--hjm-space-xxs); position:relative; flex:0 1 auto; min-inline-size:0; min-block-size:max(var(--hjm-control-min-touch-target), calc(var(--hjm-segmented-height) + 2 * var(--hjm-space-xxs))); border:0; border-radius:var(--hjm-radius-full); background:transparent; box-shadow:none; padding-inline:var(--hjm-space-md); color:var(--hjm-color-text-muted); }
3596
- .hjm-segmented[data-presentation="pills"] .hjm-segmented__item::before { content:""; position:absolute; inset:var(--hjm-space-xxs) 0; border-radius:var(--hjm-radius-full); background:var(--hjm-color-surface-alt); }
3621
+ /* Outline the inset surface, preserving the pill's layout and touch target on colored scenes. */
3622
+ .hjm-segmented[data-presentation="pills"] .hjm-segmented__item::before { content:""; position:absolute; inset:var(--hjm-space-xxs) 0; border-radius:var(--hjm-radius-full); background:var(--hjm-color-bg); border:1px solid var(--hjm-color-border-control); }
3597
3623
  .hjm-segmented[data-presentation="pills"][data-size="small"] .hjm-segmented__item { padding-inline:var(--hjm-space-sm); }
3598
3624
  .hjm-segmented[data-presentation="pills"] .hjm-segmented__item > span { position:relative; overflow-wrap:anywhere; }
3599
3625
  .hjm-segmented[data-presentation="pills"] .hjm-segmented__item[data-state="checked"] { color:var(--hjm-color-bg); font-weight:var(--hjm-font-weight-semibold); }
3600
- .hjm-segmented[data-presentation="pills"] .hjm-segmented__item[data-state="checked"]::before { background:var(--hjm-color-text-body); }
3626
+ .hjm-segmented[data-presentation="pills"] .hjm-segmented__item[data-state="checked"]::before { background:var(--hjm-color-text-body); border-color:var(--hjm-color-text-body); }
3601
3627
  .hjm-segmented[data-presentation="pills"] .hjm-segmented__item:focus-within { outline:2px solid var(--hjm-color-focus); outline-offset:2px; }
3602
3628
 
3603
3629
  /* Reference rating: real radios preserve browser keyboard and form behavior. */
@@ -4,6 +4,8 @@ import { type HTMLAttributes } from "react";
4
4
  import type { HjmCompositionStyleProp } from "./composition-style.js";
5
5
  export type LoadMoreProps = Omit<HTMLAttributes<HTMLDivElement>, "children"> & Readonly<{
6
6
  descriptor: LoadMoreDescriptor;
7
+ /** Product mutation/refetch lock, separate from the next-page loading state. */
8
+ disabled?: boolean;
7
9
  mode?: LoadMoreMode;
8
10
  density?: LoadMoreDensity;
9
11
  onLoadMore: LoadMoreRequestHandler;
@@ -20,6 +22,8 @@ export type LoadMoreProps = Omit<HTMLAttributes<HTMLDivElement>, "children"> & R
20
22
  */
21
23
  export declare const LoadMore: import("react").ForwardRefExoticComponent<Omit<HTMLAttributes<HTMLDivElement>, "children"> & Readonly<{
22
24
  descriptor: LoadMoreDescriptor;
25
+ /** Product mutation/refetch lock, separate from the next-page loading state. */
26
+ disabled?: boolean;
23
27
  mode?: LoadMoreMode;
24
28
  density?: LoadMoreDensity;
25
29
  onLoadMore: LoadMoreRequestHandler;
@@ -1 +1 @@
1
- {"version":3,"file":"supplemental-navigation.d.ts","sourceRoot":"","sources":["../src/supplemental-navigation.tsx"],"names":[],"mappings":"AAAA,OAAO,EAKL,KAAK,kBAAkB,EACvB,KAAK,YAAY,EACjB,KAAK,sBAAsB,EAC3B,KAAK,sBAAsB,EAC3B,KAAK,qBAAqB,EAC3B,MAAM,8CAA8C,CAAC;AACtD,OAAO,EAEL,KAAK,eAAe,EACrB,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAOL,KAAK,cAAc,EACpB,MAAM,OAAO,CAAC;AAEf,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AA8BtE,MAAM,MAAM,aAAa,GAAG,IAAI,CAAC,cAAc,CAAC,cAAc,CAAC,EAAE,UAAU,CAAC,GAC1E,QAAQ,CAAC;IACP,UAAU,EAAE,kBAAkB,CAAC;IAC/B,IAAI,CAAC,EAAE,YAAY,CAAC;IACpB,OAAO,CAAC,EAAE,eAAe,CAAC;IAC1B,UAAU,EAAE,sBAAsB,CAAC;IACnC,gBAAgB,CAAC,EAAE,CACjB,OAAO,EAAE,sBAAsB,EAC/B,MAAM,EAAE,qBAAqB,KAC1B,IAAI,CAAC;IACV,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,qBAAqB,KAAK,IAAI,CAAC;IACzE,gBAAgB,CAAC,EAAE,OAAO,GAAG,QAAQ,GAAG,IAAI,CAAC;IAC7C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gGAAgG;IAChG,WAAW,CAAC,EAAE,uBAAuB,CAAC;CACvC,CAAC,CAAC;AAEL;;;GAGG;AACH,eAAO,MAAM,QAAQ;gBAnBL,kBAAkB;WACvB,YAAY;cACT,eAAe;gBACb,sBAAsB;uBACf,CACjB,OAAO,EAAE,sBAAsB,EAC/B,MAAM,EAAE,qBAAqB,KAC1B,IAAI;qBACQ,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,qBAAqB,KAAK,IAAI;uBACrD,OAAO,GAAG,QAAQ,GAAG,IAAI;iBAC/B,MAAM;IACnB,gGAAgG;kBAClF,uBAAuB;mDAyJxC,CAAC"}
1
+ {"version":3,"file":"supplemental-navigation.d.ts","sourceRoot":"","sources":["../src/supplemental-navigation.tsx"],"names":[],"mappings":"AAAA,OAAO,EAKL,KAAK,kBAAkB,EACvB,KAAK,YAAY,EACjB,KAAK,sBAAsB,EAC3B,KAAK,sBAAsB,EAC3B,KAAK,qBAAqB,EAC3B,MAAM,8CAA8C,CAAC;AACtD,OAAO,EAEL,KAAK,eAAe,EACrB,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAOL,KAAK,cAAc,EACpB,MAAM,OAAO,CAAC;AAEf,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AA8BtE,MAAM,MAAM,aAAa,GAAG,IAAI,CAAC,cAAc,CAAC,cAAc,CAAC,EAAE,UAAU,CAAC,GAC1E,QAAQ,CAAC;IACP,UAAU,EAAE,kBAAkB,CAAC;IAC/B,gFAAgF;IAChF,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,IAAI,CAAC,EAAE,YAAY,CAAC;IACpB,OAAO,CAAC,EAAE,eAAe,CAAC;IAC1B,UAAU,EAAE,sBAAsB,CAAC;IACnC,gBAAgB,CAAC,EAAE,CACjB,OAAO,EAAE,sBAAsB,EAC/B,MAAM,EAAE,qBAAqB,KAC1B,IAAI,CAAC;IACV,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,qBAAqB,KAAK,IAAI,CAAC;IACzE,gBAAgB,CAAC,EAAE,OAAO,GAAG,QAAQ,GAAG,IAAI,CAAC;IAC7C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gGAAgG;IAChG,WAAW,CAAC,EAAE,uBAAuB,CAAC;CACvC,CAAC,CAAC;AAEL;;;GAGG;AACH,eAAO,MAAM,QAAQ;gBArBL,kBAAkB;IAC9B,gFAAgF;eACrE,OAAO;WACX,YAAY;cACT,eAAe;gBACb,sBAAsB;uBACf,CACjB,OAAO,EAAE,sBAAsB,EAC/B,MAAM,EAAE,qBAAqB,KAC1B,IAAI;qBACQ,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,qBAAqB,KAAK,IAAI;uBACrD,OAAO,GAAG,QAAQ,GAAG,IAAI;iBAC/B,MAAM;IACnB,gGAAgG;kBAClF,uBAAuB;mDA+JxC,CAAC"}
@@ -33,8 +33,10 @@ function createLoadMoreControllerFacade() {
33
33
  * A collection footer that keeps product data controlled while the shared
34
34
  * controller prevents overlapping cursor requests.
35
35
  */
36
- export const LoadMore = forwardRef(function LoadMore({ descriptor, mode = loadMoreRecipe.defaults.mode, density = loadMoreRecipe.defaults.density, onLoadMore, onRequestOutcome, onRequestError, intersectionRoot = null, rootMargin = "200px 0px", className, layoutStyle, style, ...props }, ref) {
36
+ export const LoadMore = forwardRef(function LoadMore({ descriptor, disabled = false, mode = loadMoreRecipe.defaults.mode, density = loadMoreRecipe.defaults.density, onLoadMore, onRequestOutcome, onRequestError, intersectionRoot = null, rootMargin = "200px 0px", className, layoutStyle, style, ...props }, ref) {
37
37
  validateLoadMoreDescriptor(descriptor);
38
+ const disabledRef = useRef(disabled);
39
+ disabledRef.current = disabled;
38
40
  const onLoadMoreRef = useRef(onLoadMore);
39
41
  onLoadMoreRef.current = onLoadMore;
40
42
  const [controllerFacade] = useState(createLoadMoreControllerFacade);
@@ -51,7 +53,7 @@ export const LoadMore = forwardRef(function LoadMore({ descriptor, mode = loadMo
51
53
  return () => { currentRequestIdentityRef.current = null; };
52
54
  }, [currentRequestIdentity]);
53
55
  const request = useCallback(async (state, reason) => {
54
- if (state.status === "loading" || state.status === "complete")
56
+ if (disabledRef.current || state.status === "loading" || state.status === "complete")
55
57
  return;
56
58
  const requestIdentity = `${state.status}:${state.requestKey}`;
57
59
  // IntersectionObserver may deliver an already queued callback after
@@ -93,7 +95,7 @@ export const LoadMore = forwardRef(function LoadMore({ descriptor, mode = loadMo
93
95
  };
94
96
  }, [controllerFacade, mode]);
95
97
  useEffect(() => {
96
- if (mode !== "automatic" ||
98
+ if (disabled || mode !== "automatic" ||
97
99
  descriptor.state.status !== "ready" ||
98
100
  typeof IntersectionObserver === "undefined") {
99
101
  return;
@@ -108,8 +110,8 @@ export const LoadMore = forwardRef(function LoadMore({ descriptor, mode = loadMo
108
110
  }, { root: intersectionRoot, rootMargin });
109
111
  observer.observe(sentinel);
110
112
  return () => observer.disconnect();
111
- }, [descriptor.state, intersectionRoot, mode, request, rootMargin]);
113
+ }, [descriptor.state, disabled, intersectionRoot, mode, request, rootMargin]);
112
114
  const { state, labels } = descriptor;
113
- return (_jsxs("div", { ...props, style: { ...style, ...layoutStyle }, ref: ref, className: classNames("hjm-load-more", className), "data-mode": mode, "data-density": density, "data-state": state.status, "aria-busy": state.status === "loading" || undefined, children: [_jsx("span", { ref: sentinelRef, className: "hjm-load-more__sentinel", "aria-hidden": "true" }), state.status === "ready" ? (_jsx("button", { type: "button", className: "hjm-load-more__trigger", onClick: () => void request(state, "manual"), children: labels.loadMore })) : state.status === "loading" ? (_jsxs("div", { className: "hjm-load-more__status", role: "status", children: [_jsx("span", { className: "hjm-load-more__spinner", "aria-hidden": "true" }), _jsx("span", { className: "hjm-visually-hidden", children: labels.loading })] })) : state.status === "error" ? (_jsxs("div", { className: "hjm-load-more__error", children: [_jsx("span", { role: "alert", children: state.message }), _jsx("button", { type: "button", className: "hjm-load-more__trigger", onClick: () => void request(state, "retry"), children: labels.retry })] })) : (_jsx("div", { className: "hjm-load-more__end", children: labels.complete }))] }));
115
+ return (_jsxs("div", { ...props, style: { ...style, ...layoutStyle }, ref: ref, className: classNames("hjm-load-more", className), "data-mode": mode, "data-density": density, "data-state": state.status, "aria-disabled": disabled || undefined, "aria-busy": state.status === "loading" || undefined, children: [_jsx("span", { ref: sentinelRef, className: "hjm-load-more__sentinel", "aria-hidden": "true" }), state.status === "ready" ? (_jsx("button", { type: "button", className: "hjm-load-more__trigger", disabled: disabled, onClick: () => void request(state, "manual"), children: labels.loadMore })) : state.status === "loading" ? (_jsxs("div", { className: "hjm-load-more__status", role: "status", children: [_jsx("span", { className: "hjm-load-more__spinner", "aria-hidden": "true" }), _jsx("span", { className: "hjm-visually-hidden", children: labels.loading })] })) : state.status === "error" ? (_jsxs("div", { className: "hjm-load-more__error", children: [_jsx("span", { role: "alert", children: state.message }), _jsx("button", { type: "button", className: "hjm-load-more__trigger", disabled: disabled, onClick: () => void request(state, "retry"), children: labels.retry })] })) : (_jsx("div", { className: "hjm-load-more__end", children: labels.complete }))] }));
114
116
  });
115
117
  //# sourceMappingURL=supplemental-navigation.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"supplemental-navigation.js","sourceRoot":"","sources":["../src/supplemental-navigation.tsx"],"names":[],"mappings":"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","sourcesContent":["import {\n createLoadMoreController,\n validateLoadMoreDescriptor,\n type LoadMoreController,\n type LoadMoreControllerSnapshot,\n type LoadMoreDescriptor,\n type LoadMoreMode,\n type LoadMoreRequestHandler,\n type LoadMoreRequestOutcome,\n type LoadMoreRequestReason,\n} from \"@hjmds/design-contracts/components/load-more\";\nimport {\n loadMoreRecipe,\n type LoadMoreDensity,\n} from \"@hjmds/design-contracts/recipes\";\nimport {\n forwardRef,\n useCallback,\n useEffect,\n useLayoutEffect,\n useRef,\n useState,\n type HTMLAttributes,\n} from \"react\";\nimport { classNames } from \"./internal.js\";\nimport type { HjmCompositionStyleProp } from \"./composition-style.js\";\n\nfunction createLoadMoreControllerFacade(): Readonly<{\n facade: LoadMoreController;\n attach(controller: LoadMoreController): () => void;\n}> {\n const detachedSnapshot: LoadMoreControllerSnapshot = {\n mode: \"automatic\",\n inFlightRequestKey: null,\n disposed: true,\n };\n let active: LoadMoreController | null = null;\n return {\n facade: {\n getSnapshot: () => active?.getSnapshot() ?? detachedSnapshot,\n request: (state, reason) => {\n if (!active) throw new Error(\"Cannot use a detached LoadMore controller\");\n return active.request(state, reason);\n },\n dispose: () => active?.dispose() ?? false,\n },\n attach(controller) {\n active = controller;\n return () => {\n if (active === controller) active = null;\n };\n },\n };\n}\n\nexport type LoadMoreProps = Omit<HTMLAttributes<HTMLDivElement>, \"children\"> &\n Readonly<{\n descriptor: LoadMoreDescriptor;\n mode?: LoadMoreMode;\n density?: LoadMoreDensity;\n onLoadMore: LoadMoreRequestHandler;\n onRequestOutcome?: (\n outcome: LoadMoreRequestOutcome,\n reason: LoadMoreRequestReason,\n ) => void;\n onRequestError?: (error: unknown, reason: LoadMoreRequestReason) => void;\n intersectionRoot?: Element | Document | null;\n rootMargin?: string;\n /** Canonical layout-only placement on the root element. Controlled visual keys are excluded. */\n layoutStyle?: HjmCompositionStyleProp;\n }>;\n\n/**\n * A collection footer that keeps product data controlled while the shared\n * controller prevents overlapping cursor requests.\n */\nexport const LoadMore = forwardRef<HTMLDivElement, LoadMoreProps>(\n function LoadMore(\n {\n descriptor,\n mode = loadMoreRecipe.defaults.mode,\n density = loadMoreRecipe.defaults.density,\n onLoadMore,\n onRequestOutcome,\n onRequestError,\n intersectionRoot = null,\n rootMargin = \"200px 0px\",\n className,\n layoutStyle,\n style,\n ...props\n },\n ref,\n ) {\n validateLoadMoreDescriptor(descriptor);\n const onLoadMoreRef = useRef(onLoadMore);\n onLoadMoreRef.current = onLoadMore;\n const [controllerFacade] = useState(createLoadMoreControllerFacade);\n const controller = controllerFacade.facade;\n const requestGeneration = useRef(0);\n const sentinelRef = useRef<HTMLSpanElement>(null);\n const currentRequestIdentityRef = useRef<string | null>(null);\n const completedRequestIdentityRef = useRef<string | null>(null);\n const currentRequestIdentity =\n descriptor.state.status === \"ready\" || descriptor.state.status === \"error\"\n ? `${descriptor.state.status}:${descriptor.state.requestKey}`\n : null;\n\n useLayoutEffect(() => {\n currentRequestIdentityRef.current = currentRequestIdentity;\n return () => { currentRequestIdentityRef.current = null; };\n }, [currentRequestIdentity]);\n\n const request = useCallback(\n async (\n state: LoadMoreDescriptor[\"state\"],\n reason: LoadMoreRequestReason,\n ) => {\n if (state.status === \"loading\" || state.status === \"complete\") return;\n const requestIdentity = `${state.status}:${state.requestKey}`;\n // IntersectionObserver may deliver an already queued callback after\n // disconnect. Only events for the currently committed descriptor may\n // enter the shared request controller.\n if (currentRequestIdentityRef.current !== requestIdentity) return;\n // Once a request settles successfully, retire that exact state/key\n // until the product commits a new cursor or a retryable error state.\n if (completedRequestIdentityRef.current === requestIdentity) return;\n const generation = requestGeneration.current;\n try {\n const outcome = await controller.request(state, reason);\n if (generation !== requestGeneration.current) return;\n if (outcome === \"started\") {\n completedRequestIdentityRef.current = requestIdentity;\n }\n onRequestOutcome?.(outcome, reason);\n } catch (error) {\n if (generation === requestGeneration.current) onRequestError?.(error, reason);\n }\n },\n [controller, onRequestError, onRequestOutcome],\n );\n\n useEffect(() => {\n const attached = createLoadMoreController({\n mode,\n onLoadMore: (nextRequest) => onLoadMoreRef.current(nextRequest),\n });\n const detach = controllerFacade.attach(attached);\n requestGeneration.current += 1;\n return () => {\n // The query remains product-owned; only this retired footer's callbacks stop.\n requestGeneration.current += 1;\n detach();\n attached.dispose();\n };\n }, [controllerFacade, mode]);\n\n useEffect(() => {\n if (\n mode !== \"automatic\" ||\n descriptor.state.status !== \"ready\" ||\n typeof IntersectionObserver === \"undefined\"\n ) {\n return;\n }\n const sentinel = sentinelRef.current;\n if (!sentinel) return;\n const observer = new IntersectionObserver(\n (entries) => {\n if (entries.some((entry) => entry.isIntersecting)) {\n void request(descriptor.state, \"viewport\");\n }\n },\n { root: intersectionRoot, rootMargin },\n );\n observer.observe(sentinel);\n return () => observer.disconnect();\n }, [descriptor.state, intersectionRoot, mode, request, rootMargin]);\n\n const { state, labels } = descriptor;\n return (\n <div\n {...props}\n style={{ ...style, ...layoutStyle }}\n ref={ref}\n className={classNames(\"hjm-load-more\", className)}\n data-mode={mode}\n data-density={density}\n data-state={state.status}\n aria-busy={state.status === \"loading\" || undefined}\n >\n <span ref={sentinelRef} className=\"hjm-load-more__sentinel\" aria-hidden=\"true\" />\n {state.status === \"ready\" ? (\n <button\n type=\"button\"\n className=\"hjm-load-more__trigger\"\n onClick={() => void request(state, \"manual\")}\n >\n {labels.loadMore}\n </button>\n ) : state.status === \"loading\" ? (\n <div className=\"hjm-load-more__status\" role=\"status\">\n <span className=\"hjm-load-more__spinner\" aria-hidden=\"true\" />\n <span className=\"hjm-visually-hidden\">{labels.loading}</span>\n </div>\n ) : state.status === \"error\" ? (\n <div className=\"hjm-load-more__error\">\n <span role=\"alert\">{state.message}</span>\n <button\n type=\"button\"\n className=\"hjm-load-more__trigger\"\n onClick={() => void request(state, \"retry\")}\n >\n {labels.retry}\n </button>\n </div>\n ) : (\n <div className=\"hjm-load-more__end\">{labels.complete}</div>\n )}\n </div>\n );\n },\n);\n"]}
1
+ {"version":3,"file":"supplemental-navigation.js","sourceRoot":"","sources":["../src/supplemental-navigation.tsx"],"names":[],"mappings":";AAAA,OAAO,EACL,wBAAwB,EACxB,0BAA0B,GAQ3B,MAAM,8CAA8C,CAAC;AACtD,OAAO,EACL,cAAc,GAEf,MAAM,iCAAiC,CAAC;AACzC,OAAO,EACL,UAAU,EACV,WAAW,EACX,SAAS,EACT,eAAe,EACf,MAAM,EACN,QAAQ,GAET,MAAM,OAAO,CAAC;AACf,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAG3C,SAAS,8BAA8B;IAIrC,MAAM,gBAAgB,GAA+B;QACnD,IAAI,EAAE,WAAW;QACjB,kBAAkB,EAAE,IAAI;QACxB,QAAQ,EAAE,IAAI;KACf,CAAC;IACF,IAAI,MAAM,GAA8B,IAAI,CAAC;IAC7C,OAAO;QACL,MAAM,EAAE;YACN,WAAW,EAAE,GAAG,EAAE,CAAC,MAAM,EAAE,WAAW,EAAE,IAAI,gBAAgB;YAC5D,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE;gBACzB,IAAI,CAAC,MAAM;oBAAE,MAAM,IAAI,KAAK,CAAC,2CAA2C,CAAC,CAAC;gBAC1E,OAAO,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;YACvC,CAAC;YACD,OAAO,EAAE,GAAG,EAAE,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,KAAK;SAC1C;QACD,MAAM,CAAC,UAAU;YACf,MAAM,GAAG,UAAU,CAAC;YACpB,OAAO,GAAG,EAAE;gBACV,IAAI,MAAM,KAAK,UAAU;oBAAE,MAAM,GAAG,IAAI,CAAC;YAC3C,CAAC,CAAC;QACJ,CAAC;KACF,CAAC;AACJ,CAAC;AAqBD;;;GAGG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAG,UAAU,CAChC,SAAS,QAAQ,CACf,EACE,UAAU,EACV,QAAQ,GAAG,KAAK,EAChB,IAAI,GAAG,cAAc,CAAC,QAAQ,CAAC,IAAI,EACnC,OAAO,GAAG,cAAc,CAAC,QAAQ,CAAC,OAAO,EACzC,UAAU,EACV,gBAAgB,EAChB,cAAc,EACd,gBAAgB,GAAG,IAAI,EACvB,UAAU,GAAG,WAAW,EACxB,SAAS,EACT,WAAW,EACX,KAAK,EACL,GAAG,KAAK,EACT,EACD,GAAG;IAEH,0BAA0B,CAAC,UAAU,CAAC,CAAC;IACvC,MAAM,WAAW,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC;IACrC,WAAW,CAAC,OAAO,GAAG,QAAQ,CAAC;IAC/B,MAAM,aAAa,GAAG,MAAM,CAAC,UAAU,CAAC,CAAC;IACzC,aAAa,CAAC,OAAO,GAAG,UAAU,CAAC;IACnC,MAAM,CAAC,gBAAgB,CAAC,GAAG,QAAQ,CAAC,8BAA8B,CAAC,CAAC;IACpE,MAAM,UAAU,GAAG,gBAAgB,CAAC,MAAM,CAAC;IAC3C,MAAM,iBAAiB,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;IACpC,MAAM,WAAW,GAAG,MAAM,CAAkB,IAAI,CAAC,CAAC;IAClD,MAAM,yBAAyB,GAAG,MAAM,CAAgB,IAAI,CAAC,CAAC;IAC9D,MAAM,2BAA2B,GAAG,MAAM,CAAgB,IAAI,CAAC,CAAC;IAChE,MAAM,sBAAsB,GAC1B,UAAU,CAAC,KAAK,CAAC,MAAM,KAAK,OAAO,IAAI,UAAU,CAAC,KAAK,CAAC,MAAM,KAAK,OAAO;QACxE,CAAC,CAAC,GAAG,UAAU,CAAC,KAAK,CAAC,MAAM,IAAI,UAAU,CAAC,KAAK,CAAC,UAAU,EAAE;QAC7D,CAAC,CAAC,IAAI,CAAC;IAEX,eAAe,CAAC,GAAG,EAAE;QACnB,yBAAyB,CAAC,OAAO,GAAG,sBAAsB,CAAC;QAC3D,OAAO,GAAG,EAAE,GAAG,yBAAyB,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;IAC7D,CAAC,EAAE,CAAC,sBAAsB,CAAC,CAAC,CAAC;IAE7B,MAAM,OAAO,GAAG,WAAW,CACzB,KAAK,EACH,KAAkC,EAClC,MAA6B,EAC7B,EAAE;QACF,IAAI,WAAW,CAAC,OAAO,IAAI,KAAK,CAAC,MAAM,KAAK,SAAS,IAAI,KAAK,CAAC,MAAM,KAAK,UAAU;YAAE,OAAO;QAC7F,MAAM,eAAe,GAAG,GAAG,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,UAAU,EAAE,CAAC;QAC9D,oEAAoE;QACpE,qEAAqE;QACrE,uCAAuC;QACvC,IAAI,yBAAyB,CAAC,OAAO,KAAK,eAAe;YAAE,OAAO;QAClE,mEAAmE;QACnE,qEAAqE;QACrE,IAAI,2BAA2B,CAAC,OAAO,KAAK,eAAe;YAAE,OAAO;QACpE,MAAM,UAAU,GAAG,iBAAiB,CAAC,OAAO,CAAC;QAC7C,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,MAAM,UAAU,CAAC,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;YACxD,IAAI,UAAU,KAAK,iBAAiB,CAAC,OAAO;gBAAE,OAAO;YACrD,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;gBAC1B,2BAA2B,CAAC,OAAO,GAAG,eAAe,CAAC;YACxD,CAAC;YACD,gBAAgB,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QACtC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,UAAU,KAAK,iBAAiB,CAAC,OAAO;gBAAE,cAAc,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;QAChF,CAAC;IACH,CAAC,EACD,CAAC,UAAU,EAAE,cAAc,EAAE,gBAAgB,CAAC,CAC/C,CAAC;IAEF,SAAS,CAAC,GAAG,EAAE;QACb,MAAM,QAAQ,GAAG,wBAAwB,CAAC;YACxC,IAAI;YACJ,UAAU,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC,aAAa,CAAC,OAAO,CAAC,WAAW,CAAC;SAChE,CAAC,CAAC;QACH,MAAM,MAAM,GAAG,gBAAgB,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QACjD,iBAAiB,CAAC,OAAO,IAAI,CAAC,CAAC;QAC/B,OAAO,GAAG,EAAE;YACV,8EAA8E;YAC9E,iBAAiB,CAAC,OAAO,IAAI,CAAC,CAAC;YAC/B,MAAM,EAAE,CAAC;YACT,QAAQ,CAAC,OAAO,EAAE,CAAC;QACrB,CAAC,CAAC;IACJ,CAAC,EAAE,CAAC,gBAAgB,EAAE,IAAI,CAAC,CAAC,CAAC;IAE7B,SAAS,CAAC,GAAG,EAAE;QACb,IACE,QAAQ,IAAI,IAAI,KAAK,WAAW;YAChC,UAAU,CAAC,KAAK,CAAC,MAAM,KAAK,OAAO;YACnC,OAAO,oBAAoB,KAAK,WAAW,EAC3C,CAAC;YACD,OAAO;QACT,CAAC;QACD,MAAM,QAAQ,GAAG,WAAW,CAAC,OAAO,CAAC;QACrC,IAAI,CAAC,QAAQ;YAAE,OAAO;QACtB,MAAM,QAAQ,GAAG,IAAI,oBAAoB,CACvC,CAAC,OAAO,EAAE,EAAE;YACV,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,cAAc,CAAC,EAAE,CAAC;gBAClD,KAAK,OAAO,CAAC,UAAU,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC;YAC7C,CAAC;QACH,CAAC,EACD,EAAE,IAAI,EAAE,gBAAgB,EAAE,UAAU,EAAE,CACvC,CAAC;QACF,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QAC3B,OAAO,GAAG,EAAE,CAAC,QAAQ,CAAC,UAAU,EAAE,CAAC;IACrC,CAAC,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,QAAQ,EAAE,gBAAgB,EAAE,IAAI,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC,CAAC;IAE9E,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,UAAU,CAAC;IACrC,OAAO,CACL,kBACM,KAAK,EACT,KAAK,EAAE,EAAE,GAAG,KAAK,EAAE,GAAG,WAAW,EAAE,EACnC,GAAG,EAAE,GAAG,EACR,SAAS,EAAE,UAAU,CAAC,eAAe,EAAE,SAAS,CAAC,eACtC,IAAI,kBACD,OAAO,gBACT,KAAK,CAAC,MAAM,mBACT,QAAQ,IAAI,SAAS,eACzB,KAAK,CAAC,MAAM,KAAK,SAAS,IAAI,SAAS,aAElD,eAAM,GAAG,EAAE,WAAW,EAAE,SAAS,EAAC,yBAAyB,iBAAa,MAAM,GAAG,EAChF,KAAK,CAAC,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,CAC1B,iBACE,IAAI,EAAC,QAAQ,EACb,SAAS,EAAC,wBAAwB,EAClC,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,GAAG,EAAE,CAAC,KAAK,OAAO,CAAC,KAAK,EAAE,QAAQ,CAAC,YAE3C,MAAM,CAAC,QAAQ,GACT,CACV,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,CAC/B,eAAK,SAAS,EAAC,uBAAuB,EAAC,IAAI,EAAC,QAAQ,aAClD,eAAM,SAAS,EAAC,wBAAwB,iBAAa,MAAM,GAAG,EAC9D,eAAM,SAAS,EAAC,qBAAqB,YAAE,MAAM,CAAC,OAAO,GAAQ,IACzD,CACP,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,CAC7B,eAAK,SAAS,EAAC,sBAAsB,aACnC,eAAM,IAAI,EAAC,OAAO,YAAE,KAAK,CAAC,OAAO,GAAQ,EACzC,iBACE,IAAI,EAAC,QAAQ,EACb,SAAS,EAAC,wBAAwB,EAClC,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,GAAG,EAAE,CAAC,KAAK,OAAO,CAAC,KAAK,EAAE,OAAO,CAAC,YAE1C,MAAM,CAAC,KAAK,GACN,IACL,CACP,CAAC,CAAC,CAAC,CACF,cAAK,SAAS,EAAC,oBAAoB,YAAE,MAAM,CAAC,QAAQ,GAAO,CAC5D,IACG,CACP,CAAC;AACJ,CAAC,CACF,CAAC","sourcesContent":["import {\n createLoadMoreController,\n validateLoadMoreDescriptor,\n type LoadMoreController,\n type LoadMoreControllerSnapshot,\n type LoadMoreDescriptor,\n type LoadMoreMode,\n type LoadMoreRequestHandler,\n type LoadMoreRequestOutcome,\n type LoadMoreRequestReason,\n} from \"@hjmds/design-contracts/components/load-more\";\nimport {\n loadMoreRecipe,\n type LoadMoreDensity,\n} from \"@hjmds/design-contracts/recipes\";\nimport {\n forwardRef,\n useCallback,\n useEffect,\n useLayoutEffect,\n useRef,\n useState,\n type HTMLAttributes,\n} from \"react\";\nimport { classNames } from \"./internal.js\";\nimport type { HjmCompositionStyleProp } from \"./composition-style.js\";\n\nfunction createLoadMoreControllerFacade(): Readonly<{\n facade: LoadMoreController;\n attach(controller: LoadMoreController): () => void;\n}> {\n const detachedSnapshot: LoadMoreControllerSnapshot = {\n mode: \"automatic\",\n inFlightRequestKey: null,\n disposed: true,\n };\n let active: LoadMoreController | null = null;\n return {\n facade: {\n getSnapshot: () => active?.getSnapshot() ?? detachedSnapshot,\n request: (state, reason) => {\n if (!active) throw new Error(\"Cannot use a detached LoadMore controller\");\n return active.request(state, reason);\n },\n dispose: () => active?.dispose() ?? false,\n },\n attach(controller) {\n active = controller;\n return () => {\n if (active === controller) active = null;\n };\n },\n };\n}\n\nexport type LoadMoreProps = Omit<HTMLAttributes<HTMLDivElement>, \"children\"> &\n Readonly<{\n descriptor: LoadMoreDescriptor;\n /** Product mutation/refetch lock, separate from the next-page loading state. */\n disabled?: boolean;\n mode?: LoadMoreMode;\n density?: LoadMoreDensity;\n onLoadMore: LoadMoreRequestHandler;\n onRequestOutcome?: (\n outcome: LoadMoreRequestOutcome,\n reason: LoadMoreRequestReason,\n ) => void;\n onRequestError?: (error: unknown, reason: LoadMoreRequestReason) => void;\n intersectionRoot?: Element | Document | null;\n rootMargin?: string;\n /** Canonical layout-only placement on the root element. Controlled visual keys are excluded. */\n layoutStyle?: HjmCompositionStyleProp;\n }>;\n\n/**\n * A collection footer that keeps product data controlled while the shared\n * controller prevents overlapping cursor requests.\n */\nexport const LoadMore = forwardRef<HTMLDivElement, LoadMoreProps>(\n function LoadMore(\n {\n descriptor,\n disabled = false,\n mode = loadMoreRecipe.defaults.mode,\n density = loadMoreRecipe.defaults.density,\n onLoadMore,\n onRequestOutcome,\n onRequestError,\n intersectionRoot = null,\n rootMargin = \"200px 0px\",\n className,\n layoutStyle,\n style,\n ...props\n },\n ref,\n ) {\n validateLoadMoreDescriptor(descriptor);\n const disabledRef = useRef(disabled);\n disabledRef.current = disabled;\n const onLoadMoreRef = useRef(onLoadMore);\n onLoadMoreRef.current = onLoadMore;\n const [controllerFacade] = useState(createLoadMoreControllerFacade);\n const controller = controllerFacade.facade;\n const requestGeneration = useRef(0);\n const sentinelRef = useRef<HTMLSpanElement>(null);\n const currentRequestIdentityRef = useRef<string | null>(null);\n const completedRequestIdentityRef = useRef<string | null>(null);\n const currentRequestIdentity =\n descriptor.state.status === \"ready\" || descriptor.state.status === \"error\"\n ? `${descriptor.state.status}:${descriptor.state.requestKey}`\n : null;\n\n useLayoutEffect(() => {\n currentRequestIdentityRef.current = currentRequestIdentity;\n return () => { currentRequestIdentityRef.current = null; };\n }, [currentRequestIdentity]);\n\n const request = useCallback(\n async (\n state: LoadMoreDescriptor[\"state\"],\n reason: LoadMoreRequestReason,\n ) => {\n if (disabledRef.current || state.status === \"loading\" || state.status === \"complete\") return;\n const requestIdentity = `${state.status}:${state.requestKey}`;\n // IntersectionObserver may deliver an already queued callback after\n // disconnect. Only events for the currently committed descriptor may\n // enter the shared request controller.\n if (currentRequestIdentityRef.current !== requestIdentity) return;\n // Once a request settles successfully, retire that exact state/key\n // until the product commits a new cursor or a retryable error state.\n if (completedRequestIdentityRef.current === requestIdentity) return;\n const generation = requestGeneration.current;\n try {\n const outcome = await controller.request(state, reason);\n if (generation !== requestGeneration.current) return;\n if (outcome === \"started\") {\n completedRequestIdentityRef.current = requestIdentity;\n }\n onRequestOutcome?.(outcome, reason);\n } catch (error) {\n if (generation === requestGeneration.current) onRequestError?.(error, reason);\n }\n },\n [controller, onRequestError, onRequestOutcome],\n );\n\n useEffect(() => {\n const attached = createLoadMoreController({\n mode,\n onLoadMore: (nextRequest) => onLoadMoreRef.current(nextRequest),\n });\n const detach = controllerFacade.attach(attached);\n requestGeneration.current += 1;\n return () => {\n // The query remains product-owned; only this retired footer's callbacks stop.\n requestGeneration.current += 1;\n detach();\n attached.dispose();\n };\n }, [controllerFacade, mode]);\n\n useEffect(() => {\n if (\n disabled || mode !== \"automatic\" ||\n descriptor.state.status !== \"ready\" ||\n typeof IntersectionObserver === \"undefined\"\n ) {\n return;\n }\n const sentinel = sentinelRef.current;\n if (!sentinel) return;\n const observer = new IntersectionObserver(\n (entries) => {\n if (entries.some((entry) => entry.isIntersecting)) {\n void request(descriptor.state, \"viewport\");\n }\n },\n { root: intersectionRoot, rootMargin },\n );\n observer.observe(sentinel);\n return () => observer.disconnect();\n }, [descriptor.state, disabled, intersectionRoot, mode, request, rootMargin]);\n\n const { state, labels } = descriptor;\n return (\n <div\n {...props}\n style={{ ...style, ...layoutStyle }}\n ref={ref}\n className={classNames(\"hjm-load-more\", className)}\n data-mode={mode}\n data-density={density}\n data-state={state.status}\n aria-disabled={disabled || undefined}\n aria-busy={state.status === \"loading\" || undefined}\n >\n <span ref={sentinelRef} className=\"hjm-load-more__sentinel\" aria-hidden=\"true\" />\n {state.status === \"ready\" ? (\n <button\n type=\"button\"\n className=\"hjm-load-more__trigger\"\n disabled={disabled}\n onClick={() => void request(state, \"manual\")}\n >\n {labels.loadMore}\n </button>\n ) : state.status === \"loading\" ? (\n <div className=\"hjm-load-more__status\" role=\"status\">\n <span className=\"hjm-load-more__spinner\" aria-hidden=\"true\" />\n <span className=\"hjm-visually-hidden\">{labels.loading}</span>\n </div>\n ) : state.status === \"error\" ? (\n <div className=\"hjm-load-more__error\">\n <span role=\"alert\">{state.message}</span>\n <button\n type=\"button\"\n className=\"hjm-load-more__trigger\"\n disabled={disabled}\n onClick={() => void request(state, \"retry\")}\n >\n {labels.retry}\n </button>\n </div>\n ) : (\n <div className=\"hjm-load-more__end\">{labels.complete}</div>\n )}\n </div>\n );\n },\n);\n"]}
@@ -17,7 +17,7 @@ function ChoiceMenu(props) {
17
17
  if (!available)
18
18
  return _jsx(Button, { disabled: true, children: props.label });
19
19
  const trigger = props.trigger === "icon" ? _jsx(IconButton, { label: props.label, tone: "secondary", children: _jsx(Icon, { name: "chevronDown" }) }) : _jsx(Button, { tone: "secondary", loading: props.pending === true, children: props.label });
20
- return _jsx(Menu, { label: props.label, trigger: trigger, disabled: props.disabled, items: props.choices, selectionMode: "single", value: props.selectedId, onValueChange: () => undefined, onActionAfterDismiss: props.onChoose });
20
+ return _jsx(Menu, { presentation: "anchored", label: props.label, trigger: trigger, disabled: props.disabled, items: props.choices, selectionMode: "single", value: props.selectedId, onValueChange: () => undefined, onActionAfterDismiss: props.onChoose });
21
21
  }
22
22
  function Failure({ failed, label }) {
23
23
  return failed ? _jsx(Text, { role: "alert", tone: "danger", style: { textAlign: "center" }, children: label }) : null;
@@ -1 +1 @@
1
- {"version":3,"file":"task-controls.js","sourceRoot":"","sources":["../src/task-controls.tsx"],"names":[],"mappings":"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","sourcesContent":["\"use client\";\nimport { resolveTaskChoice, resolvePasswordRules, resolvePriceOption, type TaskChoice, type PasswordRule, type PriceOption } from \"@hjmds/design-contracts/task-controls\";\nimport { Button, IconButton } from \"./actions.js\";\nimport { Icon } from \"./supplemental-display.js\";\nimport { Menu } from \"./overlays.js\";\nimport { PasswordField, type PasswordFieldProps } from \"./forms.js\";\nimport { RadioGroup } from \"./selection.js\";\nimport { Card } from \"./display.js\";\nimport { Progress } from \"./feedback.js\";\nimport { Stack, Text } from \"./layout.js\";\nimport { useCompositionAction } from \"./internal/use-composition-action.js\";\n\ntype ChoiceMenuProps = Readonly<{ choices: readonly TaskChoice[]; selectedId: string; label: string; dismissLabel: string; disabled: boolean; pending?: boolean; onChoose: (id: string) => void;\n /** `icon`: a chevron tool beside the action it modifies (SplitAction); the label stays the accessible name. */\n trigger?: \"text\" | \"icon\" }>;\nfunction ChoiceMenu(props: ChoiceMenuProps) {\n const available = props.choices.some(choice => !choice.disabled);\n if (props.trigger === \"icon\" && !available) return <IconButton label={props.label} tone=\"secondary\" disabled><Icon name=\"chevronDown\" /></IconButton>;\n if (!available) return <Button disabled>{props.label}</Button>;\n const trigger = props.trigger === \"icon\" ? <IconButton label={props.label} tone=\"secondary\"><Icon name=\"chevronDown\" /></IconButton> : <Button tone=\"secondary\" loading={props.pending === true}>{props.label}</Button>;\n return <Menu label={props.label} trigger={trigger} disabled={props.disabled}\n items={props.choices} selectionMode=\"single\" value={props.selectedId} onValueChange={() => undefined} onActionAfterDismiss={props.onChoose} />;\n}\nfunction Failure({ failed, label }: Readonly<{ failed: boolean; label: string }>) {\n return failed ? <Text role=\"alert\" tone=\"danger\" style={{ textAlign: \"center\" }}>{label}</Text> : null;\n}\n\nexport type SplitActionProps = Readonly<{\n modes: readonly TaskChoice[]; modeId: string; onModeChange: (id: string) => void;\n onExecute: (modeId: string) => void | Promise<void>; executeLabel: (mode: TaskChoice) => string;\n menuLabel: string; dismissLabel: string; errorLabel: string; disabled?: boolean;\n}>;\nexport function SplitAction(props: SplitActionProps) {\n const mode = resolveTaskChoice(props.modes, props.modeId), action = useCompositionAction(props.disabled);\n const locked = props.disabled === true || action.pending;\n // The mode menu is a chevron tool at the action's end, inline gap 12 (button.md); a second text button read as an unrelated action (2026-10-17 review).\n return <Stack gap=\"sm\"><Stack axis=\"inline\" gap=\"sm\" align=\"center\">\n <Button loading={action.pending} disabled={props.disabled === true || mode.disabled === true} onClick={() => { if (!mode.disabled) void action.run(mode.id, () => props.onExecute(mode.id)); }}>{props.executeLabel(mode)}</Button>\n <ChoiceMenu trigger=\"icon\" choices={props.modes} selectedId={mode.id} label={props.menuLabel} dismissLabel={props.dismissLabel} disabled={locked} onChoose={id => { if (!locked && !resolveTaskChoice(props.modes, id).disabled) props.onModeChange(id); }} />\n </Stack><Failure failed={action.failed} label={props.errorLabel} /></Stack>;\n}\n\nexport type AccountSwitcherProps = Readonly<{\n accounts: readonly TaskChoice[]; accountId: string; label: string; dismissLabel: string; errorLabel: string;\n onSwitch: (accountId: string) => void | Promise<void>; disabled?: boolean;\n}>;\nexport function AccountSwitcher(props: AccountSwitcherProps) {\n const account = resolveTaskChoice(props.accounts, props.accountId), action = useCompositionAction(props.disabled);\n const locked = props.disabled === true || action.pending;\n // The controlled account stays confirmed until the product completes the session change.\n return <Stack gap=\"sm\"><Text emphasis=\"strong\">{account.label}</Text><ChoiceMenu choices={props.accounts} selectedId={account.id} label={props.label} dismissLabel={props.dismissLabel} disabled={locked} pending={action.pending}\n onChoose={id => { if (id !== account.id && !resolveTaskChoice(props.accounts, id).disabled) void action.run(id, () => props.onSwitch(id)); }} />\n <Failure failed={action.failed} label={props.errorLabel} /></Stack>;\n}\n\nexport type PasswordRulesFieldProps = Omit<PasswordFieldProps, \"value\" | \"defaultValue\" | \"onValueChange\"> & Readonly<{\n label: string; value: string; onValueChange: (value: string) => void; rules: readonly PasswordRule[];\n progressLabel: string; summaryLabel: (satisfied: number, total: number) => string;\n ruleLabel: (rule: ReturnType<typeof resolvePasswordRules>[\"rules\"][number]) => string;\n}>;\nexport function PasswordRulesField({ rules, progressLabel, summaryLabel, ruleLabel, ...field }: PasswordRulesFieldProps) {\n const state = resolvePasswordRules(field.value, rules);\n return <Stack gap=\"sm\"><PasswordField {...field} />\n <Progress label={progressLabel} value={state.satisfied} max={state.total} valueText={summaryLabel(state.satisfied, state.total)} />\n {state.rules.map(rule => <Text key={rule.id} variant=\"caption\" tone={rule.satisfied ? \"primary\" : \"muted\"}>{ruleLabel(rule)}</Text>)}\n </Stack>;\n}\n\nexport type PricingChoiceProps = Readonly<{\n label: string; options: readonly PriceOption[]; selectedId: string; onSelectionChange: (id: string) => void;\n formatPrice: (option: PriceOption) => string; continueLabel: string; errorLabel: string;\n onContinue: (option: PriceOption) => void | Promise<void>; disabled?: boolean;\n}>;\nexport function PricingChoice(props: PricingChoiceProps) {\n const option = resolvePriceOption(props.options, props.selectedId), action = useCompositionAction(props.disabled);\n const locked = props.disabled === true || action.pending;\n return <Card title={props.label}><Stack gap=\"md\"><RadioGroup accessibilityLabel={props.label} presentation=\"card\" value={option.id} disabled={locked}\n items={props.options.map(price => ({ value: price.id, label: price.label, description: props.formatPrice(price), disabled: price.disabled === true }))}\n onValueChange={id => { if (id !== null && !locked && !resolveTaskChoice(props.options, id).disabled) props.onSelectionChange(id); }} />\n <Text emphasis=\"strong\">{props.formatPrice(option)}</Text>\n {option.benefits.map((benefit, index) => <Text key={index}>{benefit}</Text>)}\n <Button loading={action.pending} disabled={props.disabled === true || option.disabled === true} onClick={() => { if (!option.disabled) void action.run(option.id, () => props.onContinue(Object.freeze({ ...option, benefits: Object.freeze([...option.benefits]) }))); }}>{props.continueLabel}</Button>\n <Failure failed={action.failed} label={props.errorLabel} /></Stack></Card>;\n}\n"]}
1
+ {"version":3,"file":"task-controls.js","sourceRoot":"","sources":["../src/task-controls.tsx"],"names":[],"mappings":"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","sourcesContent":["\"use client\";\nimport { resolveTaskChoice, resolvePasswordRules, resolvePriceOption, type TaskChoice, type PasswordRule, type PriceOption } from \"@hjmds/design-contracts/task-controls\";\nimport { Button, IconButton } from \"./actions.js\";\nimport { Icon } from \"./supplemental-display.js\";\nimport { Menu } from \"./overlays.js\";\nimport { PasswordField, type PasswordFieldProps } from \"./forms.js\";\nimport { RadioGroup } from \"./selection.js\";\nimport { Card } from \"./display.js\";\nimport { Progress } from \"./feedback.js\";\nimport { Stack, Text } from \"./layout.js\";\nimport { useCompositionAction } from \"./internal/use-composition-action.js\";\n\ntype ChoiceMenuProps = Readonly<{ choices: readonly TaskChoice[]; selectedId: string; label: string; dismissLabel: string; disabled: boolean; pending?: boolean; onChoose: (id: string) => void;\n /** `icon`: a chevron tool beside the action it modifies (SplitAction); the label stays the accessible name. */\n trigger?: \"text\" | \"icon\" }>;\nfunction ChoiceMenu(props: ChoiceMenuProps) {\n const available = props.choices.some(choice => !choice.disabled);\n if (props.trigger === \"icon\" && !available) return <IconButton label={props.label} tone=\"secondary\" disabled><Icon name=\"chevronDown\" /></IconButton>;\n if (!available) return <Button disabled>{props.label}</Button>;\n const trigger = props.trigger === \"icon\" ? <IconButton label={props.label} tone=\"secondary\"><Icon name=\"chevronDown\" /></IconButton> : <Button tone=\"secondary\" loading={props.pending === true}>{props.label}</Button>;\n return <Menu presentation=\"anchored\" label={props.label} trigger={trigger} disabled={props.disabled}\n items={props.choices} selectionMode=\"single\" value={props.selectedId} onValueChange={() => undefined} onActionAfterDismiss={props.onChoose} />;\n}\nfunction Failure({ failed, label }: Readonly<{ failed: boolean; label: string }>) {\n return failed ? <Text role=\"alert\" tone=\"danger\" style={{ textAlign: \"center\" }}>{label}</Text> : null;\n}\n\nexport type SplitActionProps = Readonly<{\n modes: readonly TaskChoice[]; modeId: string; onModeChange: (id: string) => void;\n onExecute: (modeId: string) => void | Promise<void>; executeLabel: (mode: TaskChoice) => string;\n menuLabel: string; dismissLabel: string; errorLabel: string; disabled?: boolean;\n}>;\nexport function SplitAction(props: SplitActionProps) {\n const mode = resolveTaskChoice(props.modes, props.modeId), action = useCompositionAction(props.disabled);\n const locked = props.disabled === true || action.pending;\n // The mode menu is a chevron tool at the action's end, inline gap 12 (button.md); a second text button read as an unrelated action (2026-10-17 review).\n return <Stack gap=\"sm\"><Stack axis=\"inline\" gap=\"sm\" align=\"center\">\n <Button loading={action.pending} disabled={props.disabled === true || mode.disabled === true} onClick={() => { if (!mode.disabled) void action.run(mode.id, () => props.onExecute(mode.id)); }}>{props.executeLabel(mode)}</Button>\n <ChoiceMenu trigger=\"icon\" choices={props.modes} selectedId={mode.id} label={props.menuLabel} dismissLabel={props.dismissLabel} disabled={locked} onChoose={id => { if (!locked && !resolveTaskChoice(props.modes, id).disabled) props.onModeChange(id); }} />\n </Stack><Failure failed={action.failed} label={props.errorLabel} /></Stack>;\n}\n\nexport type AccountSwitcherProps = Readonly<{\n accounts: readonly TaskChoice[]; accountId: string; label: string; dismissLabel: string; errorLabel: string;\n onSwitch: (accountId: string) => void | Promise<void>; disabled?: boolean;\n}>;\nexport function AccountSwitcher(props: AccountSwitcherProps) {\n const account = resolveTaskChoice(props.accounts, props.accountId), action = useCompositionAction(props.disabled);\n const locked = props.disabled === true || action.pending;\n // The controlled account stays confirmed until the product completes the session change.\n return <Stack gap=\"sm\"><Text emphasis=\"strong\">{account.label}</Text><ChoiceMenu choices={props.accounts} selectedId={account.id} label={props.label} dismissLabel={props.dismissLabel} disabled={locked} pending={action.pending}\n onChoose={id => { if (id !== account.id && !resolveTaskChoice(props.accounts, id).disabled) void action.run(id, () => props.onSwitch(id)); }} />\n <Failure failed={action.failed} label={props.errorLabel} /></Stack>;\n}\n\nexport type PasswordRulesFieldProps = Omit<PasswordFieldProps, \"value\" | \"defaultValue\" | \"onValueChange\"> & Readonly<{\n label: string; value: string; onValueChange: (value: string) => void; rules: readonly PasswordRule[];\n progressLabel: string; summaryLabel: (satisfied: number, total: number) => string;\n ruleLabel: (rule: ReturnType<typeof resolvePasswordRules>[\"rules\"][number]) => string;\n}>;\nexport function PasswordRulesField({ rules, progressLabel, summaryLabel, ruleLabel, ...field }: PasswordRulesFieldProps) {\n const state = resolvePasswordRules(field.value, rules);\n return <Stack gap=\"sm\"><PasswordField {...field} />\n <Progress label={progressLabel} value={state.satisfied} max={state.total} valueText={summaryLabel(state.satisfied, state.total)} />\n {state.rules.map(rule => <Text key={rule.id} variant=\"caption\" tone={rule.satisfied ? \"primary\" : \"muted\"}>{ruleLabel(rule)}</Text>)}\n </Stack>;\n}\n\nexport type PricingChoiceProps = Readonly<{\n label: string; options: readonly PriceOption[]; selectedId: string; onSelectionChange: (id: string) => void;\n formatPrice: (option: PriceOption) => string; continueLabel: string; errorLabel: string;\n onContinue: (option: PriceOption) => void | Promise<void>; disabled?: boolean;\n}>;\nexport function PricingChoice(props: PricingChoiceProps) {\n const option = resolvePriceOption(props.options, props.selectedId), action = useCompositionAction(props.disabled);\n const locked = props.disabled === true || action.pending;\n return <Card title={props.label}><Stack gap=\"md\"><RadioGroup accessibilityLabel={props.label} presentation=\"card\" value={option.id} disabled={locked}\n items={props.options.map(price => ({ value: price.id, label: price.label, description: props.formatPrice(price), disabled: price.disabled === true }))}\n onValueChange={id => { if (id !== null && !locked && !resolveTaskChoice(props.options, id).disabled) props.onSelectionChange(id); }} />\n <Text emphasis=\"strong\">{props.formatPrice(option)}</Text>\n {option.benefits.map((benefit, index) => <Text key={index}>{benefit}</Text>)}\n <Button loading={action.pending} disabled={props.disabled === true || option.disabled === true} onClick={() => { if (!option.disabled) void action.run(option.id, () => props.onContinue(Object.freeze({ ...option, benefits: Object.freeze([...option.benefits]) }))); }}>{props.continueLabel}</Button>\n <Failure failed={action.failed} label={props.errorLabel} /></Stack></Card>;\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hjmds/react",
3
- "version": "1.35.0",
3
+ "version": "1.36.0",
4
4
  "description": "Accessible React 19 renderers for HJM design contracts.",
5
5
  "license": "MIT",
6
6
  "publishConfig": {
@@ -608,7 +608,7 @@
608
608
  "THIRD_PARTY_NOTICES.md"
609
609
  ],
610
610
  "peerDependencies": {
611
- "@hjmds/design-contracts": ">=1.35.0 <1.36.0",
611
+ "@hjmds/design-contracts": ">=1.36.0 <1.37.0",
612
612
  "react": ">=19.0.0",
613
613
  "react-dom": ">=19.0.0",
614
614
  "@number-flow/react": "0.6.2",
@@ -646,7 +646,7 @@
646
646
  "@blobatar/react": "2.7.0",
647
647
  "lucide-react": "1.59.0",
648
648
  "vite": "8.3.4",
649
- "@hjmds/design-contracts": "1.35.0"
649
+ "@hjmds/design-contracts": "1.36.0"
650
650
  },
651
651
  "peerDependenciesMeta": {
652
652
  "@number-flow/react": {