@hjmds/react 1.37.2 → 1.38.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/actions.d.ts +8 -0
- package/dist/actions.d.ts.map +1 -1
- package/dist/actions.js +4 -4
- package/dist/actions.js.map +1 -1
- package/dist/authoring-tools.js +1 -1
- package/dist/authoring-tools.js.map +1 -1
- package/dist/bottom-cta.d.ts.map +1 -1
- package/dist/bottom-cta.js +2 -1
- package/dist/bottom-cta.js.map +1 -1
- package/dist/carousel-motion.js +1 -1
- package/dist/carousel-motion.js.map +1 -1
- package/dist/collection-editing.js +4 -4
- package/dist/collection-editing.js.map +1 -1
- package/dist/collection-rail.d.ts +3 -1
- package/dist/collection-rail.d.ts.map +1 -1
- package/dist/collection-rail.js +2 -2
- package/dist/collection-rail.js.map +1 -1
- package/dist/display.d.ts +4 -0
- package/dist/display.d.ts.map +1 -1
- package/dist/display.js +2 -2
- package/dist/display.js.map +1 -1
- package/dist/evidence.d.ts +1 -1
- package/dist/evidence.js +1 -1
- package/dist/evidence.js.map +1 -1
- package/dist/inline-confirm.js +1 -1
- package/dist/inline-confirm.js.map +1 -1
- package/dist/internal/document-resource.js +1 -1
- package/dist/internal/document-resource.js.map +1 -1
- package/dist/internal/screen-exit.js +2 -2
- package/dist/internal/screen-exit.js.map +1 -1
- package/dist/notification-bell.js +1 -1
- package/dist/notification-bell.js.map +1 -1
- package/dist/screen-flows.d.ts +1 -0
- package/dist/screen-flows.d.ts.map +1 -1
- package/dist/screen-flows.js +3 -3
- package/dist/screen-flows.js.map +1 -1
- package/dist/screens.d.ts +5 -1
- package/dist/screens.d.ts.map +1 -1
- package/dist/screens.js +7 -3
- package/dist/screens.js.map +1 -1
- package/dist/selection.d.ts +4 -0
- package/dist/selection.d.ts.map +1 -1
- package/dist/selection.js +2 -2
- package/dist/selection.js.map +1 -1
- package/dist/sortable.js +1 -1
- package/dist/sortable.js.map +1 -1
- package/dist/step-player.js +1 -1
- package/dist/step-player.js.map +1 -1
- package/dist/steps.js +1 -1
- package/dist/steps.js.map +1 -1
- package/dist/streaming-answer.js +1 -1
- package/dist/streaming-answer.js.map +1 -1
- package/dist/styles.css +34 -22
- package/dist/styles.layered.css +34 -22
- package/dist/task-controls.js +2 -2
- package/dist/task-controls.js.map +1 -1
- package/dist/transfer-task.js +1 -1
- package/dist/transfer-task.js.map +1 -1
- package/dist/voice-note.js +1 -1
- package/dist/voice-note.js.map +1 -1
- package/package.json +3 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"streaming-answer.js","sourceRoot":"","sources":["../src/streaming-answer.tsx"],"names":[],"mappings":"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","sourcesContent":["\"use client\";\nimport { useEffect, useRef, useState, type ReactNode } from \"react\";\nimport { consumeAnswerStream, type AnswerStreamEvent, type AnswerGenerationContext } from \"@hjmds/design-contracts/streaming-answer\";\nimport { Button } from \"./actions.js\";\nimport { Progress } from \"./feedback.js\";\nimport { Stack, Text } from \"./layout.js\";\nimport { useCompositionAction } from \"./internal/use-composition-action.js\";\nexport type StreamingAnswerProps = Readonly<{\n answerId: string; initialText?: string; label: string;\n onGenerate: (context: AnswerGenerationContext) => AsyncIterable<AnswerStreamEvent> | Promise<AsyncIterable<AnswerStreamEvent>>;\n labels: Readonly<{ generate: string; regenerate: string; stop: string; thinking: string; streaming: string; stopping: string; complete: string; stopped: string; error: string }>;\n thinkingIndicator?: ReactNode; renderText?: (text: string) => ReactNode; disabled?: boolean;\n}>;\ntype Phase = \"idle\" | \"thinking\" | \"streaming\" | \"stopping\" | \"complete\" | \"stopped\" | \"error\";\nexport function StreamingAnswer(props: StreamingAnswerProps) {\n if (!props.answerId.trim()) throw new TypeError(\"Streaming answers require a stable id\");\n return <AnswerBody key={props.answerId} {...props} />;\n}\nfunction AnswerBody(props: StreamingAnswerProps) {\n const [text, setText] = useState(props.initialText ?? \"\"), [phase, setPhase] = useState<Phase>(props.initialText ? \"complete\" : \"idle\");\n const action = useCompositionAction(props.disabled), request = useRef<AbortController | null>(null), mounted = useRef(true), disabled = useRef(props.disabled), requestWasRegenerate = useRef(false);\n disabled.current = props.disabled;\n useEffect(() => { mounted.current = true; return () => { mounted.current = false; request.current?.abort(); request.current = null; }; }, []);\n const generate = () => {\n if (!mounted.current || disabled.current || request.current) return;\n const controller = new AbortController(); request.current = controller;\n const previousText = text, regenerate = phase !== \"idle\"; requestWasRegenerate.current = regenerate;\n setPhase(\"thinking\");\n const current = () => mounted.current && request.current === controller;\n void action.run(\"generate\", async () => {\n try {\n const source = await props.onGenerate({ signal: controller.signal, previousText, regenerate });\n const result = await consumeAnswerStream(source, controller.signal, previousText, value => { if (current()) { setText(value); setPhase(\"streaming\"); } });\n if (current()) { setText(result.text); setPhase(result.phase); }\n } catch (error) {\n const aborted = controller.signal.aborted && error && typeof error === \"object\" && \"name\" in error && error.name === \"AbortError\";\n if (current()) setPhase(aborted ? \"stopped\" : \"error\");\n throw error;\n }\n }).then(() => { if (request.current === controller) request.current = null; });\n };\n const stop = () => { if (mounted.current && !disabled.current && request.current && !request.current.signal.aborted) { setPhase(\"stopping\"); request.current.abort(); } };\n const pending = action.pending;\n const status = phase === \"idle\" ? null : props.labels[phase];\n return <Stack gap=\"md\"><Text emphasis=\"strong\">{props.label}</Text>\n {text ? (props.renderText ? props.renderText(text) : <Text style={{ whiteSpace: \"pre-wrap\", overflowWrap: \"anywhere\" }}>{text}</Text>) : null}\n {phase === \"thinking\" ? <Stack align=\"center\" justify=\"center\">{props.thinkingIndicator ?? <Progress label={props.labels.thinking} />}</Stack> : null}\n <Stack axis=\"inline\" gap=\"
|
|
1
|
+
{"version":3,"file":"streaming-answer.js","sourceRoot":"","sources":["../src/streaming-answer.tsx"],"names":[],"mappings":"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","sourcesContent":["\"use client\";\nimport { useEffect, useRef, useState, type ReactNode } from \"react\";\nimport { consumeAnswerStream, type AnswerStreamEvent, type AnswerGenerationContext } from \"@hjmds/design-contracts/streaming-answer\";\nimport { Button } from \"./actions.js\";\nimport { Progress } from \"./feedback.js\";\nimport { Stack, Text } from \"./layout.js\";\nimport { useCompositionAction } from \"./internal/use-composition-action.js\";\nexport type StreamingAnswerProps = Readonly<{\n answerId: string; initialText?: string; label: string;\n onGenerate: (context: AnswerGenerationContext) => AsyncIterable<AnswerStreamEvent> | Promise<AsyncIterable<AnswerStreamEvent>>;\n labels: Readonly<{ generate: string; regenerate: string; stop: string; thinking: string; streaming: string; stopping: string; complete: string; stopped: string; error: string }>;\n thinkingIndicator?: ReactNode; renderText?: (text: string) => ReactNode; disabled?: boolean;\n}>;\ntype Phase = \"idle\" | \"thinking\" | \"streaming\" | \"stopping\" | \"complete\" | \"stopped\" | \"error\";\nexport function StreamingAnswer(props: StreamingAnswerProps) {\n if (!props.answerId.trim()) throw new TypeError(\"Streaming answers require a stable id\");\n return <AnswerBody key={props.answerId} {...props} />;\n}\nfunction AnswerBody(props: StreamingAnswerProps) {\n const [text, setText] = useState(props.initialText ?? \"\"), [phase, setPhase] = useState<Phase>(props.initialText ? \"complete\" : \"idle\");\n const action = useCompositionAction(props.disabled), request = useRef<AbortController | null>(null), mounted = useRef(true), disabled = useRef(props.disabled), requestWasRegenerate = useRef(false);\n disabled.current = props.disabled;\n useEffect(() => { mounted.current = true; return () => { mounted.current = false; request.current?.abort(); request.current = null; }; }, []);\n const generate = () => {\n if (!mounted.current || disabled.current || request.current) return;\n const controller = new AbortController(); request.current = controller;\n const previousText = text, regenerate = phase !== \"idle\"; requestWasRegenerate.current = regenerate;\n setPhase(\"thinking\");\n const current = () => mounted.current && request.current === controller;\n void action.run(\"generate\", async () => {\n try {\n const source = await props.onGenerate({ signal: controller.signal, previousText, regenerate });\n const result = await consumeAnswerStream(source, controller.signal, previousText, value => { if (current()) { setText(value); setPhase(\"streaming\"); } });\n if (current()) { setText(result.text); setPhase(result.phase); }\n } catch (error) {\n const aborted = controller.signal.aborted && error && typeof error === \"object\" && \"name\" in error && error.name === \"AbortError\";\n if (current()) setPhase(aborted ? \"stopped\" : \"error\");\n throw error;\n }\n }).then(() => { if (request.current === controller) request.current = null; });\n };\n const stop = () => { if (mounted.current && !disabled.current && request.current && !request.current.signal.aborted) { setPhase(\"stopping\"); request.current.abort(); } };\n const pending = action.pending;\n const status = phase === \"idle\" ? null : props.labels[phase];\n return <Stack gap=\"md\"><Text emphasis=\"strong\">{props.label}</Text>\n {text ? (props.renderText ? props.renderText(text) : <Text style={{ whiteSpace: \"pre-wrap\", overflowWrap: \"anywhere\" }}>{text}</Text>) : null}\n {phase === \"thinking\" ? <Stack align=\"center\" justify=\"center\">{props.thinkingIndicator ?? <Progress label={props.labels.thinking} />}</Stack> : null}\n <Stack axis=\"inline\" gap=\"xs\" wrap><Button loading={pending} disabled={props.disabled === true} onClick={generate}>{(pending ? requestWasRegenerate.current : phase !== \"idle\") ? props.labels.regenerate : props.labels.generate}</Button>\n {pending ? <Button tone=\"secondary\" disabled={props.disabled === true || phase === \"stopping\"} onClick={stop}>{props.labels.stop}</Button> : null}</Stack>\n {status && phase !== \"thinking\" ? <Text role={phase === \"error\" ? \"alert\" : \"status\"} style={{ textAlign: \"center\" }} tone={phase === \"error\" ? \"danger\" : \"primary\"}>{status}</Text> : null}\n </Stack>;\n}\n"]}
|
package/dist/styles.css
CHANGED
|
@@ -245,7 +245,7 @@
|
|
|
245
245
|
.hjm-button[data-size="small"]::after {
|
|
246
246
|
content: "";
|
|
247
247
|
position: absolute;
|
|
248
|
-
inset: calc(-1 * var(--hjm-space-xxs));
|
|
248
|
+
inset: calc(-1 * var(--hjm-button-hit-slop, var(--hjm-space-xxs)));
|
|
249
249
|
}
|
|
250
250
|
/* Shape and label alignment are recipe axes; a product must not override
|
|
251
251
|
border-radius or justify-content on the control itself. */
|
|
@@ -315,7 +315,7 @@
|
|
|
315
315
|
}
|
|
316
316
|
.hjm-icon-button[data-shape="circle"] { border-radius: var(--hjm-radius-full); }
|
|
317
317
|
.hjm-icon-button[data-size="small"] { inline-size: var(--hjm-control-button-small); block-size: var(--hjm-control-button-small); min-inline-size: 0; min-block-size: 0; }
|
|
318
|
-
.hjm-icon-button[data-size="small"]::after { content: ""; position: absolute; inset: calc(-1 * var(--hjm-space-xxs)); }
|
|
318
|
+
.hjm-icon-button[data-size="small"]::after { content: ""; position: absolute; inset: calc(-1 * var(--hjm-button-hit-slop, var(--hjm-space-xxs))); }
|
|
319
319
|
.hjm-icon-button[data-size="large"] { inline-size: var(--hjm-control-button-large); block-size: var(--hjm-control-button-large); }
|
|
320
320
|
/* Edge alignment (iconButtonRecipe.edge / resolveButtonEdgeOverhang, 2026-10-17 measured audit): a ghost control on a
|
|
321
321
|
container edge keeps its hit area but overhangs that edge, so its glyph slot or label sits on the inset like text.
|
|
@@ -332,8 +332,8 @@
|
|
|
332
332
|
:is(.hjm-icon-button, .hjm-button):is([data-edge="end"], [data-edge="both"]) { margin-inline-end: calc(-1 * var(--hjm-edge-overhang, 0px)); }
|
|
333
333
|
/* NotificationBell wraps a default (ghost, medium) IconButton with a badge anchored to its own end, so the bell root
|
|
334
334
|
takes the same overhang and the badge keeps the icon's corner (2026-10-17 1.27.2 adoption: Spint's top-bar bell). */
|
|
335
|
-
.hjm-notification-bell:is([data-edge="start"], [data-edge="both"]) { margin-inline-start: calc(-1 * var(--hjm-icon-button-edge-
|
|
336
|
-
.hjm-notification-bell:is([data-edge="end"], [data-edge="both"]) { margin-inline-end: calc(-1 * var(--hjm-icon-button-edge-
|
|
335
|
+
.hjm-notification-bell:is([data-edge="start"], [data-edge="both"]) { margin-inline-start: calc(-1 * var(--hjm-icon-button-edge-small)); }
|
|
336
|
+
.hjm-notification-bell:is([data-edge="end"], [data-edge="both"]) { margin-inline-end: calc(-1 * var(--hjm-icon-button-edge-small)); }
|
|
337
337
|
.hjm-link { display: inline-flex; align-items: center; gap: var(--hjm-space-xxs); max-inline-size: 100%; min-inline-size: 0; overflow-wrap: anywhere; color: var(--hjm-color-content-brand); text-underline-offset: 0.18em; }
|
|
338
338
|
.hjm-link[data-tone="neutral"] { color: var(--hjm-color-text-body); }
|
|
339
339
|
.hjm-link[data-variant="standalone"] { min-block-size: var(--hjm-control-min-touch-target); min-inline-size: var(--hjm-control-min-touch-target); justify-content: center; text-decoration: none; }
|
|
@@ -1020,7 +1020,7 @@
|
|
|
1020
1020
|
/* cardRecipe.title.emphasis "strong": without a weight the h2–h6 element fell back to the UA bold (700). */
|
|
1021
1021
|
.hjm-card__title { margin: 0; color: var(--hjm-color-text); font-size: var(--hjm-type-title-size); line-height: var(--hjm-type-title-line-height); font-weight: var(--hjm-text-emphasis-strong); overflow-wrap: anywhere; }
|
|
1022
1022
|
.hjm-card__description { margin: 0; overflow-wrap: anywhere; }
|
|
1023
|
-
.hjm-card__actions { display: flex; flex-wrap: wrap; gap: var(--hjm-space-
|
|
1023
|
+
.hjm-card__actions { display: flex; flex-wrap: wrap; gap: var(--hjm-space-xs); padding: 0 var(--hjm-space-md) var(--hjm-space-md); }
|
|
1024
1024
|
/* Row rhythm reads the recipe density variables so the stylesheet does not
|
|
1025
1025
|
carry a second copy of the same numbers. */
|
|
1026
1026
|
/* Inline placement (listRowRecipe.surfaceBleed, 2026-10-17 user decision): the row text sits on the container's content
|
|
@@ -1135,14 +1135,14 @@ button.hjm-list-row, a.hjm-list-row { cursor: pointer; }
|
|
|
1135
1135
|
.hjm-statistic[data-density="compact"] { gap: var(--hjm-space-xxs); }
|
|
1136
1136
|
.hjm-statistic[data-density="compact"][data-presentation="surface"] { padding: var(--hjm-space-sm); }
|
|
1137
1137
|
/* Text variants follow statisticRecipe as Native does: label `label` (compact `caption`) semibold, value `heading`
|
|
1138
|
-
(compact `
|
|
1138
|
+
(compact `bodyLarge`) heavy, affix `body` semibold in content.body, hint and trend `caption` (trend bold). Until 2026-10-06
|
|
1139
1139
|
Web drew a body-size medium label, a title-size value at both densities (scaled twice by --hjm-text-scale, which the
|
|
1140
1140
|
--hjm-type-* sizes already include) and muted affixes. */
|
|
1141
1141
|
.hjm-statistic__label { color: var(--hjm-color-text-muted); font-size: var(--hjm-type-label-size); line-height: var(--hjm-type-label-line-height); font-weight: var(--hjm-text-emphasis-medium); overflow-wrap: anywhere; }
|
|
1142
1142
|
.hjm-statistic[data-density="compact"] .hjm-statistic__label { font-size: var(--hjm-type-caption-size); line-height: var(--hjm-type-caption-line-height); }
|
|
1143
1143
|
.hjm-statistic__value-row { display: flex; align-items: baseline; flex-wrap: wrap; gap: var(--hjm-space-xxs); min-inline-size: 0; }
|
|
1144
1144
|
.hjm-statistic__value { color: var(--hjm-statistic-value-color, var(--hjm-color-text)); font-size: var(--hjm-type-heading-size); line-height: var(--hjm-type-heading-line-height); font-weight: var(--hjm-font-weight-semibold); font-variant-numeric: tabular-nums; overflow-wrap: anywhere; }
|
|
1145
|
-
.hjm-statistic[data-density="compact"] .hjm-statistic__value { font-size: var(--hjm-type-
|
|
1145
|
+
.hjm-statistic[data-density="compact"] .hjm-statistic__value { font-size: var(--hjm-type-body-large-size); line-height: var(--hjm-type-body-large-line-height); }
|
|
1146
1146
|
.hjm-statistic__affix { color: var(--hjm-color-text-body); font-size: var(--hjm-type-body-size); line-height: var(--hjm-type-body-line-height); font-weight: var(--hjm-text-emphasis-medium); }
|
|
1147
1147
|
.hjm-statistic__hint { color: var(--hjm-color-text-muted); font-size: var(--hjm-type-caption-size); line-height: var(--hjm-type-caption-line-height); }
|
|
1148
1148
|
.hjm-statistic__trend { display: inline-flex; align-items: center; gap: var(--hjm-space-xxs); font-size: var(--hjm-type-caption-size); line-height: var(--hjm-type-caption-line-height); font-weight: var(--hjm-text-emphasis-medium); overflow-wrap: anywhere; }
|
|
@@ -1186,7 +1186,7 @@ button.hjm-list-row, a.hjm-list-row { cursor: pointer; }
|
|
|
1186
1186
|
.hjm-result[data-status="info"] .hjm-result__icon { color: var(--hjm-accent-info); background: var(--hjm-color-bg); }
|
|
1187
1187
|
.hjm-result__title { margin: 0; color: var(--hjm-color-text); font-size: var(--hjm-type-title-large-size); line-height: var(--hjm-type-title-large-line-height); font-weight: var(--hjm-type-title-large-weight); overflow-wrap: anywhere; }
|
|
1188
1188
|
.hjm-result__description { max-inline-size: 40rem; margin: 0; color: var(--hjm-color-text-muted); overflow-wrap: anywhere; }
|
|
1189
|
-
.hjm-result__actions { display: flex; flex-wrap: wrap; justify-content: center; gap: var(--hjm-space-
|
|
1189
|
+
.hjm-result__actions { display: flex; flex-wrap: wrap; justify-content: center; gap: var(--hjm-space-xs); margin-block-start: var(--hjm-space-xs); }
|
|
1190
1190
|
.hjm-progress { display: grid; gap: var(--hjm-space-xs); }
|
|
1191
1191
|
.hjm-progress__copy { display: flex; justify-content: space-between; gap: var(--hjm-space-md); color: var(--hjm-color-text-body); }
|
|
1192
1192
|
/*
|
|
@@ -2583,7 +2583,7 @@ button.hjm-list-row, a.hjm-list-row { cursor: pointer; }
|
|
|
2583
2583
|
flex: 0 0 auto;
|
|
2584
2584
|
flex-wrap: wrap;
|
|
2585
2585
|
justify-content: flex-end;
|
|
2586
|
-
gap: var(--hjm-space-
|
|
2586
|
+
gap: var(--hjm-space-xs);
|
|
2587
2587
|
padding: var(--hjm-space-sm) var(--hjm-space-lg)
|
|
2588
2588
|
max(var(--hjm-space-sm), env(safe-area-inset-bottom, 0px));
|
|
2589
2589
|
}
|
|
@@ -2774,7 +2774,7 @@ button.hjm-list-row, a.hjm-list-row { cursor: pointer; }
|
|
|
2774
2774
|
.hjm-form__fields { display: grid; gap: var(--hjm-space-lg); }
|
|
2775
2775
|
.hjm-form[data-density="compact"] .hjm-form__fields { gap: var(--hjm-space-sm); }
|
|
2776
2776
|
.hjm-form__error { margin-block-start: var(--hjm-space-sm); color: var(--hjm-color-danger); }
|
|
2777
|
-
.hjm-form__actions { display: flex; flex-wrap: wrap; gap: var(--hjm-space-
|
|
2777
|
+
.hjm-form__actions { display: flex; flex-wrap: wrap; gap: var(--hjm-space-xs); margin-block-start: var(--hjm-space-sm); }
|
|
2778
2778
|
|
|
2779
2779
|
/* Advanced display ------------------------------------------------------- */
|
|
2780
2780
|
/* timelineRecipe label/description are `body`; binding it here lets the rail and timestamp derive from the same line box. */
|
|
@@ -2896,10 +2896,10 @@ button.hjm-list-row, a.hjm-list-row { cursor: pointer; }
|
|
|
2896
2896
|
.hjm-load-more__spinner { inline-size: 1em; block-size: 1em; border: 2px solid var(--hjm-color-content-brand); border-inline-end-color: transparent; border-radius: 50%; animation: hjm-spin 800ms linear infinite; }
|
|
2897
2897
|
|
|
2898
2898
|
/* Expansion renderers --------------------------------------------------- */
|
|
2899
|
-
.hjm-steps { display: grid; grid-template-columns: repeat(var(--hjm-steps-connector-count), minmax(0, 1fr)) fit-content(calc(100% / var(--hjm-steps-count))); gap: 0; margin: 0; padding: 0; list-style: none; }
|
|
2899
|
+
.hjm-steps { display: grid; grid-template-columns: repeat(var(--hjm-steps-connector-count), minmax(0, 1fr)) fit-content(calc(100% / var(--hjm-steps-count))); gap: 0; margin: 0; padding: 0 var(--hjm-steps-inset); list-style: none; }
|
|
2900
2900
|
.hjm-steps__step { min-inline-size: 0; display: grid; align-content: start; gap: var(--hjm-space-xs); }
|
|
2901
2901
|
.hjm-steps__rail { display: flex; align-items: center; min-inline-size: 0; }
|
|
2902
|
-
.hjm-steps__indicator { flex: 0 0 auto; inline-size:
|
|
2902
|
+
.hjm-steps__indicator { flex: 0 0 auto; inline-size: var(--hjm-steps-indicator-size); block-size: var(--hjm-steps-indicator-size); display: grid; place-items: center; border: 1px solid var(--hjm-color-border); border-radius: 50%; color: var(--hjm-color-text-muted); background: var(--hjm-color-bg); font-size: var(--hjm-type-label-size); font-weight: var(--hjm-text-emphasis-medium); }
|
|
2903
2903
|
.hjm-steps__connector { flex: 1 1 auto; block-size: 1px; background: var(--hjm-color-border); }
|
|
2904
2904
|
.hjm-steps__step[data-status="current"] .hjm-steps__indicator { border: 2px solid var(--hjm-color-content-brand); color: var(--hjm-color-content-brand); }
|
|
2905
2905
|
.hjm-steps__step[data-status="complete"] .hjm-steps__indicator { border-color: var(--hjm-accent-success); color: var(--hjm-accent-success); background: var(--hjm-color-bg); }
|
|
@@ -3076,7 +3076,7 @@ button.hjm-list-row, a.hjm-list-row { cursor: pointer; }
|
|
|
3076
3076
|
/* TDS-inspired screen rhythm: shared Native recipes, content-driven height. See docs/screen-chrome.md. */
|
|
3077
3077
|
/* Intrinsic action columns keep short labels readable at 320px; the title wraps
|
|
3078
3078
|
in the remaining space instead of squeezing actions to equal-width tracks. */
|
|
3079
|
-
.hjm-top-bar { display: grid; grid-template-columns: minmax(var(--hjm-control-
|
|
3079
|
+
.hjm-top-bar { display: grid; grid-template-columns: minmax(var(--hjm-control-button-small), auto) minmax(0, 1fr) minmax(var(--hjm-control-button-small), auto); align-items: center; min-block-size: var(--hjm-top-bar-min-height); gap: var(--hjm-top-bar-gap); padding-inline: var(--hjm-top-bar-padding); padding-block-start: max(env(safe-area-inset-top, 0px), var(--hjm-top-bar-safe-area)); background: var(--hjm-color-bg); }
|
|
3080
3080
|
.hjm-top-bar[data-surface="transparent"] { background: transparent; }
|
|
3081
3081
|
.hjm-top-bar__leading, .hjm-top-bar__trailing { display: flex; flex-wrap: wrap; align-items: center; min-inline-size: 0; gap: var(--hjm-top-bar-gap); }
|
|
3082
3082
|
.hjm-top-bar__trailing { justify-content: flex-end; }
|
|
@@ -3097,7 +3097,7 @@ button.hjm-list-row, a.hjm-list-row { cursor: pointer; }
|
|
|
3097
3097
|
the remainder so the gap is max(footer, inset), not their sum (2026-10-17 "버튼 아래 여백이 많아"). */
|
|
3098
3098
|
.hjm-bottom-cta[data-placement="screen-footer"] { position: static; box-sizing: border-box; inline-size: 100%; min-inline-size: 0; min-block-size: 0; padding: 0 0 max(0px, calc(var(--hjm-bottom-cta-safe-area) - var(--hjm-bottom-cta-parent-padding))); border: 0; background: none; box-shadow: none; }
|
|
3099
3099
|
.hjm-bottom-cta__description { margin: 0; font-size: var(--hjm-type-caption-size); line-height: var(--hjm-type-caption-line-height); color: var(--hjm-color-text-muted); overflow-wrap: anywhere; }
|
|
3100
|
-
.hjm-bottom-cta__actions { display: flex; flex-wrap: wrap; gap: var(--hjm-bottom-cta-gap); }
|
|
3100
|
+
.hjm-bottom-cta__actions { display: flex; flex-wrap: wrap; gap: var(--hjm-bottom-cta-actions-gap); }
|
|
3101
3101
|
/* bottomCtaRecipe.contentMaxWidth: the surface spans the viewport, its copy and actions stop at the reading width. */
|
|
3102
3102
|
.hjm-bottom-cta__description, .hjm-bottom-cta__actions { box-sizing: border-box; inline-size: 100%; max-inline-size: var(--hjm-bottom-cta-content-max-width); margin-inline: auto; }
|
|
3103
3103
|
.hjm-bottom-cta__actions > div { flex: 1 1 calc(var(--hjm-control-min-touch-target) * 3); min-inline-size: 0; }
|
|
@@ -3302,14 +3302,14 @@ button.hjm-list-row, a.hjm-list-row { cursor: pointer; }
|
|
|
3302
3302
|
.hjm-tabs__indicator { position: absolute; bottom: 0; height: 2px; border-radius: var(--hjm-radius-full); background: var(--hjm-color-content-brand); pointer-events: none; }
|
|
3303
3303
|
/* indicator="filled" (tabsRecipe.indicators.filled): a surface-accent pill behind the selected tab, no list divider.
|
|
3304
3304
|
The moving pill spans the tab height and sits under the labels. */
|
|
3305
|
-
.hjm-tabs[data-indicator="filled"] .hjm-tabs__list { border: 0; }
|
|
3306
|
-
.hjm-tabs[data-indicator="filled"] .hjm-tabs__tab { border-radius: var(--hjm-radius-full); }
|
|
3307
|
-
.hjm-tabs[data-indicator="filled"] .hjm-tabs__tab[data-state="selected"] { color: var(--hjm-color-content-brand); }
|
|
3308
|
-
.hjm-tabs[data-indicator="filled"] .hjm-tabs__tab[data-state="selected"]::after { display: none; }
|
|
3309
|
-
.hjm-tabs[data-indicator="filled"]:not([data-indicator-motion="moving"]) .hjm-tabs__tab[data-state="selected"] { background: var(--hjm-color-surface-accent); }
|
|
3310
|
-
.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; }
|
|
3311
|
-
.hjm-tabs[data-indicator="filled"] .hjm-tabs__list { position: relative; }
|
|
3312
|
-
.hjm-tabs[data-indicator="filled"] .hjm-tabs__tab { z-index: 1; }
|
|
3305
|
+
.hjm-tabs:is([data-indicator="filled"],[data-indicator="solid"]) .hjm-tabs__list { border: 0; }
|
|
3306
|
+
.hjm-tabs:is([data-indicator="filled"],[data-indicator="solid"]) .hjm-tabs__tab { border-radius: var(--hjm-radius-full); }
|
|
3307
|
+
.hjm-tabs:is([data-indicator="filled"],[data-indicator="solid"]) .hjm-tabs__tab[data-state="selected"] { color: var(--hjm-color-content-brand); }
|
|
3308
|
+
.hjm-tabs:is([data-indicator="filled"],[data-indicator="solid"]) .hjm-tabs__tab[data-state="selected"]::after { display: none; }
|
|
3309
|
+
.hjm-tabs:is([data-indicator="filled"],[data-indicator="solid"]):not([data-indicator-motion="moving"]) .hjm-tabs__tab[data-state="selected"] { background: var(--hjm-color-surface-accent); }
|
|
3310
|
+
.hjm-tabs:is([data-indicator="filled"],[data-indicator="solid"]) .hjm-tabs__indicator { top: 0; bottom: 0; height: auto; border-radius: var(--hjm-radius-full); background: var(--hjm-color-surface-accent); z-index: 0; }
|
|
3311
|
+
.hjm-tabs:is([data-indicator="filled"],[data-indicator="solid"]) .hjm-tabs__list { position: relative; }
|
|
3312
|
+
.hjm-tabs:is([data-indicator="filled"],[data-indicator="solid"]) .hjm-tabs__tab { z-index: 1; }
|
|
3313
3313
|
.hjm-tabs__gooey { height: 6px; }
|
|
3314
3314
|
|
|
3315
3315
|
/* Capsule destinations retain route/link semantics. At larger text sizes we show
|
|
@@ -3722,6 +3722,7 @@ button.hjm-chat-message__media-item:focus-visible { outline: 2px solid var(--hjm
|
|
|
3722
3722
|
.hjm-card__media-badges { position: absolute; inset-block-start: var(--hjm-space-sm); inset-inline-end: var(--hjm-space-sm); display: flex; flex-wrap: wrap; gap: var(--hjm-space-xs); z-index: 1; }
|
|
3723
3723
|
.hjm-card__scrim { position: absolute; inset: 0; background: var(--hjm-card-background-scrim); }
|
|
3724
3724
|
.hjm-card__badges { display: flex; flex-wrap: wrap; gap: var(--hjm-space-xs); }
|
|
3725
|
+
.hjm-card__badges[data-align="center"] { justify-content: center; }
|
|
3725
3726
|
.hjm-card[data-background-media="true"] > .hjm-card__body { position: relative; flex: 0 1 auto; margin-block-start: auto; }
|
|
3726
3727
|
.hjm-card[data-background-media="true"] > .hjm-card__actions { position: relative; }
|
|
3727
3728
|
.hjm-card[data-background-media="true"] .hjm-card__title,
|
|
@@ -3820,3 +3821,14 @@ button.hjm-chat-message__media-item:focus-visible { outline: 2px solid var(--hjm
|
|
|
3820
3821
|
/* Commands remain independent of the passive record and rail. */
|
|
3821
3822
|
.hjm-timeline__item:has(> .hjm-timeline__actions) { grid-template-columns: 1rem minmax(0, 1fr) auto; }
|
|
3822
3823
|
.hjm-timeline__actions { align-self: center; display: flex; align-items: center; gap: var(--hjm-space-xs); }
|
|
3824
|
+
|
|
3825
|
+
/* Strong filled tabs use one opaque contrast pair for static and moving marks. */
|
|
3826
|
+
.hjm-tabs[data-indicator="solid"] .hjm-tabs__tab[data-state="selected"] { color: var(--hjm-color-on-primary); }
|
|
3827
|
+
.hjm-tabs[data-indicator="solid"]:not([data-indicator-motion="moving"]) .hjm-tabs__tab[data-state="selected"],
|
|
3828
|
+
.hjm-tabs[data-indicator="solid"] .hjm-tabs__indicator { background: var(--hjm-color-primary); }
|
|
3829
|
+
.hjm-segmented[data-selection-tone="brand"]:not([data-presentation="text"]) .hjm-segmented__item[data-state="checked"] { color: var(--hjm-color-on-primary); background: var(--hjm-color-primary); }
|
|
3830
|
+
.hjm-segmented[data-selection-tone="brand"][data-presentation="pills"] .hjm-segmented__item[data-state="checked"] { background: transparent; }
|
|
3831
|
+
.hjm-segmented[data-selection-tone="brand"][data-presentation="pills"] .hjm-segmented__item[data-state="checked"]::before { background: var(--hjm-color-primary); border-color: var(--hjm-color-primary); }
|
|
3832
|
+
.hjm-segmented[data-selection-tone="brand"] .hjm-segmented__highlight { background: var(--hjm-color-primary); }
|
|
3833
|
+
.hjm-segmented[data-selection-tone="brand"] .hjm-segmented__items[data-highlight-ready="true"] > .hjm-segmented__item[data-state="checked"],
|
|
3834
|
+
.hjm-segmented[data-selection-tone="brand"][data-presentation="pills"] .hjm-segmented__items[data-highlight-ready="true"] > .hjm-segmented__item[data-state="checked"]::before { background: transparent; }
|
package/dist/styles.layered.css
CHANGED
|
@@ -246,7 +246,7 @@
|
|
|
246
246
|
.hjm-button[data-size="small"]::after {
|
|
247
247
|
content: "";
|
|
248
248
|
position: absolute;
|
|
249
|
-
inset: calc(-1 * var(--hjm-space-xxs));
|
|
249
|
+
inset: calc(-1 * var(--hjm-button-hit-slop, var(--hjm-space-xxs)));
|
|
250
250
|
}
|
|
251
251
|
/* Shape and label alignment are recipe axes; a product must not override
|
|
252
252
|
border-radius or justify-content on the control itself. */
|
|
@@ -316,7 +316,7 @@
|
|
|
316
316
|
}
|
|
317
317
|
.hjm-icon-button[data-shape="circle"] { border-radius: var(--hjm-radius-full); }
|
|
318
318
|
.hjm-icon-button[data-size="small"] { inline-size: var(--hjm-control-button-small); block-size: var(--hjm-control-button-small); min-inline-size: 0; min-block-size: 0; }
|
|
319
|
-
.hjm-icon-button[data-size="small"]::after { content: ""; position: absolute; inset: calc(-1 * var(--hjm-space-xxs)); }
|
|
319
|
+
.hjm-icon-button[data-size="small"]::after { content: ""; position: absolute; inset: calc(-1 * var(--hjm-button-hit-slop, var(--hjm-space-xxs))); }
|
|
320
320
|
.hjm-icon-button[data-size="large"] { inline-size: var(--hjm-control-button-large); block-size: var(--hjm-control-button-large); }
|
|
321
321
|
/* Edge alignment (iconButtonRecipe.edge / resolveButtonEdgeOverhang, 2026-10-17 measured audit): a ghost control on a
|
|
322
322
|
container edge keeps its hit area but overhangs that edge, so its glyph slot or label sits on the inset like text.
|
|
@@ -333,8 +333,8 @@
|
|
|
333
333
|
:is(.hjm-icon-button, .hjm-button):is([data-edge="end"], [data-edge="both"]) { margin-inline-end: calc(-1 * var(--hjm-edge-overhang, 0px)); }
|
|
334
334
|
/* NotificationBell wraps a default (ghost, medium) IconButton with a badge anchored to its own end, so the bell root
|
|
335
335
|
takes the same overhang and the badge keeps the icon's corner (2026-10-17 1.27.2 adoption: Spint's top-bar bell). */
|
|
336
|
-
.hjm-notification-bell:is([data-edge="start"], [data-edge="both"]) { margin-inline-start: calc(-1 * var(--hjm-icon-button-edge-
|
|
337
|
-
.hjm-notification-bell:is([data-edge="end"], [data-edge="both"]) { margin-inline-end: calc(-1 * var(--hjm-icon-button-edge-
|
|
336
|
+
.hjm-notification-bell:is([data-edge="start"], [data-edge="both"]) { margin-inline-start: calc(-1 * var(--hjm-icon-button-edge-small)); }
|
|
337
|
+
.hjm-notification-bell:is([data-edge="end"], [data-edge="both"]) { margin-inline-end: calc(-1 * var(--hjm-icon-button-edge-small)); }
|
|
338
338
|
.hjm-link { display: inline-flex; align-items: center; gap: var(--hjm-space-xxs); max-inline-size: 100%; min-inline-size: 0; overflow-wrap: anywhere; color: var(--hjm-color-content-brand); text-underline-offset: 0.18em; }
|
|
339
339
|
.hjm-link[data-tone="neutral"] { color: var(--hjm-color-text-body); }
|
|
340
340
|
.hjm-link[data-variant="standalone"] { min-block-size: var(--hjm-control-min-touch-target); min-inline-size: var(--hjm-control-min-touch-target); justify-content: center; text-decoration: none; }
|
|
@@ -1021,7 +1021,7 @@
|
|
|
1021
1021
|
/* cardRecipe.title.emphasis "strong": without a weight the h2–h6 element fell back to the UA bold (700). */
|
|
1022
1022
|
.hjm-card__title { margin: 0; color: var(--hjm-color-text); font-size: var(--hjm-type-title-size); line-height: var(--hjm-type-title-line-height); font-weight: var(--hjm-text-emphasis-strong); overflow-wrap: anywhere; }
|
|
1023
1023
|
.hjm-card__description { margin: 0; overflow-wrap: anywhere; }
|
|
1024
|
-
.hjm-card__actions { display: flex; flex-wrap: wrap; gap: var(--hjm-space-
|
|
1024
|
+
.hjm-card__actions { display: flex; flex-wrap: wrap; gap: var(--hjm-space-xs); padding: 0 var(--hjm-space-md) var(--hjm-space-md); }
|
|
1025
1025
|
/* Row rhythm reads the recipe density variables so the stylesheet does not
|
|
1026
1026
|
carry a second copy of the same numbers. */
|
|
1027
1027
|
/* Inline placement (listRowRecipe.surfaceBleed, 2026-10-17 user decision): the row text sits on the container's content
|
|
@@ -1136,14 +1136,14 @@ button.hjm-list-row, a.hjm-list-row { cursor: pointer; }
|
|
|
1136
1136
|
.hjm-statistic[data-density="compact"] { gap: var(--hjm-space-xxs); }
|
|
1137
1137
|
.hjm-statistic[data-density="compact"][data-presentation="surface"] { padding: var(--hjm-space-sm); }
|
|
1138
1138
|
/* Text variants follow statisticRecipe as Native does: label `label` (compact `caption`) semibold, value `heading`
|
|
1139
|
-
(compact `
|
|
1139
|
+
(compact `bodyLarge`) heavy, affix `body` semibold in content.body, hint and trend `caption` (trend bold). Until 2026-10-06
|
|
1140
1140
|
Web drew a body-size medium label, a title-size value at both densities (scaled twice by --hjm-text-scale, which the
|
|
1141
1141
|
--hjm-type-* sizes already include) and muted affixes. */
|
|
1142
1142
|
.hjm-statistic__label { color: var(--hjm-color-text-muted); font-size: var(--hjm-type-label-size); line-height: var(--hjm-type-label-line-height); font-weight: var(--hjm-text-emphasis-medium); overflow-wrap: anywhere; }
|
|
1143
1143
|
.hjm-statistic[data-density="compact"] .hjm-statistic__label { font-size: var(--hjm-type-caption-size); line-height: var(--hjm-type-caption-line-height); }
|
|
1144
1144
|
.hjm-statistic__value-row { display: flex; align-items: baseline; flex-wrap: wrap; gap: var(--hjm-space-xxs); min-inline-size: 0; }
|
|
1145
1145
|
.hjm-statistic__value { color: var(--hjm-statistic-value-color, var(--hjm-color-text)); font-size: var(--hjm-type-heading-size); line-height: var(--hjm-type-heading-line-height); font-weight: var(--hjm-font-weight-semibold); font-variant-numeric: tabular-nums; overflow-wrap: anywhere; }
|
|
1146
|
-
.hjm-statistic[data-density="compact"] .hjm-statistic__value { font-size: var(--hjm-type-
|
|
1146
|
+
.hjm-statistic[data-density="compact"] .hjm-statistic__value { font-size: var(--hjm-type-body-large-size); line-height: var(--hjm-type-body-large-line-height); }
|
|
1147
1147
|
.hjm-statistic__affix { color: var(--hjm-color-text-body); font-size: var(--hjm-type-body-size); line-height: var(--hjm-type-body-line-height); font-weight: var(--hjm-text-emphasis-medium); }
|
|
1148
1148
|
.hjm-statistic__hint { color: var(--hjm-color-text-muted); font-size: var(--hjm-type-caption-size); line-height: var(--hjm-type-caption-line-height); }
|
|
1149
1149
|
.hjm-statistic__trend { display: inline-flex; align-items: center; gap: var(--hjm-space-xxs); font-size: var(--hjm-type-caption-size); line-height: var(--hjm-type-caption-line-height); font-weight: var(--hjm-text-emphasis-medium); overflow-wrap: anywhere; }
|
|
@@ -1187,7 +1187,7 @@ button.hjm-list-row, a.hjm-list-row { cursor: pointer; }
|
|
|
1187
1187
|
.hjm-result[data-status="info"] .hjm-result__icon { color: var(--hjm-accent-info); background: var(--hjm-color-bg); }
|
|
1188
1188
|
.hjm-result__title { margin: 0; color: var(--hjm-color-text); font-size: var(--hjm-type-title-large-size); line-height: var(--hjm-type-title-large-line-height); font-weight: var(--hjm-type-title-large-weight); overflow-wrap: anywhere; }
|
|
1189
1189
|
.hjm-result__description { max-inline-size: 40rem; margin: 0; color: var(--hjm-color-text-muted); overflow-wrap: anywhere; }
|
|
1190
|
-
.hjm-result__actions { display: flex; flex-wrap: wrap; justify-content: center; gap: var(--hjm-space-
|
|
1190
|
+
.hjm-result__actions { display: flex; flex-wrap: wrap; justify-content: center; gap: var(--hjm-space-xs); margin-block-start: var(--hjm-space-xs); }
|
|
1191
1191
|
.hjm-progress { display: grid; gap: var(--hjm-space-xs); }
|
|
1192
1192
|
.hjm-progress__copy { display: flex; justify-content: space-between; gap: var(--hjm-space-md); color: var(--hjm-color-text-body); }
|
|
1193
1193
|
/*
|
|
@@ -2584,7 +2584,7 @@ button.hjm-list-row, a.hjm-list-row { cursor: pointer; }
|
|
|
2584
2584
|
flex: 0 0 auto;
|
|
2585
2585
|
flex-wrap: wrap;
|
|
2586
2586
|
justify-content: flex-end;
|
|
2587
|
-
gap: var(--hjm-space-
|
|
2587
|
+
gap: var(--hjm-space-xs);
|
|
2588
2588
|
padding: var(--hjm-space-sm) var(--hjm-space-lg)
|
|
2589
2589
|
max(var(--hjm-space-sm), env(safe-area-inset-bottom, 0px));
|
|
2590
2590
|
}
|
|
@@ -2775,7 +2775,7 @@ button.hjm-list-row, a.hjm-list-row { cursor: pointer; }
|
|
|
2775
2775
|
.hjm-form__fields { display: grid; gap: var(--hjm-space-lg); }
|
|
2776
2776
|
.hjm-form[data-density="compact"] .hjm-form__fields { gap: var(--hjm-space-sm); }
|
|
2777
2777
|
.hjm-form__error { margin-block-start: var(--hjm-space-sm); color: var(--hjm-color-danger); }
|
|
2778
|
-
.hjm-form__actions { display: flex; flex-wrap: wrap; gap: var(--hjm-space-
|
|
2778
|
+
.hjm-form__actions { display: flex; flex-wrap: wrap; gap: var(--hjm-space-xs); margin-block-start: var(--hjm-space-sm); }
|
|
2779
2779
|
|
|
2780
2780
|
/* Advanced display ------------------------------------------------------- */
|
|
2781
2781
|
/* timelineRecipe label/description are `body`; binding it here lets the rail and timestamp derive from the same line box. */
|
|
@@ -2897,10 +2897,10 @@ button.hjm-list-row, a.hjm-list-row { cursor: pointer; }
|
|
|
2897
2897
|
.hjm-load-more__spinner { inline-size: 1em; block-size: 1em; border: 2px solid var(--hjm-color-content-brand); border-inline-end-color: transparent; border-radius: 50%; animation: hjm-spin 800ms linear infinite; }
|
|
2898
2898
|
|
|
2899
2899
|
/* Expansion renderers --------------------------------------------------- */
|
|
2900
|
-
.hjm-steps { display: grid; grid-template-columns: repeat(var(--hjm-steps-connector-count), minmax(0, 1fr)) fit-content(calc(100% / var(--hjm-steps-count))); gap: 0; margin: 0; padding: 0; list-style: none; }
|
|
2900
|
+
.hjm-steps { display: grid; grid-template-columns: repeat(var(--hjm-steps-connector-count), minmax(0, 1fr)) fit-content(calc(100% / var(--hjm-steps-count))); gap: 0; margin: 0; padding: 0 var(--hjm-steps-inset); list-style: none; }
|
|
2901
2901
|
.hjm-steps__step { min-inline-size: 0; display: grid; align-content: start; gap: var(--hjm-space-xs); }
|
|
2902
2902
|
.hjm-steps__rail { display: flex; align-items: center; min-inline-size: 0; }
|
|
2903
|
-
.hjm-steps__indicator { flex: 0 0 auto; inline-size:
|
|
2903
|
+
.hjm-steps__indicator { flex: 0 0 auto; inline-size: var(--hjm-steps-indicator-size); block-size: var(--hjm-steps-indicator-size); display: grid; place-items: center; border: 1px solid var(--hjm-color-border); border-radius: 50%; color: var(--hjm-color-text-muted); background: var(--hjm-color-bg); font-size: var(--hjm-type-label-size); font-weight: var(--hjm-text-emphasis-medium); }
|
|
2904
2904
|
.hjm-steps__connector { flex: 1 1 auto; block-size: 1px; background: var(--hjm-color-border); }
|
|
2905
2905
|
.hjm-steps__step[data-status="current"] .hjm-steps__indicator { border: 2px solid var(--hjm-color-content-brand); color: var(--hjm-color-content-brand); }
|
|
2906
2906
|
.hjm-steps__step[data-status="complete"] .hjm-steps__indicator { border-color: var(--hjm-accent-success); color: var(--hjm-accent-success); background: var(--hjm-color-bg); }
|
|
@@ -3077,7 +3077,7 @@ button.hjm-list-row, a.hjm-list-row { cursor: pointer; }
|
|
|
3077
3077
|
/* TDS-inspired screen rhythm: shared Native recipes, content-driven height. See docs/screen-chrome.md. */
|
|
3078
3078
|
/* Intrinsic action columns keep short labels readable at 320px; the title wraps
|
|
3079
3079
|
in the remaining space instead of squeezing actions to equal-width tracks. */
|
|
3080
|
-
.hjm-top-bar { display: grid; grid-template-columns: minmax(var(--hjm-control-
|
|
3080
|
+
.hjm-top-bar { display: grid; grid-template-columns: minmax(var(--hjm-control-button-small), auto) minmax(0, 1fr) minmax(var(--hjm-control-button-small), auto); align-items: center; min-block-size: var(--hjm-top-bar-min-height); gap: var(--hjm-top-bar-gap); padding-inline: var(--hjm-top-bar-padding); padding-block-start: max(env(safe-area-inset-top, 0px), var(--hjm-top-bar-safe-area)); background: var(--hjm-color-bg); }
|
|
3081
3081
|
.hjm-top-bar[data-surface="transparent"] { background: transparent; }
|
|
3082
3082
|
.hjm-top-bar__leading, .hjm-top-bar__trailing { display: flex; flex-wrap: wrap; align-items: center; min-inline-size: 0; gap: var(--hjm-top-bar-gap); }
|
|
3083
3083
|
.hjm-top-bar__trailing { justify-content: flex-end; }
|
|
@@ -3098,7 +3098,7 @@ button.hjm-list-row, a.hjm-list-row { cursor: pointer; }
|
|
|
3098
3098
|
the remainder so the gap is max(footer, inset), not their sum (2026-10-17 "버튼 아래 여백이 많아"). */
|
|
3099
3099
|
.hjm-bottom-cta[data-placement="screen-footer"] { position: static; box-sizing: border-box; inline-size: 100%; min-inline-size: 0; min-block-size: 0; padding: 0 0 max(0px, calc(var(--hjm-bottom-cta-safe-area) - var(--hjm-bottom-cta-parent-padding))); border: 0; background: none; box-shadow: none; }
|
|
3100
3100
|
.hjm-bottom-cta__description { margin: 0; font-size: var(--hjm-type-caption-size); line-height: var(--hjm-type-caption-line-height); color: var(--hjm-color-text-muted); overflow-wrap: anywhere; }
|
|
3101
|
-
.hjm-bottom-cta__actions { display: flex; flex-wrap: wrap; gap: var(--hjm-bottom-cta-gap); }
|
|
3101
|
+
.hjm-bottom-cta__actions { display: flex; flex-wrap: wrap; gap: var(--hjm-bottom-cta-actions-gap); }
|
|
3102
3102
|
/* bottomCtaRecipe.contentMaxWidth: the surface spans the viewport, its copy and actions stop at the reading width. */
|
|
3103
3103
|
.hjm-bottom-cta__description, .hjm-bottom-cta__actions { box-sizing: border-box; inline-size: 100%; max-inline-size: var(--hjm-bottom-cta-content-max-width); margin-inline: auto; }
|
|
3104
3104
|
.hjm-bottom-cta__actions > div { flex: 1 1 calc(var(--hjm-control-min-touch-target) * 3); min-inline-size: 0; }
|
|
@@ -3303,14 +3303,14 @@ button.hjm-list-row, a.hjm-list-row { cursor: pointer; }
|
|
|
3303
3303
|
.hjm-tabs__indicator { position: absolute; bottom: 0; height: 2px; border-radius: var(--hjm-radius-full); background: var(--hjm-color-content-brand); pointer-events: none; }
|
|
3304
3304
|
/* indicator="filled" (tabsRecipe.indicators.filled): a surface-accent pill behind the selected tab, no list divider.
|
|
3305
3305
|
The moving pill spans the tab height and sits under the labels. */
|
|
3306
|
-
.hjm-tabs[data-indicator="filled"] .hjm-tabs__list { border: 0; }
|
|
3307
|
-
.hjm-tabs[data-indicator="filled"] .hjm-tabs__tab { border-radius: var(--hjm-radius-full); }
|
|
3308
|
-
.hjm-tabs[data-indicator="filled"] .hjm-tabs__tab[data-state="selected"] { color: var(--hjm-color-content-brand); }
|
|
3309
|
-
.hjm-tabs[data-indicator="filled"] .hjm-tabs__tab[data-state="selected"]::after { display: none; }
|
|
3310
|
-
.hjm-tabs[data-indicator="filled"]:not([data-indicator-motion="moving"]) .hjm-tabs__tab[data-state="selected"] { background: var(--hjm-color-surface-accent); }
|
|
3311
|
-
.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; }
|
|
3312
|
-
.hjm-tabs[data-indicator="filled"] .hjm-tabs__list { position: relative; }
|
|
3313
|
-
.hjm-tabs[data-indicator="filled"] .hjm-tabs__tab { z-index: 1; }
|
|
3306
|
+
.hjm-tabs:is([data-indicator="filled"],[data-indicator="solid"]) .hjm-tabs__list { border: 0; }
|
|
3307
|
+
.hjm-tabs:is([data-indicator="filled"],[data-indicator="solid"]) .hjm-tabs__tab { border-radius: var(--hjm-radius-full); }
|
|
3308
|
+
.hjm-tabs:is([data-indicator="filled"],[data-indicator="solid"]) .hjm-tabs__tab[data-state="selected"] { color: var(--hjm-color-content-brand); }
|
|
3309
|
+
.hjm-tabs:is([data-indicator="filled"],[data-indicator="solid"]) .hjm-tabs__tab[data-state="selected"]::after { display: none; }
|
|
3310
|
+
.hjm-tabs:is([data-indicator="filled"],[data-indicator="solid"]):not([data-indicator-motion="moving"]) .hjm-tabs__tab[data-state="selected"] { background: var(--hjm-color-surface-accent); }
|
|
3311
|
+
.hjm-tabs:is([data-indicator="filled"],[data-indicator="solid"]) .hjm-tabs__indicator { top: 0; bottom: 0; height: auto; border-radius: var(--hjm-radius-full); background: var(--hjm-color-surface-accent); z-index: 0; }
|
|
3312
|
+
.hjm-tabs:is([data-indicator="filled"],[data-indicator="solid"]) .hjm-tabs__list { position: relative; }
|
|
3313
|
+
.hjm-tabs:is([data-indicator="filled"],[data-indicator="solid"]) .hjm-tabs__tab { z-index: 1; }
|
|
3314
3314
|
.hjm-tabs__gooey { height: 6px; }
|
|
3315
3315
|
|
|
3316
3316
|
/* Capsule destinations retain route/link semantics. At larger text sizes we show
|
|
@@ -3723,6 +3723,7 @@ button.hjm-chat-message__media-item:focus-visible { outline: 2px solid var(--hjm
|
|
|
3723
3723
|
.hjm-card__media-badges { position: absolute; inset-block-start: var(--hjm-space-sm); inset-inline-end: var(--hjm-space-sm); display: flex; flex-wrap: wrap; gap: var(--hjm-space-xs); z-index: 1; }
|
|
3724
3724
|
.hjm-card__scrim { position: absolute; inset: 0; background: var(--hjm-card-background-scrim); }
|
|
3725
3725
|
.hjm-card__badges { display: flex; flex-wrap: wrap; gap: var(--hjm-space-xs); }
|
|
3726
|
+
.hjm-card__badges[data-align="center"] { justify-content: center; }
|
|
3726
3727
|
.hjm-card[data-background-media="true"] > .hjm-card__body { position: relative; flex: 0 1 auto; margin-block-start: auto; }
|
|
3727
3728
|
.hjm-card[data-background-media="true"] > .hjm-card__actions { position: relative; }
|
|
3728
3729
|
.hjm-card[data-background-media="true"] .hjm-card__title,
|
|
@@ -3822,4 +3823,15 @@ button.hjm-chat-message__media-item:focus-visible { outline: 2px solid var(--hjm
|
|
|
3822
3823
|
.hjm-timeline__item:has(> .hjm-timeline__actions) { grid-template-columns: 1rem minmax(0, 1fr) auto; }
|
|
3823
3824
|
.hjm-timeline__actions { align-self: center; display: flex; align-items: center; gap: var(--hjm-space-xs); }
|
|
3824
3825
|
|
|
3826
|
+
/* Strong filled tabs use one opaque contrast pair for static and moving marks. */
|
|
3827
|
+
.hjm-tabs[data-indicator="solid"] .hjm-tabs__tab[data-state="selected"] { color: var(--hjm-color-on-primary); }
|
|
3828
|
+
.hjm-tabs[data-indicator="solid"]:not([data-indicator-motion="moving"]) .hjm-tabs__tab[data-state="selected"],
|
|
3829
|
+
.hjm-tabs[data-indicator="solid"] .hjm-tabs__indicator { background: var(--hjm-color-primary); }
|
|
3830
|
+
.hjm-segmented[data-selection-tone="brand"]:not([data-presentation="text"]) .hjm-segmented__item[data-state="checked"] { color: var(--hjm-color-on-primary); background: var(--hjm-color-primary); }
|
|
3831
|
+
.hjm-segmented[data-selection-tone="brand"][data-presentation="pills"] .hjm-segmented__item[data-state="checked"] { background: transparent; }
|
|
3832
|
+
.hjm-segmented[data-selection-tone="brand"][data-presentation="pills"] .hjm-segmented__item[data-state="checked"]::before { background: var(--hjm-color-primary); border-color: var(--hjm-color-primary); }
|
|
3833
|
+
.hjm-segmented[data-selection-tone="brand"] .hjm-segmented__highlight { background: var(--hjm-color-primary); }
|
|
3834
|
+
.hjm-segmented[data-selection-tone="brand"] .hjm-segmented__items[data-highlight-ready="true"] > .hjm-segmented__item[data-state="checked"],
|
|
3835
|
+
.hjm-segmented[data-selection-tone="brand"][data-presentation="pills"] .hjm-segmented__items[data-highlight-ready="true"] > .hjm-segmented__item[data-state="checked"]::before { background: transparent; }
|
|
3836
|
+
|
|
3825
3837
|
}
|
package/dist/task-controls.js
CHANGED
|
@@ -25,8 +25,8 @@ function Failure({ failed, label }) {
|
|
|
25
25
|
export function SplitAction(props) {
|
|
26
26
|
const mode = resolveTaskChoice(props.modes, props.modeId), action = useCompositionAction(props.disabled);
|
|
27
27
|
const locked = props.disabled === true || action.pending;
|
|
28
|
-
// The mode menu is a chevron tool at the action's end, inline gap
|
|
29
|
-
return _jsxs(Stack, { gap: "sm", children: [_jsxs(Stack, { axis: "inline", gap: "
|
|
28
|
+
// The mode menu is a chevron tool at the action's end, shared inline gap 8 (button.md); a second text button read as an unrelated action (2026-10-17 review).
|
|
29
|
+
return _jsxs(Stack, { gap: "sm", children: [_jsxs(Stack, { axis: "inline", gap: "xs", align: "center", children: [_jsx(Button, { loading: action.pending, disabled: props.disabled === true || mode.disabled === true, onClick: () => { if (!mode.disabled)
|
|
30
30
|
void action.run(mode.id, () => props.onExecute(mode.id)); }, children: props.executeLabel(mode) }), _jsx(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)
|
|
31
31
|
props.onModeChange(id); } })] }), _jsx(Failure, { failed: action.failed, label: props.errorLabel })] });
|
|
32
32
|
}
|
|
@@ -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 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"]}
|
|
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, shared inline gap 8 (button.md); a second text button read as an unrelated action (2026-10-17 review).\n return <Stack gap=\"sm\"><Stack axis=\"inline\" gap=\"xs\" 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/dist/transfer-task.js
CHANGED
|
@@ -51,6 +51,6 @@ export function TransferTask(props) {
|
|
|
51
51
|
const status = action.pending ? cancelRequested ? props.labels.cancelling : observation ? props.labels.transferring : props.labels.queued
|
|
52
52
|
: cancelled ? props.labels.cancelled : phase === "success" ? props.labels.success : action.failed ? props.labels.error : null;
|
|
53
53
|
const known = observation !== null && observation.total !== null;
|
|
54
|
-
return _jsxs(Stack, { gap: "md", children: [_jsxs(Stack, { axis: "inline", gap: "
|
|
54
|
+
return _jsxs(Stack, { gap: "md", children: [_jsxs(Stack, { axis: "inline", gap: "xs", wrap: true, children: [_jsx(Button, { loading: action.pending, disabled: props.disabled === true, onClick: start, children: props.labels.start }), action.pending ? _jsx(Button, { tone: "secondary", disabled: props.disabled === true || cancelRequested, onClick: cancel, children: props.labels.cancel }) : null] }), action.pending || known ? _jsx(Progress, { label: status ?? props.labels.transferring, ...(known ? { value: observation.completed, max: observation.total } : {}), ...(observation ? { valueText: props.formatProgress(observation) } : {}) }) : null, observation && !action.pending && !known ? _jsx(Text, { variant: "caption", children: props.formatProgress(observation) }) : null, status && !action.pending ? _jsx(Text, { role: action.failed && !cancelled ? "alert" : "status", style: { textAlign: "center" }, tone: action.failed && !cancelled ? "danger" : "primary", children: status }) : null] });
|
|
55
55
|
}
|
|
56
56
|
//# sourceMappingURL=transfer-task.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transfer-task.js","sourceRoot":"","sources":["../src/transfer-task.tsx"],"names":[],"mappings":"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","sourcesContent":["\"use client\";\nimport { useEffect, useRef, useState } from \"react\";\nimport { isConfirmedTransferAbort, resolveTransferObservation, type TransferObservation, type TransferContext } from \"@hjmds/design-contracts/transfer-task\";\nimport { Button } from \"./actions.js\";\nimport { Progress } from \"./feedback.js\";\nimport { Stack, Text } from \"./layout.js\";\nimport { useCompositionAction } from \"./internal/use-composition-action.js\";\nexport type TransferTaskProps = Readonly<{\n onTransfer: (context: TransferContext) => Promise<void>;\n labels: Readonly<{ start: string; queued: string; transferring: string; cancel: string; cancelling: string; cancelled: string; success: string; error: string }>;\n formatProgress: (observation: TransferObservation) => string; disabled?: boolean;\n}>;\nexport function TransferTask(props: TransferTaskProps) {\n const action = useCompositionAction(props.disabled), mounted = useRef(true), disabled = useRef(props.disabled);\n disabled.current = props.disabled;\n const request = useRef<AbortController | null>(null), latest = useRef<TransferObservation | null>(null);\n const [observation, setObservation] = useState<TransferObservation | null>(null), [cancelRequested, setCancelRequested] = useState(false), [cancelled, setCancelled] = useState(false);\n useEffect(() => { mounted.current = true; return () => { mounted.current = false; request.current?.abort(); request.current = null; }; }, []);\n const start = () => {\n if (!mounted.current || disabled.current || request.current) return;\n const controller = new AbortController(); let accepting = true; request.current = controller; latest.current = null;\n setObservation(null); setCancelled(false); setCancelRequested(false);\n void action.run(\"transfer\", async () => {\n try {\n await props.onTransfer({ signal: controller.signal, report: next => {\n if (!accepting || !mounted.current || request.current !== controller || controller.signal.aborted) return;\n const value = resolveTransferObservation(next, latest.current); latest.current = value; setObservation(value);\n } });\n } catch (error) {\n if (mounted.current && request.current === controller && isConfirmedTransferAbort(error, controller.signal)) setCancelled(true);\n throw error;\n } finally { accepting = false; }\n }).then(() => { if (request.current === controller) request.current = null; });\n };\n const cancel = () => { if (mounted.current && !disabled.current && request.current && !request.current.signal.aborted) { setCancelRequested(true); request.current.abort(); } };\n const phase = action.session.getSnapshot().status;\n const status = action.pending ? cancelRequested ? props.labels.cancelling : observation ? props.labels.transferring : props.labels.queued\n : cancelled ? props.labels.cancelled : phase === \"success\" ? props.labels.success : action.failed ? props.labels.error : null;\n const known = observation !== null && observation.total !== null;\n return <Stack gap=\"md\"><Stack axis=\"inline\" gap=\"
|
|
1
|
+
{"version":3,"file":"transfer-task.js","sourceRoot":"","sources":["../src/transfer-task.tsx"],"names":[],"mappings":"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","sourcesContent":["\"use client\";\nimport { useEffect, useRef, useState } from \"react\";\nimport { isConfirmedTransferAbort, resolveTransferObservation, type TransferObservation, type TransferContext } from \"@hjmds/design-contracts/transfer-task\";\nimport { Button } from \"./actions.js\";\nimport { Progress } from \"./feedback.js\";\nimport { Stack, Text } from \"./layout.js\";\nimport { useCompositionAction } from \"./internal/use-composition-action.js\";\nexport type TransferTaskProps = Readonly<{\n onTransfer: (context: TransferContext) => Promise<void>;\n labels: Readonly<{ start: string; queued: string; transferring: string; cancel: string; cancelling: string; cancelled: string; success: string; error: string }>;\n formatProgress: (observation: TransferObservation) => string; disabled?: boolean;\n}>;\nexport function TransferTask(props: TransferTaskProps) {\n const action = useCompositionAction(props.disabled), mounted = useRef(true), disabled = useRef(props.disabled);\n disabled.current = props.disabled;\n const request = useRef<AbortController | null>(null), latest = useRef<TransferObservation | null>(null);\n const [observation, setObservation] = useState<TransferObservation | null>(null), [cancelRequested, setCancelRequested] = useState(false), [cancelled, setCancelled] = useState(false);\n useEffect(() => { mounted.current = true; return () => { mounted.current = false; request.current?.abort(); request.current = null; }; }, []);\n const start = () => {\n if (!mounted.current || disabled.current || request.current) return;\n const controller = new AbortController(); let accepting = true; request.current = controller; latest.current = null;\n setObservation(null); setCancelled(false); setCancelRequested(false);\n void action.run(\"transfer\", async () => {\n try {\n await props.onTransfer({ signal: controller.signal, report: next => {\n if (!accepting || !mounted.current || request.current !== controller || controller.signal.aborted) return;\n const value = resolveTransferObservation(next, latest.current); latest.current = value; setObservation(value);\n } });\n } catch (error) {\n if (mounted.current && request.current === controller && isConfirmedTransferAbort(error, controller.signal)) setCancelled(true);\n throw error;\n } finally { accepting = false; }\n }).then(() => { if (request.current === controller) request.current = null; });\n };\n const cancel = () => { if (mounted.current && !disabled.current && request.current && !request.current.signal.aborted) { setCancelRequested(true); request.current.abort(); } };\n const phase = action.session.getSnapshot().status;\n const status = action.pending ? cancelRequested ? props.labels.cancelling : observation ? props.labels.transferring : props.labels.queued\n : cancelled ? props.labels.cancelled : phase === \"success\" ? props.labels.success : action.failed ? props.labels.error : null;\n const known = observation !== null && observation.total !== null;\n return <Stack gap=\"md\"><Stack axis=\"inline\" gap=\"xs\" wrap>\n <Button loading={action.pending} disabled={props.disabled === true} onClick={start}>{props.labels.start}</Button>\n {action.pending ? <Button tone=\"secondary\" disabled={props.disabled === true || cancelRequested} onClick={cancel}>{props.labels.cancel}</Button> : null}</Stack>\n {action.pending || known ? <Progress label={status ?? props.labels.transferring} {...(known ? { value: observation.completed, max: observation.total! } : {})}\n {...(observation ? { valueText: props.formatProgress(observation) } : {})} /> : null}\n {observation && !action.pending && !known ? <Text variant=\"caption\">{props.formatProgress(observation)}</Text> : null}\n {status && !action.pending ? <Text role={action.failed && !cancelled ? \"alert\" : \"status\"} style={{ textAlign: \"center\" }} tone={action.failed && !cancelled ? \"danger\" : \"primary\"}>{status}</Text> : null}\n </Stack>;\n}\n"]}
|
package/dist/voice-note.js
CHANGED
|
@@ -8,6 +8,6 @@ import { Stack, Surface, Text } from "./layout.js";
|
|
|
8
8
|
export function VoiceNote({ descriptor, labels, formatTime, artwork, onPlayingChange, onSeek, onRetry, layoutStyle }) {
|
|
9
9
|
const media = resolveVoiceNote(descriptor);
|
|
10
10
|
const error = media.state === "error";
|
|
11
|
-
return _jsx(Surface, { padding: "lg", ...(layoutStyle === undefined ? {} : { layoutStyle }), children: _jsxs(Stack, { gap: "md", children: [_jsxs(Stack, { axis: "inline", gap: "md", children: [artwork ? _jsx(Asset, { descriptor: { kind: "image", decorative: true, shape: "circle" }, children: artwork }) : null, _jsx(Text, { emphasis: "strong", children: media.title })] }), _jsx(Slider, { label: labels.seek, min: 0, max: media.duration || 1, step: 0.1, value: media.position, disabled: !media.canSeek, onValueChange: onSeek, getValueText: formatTime }), _jsxs(Text, { tone: "muted", children: [formatTime(media.position), media.duration === null ? "" : ` / ${formatTime(media.duration)}`] }), error ? _jsx(Text, { role: "alert", children: labels.error }) : null, _jsxs(Stack, { axis: "inline", gap: "
|
|
11
|
+
return _jsx(Surface, { padding: "lg", ...(layoutStyle === undefined ? {} : { layoutStyle }), children: _jsxs(Stack, { gap: "md", children: [_jsxs(Stack, { axis: "inline", gap: "md", children: [artwork ? _jsx(Asset, { descriptor: { kind: "image", decorative: true, shape: "circle" }, children: artwork }) : null, _jsx(Text, { emphasis: "strong", children: media.title })] }), _jsx(Slider, { label: labels.seek, min: 0, max: media.duration || 1, step: 0.1, value: media.position, disabled: !media.canSeek, onValueChange: onSeek, getValueText: formatTime }), _jsxs(Text, { tone: "muted", children: [formatTime(media.position), media.duration === null ? "" : ` / ${formatTime(media.duration)}`] }), error ? _jsx(Text, { role: "alert", children: labels.error }) : null, _jsxs(Stack, { axis: "inline", gap: "xs", children: [_jsx(Button, { disabled: !media.canPlay, loading: media.state === "loading", onClick: () => onPlayingChange(media.state !== "playing"), children: media.state === "loading" ? labels.loading : media.state === "playing" ? labels.pause : labels.play }), error && onRetry ? _jsx(Button, { disabled: media.disabled ?? false, onClick: onRetry, children: labels.retry }) : null] })] }) });
|
|
12
12
|
}
|
|
13
13
|
//# sourceMappingURL=voice-note.js.map
|
package/dist/voice-note.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"voice-note.js","sourceRoot":"","sources":["../src/voice-note.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,gBAAgB,EAA4B,MAAM,oCAAoC,CAAC;AAChG,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AACtC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAgBnD,uFAAuF;AACvF,MAAM,UAAU,SAAS,CAAC,EAAE,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,eAAe,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,EAAkB;IAClI,MAAM,KAAK,GAAG,gBAAgB,CAAC,UAAU,CAAC,CAAC;IAC3C,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,KAAK,OAAO,CAAC;IACtC,OAAO,KAAC,OAAO,IAAC,OAAO,EAAC,IAAI,KAAK,CAAC,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC,YAAE,MAAC,KAAK,IAAC,GAAG,EAAC,IAAI,aAClG,MAAC,KAAK,IAAC,IAAI,EAAC,QAAQ,EAAC,GAAG,EAAC,IAAI,aAC1B,OAAO,CAAC,CAAC,CAAC,KAAC,KAAK,IAAC,UAAU,EAAE,EAAC,IAAI,EAAC,OAAO,EAAC,UAAU,EAAC,IAAI,EAAC,KAAK,EAAC,QAAQ,EAAC,YAAG,OAAO,GAAS,CAAC,CAAC,CAAC,IAAI,EACrG,KAAC,IAAI,IAAC,QAAQ,EAAC,QAAQ,YAAE,KAAK,CAAC,KAAK,GAAQ,IACtC,EACR,KAAC,MAAM,IAAC,KAAK,EAAE,MAAM,CAAC,IAAI,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,KAAK,CAAC,QAAQ,IAAI,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,KAAK,CAAC,QAAQ,EAAE,QAAQ,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,aAAa,EAAE,MAAM,EAAE,YAAY,EAAE,UAAU,GAAK,EAC9K,MAAC,IAAI,IAAC,IAAI,EAAC,OAAO,aAAE,UAAU,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,KAAK,CAAC,QAAQ,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,UAAU,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,IAAQ,EACxH,KAAK,CAAC,CAAC,CAAC,KAAC,IAAI,IAAC,IAAI,EAAC,OAAO,YAAE,MAAM,CAAC,KAAK,GAAQ,CAAC,CAAC,CAAC,IAAI,EACxD,MAAC,KAAK,IAAC,IAAI,EAAC,QAAQ,EAAC,GAAG,EAAC,IAAI,aAC3B,KAAC,MAAM,IAAC,QAAQ,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,CAAC,KAAK,KAAK,SAAS,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,eAAe,CAAC,KAAK,CAAC,KAAK,KAAK,SAAS,CAAC,YAAG,KAAK,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,GAAU,EAC9O,KAAK,IAAI,OAAO,CAAC,CAAC,CAAC,KAAC,MAAM,IAAC,QAAQ,EAAE,KAAK,CAAC,QAAQ,IAAI,KAAK,EAAE,OAAO,EAAE,OAAO,YAAG,MAAM,CAAC,KAAK,GAAU,CAAC,CAAC,CAAC,IAAI,IACzG,IACF,GAAU,CAAC;AACrB,CAAC","sourcesContent":["import type { ReactNode } from \"react\";\nimport { resolveVoiceNote, type VoiceNoteDescriptor } from \"@hjmds/design-contracts/voice-note\";\nimport { Asset } from \"./asset.js\";\nimport { Button } from \"./actions.js\";\nimport { Slider } from \"./slider.js\";\nimport { Stack, Surface, Text } from \"./layout.js\";\nimport type { HjmCompositionStyleProp } from \"./composition-style.js\";\n\nexport type VoiceNoteProps = Readonly<{\n descriptor: VoiceNoteDescriptor;\n labels: Readonly<{ play: string; pause: string; seek: string; loading: string; error: string; retry: string; backward: string; forward: string }>;\n /** Localized elapsed/duration text and slider accessible value. */\n formatTime: (seconds: number) => string;\n artwork?: ReactNode;\n onPlayingChange: (playing: boolean) => void;\n onSeek: (seconds: number) => void;\n onRetry?: () => void;\n /** Canonical layout-only placement on the root element. Controlled visual keys are excluded. */\n layoutStyle?: HjmCompositionStyleProp;\n}>;\n\n/** Audio engine, network, file permission and playback lifecycle remain host-owned. */\nexport function VoiceNote({ descriptor, labels, formatTime, artwork, onPlayingChange, onSeek, onRetry, layoutStyle }: VoiceNoteProps) {\n const media = resolveVoiceNote(descriptor);\n const error = media.state === \"error\";\n return <Surface padding=\"lg\" {...(layoutStyle === undefined ? {} : { layoutStyle })}><Stack gap=\"md\">\n <Stack axis=\"inline\" gap=\"md\">\n {artwork ? <Asset descriptor={{kind:\"image\",decorative:true,shape:\"circle\"}}>{artwork}</Asset> : null}\n <Text emphasis=\"strong\">{media.title}</Text>\n </Stack>\n <Slider label={labels.seek} min={0} max={media.duration || 1} step={0.1} value={media.position} disabled={!media.canSeek} onValueChange={onSeek} getValueText={formatTime} />\n <Text tone=\"muted\">{formatTime(media.position)}{media.duration === null ? \"\" : ` / ${formatTime(media.duration)}`}</Text>\n {error ? <Text role=\"alert\">{labels.error}</Text> : null}\n <Stack axis=\"inline\" gap=\"
|
|
1
|
+
{"version":3,"file":"voice-note.js","sourceRoot":"","sources":["../src/voice-note.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,gBAAgB,EAA4B,MAAM,oCAAoC,CAAC;AAChG,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AACtC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAgBnD,uFAAuF;AACvF,MAAM,UAAU,SAAS,CAAC,EAAE,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,eAAe,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,EAAkB;IAClI,MAAM,KAAK,GAAG,gBAAgB,CAAC,UAAU,CAAC,CAAC;IAC3C,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,KAAK,OAAO,CAAC;IACtC,OAAO,KAAC,OAAO,IAAC,OAAO,EAAC,IAAI,KAAK,CAAC,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC,YAAE,MAAC,KAAK,IAAC,GAAG,EAAC,IAAI,aAClG,MAAC,KAAK,IAAC,IAAI,EAAC,QAAQ,EAAC,GAAG,EAAC,IAAI,aAC1B,OAAO,CAAC,CAAC,CAAC,KAAC,KAAK,IAAC,UAAU,EAAE,EAAC,IAAI,EAAC,OAAO,EAAC,UAAU,EAAC,IAAI,EAAC,KAAK,EAAC,QAAQ,EAAC,YAAG,OAAO,GAAS,CAAC,CAAC,CAAC,IAAI,EACrG,KAAC,IAAI,IAAC,QAAQ,EAAC,QAAQ,YAAE,KAAK,CAAC,KAAK,GAAQ,IACtC,EACR,KAAC,MAAM,IAAC,KAAK,EAAE,MAAM,CAAC,IAAI,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,KAAK,CAAC,QAAQ,IAAI,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,KAAK,CAAC,QAAQ,EAAE,QAAQ,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,aAAa,EAAE,MAAM,EAAE,YAAY,EAAE,UAAU,GAAK,EAC9K,MAAC,IAAI,IAAC,IAAI,EAAC,OAAO,aAAE,UAAU,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,KAAK,CAAC,QAAQ,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,UAAU,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,IAAQ,EACxH,KAAK,CAAC,CAAC,CAAC,KAAC,IAAI,IAAC,IAAI,EAAC,OAAO,YAAE,MAAM,CAAC,KAAK,GAAQ,CAAC,CAAC,CAAC,IAAI,EACxD,MAAC,KAAK,IAAC,IAAI,EAAC,QAAQ,EAAC,GAAG,EAAC,IAAI,aAC3B,KAAC,MAAM,IAAC,QAAQ,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,CAAC,KAAK,KAAK,SAAS,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,eAAe,CAAC,KAAK,CAAC,KAAK,KAAK,SAAS,CAAC,YAAG,KAAK,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,GAAU,EAC9O,KAAK,IAAI,OAAO,CAAC,CAAC,CAAC,KAAC,MAAM,IAAC,QAAQ,EAAE,KAAK,CAAC,QAAQ,IAAI,KAAK,EAAE,OAAO,EAAE,OAAO,YAAG,MAAM,CAAC,KAAK,GAAU,CAAC,CAAC,CAAC,IAAI,IACzG,IACF,GAAU,CAAC;AACrB,CAAC","sourcesContent":["import type { ReactNode } from \"react\";\nimport { resolveVoiceNote, type VoiceNoteDescriptor } from \"@hjmds/design-contracts/voice-note\";\nimport { Asset } from \"./asset.js\";\nimport { Button } from \"./actions.js\";\nimport { Slider } from \"./slider.js\";\nimport { Stack, Surface, Text } from \"./layout.js\";\nimport type { HjmCompositionStyleProp } from \"./composition-style.js\";\n\nexport type VoiceNoteProps = Readonly<{\n descriptor: VoiceNoteDescriptor;\n labels: Readonly<{ play: string; pause: string; seek: string; loading: string; error: string; retry: string; backward: string; forward: string }>;\n /** Localized elapsed/duration text and slider accessible value. */\n formatTime: (seconds: number) => string;\n artwork?: ReactNode;\n onPlayingChange: (playing: boolean) => void;\n onSeek: (seconds: number) => void;\n onRetry?: () => void;\n /** Canonical layout-only placement on the root element. Controlled visual keys are excluded. */\n layoutStyle?: HjmCompositionStyleProp;\n}>;\n\n/** Audio engine, network, file permission and playback lifecycle remain host-owned. */\nexport function VoiceNote({ descriptor, labels, formatTime, artwork, onPlayingChange, onSeek, onRetry, layoutStyle }: VoiceNoteProps) {\n const media = resolveVoiceNote(descriptor);\n const error = media.state === \"error\";\n return <Surface padding=\"lg\" {...(layoutStyle === undefined ? {} : { layoutStyle })}><Stack gap=\"md\">\n <Stack axis=\"inline\" gap=\"md\">\n {artwork ? <Asset descriptor={{kind:\"image\",decorative:true,shape:\"circle\"}}>{artwork}</Asset> : null}\n <Text emphasis=\"strong\">{media.title}</Text>\n </Stack>\n <Slider label={labels.seek} min={0} max={media.duration || 1} step={0.1} value={media.position} disabled={!media.canSeek} onValueChange={onSeek} getValueText={formatTime} />\n <Text tone=\"muted\">{formatTime(media.position)}{media.duration === null ? \"\" : ` / ${formatTime(media.duration)}`}</Text>\n {error ? <Text role=\"alert\">{labels.error}</Text> : null}\n <Stack axis=\"inline\" gap=\"xs\">\n <Button disabled={!media.canPlay} loading={media.state === \"loading\"} onClick={() => onPlayingChange(media.state !== \"playing\")}>{media.state === \"loading\" ? labels.loading : media.state === \"playing\" ? labels.pause : labels.play}</Button>\n {error && onRetry ? <Button disabled={media.disabled ?? false} onClick={onRetry}>{labels.retry}</Button> : null}\n </Stack>\n </Stack></Surface>;\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hjmds/react",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.38.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.
|
|
611
|
+
"@hjmds/design-contracts": ">=1.38.0 <1.39.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.
|
|
649
|
+
"@hjmds/design-contracts": "1.38.0"
|
|
650
650
|
},
|
|
651
651
|
"peerDependenciesMeta": {
|
|
652
652
|
"@number-flow/react": {
|