@hjmds/react 1.30.0 → 1.32.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/auth-screen.d.ts +18 -3
- package/dist/auth-screen.d.ts.map +1 -1
- package/dist/auth-screen.js +22 -6
- package/dist/auth-screen.js.map +1 -1
- package/dist/bottom-cta.d.ts +6 -1
- package/dist/bottom-cta.d.ts.map +1 -1
- package/dist/bottom-cta.js +1 -1
- package/dist/bottom-cta.js.map +1 -1
- package/dist/bottom-navigation.d.ts +10 -0
- package/dist/bottom-navigation.d.ts.map +1 -1
- package/dist/bottom-navigation.js +80 -8
- package/dist/bottom-navigation.js.map +1 -1
- package/dist/carousel.d.ts +29 -1
- package/dist/carousel.d.ts.map +1 -1
- package/dist/carousel.js +27 -3
- package/dist/carousel.js.map +1 -1
- package/dist/display.d.ts +8 -2
- package/dist/display.d.ts.map +1 -1
- package/dist/display.js +12 -7
- 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/forms.d.ts.map +1 -1
- package/dist/forms.js +2 -1
- package/dist/forms.js.map +1 -1
- package/dist/image-choice.d.ts +20 -2
- package/dist/image-choice.d.ts.map +1 -1
- package/dist/image-choice.js +60 -7
- package/dist/image-choice.js.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -3
- package/dist/index.js.map +1 -1
- package/dist/internal/field-error.d.ts +19 -0
- package/dist/internal/field-error.d.ts.map +1 -0
- package/dist/internal/field-error.js +19 -0
- package/dist/internal/field-error.js.map +1 -0
- package/dist/internal/initial-focus.d.ts.map +1 -1
- package/dist/internal/initial-focus.js +49 -7
- package/dist/internal/initial-focus.js.map +1 -1
- package/dist/internal/media-album.d.ts +70 -0
- package/dist/internal/media-album.d.ts.map +1 -0
- package/dist/internal/media-album.js +52 -0
- package/dist/internal/media-album.js.map +1 -0
- package/dist/internal/message-reactions.d.ts +39 -2
- package/dist/internal/message-reactions.d.ts.map +1 -1
- package/dist/internal/message-reactions.js +31 -6
- package/dist/internal/message-reactions.js.map +1 -1
- package/dist/layout.d.ts +19 -3
- package/dist/layout.d.ts.map +1 -1
- package/dist/layout.js +10 -3
- package/dist/layout.js.map +1 -1
- package/dist/navigation.d.ts +3 -1
- package/dist/navigation.d.ts.map +1 -1
- package/dist/navigation.js +4 -2
- package/dist/navigation.js.map +1 -1
- package/dist/number-field.d.ts.map +1 -1
- package/dist/number-field.js +2 -1
- package/dist/number-field.js.map +1 -1
- package/dist/overlays.d.ts +65 -0
- package/dist/overlays.d.ts.map +1 -1
- package/dist/overlays.js +36 -3
- package/dist/overlays.js.map +1 -1
- package/dist/pagination.d.ts +13 -11
- package/dist/pagination.d.ts.map +1 -1
- package/dist/pagination.js +12 -5
- package/dist/pagination.js.map +1 -1
- package/dist/public-exports.generated.d.ts +8 -0
- package/dist/public-exports.generated.d.ts.map +1 -1
- package/dist/public-exports.generated.js +24 -0
- package/dist/public-exports.generated.js.map +1 -1
- package/dist/screen-flows.d.ts +118 -14
- package/dist/screen-flows.d.ts.map +1 -1
- package/dist/screen-flows.js +95 -23
- package/dist/screen-flows.js.map +1 -1
- package/dist/screens.d.ts +69 -10
- package/dist/screens.d.ts.map +1 -1
- package/dist/screens.js +77 -15
- package/dist/screens.js.map +1 -1
- package/dist/select.d.ts.map +1 -1
- package/dist/select.js +2 -1
- package/dist/select.js.map +1 -1
- package/dist/selection.d.ts.map +1 -1
- package/dist/selection.js +3 -2
- package/dist/selection.js.map +1 -1
- package/dist/steps.d.ts +11 -1
- package/dist/steps.d.ts.map +1 -1
- package/dist/steps.js +11 -6
- package/dist/steps.js.map +1 -1
- package/dist/styles.css +181 -22
- package/dist/styles.layered.css +181 -22
- package/dist/supplemental-display.d.ts.map +1 -1
- package/dist/supplemental-display.js +2 -48
- package/dist/supplemental-display.js.map +1 -1
- package/dist/theme.d.ts.map +1 -1
- package/dist/theme.js +1 -0
- package/dist/theme.js.map +1 -1
- package/dist/toast.d.ts.map +1 -1
- package/dist/toast.js +1 -1
- package/dist/toast.js.map +1 -1
- package/package.json +3 -3
package/dist/steps.d.ts
CHANGED
|
@@ -6,10 +6,15 @@ export type StepsProps<Id extends string = string> = Omit<HTMLAttributes<HTMLOLi
|
|
|
6
6
|
statusLabels: StepsStatusLabels;
|
|
7
7
|
composeAccessibleName: ComposeStepsAccessibleName;
|
|
8
8
|
renderMark?: (status: StepStatus, position: number) => ReactNode;
|
|
9
|
+
/**
|
|
10
|
+
* Return to a step before the cursor (2026-10-18, spint compose). Only those steps become buttons; the cursor and
|
|
11
|
+
* later steps stay static so the flow never skips forward past validation. Omit it while the flow is locked.
|
|
12
|
+
*/
|
|
13
|
+
onStepPress?: (id: Id) => void;
|
|
9
14
|
/** Canonical layout-only placement on the root element. Controlled visual keys are excluded. */
|
|
10
15
|
layoutStyle?: HjmCompositionStyleProp;
|
|
11
16
|
}>;
|
|
12
|
-
/** Linear
|
|
17
|
+
/** Linear progress steps with one canonical cursor; steps before it can be pressed to go back. */
|
|
13
18
|
export declare const Steps: import("react").ForwardRefExoticComponent<Omit<HTMLAttributes<HTMLOListElement>, "children"> & Readonly<{
|
|
14
19
|
descriptor: Readonly<{
|
|
15
20
|
steps: readonly Readonly<{
|
|
@@ -28,6 +33,11 @@ export declare const Steps: import("react").ForwardRefExoticComponent<Omit<HTMLA
|
|
|
28
33
|
}>;
|
|
29
34
|
composeAccessibleName: ComposeStepsAccessibleName;
|
|
30
35
|
renderMark?: (status: StepStatus, position: number) => ReactNode;
|
|
36
|
+
/**
|
|
37
|
+
* Return to a step before the cursor (2026-10-18, spint compose). Only those steps become buttons; the cursor and
|
|
38
|
+
* later steps stay static so the flow never skips forward past validation. Omit it while the flow is locked.
|
|
39
|
+
*/
|
|
40
|
+
onStepPress?: (id: string) => void;
|
|
31
41
|
/** Canonical layout-only placement on the root element. Controlled visual keys are excluded. */
|
|
32
42
|
layoutStyle?: HjmCompositionStyleProp;
|
|
33
43
|
}> & import("react").RefAttributes<HTMLOListElement>>;
|
package/dist/steps.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"steps.d.ts","sourceRoot":"","sources":["../src/steps.tsx"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"steps.d.ts","sourceRoot":"","sources":["../src/steps.tsx"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,0BAA0B,EAC/B,KAAK,UAAU,EACf,KAAK,eAAe,EACpB,KAAK,iBAAiB,EACvB,MAAM,0CAA0C,CAAC;AAClD,OAAO,EAAqB,KAAK,cAAc,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAG/E,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AAEtE,MAAM,MAAM,UAAU,CAAC,EAAE,SAAS,MAAM,GAAG,MAAM,IAAI,IAAI,CACvD,cAAc,CAAC,gBAAgB,CAAC,EAChC,UAAU,CACX,GAAG,QAAQ,CAAC;IACX,UAAU,EAAE,eAAe,CAAC,EAAE,CAAC,CAAC;IAChC,YAAY,EAAE,iBAAiB,CAAC;IAChC,qBAAqB,EAAE,0BAA0B,CAAC;IAClD,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,KAAK,SAAS,CAAC;IACjE;;;OAGG;IACH,WAAW,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,KAAK,IAAI,CAAC;IAC/B,gGAAgG;IAChG,WAAW,CAAC,EAAE,uBAAuB,CAAC;CACvC,CAAC,CAAC;AAEH,kGAAkG;AAClG,eAAO,MAAM,KAAK;;;;;;;;;;;;;;;;2BAZO,0BAA0B;iBACpC,CAAC,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,KAAK,SAAS;IAChE;;;OAGG;kCACuB,IAAI;IAC9B,gGAAgG;kBAClF,uBAAuB;qDAgDrC,CAAC"}
|
package/dist/steps.js
CHANGED
|
@@ -1,10 +1,15 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { resolveStepsDescriptor, } from "@hjmds/design-contracts/components/steps";
|
|
3
|
-
import { forwardRef } from "react";
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { resolveStepsDescriptor, stepsRecipe, } from "@hjmds/design-contracts/components/steps";
|
|
3
|
+
import { forwardRef, useId } from "react";
|
|
4
4
|
import { classNames } from "./internal.js";
|
|
5
|
-
/** Linear
|
|
6
|
-
export const Steps = forwardRef(function Steps({ descriptor, statusLabels, composeAccessibleName, renderMark, className, layoutStyle, ...props }, ref) {
|
|
5
|
+
/** Linear progress steps with one canonical cursor; steps before it can be pressed to go back. */
|
|
6
|
+
export const Steps = forwardRef(function Steps({ descriptor, statusLabels, composeAccessibleName, renderMark, onStepPress, className, layoutStyle, ...props }, ref) {
|
|
7
7
|
const steps = resolveStepsDescriptor(descriptor, { statusLabels, composeAccessibleName });
|
|
8
|
-
|
|
8
|
+
const statusId = useId();
|
|
9
|
+
return (_jsx("ol", { ...props, style: { ["--hjm-steps-press-target"]: `${stepsRecipe.press.minTouchTarget}px`, ...props.style, ...layoutStyle }, ref: ref, className: classNames("hjm-steps", className), children: steps.map((step, index) => {
|
|
10
|
+
const content = _jsxs(_Fragment, { children: [_jsxs("div", { className: "hjm-steps__rail", "aria-hidden": "true", children: [_jsx("span", { className: "hjm-steps__indicator", children: renderMark?.(step.status, step.position) ?? (step.status === "complete" ? "✓" : step.status === "error" ? "!" : step.position) }), index === steps.length - 1 ? null : _jsx("span", { className: "hjm-steps__connector" })] }), _jsxs("div", { className: "hjm-steps__copy", children: [_jsx("span", { className: "hjm-steps__label", children: step.label }), step.description === undefined ? null : (_jsx("span", { className: "hjm-steps__description", children: step.description })), _jsx("span", { className: "hjm-visually-hidden", id: `${statusId}-${index}`, children: step.statusLabel })] })] });
|
|
11
|
+
// A pressable step is one named button; its status stays a description so the name keeps order + label.
|
|
12
|
+
return step.revisitable && onStepPress ? (_jsx("li", { className: "hjm-steps__step", "data-status": step.status, children: _jsx("button", { type: "button", className: "hjm-steps__press", "aria-label": step.accessibleName, "aria-describedby": `${statusId}-${index}`, onClick: () => onStepPress(step.id), children: content }) }, step.id)) : (_jsx("li", { "aria-label": step.accessibleName, "aria-current": step.status === "current" || step.status === "error" ? "step" : undefined, className: "hjm-steps__step", "data-status": step.status, children: content }, step.id));
|
|
13
|
+
}) }));
|
|
9
14
|
});
|
|
10
15
|
//# sourceMappingURL=steps.js.map
|
package/dist/steps.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"steps.js","sourceRoot":"","sources":["../src/steps.tsx"],"names":[],"mappings":";AAAA,OAAO,EACL,sBAAsB,
|
|
1
|
+
{"version":3,"file":"steps.js","sourceRoot":"","sources":["../src/steps.tsx"],"names":[],"mappings":";AAAA,OAAO,EACL,sBAAsB,EACtB,WAAW,GAKZ,MAAM,0CAA0C,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,KAAK,EAAuC,MAAM,OAAO,CAAC;AAE/E,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAoB3C,kGAAkG;AAClG,MAAM,CAAC,MAAM,KAAK,GAAG,UAAU,CAA+B,SAAS,KAAK,CAC1E,EAAE,UAAU,EAAE,YAAY,EAAE,qBAAqB,EAAE,UAAU,EAAE,WAAW,EAAE,SAAS,EAAE,WAAW,EAAE,GAAG,KAAK,EAAE,EAC9G,GAAG;IAEH,MAAM,KAAK,GAAG,sBAAsB,CAAC,UAAU,EAAE,EAAE,YAAY,EAAE,qBAAqB,EAAE,CAAC,CAAC;IAC1F,MAAM,QAAQ,GAAG,KAAK,EAAE,CAAC;IACzB,OAAO,CACL,gBAAQ,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC,0BAAoC,CAAC,EAAE,GAAG,WAAW,CAAC,KAAK,CAAC,cAAc,IAAI,EAAE,GAAG,KAAK,CAAC,KAAK,EAAE,GAAG,WAAW,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,SAAS,EAAE,UAAU,CAAC,WAAW,EAAE,SAAS,CAAC,YAC/L,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE;YACzB,MAAM,OAAO,GAAG,8BACd,eAAK,SAAS,EAAC,iBAAiB,iBAAa,MAAM,aACjD,eAAM,SAAS,EAAC,sBAAsB,YACnC,UAAU,EAAE,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAC3C,IAAI,CAAC,MAAM,KAAK,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CACjF,GACI,EACN,KAAK,KAAK,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,eAAM,SAAS,EAAC,sBAAsB,GAAG,IAC1E,EACN,eAAK,SAAS,EAAC,iBAAiB,aAC9B,eAAM,SAAS,EAAC,kBAAkB,YAAE,IAAI,CAAC,KAAK,GAAQ,EACrD,IAAI,CAAC,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CACvC,eAAM,SAAS,EAAC,wBAAwB,YAAE,IAAI,CAAC,WAAW,GAAQ,CACnE,EACD,eAAM,SAAS,EAAC,qBAAqB,EAAC,EAAE,EAAE,GAAG,QAAQ,IAAI,KAAK,EAAE,YAAG,IAAI,CAAC,WAAW,GAAQ,IACvF,IACL,CAAC;YACJ,wGAAwG;YACxG,OAAO,IAAI,CAAC,WAAW,IAAI,WAAW,CAAC,CAAC,CAAC,CACvC,aAAI,SAAS,EAAC,iBAAiB,iBAAc,IAAI,CAAC,MAAM,YACtD,iBAAQ,IAAI,EAAC,QAAQ,EAAC,SAAS,EAAC,kBAAkB,gBAAa,IAAI,CAAC,cAAc,sBAAoB,GAAG,QAAQ,IAAI,KAAK,EAAE,EAC1H,OAAO,EAAE,GAAG,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC,YAAG,OAAO,GAAU,IAFI,IAAI,CAAC,EAAE,CAGjE,CACN,CAAC,CAAC,CAAC,CACF,2BACc,IAAI,CAAC,cAAc,kBACjB,IAAI,CAAC,MAAM,KAAK,SAAS,IAAI,IAAI,CAAC,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,EACvF,SAAS,EAAC,iBAAiB,iBACd,IAAI,CAAC,MAAM,YAExB,OAAO,IADF,IAAI,CAAC,EAAE,CACC,CAChB,CAAC;QACJ,CAAC,CAAC,GACC,CACN,CAAC;AACJ,CAAC,CAAC,CAAC","sourcesContent":["import {\n resolveStepsDescriptor,\n stepsRecipe,\n type ComposeStepsAccessibleName,\n type StepStatus,\n type StepsDescriptor,\n type StepsStatusLabels,\n} from \"@hjmds/design-contracts/components/steps\";\nimport { forwardRef, useId, type HTMLAttributes, type ReactNode } from \"react\";\n\nimport { classNames } from \"./internal.js\";\nimport type { HjmCompositionStyleProp } from \"./composition-style.js\";\n\nexport type StepsProps<Id extends string = string> = Omit<\n HTMLAttributes<HTMLOListElement>,\n \"children\"\n> & Readonly<{\n descriptor: StepsDescriptor<Id>;\n statusLabels: StepsStatusLabels;\n composeAccessibleName: ComposeStepsAccessibleName;\n renderMark?: (status: StepStatus, position: number) => ReactNode;\n /**\n * Return to a step before the cursor (2026-10-18, spint compose). Only those steps become buttons; the cursor and\n * later steps stay static so the flow never skips forward past validation. Omit it while the flow is locked.\n */\n onStepPress?: (id: Id) => void;\n /** Canonical layout-only placement on the root element. Controlled visual keys are excluded. */\n layoutStyle?: HjmCompositionStyleProp;\n}>;\n\n/** Linear progress steps with one canonical cursor; steps before it can be pressed to go back. */\nexport const Steps = forwardRef<HTMLOListElement, StepsProps>(function Steps(\n { descriptor, statusLabels, composeAccessibleName, renderMark, onStepPress, className, layoutStyle, ...props },\n ref,\n) {\n const steps = resolveStepsDescriptor(descriptor, { statusLabels, composeAccessibleName });\n const statusId = useId();\n return (\n <ol {...props} style={{ [\"--hjm-steps-press-target\" as string]: `${stepsRecipe.press.minTouchTarget}px`, ...props.style, ...layoutStyle }} ref={ref} className={classNames(\"hjm-steps\", className)}>\n {steps.map((step, index) => {\n const content = <>\n <div className=\"hjm-steps__rail\" aria-hidden=\"true\">\n <span className=\"hjm-steps__indicator\">\n {renderMark?.(step.status, step.position) ?? (\n step.status === \"complete\" ? \"✓\" : step.status === \"error\" ? \"!\" : step.position\n )}\n </span>\n {index === steps.length - 1 ? null : <span className=\"hjm-steps__connector\" />}\n </div>\n <div className=\"hjm-steps__copy\">\n <span className=\"hjm-steps__label\">{step.label}</span>\n {step.description === undefined ? null : (\n <span className=\"hjm-steps__description\">{step.description}</span>\n )}\n <span className=\"hjm-visually-hidden\" id={`${statusId}-${index}`}>{step.statusLabel}</span>\n </div>\n </>;\n // A pressable step is one named button; its status stays a description so the name keeps order + label.\n return step.revisitable && onStepPress ? (\n <li className=\"hjm-steps__step\" data-status={step.status} key={step.id}>\n <button type=\"button\" className=\"hjm-steps__press\" aria-label={step.accessibleName} aria-describedby={`${statusId}-${index}`}\n onClick={() => onStepPress(step.id)}>{content}</button>\n </li>\n ) : (\n <li\n aria-label={step.accessibleName}\n aria-current={step.status === \"current\" || step.status === \"error\" ? \"step\" : undefined}\n className=\"hjm-steps__step\"\n data-status={step.status}\n key={step.id}\n >{content}</li>\n );\n })}\n </ol>\n );\n});\n"]}
|
package/dist/styles.css
CHANGED
|
@@ -372,7 +372,7 @@
|
|
|
372
372
|
the support text fades, so a custom Field control dims without needing a class. A component
|
|
373
373
|
recipe value (Select, NumberField, OtpField, SearchField, PasswordField) arrives as an
|
|
374
374
|
inline --hjm-field-disabled-opacity on the root. */
|
|
375
|
-
.hjm-field[data-state="disabled"] > :not(.hjm-field__description):not(.hjm-field__error) { opacity: var(--hjm-field-disabled-opacity); }
|
|
375
|
+
.hjm-field[data-state="disabled"] > :not(.hjm-field__description):not(.hjm-field__error):not([data-hjm-field-error]) { opacity: var(--hjm-field-disabled-opacity); }
|
|
376
376
|
.hjm-field__input {
|
|
377
377
|
inline-size: 100%;
|
|
378
378
|
min-inline-size: 0;
|
|
@@ -524,6 +524,13 @@
|
|
|
524
524
|
border-radius: var(--hjm-radius-xl);
|
|
525
525
|
box-shadow: var(--hjm-shadow-floating);
|
|
526
526
|
}
|
|
527
|
+
/* configuration.shape (bottomNavigationRecipe.shapes): the renderer sets the frame radius token and inner padding. */
|
|
528
|
+
.hjm-bottom-navigation[data-presentation="floating"]:not([data-shape="standard"]) .hjm-bottom-navigation__surface {
|
|
529
|
+
border-radius: var(--hjm-bottom-navigation-shape-radius);
|
|
530
|
+
}
|
|
531
|
+
.hjm-bottom-navigation[data-presentation="floating"]:not([data-shape="standard"]) .hjm-bottom-navigation__list {
|
|
532
|
+
padding: var(--hjm-bottom-navigation-shape-padding);
|
|
533
|
+
}
|
|
527
534
|
.hjm-bottom-navigation__list {
|
|
528
535
|
display: grid;
|
|
529
536
|
grid-template-columns: repeat(var(--hjm-bottom-navigation-columns), minmax(var(--hjm-bottom-navigation-item-min-width), 1fr));
|
|
@@ -573,6 +580,14 @@
|
|
|
573
580
|
}
|
|
574
581
|
.hjm-bottom-navigation__indicator > :first-child { transition: transform 160ms ease; }
|
|
575
582
|
.hjm-bottom-navigation__indicator[data-state="selected"] > :first-child { transform: scale(1.06); }
|
|
583
|
+
/* iconEmphasis "lift" (bottomNavigationRecipe.icon.liftEmphasis): the selected icon rises one step above the shared
|
|
584
|
+
scale and idle icons dim, the non-color cue for full-color artwork. The badge is a later sibling and stays opaque. */
|
|
585
|
+
.hjm-bottom-navigation[data-icon-emphasis="lift"] .hjm-bottom-navigation__indicator[data-state="selected"] > :first-child {
|
|
586
|
+
transform: translateY(var(--hjm-bottom-navigation-lift-offset)) scale(1.06);
|
|
587
|
+
}
|
|
588
|
+
.hjm-bottom-navigation[data-icon-emphasis="lift"] li:not([data-prominent="true"]) .hjm-bottom-navigation__indicator[data-state="idle"] > :first-child {
|
|
589
|
+
opacity: var(--hjm-bottom-navigation-lift-idle-opacity);
|
|
590
|
+
}
|
|
576
591
|
/* Icon-only items center the indicator in the density's minimum height instead of leaving an empty label row. */
|
|
577
592
|
.hjm-bottom-navigation[data-labels="hidden"] .hjm-bottom-navigation__item { justify-content: center; }
|
|
578
593
|
.hjm-bottom-navigation__label { font-size: var(--hjm-type-caption-size); line-height: var(--hjm-type-caption-line-height); font-weight: var(--hjm-text-emphasis-medium); }
|
|
@@ -600,6 +615,18 @@
|
|
|
600
615
|
inset-block-start: 50%;
|
|
601
616
|
translate: -50% -50%;
|
|
602
617
|
}
|
|
618
|
+
/* Prominent center destination: bottomNavigationRecipe.prominentDestination, lifted so its label stays on the
|
|
619
|
+
other labels' line. The circle keeps brand fill in both states; the label carries selection. */
|
|
620
|
+
.hjm-bottom-navigation li[data-prominent="true"] .hjm-bottom-navigation__indicator {
|
|
621
|
+
inline-size: var(--hjm-bottom-navigation-prominent-diameter);
|
|
622
|
+
block-size: var(--hjm-bottom-navigation-prominent-diameter);
|
|
623
|
+
margin-block-start: calc(-1 * var(--hjm-bottom-navigation-prominent-lift));
|
|
624
|
+
border-radius: var(--hjm-radius-full);
|
|
625
|
+
color: var(--hjm-color-on-primary);
|
|
626
|
+
background: var(--hjm-color-primary);
|
|
627
|
+
box-shadow: var(--hjm-shadow-floating);
|
|
628
|
+
}
|
|
629
|
+
.hjm-bottom-navigation li[data-prominent="true"] .hjm-bottom-navigation__indicator > :first-child { transform: none; }
|
|
603
630
|
|
|
604
631
|
.hjm-number-field__control {
|
|
605
632
|
padding-inline: 0;
|
|
@@ -1719,6 +1746,22 @@ button.hjm-list-row, a.hjm-list-row { cursor: pointer; }
|
|
|
1719
1746
|
AuthScreenLayout safeAreaBottom (2026-10-17 1.28 adoption: products wrapped the layout in their own inset). */
|
|
1720
1747
|
padding-block-end: max(var(--hjm-auth-screen-padding-block), env(safe-area-inset-bottom, 0px));
|
|
1721
1748
|
}
|
|
1749
|
+
/* With title/exit the layout owns the ScreenLayout centered header band: full-bleed over the inline padding, at the
|
|
1750
|
+
shared screen gutter, with the former top padding moved below it (2026-10-18: products kept a TopBar above). */
|
|
1751
|
+
.hjm-auth-screen[data-header] { padding-block-start: 0; }
|
|
1752
|
+
.hjm-auth-screen__header {
|
|
1753
|
+
display: grid;
|
|
1754
|
+
grid-template-columns: 1fr minmax(0, auto) 1fr;
|
|
1755
|
+
align-items: center;
|
|
1756
|
+
box-sizing: border-box;
|
|
1757
|
+
min-block-size: var(--hjm-auth-screen-header-min-height);
|
|
1758
|
+
margin-inline: calc(var(--hjm-auth-screen-padding-inline) * -1);
|
|
1759
|
+
margin-block-end: var(--hjm-auth-screen-padding-block);
|
|
1760
|
+
padding-inline: var(--hjm-auth-screen-header-padding-inline);
|
|
1761
|
+
padding-block: var(--hjm-auth-screen-header-padding-block);
|
|
1762
|
+
}
|
|
1763
|
+
.hjm-auth-screen__header-title { min-inline-size: 0; text-align: center; overflow-wrap: anywhere; }
|
|
1764
|
+
.hjm-auth-screen__header-title > * { margin: 0; }
|
|
1722
1765
|
.hjm-auth-screen__block {
|
|
1723
1766
|
display: flex;
|
|
1724
1767
|
flex: 1;
|
|
@@ -1770,17 +1813,18 @@ button.hjm-list-row, a.hjm-list-row { cursor: pointer; }
|
|
|
1770
1813
|
flex-wrap: wrap;
|
|
1771
1814
|
justify-content: center;
|
|
1772
1815
|
align-items: center;
|
|
1773
|
-
column-gap: var(--hjm-auth-screen-link-gap);
|
|
1774
1816
|
}
|
|
1775
|
-
/* 2026-10-17 "간격 줄여": 보이는 간격은
|
|
1776
|
-
|
|
1817
|
+
/* 2026-10-17 "간격 줄여": 보이는 간격은 linkGap + 구분점뿐이다. 44 터치 높이는 배경 없는 min-block-size다.
|
|
1818
|
+
2026-10-18 링크 사이 간격을 flex column-gap에서 링크의 inline 여백으로 옮겼다. 보이는 간격은 같고(column-gap 0),
|
|
1819
|
+
가로 터치 폭이 그 여백만큼 링크 상자 안에 든다. 예전 가상 요소는 상자 밖으로 linkGap만큼 뻗어, 긴 링크가 푸터 폭을
|
|
1820
|
+
다 쓰면 푸터의 스크롤 폭을 넓혔다(웹 scenario-matrix auth-screen long-copy 288 > 282). 여백을 gap과 함께 두면
|
|
1821
|
+
글자 사이가 두 배로 벌어지므로 gap은 두지 않는다. */
|
|
1777
1822
|
.hjm-auth-screen__link {
|
|
1778
|
-
position: relative;
|
|
1779
1823
|
display: inline-flex;
|
|
1780
1824
|
align-items: center;
|
|
1781
1825
|
min-block-size: var(--hjm-auth-screen-link-target);
|
|
1782
1826
|
margin: 0;
|
|
1783
|
-
padding: 0;
|
|
1827
|
+
padding: 0 var(--hjm-auth-screen-link-gap);
|
|
1784
1828
|
border: 0;
|
|
1785
1829
|
background: none;
|
|
1786
1830
|
font-family: var(--hjm-font-family-ui, inherit);
|
|
@@ -1788,12 +1832,6 @@ button.hjm-list-row, a.hjm-list-row { cursor: pointer; }
|
|
|
1788
1832
|
text-underline-offset: 0.18em;
|
|
1789
1833
|
cursor: pointer;
|
|
1790
1834
|
}
|
|
1791
|
-
.hjm-auth-screen__link::after {
|
|
1792
|
-
content: "";
|
|
1793
|
-
position: absolute;
|
|
1794
|
-
inset-block: 0;
|
|
1795
|
-
inset-inline: calc(var(--hjm-auth-screen-link-gap) * -1);
|
|
1796
|
-
}
|
|
1797
1835
|
.hjm-auth-screen__link:focus-visible {
|
|
1798
1836
|
outline: var(--hjm-focus-width) solid var(--hjm-color-focus);
|
|
1799
1837
|
outline-offset: var(--hjm-focus-offset);
|
|
@@ -2191,6 +2229,46 @@ button.hjm-list-row, a.hjm-list-row { cursor: pointer; }
|
|
|
2191
2229
|
background: var(--hjm-backdrop-modal);
|
|
2192
2230
|
overscroll-behavior: contain;
|
|
2193
2231
|
}
|
|
2232
|
+
/* Dialog overlayLayer: viewport-sized, decorative, above the card (later sibling) and never a pointer target. */
|
|
2233
|
+
.hjm-dialog__overlay-layer {
|
|
2234
|
+
position: absolute;
|
|
2235
|
+
inset: 0;
|
|
2236
|
+
pointer-events: none;
|
|
2237
|
+
}
|
|
2238
|
+
/* ImmersiveOverlay: an edge-to-edge stage and control bar with no scrim, card or gutter. */
|
|
2239
|
+
.hjm-overlay.hjm-immersive-positioner {
|
|
2240
|
+
align-items: stretch;
|
|
2241
|
+
padding: 0;
|
|
2242
|
+
background: var(--hjm-immersive-background);
|
|
2243
|
+
}
|
|
2244
|
+
.hjm-immersive {
|
|
2245
|
+
display: flex;
|
|
2246
|
+
flex-direction: column;
|
|
2247
|
+
inline-size: 100%;
|
|
2248
|
+
block-size: 100%;
|
|
2249
|
+
color: var(--hjm-color-text);
|
|
2250
|
+
background: var(--hjm-immersive-background);
|
|
2251
|
+
outline: none;
|
|
2252
|
+
}
|
|
2253
|
+
.hjm-immersive__stage {
|
|
2254
|
+
position: relative;
|
|
2255
|
+
flex: 1 1 auto;
|
|
2256
|
+
min-block-size: 0;
|
|
2257
|
+
overflow: hidden;
|
|
2258
|
+
}
|
|
2259
|
+
.hjm-immersive__controls {
|
|
2260
|
+
display: flex;
|
|
2261
|
+
flex-direction: column;
|
|
2262
|
+
gap: var(--hjm-immersive-gap);
|
|
2263
|
+
padding: var(--hjm-immersive-padding);
|
|
2264
|
+
padding-inline: max(var(--hjm-immersive-padding), env(safe-area-inset-left)) max(var(--hjm-immersive-padding), env(safe-area-inset-right));
|
|
2265
|
+
padding-block-end: max(var(--hjm-immersive-padding), env(safe-area-inset-bottom));
|
|
2266
|
+
}
|
|
2267
|
+
.hjm-immersive__actions {
|
|
2268
|
+
display: flex;
|
|
2269
|
+
align-items: center;
|
|
2270
|
+
gap: var(--hjm-immersive-action-gap);
|
|
2271
|
+
}
|
|
2194
2272
|
.hjm-dialog,
|
|
2195
2273
|
.hjm-alert-dialog,
|
|
2196
2274
|
.hjm-sheet {
|
|
@@ -2207,6 +2285,8 @@ button.hjm-list-row, a.hjm-list-row { cursor: pointer; }
|
|
|
2207
2285
|
.hjm-dialog { inline-size: min(36rem, 100%); }
|
|
2208
2286
|
.hjm-dialog[data-size="small"] { inline-size: min(28rem, 100%); }
|
|
2209
2287
|
.hjm-dialog[data-size="large"] { inline-size: min(48rem, 100%); }
|
|
2288
|
+
/* Dialog scrollEnabled={false}: the card keeps its scroll offset while a gesture in the body owns the pointer. */
|
|
2289
|
+
.hjm-dialog[data-scroll="locked"] { overflow: hidden; overscroll-behavior: contain; touch-action: none; }
|
|
2210
2290
|
.hjm-alert-dialog[data-size="small"] { inline-size: min(28rem, 100%); }
|
|
2211
2291
|
.hjm-alert-dialog[data-size="large"] { inline-size: min(48rem, 100%); }
|
|
2212
2292
|
.hjm-dialog__header,
|
|
@@ -2724,6 +2804,8 @@ button.hjm-list-row, a.hjm-list-row { cursor: pointer; }
|
|
|
2724
2804
|
.hjm-pagination__item[data-state="current"] { border-color: var(--hjm-color-content-brand); color: var(--hjm-color-content-brand); font-weight: var(--hjm-text-emphasis-strong); }
|
|
2725
2805
|
.hjm-pagination__item[aria-disabled="true"] { opacity: 0.5; cursor: not-allowed; }
|
|
2726
2806
|
.hjm-pagination__ellipsis { color: var(--hjm-color-text-muted); }
|
|
2807
|
+
/* Open-ended current page label (paginationRecipe.pageLabel): text, not a button, on the steps' 44px row. */
|
|
2808
|
+
.hjm-pagination__page-label { min-block-size: var(--hjm-control-min-touch-target); display: grid; place-items: center; padding-inline: var(--hjm-space-xs); color: var(--hjm-color-text-body); overflow-wrap: anywhere; }
|
|
2727
2809
|
.hjm-load-more { display: grid; justify-items: center; gap: var(--hjm-space-sm); padding-block: var(--hjm-space-lg); text-align: center; }
|
|
2728
2810
|
.hjm-load-more[data-density="compact"] { gap: var(--hjm-space-xs); padding-block: var(--hjm-space-sm); }
|
|
2729
2811
|
.hjm-load-more__sentinel { inline-size: 1px; block-size: 1px; }
|
|
@@ -2748,6 +2830,9 @@ button.hjm-list-row, a.hjm-list-row { cursor: pointer; }
|
|
|
2748
2830
|
.hjm-steps__step[data-status="pending"] .hjm-steps__label { color: var(--hjm-color-text-muted); }
|
|
2749
2831
|
.hjm-steps__step[data-status="error"] .hjm-steps__label { color: var(--hjm-color-danger); }
|
|
2750
2832
|
.hjm-steps__description { color: var(--hjm-color-text-muted); font-size: var(--hjm-type-caption-size); overflow-wrap: anywhere; }
|
|
2833
|
+
/* A step before the cursor is one button over marker and label (Steps onStepPress); the cell keeps its static layout. */
|
|
2834
|
+
.hjm-steps__press { display: grid; align-content: start; gap: var(--hjm-space-xs); min-inline-size: 0; min-block-size: var(--hjm-steps-press-target); margin: 0; padding: 0; border: 0; background: none; color: inherit; font: inherit; text-align: start; cursor: pointer; }
|
|
2835
|
+
.hjm-steps__press:focus-visible { outline: var(--hjm-focus-width) solid var(--hjm-color-focus); outline-offset: var(--hjm-focus-offset); }
|
|
2751
2836
|
|
|
2752
2837
|
.hjm-file-picker { display: grid; gap: var(--hjm-space-xs); }
|
|
2753
2838
|
.hjm-file-picker__label { color: var(--hjm-color-text); font-weight: var(--hjm-text-emphasis-medium); }
|
|
@@ -2796,14 +2881,14 @@ button.hjm-list-row, a.hjm-list-row { cursor: pointer; }
|
|
|
2796
2881
|
/* Cards stay narrow on desktop too; keep close/action rows explicit (docs/toast.md). The card owns its width cap so a
|
|
2797
2882
|
controlled Toast outside the viewport keeps it too (it stretched to 1200px in the layout story, 2026-10-17 review).
|
|
2798
2883
|
1.10.0 layout: [tone badge][title + description][close] / action pill on its own row, end-aligned.
|
|
2799
|
-
|
|
2884
|
+
There is no edge stripe: the tinted badge (or product media) carries tone. 1.10.0 retired the 2px strip and 1.32.0
|
|
2885
|
+
removed its always-hidden element, so no product rule is needed to hide it (docs/toast.md). */
|
|
2800
2886
|
.hjm-toast { position: relative; min-inline-size: 0; max-inline-size: min(26.25rem, 100%); min-block-size: 3.5rem; display: grid; grid-template-columns: auto minmax(0, 1fr) auto; align-items: start; column-gap: var(--hjm-space-sm); row-gap: var(--hjm-space-xs); padding: var(--hjm-toast-padding-block) var(--hjm-toast-padding-inline); overflow: hidden; border: var(--hjm-toast-border-width) solid var(--hjm-toast-border); border-radius: var(--hjm-toast-radius); color: var(--hjm-color-text); background: var(--hjm-toast-background); box-shadow: var(--hjm-toast-shadow); pointer-events: auto; }
|
|
2801
2887
|
/* Whole-card activation is a sibling surface; explicit controls stay above it. */
|
|
2802
2888
|
.hjm-toast__press { position: absolute; inset: 0; z-index: 1; border: 0; border-radius: inherit; padding: 0; background: transparent; cursor: pointer; }
|
|
2803
2889
|
.hjm-toast__press:focus-visible { outline: 2px solid var(--hjm-color-content-brand); outline-offset: -2px; }
|
|
2804
2890
|
.hjm-toast:has(> .hjm-toast__press:active) { opacity: var(--hjm-toast-pressed-opacity); }
|
|
2805
2891
|
.hjm-toast:has(> .hjm-toast__press) > :is(.hjm-toast__action, .hjm-toast__close) { position: relative; z-index: 2; }
|
|
2806
|
-
.hjm-toast__tone-mark { display: none; }
|
|
2807
2892
|
.hjm-toast__icon { grid-column: 1; grid-row: 1; align-self: start; display: grid; place-items: center; inline-size: var(--hjm-toast-badge-size); block-size: var(--hjm-toast-badge-size); border-radius: 50%; color: var(--hjm-toast-accent-neutral); background: var(--hjm-toast-badge-neutral); }
|
|
2808
2893
|
.hjm-toast[data-tone="info"] .hjm-toast__icon { color: var(--hjm-toast-accent-info); background: var(--hjm-toast-badge-info); }
|
|
2809
2894
|
.hjm-toast[data-tone="success"] .hjm-toast__icon { color: var(--hjm-toast-accent-success); background: var(--hjm-toast-badge-success); }
|
|
@@ -2934,10 +3019,12 @@ button.hjm-list-row, a.hjm-list-row { cursor: pointer; }
|
|
|
2934
3019
|
.hjm-carousel__rotation { justify-self: start; }
|
|
2935
3020
|
.hjm-carousel__controls, .hjm-carousel__dots { display: flex; align-items: center; justify-content: center; flex-wrap: wrap; gap: var(--hjm-space-xs); }
|
|
2936
3021
|
.hjm-carousel__controls { flex-wrap: nowrap; } .hjm-carousel__dots { flex-shrink: 1; min-inline-size: 0; }
|
|
2937
|
-
|
|
2938
|
-
.hjm-
|
|
2939
|
-
.hjm-carousel__dot
|
|
2940
|
-
.hjm-carousel__dot
|
|
3022
|
+
/* PageIndicator is the same dot row for a product-owned pager (carouselRecipe.dot). */
|
|
3023
|
+
.hjm-page-indicator { display: flex; align-items: center; justify-content: center; flex-wrap: wrap; gap: var(--hjm-space-xs); min-inline-size: 0; }
|
|
3024
|
+
.hjm-carousel__dot, .hjm-page-indicator__dot { display: grid; place-items: center; min-inline-size: var(--hjm-control-min-touch-target); min-block-size: var(--hjm-control-min-touch-target); border: 0; border-radius: var(--hjm-radius-full); background: transparent; cursor: pointer; }
|
|
3025
|
+
.hjm-carousel__dot > span, .hjm-page-indicator__dot > span { inline-size: var(--hjm-space-xs); block-size: var(--hjm-space-xs); border-radius: var(--hjm-radius-full); background: var(--hjm-color-text-weak); } /* carouselRecipe.dot.color.inactive (border.strong), as Native */
|
|
3026
|
+
.hjm-carousel__dot[data-current="true"] > span, .hjm-page-indicator__dot[data-current="true"] > span { background: var(--hjm-color-content-brand); }
|
|
3027
|
+
.hjm-carousel__dot:focus-visible, .hjm-page-indicator__dot:focus-visible { outline: 2px solid var(--hjm-color-content-brand); outline-offset: 2px; }
|
|
2941
3028
|
|
|
2942
3029
|
/* The viewport action follows the content in DOM order. Its measured clearance
|
|
2943
3030
|
belongs on the scroll content, not on the fixed button (docs/floating-action-button.md). */
|
|
@@ -3113,6 +3200,16 @@ button.hjm-list-row, a.hjm-list-row { cursor: pointer; }
|
|
|
3113
3200
|
.hjm-tabs:is([data-appearance="gooey"], [data-appearance="slide"]) .hjm-tabs__list { position: relative; }
|
|
3114
3201
|
.hjm-tabs:is([data-appearance="gooey"], [data-appearance="slide"]) .hjm-tabs__tab[data-state="selected"]::after { display: none; }
|
|
3115
3202
|
.hjm-tabs__indicator { position: absolute; bottom: 0; height: 2px; border-radius: var(--hjm-radius-full); background: var(--hjm-color-content-brand); pointer-events: none; }
|
|
3203
|
+
/* indicator="filled" (tabsRecipe.indicators.filled): a surface-accent pill behind the selected tab, no list divider.
|
|
3204
|
+
The moving pill spans the tab height and sits under the labels. */
|
|
3205
|
+
.hjm-tabs[data-indicator="filled"] .hjm-tabs__list { border: 0; }
|
|
3206
|
+
.hjm-tabs[data-indicator="filled"] .hjm-tabs__tab { border-radius: var(--hjm-radius-full); }
|
|
3207
|
+
.hjm-tabs[data-indicator="filled"] .hjm-tabs__tab[data-state="selected"] { color: var(--hjm-color-content-brand); }
|
|
3208
|
+
.hjm-tabs[data-indicator="filled"] .hjm-tabs__tab[data-state="selected"]::after { display: none; }
|
|
3209
|
+
.hjm-tabs[data-indicator="filled"]:not([data-indicator-motion="moving"]) .hjm-tabs__tab[data-state="selected"] { background: var(--hjm-color-surface-accent); }
|
|
3210
|
+
.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; }
|
|
3211
|
+
.hjm-tabs[data-indicator="filled"] .hjm-tabs__list { position: relative; }
|
|
3212
|
+
.hjm-tabs[data-indicator="filled"] .hjm-tabs__tab { z-index: 1; }
|
|
3116
3213
|
.hjm-tabs__gooey { height: 6px; }
|
|
3117
3214
|
|
|
3118
3215
|
/* Capsule destinations retain route/link semantics. At larger text sizes we show
|
|
@@ -3167,6 +3264,7 @@ button.hjm-list-row, a.hjm-list-row { cursor: pointer; }
|
|
|
3167
3264
|
.hjm-screen__header { display: flex; flex-wrap: wrap; align-items: center; gap: var(--hjm-screen-item-gap, var(--hjm-space-sm)); padding: var(--hjm-screen-padding); flex: 0 0 auto; }
|
|
3168
3265
|
.hjm-screen__heading { flex: 1 1 calc(var(--hjm-screen-header-min) * var(--hjm-text-scale, 1)); min-inline-size: 0; overflow-wrap: anywhere; }
|
|
3169
3266
|
.hjm-screen__heading > * { margin: 0; }
|
|
3267
|
+
.hjm-screen__title-leading { display: inline-flex; flex-shrink: 0; align-items: center; justify-content: center; }
|
|
3170
3268
|
.hjm-screen__notice { padding-inline: var(--hjm-screen-padding); flex: 0 0 auto; }
|
|
3171
3269
|
/* --hjm-screen-body-inline is the body's inline padding and the distance a bleeding CollectionRail crosses (Native
|
|
3172
3270
|
ScreenBodyInsetContext); inset variants change this one value instead of the padding itself. */
|
|
@@ -3174,8 +3272,15 @@ button.hjm-list-row, a.hjm-list-row { cursor: pointer; }
|
|
|
3174
3272
|
/* contentInset="body-edge": header, notice and footer keep the gutter; full-width list rows own their inline inset
|
|
3175
3273
|
(review S5#9: body 16 + row 16 put DM avatars ~32 from the edge). "none" keeps its host-owns-all meaning. */
|
|
3176
3274
|
.hjm-screen[data-content-inset="body-edge"] > .hjm-screen__body { --hjm-screen-body-inline: 0px; }
|
|
3275
|
+
/* contentInset="body-bleed": the same gutters stay on header, notice and footer; a map or canvas body has none on any
|
|
3276
|
+
side. As the last region it still clears the fixed BottomNavigation, without the gutter (Native twin). */
|
|
3277
|
+
.hjm-screen[data-content-inset="body-bleed"] > .hjm-screen__body { --hjm-screen-body-inline: 0px; padding-block: 0; }
|
|
3278
|
+
.hjm-screen[data-content-inset="body-bleed"] > .hjm-screen__body:last-child { padding-block-end: var(--hjm-bottom-navigation-inset, 0px); }
|
|
3279
|
+
/* Both hand the body gutter to product content; the shared state group has no inset of its own, so it keeps the gutter. */
|
|
3280
|
+
.hjm-screen[data-content-inset="body-edge"] > .hjm-screen__body > .hjm-screen__state,
|
|
3281
|
+
.hjm-screen[data-content-inset="body-bleed"] > .hjm-screen__body > .hjm-screen__state { padding-inline: var(--hjm-screen-padding); }
|
|
3177
3282
|
/* Overlay content is not in the screen body, even when rendered inside it: a bleeding rail there stays in its box. */
|
|
3178
|
-
.hjm-sheet, .hjm-dialog, .hjm-alert-dialog, .hjm-popover { --hjm-screen-body-inline: 0px; }
|
|
3283
|
+
.hjm-sheet, .hjm-dialog, .hjm-alert-dialog, .hjm-popover { --hjm-screen-body-inline: 0px; --hjm-bottom-navigation-inset: 0px; }
|
|
3179
3284
|
/* contentInset="none" hands every inset to the host: no footer rule, as on Native (BottomCTA then draws its own bar). */
|
|
3180
3285
|
.hjm-screen[data-content-inset="none"] > .hjm-screen__footer { border-block-start: 0; }
|
|
3181
3286
|
.hjm-screen__body[data-scroll="screen"] { overflow-y: auto; }
|
|
@@ -3184,7 +3289,11 @@ button.hjm-list-row, a.hjm-list-row { cursor: pointer; }
|
|
|
3184
3289
|
.hjm-screen__centered-content { margin-block: auto; flex-shrink: 0; inline-size: 100%; }
|
|
3185
3290
|
.hjm-screen__body[data-replacement="true"] { display: flex; flex-direction: column; }
|
|
3186
3291
|
.hjm-screen__state { margin-block: auto; flex-shrink: 0; display: flex; flex-direction: column; align-items: center; gap: var(--hjm-screen-state-gap, var(--hjm-space-md)); padding-block: var(--hjm-screen-gap); text-align: center; }
|
|
3187
|
-
.hjm-screen__footer { flex: 0 0 auto; padding: var(--hjm-screen-padding); padding-block-end: max(var(--hjm-screen-padding), env(safe-area-inset-bottom)); border-block-start: 1px solid var(--hjm-color-border); }
|
|
3292
|
+
.hjm-screen__footer { flex: 0 0 auto; padding: var(--hjm-screen-padding); padding-block-end: max(var(--hjm-screen-padding), env(safe-area-inset-bottom), calc(var(--hjm-screen-padding) + var(--hjm-bottom-navigation-inset, 0px))); border-block-start: 1px solid var(--hjm-color-border); }
|
|
3293
|
+
/* --hjm-bottom-navigation-inset (BottomNavigationInsetProvider) is the viewport bottom the fixed bar covers. The last
|
|
3294
|
+
region keeps its gutter above the bar; without a provider the value is 0 and the padding is unchanged. This is the
|
|
3295
|
+
only place the inset is applied: a scroll="content" list inside must not add it again. */
|
|
3296
|
+
.hjm-screen__body:last-child { padding-block-end: calc(var(--hjm-screen-padding) + var(--hjm-bottom-navigation-inset, 0px)); }
|
|
3188
3297
|
/* SearchScreen filtersOverflow=scroll; why: screen-flows.tsx. Block padding keeps focus rings unclipped.
|
|
3189
3298
|
--hjm-search-filters-bleed = screen padding + hostGutter (1.13.1), set inline by SearchScreen. */
|
|
3190
3299
|
.hjm-search-screen__filters { --f: calc(var(--hjm-focus-width) + var(--hjm-focus-offset)); --b: var(--hjm-search-filters-bleed, var(--hjm-screen-padding)); overflow-x: auto; margin: calc(-1 * var(--f)) calc(-1 * var(--b)); padding: var(--f) var(--b); scroll-padding-inline: var(--b); scrollbar-width: none; }
|
|
@@ -3232,6 +3341,19 @@ button.hjm-list-row, a.hjm-list-row { cursor: pointer; }
|
|
|
3232
3341
|
[dir="rtl"] .hjm-chat-message[data-tail] .hjm-chat-message__bubble::before { transform: scaleX(-1); }
|
|
3233
3342
|
|
|
3234
3343
|
.hjm-chat-message__meta { display: flex; flex-shrink: 0; align-items: center; gap: var(--hjm-space-xs); }
|
|
3344
|
+
/* Reaction summary pill (sizes inline from chatMessageRecipe.reactionSummary); own reaction shows the brand border. */
|
|
3345
|
+
.hjm-chat-message__reaction-summary { display: inline-flex; align-items: center; box-sizing: border-box; border: 1px solid var(--hjm-color-border); border-radius: var(--hjm-radius-full); background: var(--hjm-color-surface); color: var(--hjm-color-text); font: inherit; line-height: 1; cursor: pointer; }
|
|
3346
|
+
.hjm-chat-message__reaction-summary[data-selected] { border-color: var(--hjm-color-content-brand); }
|
|
3347
|
+
.hjm-chat-message__reaction-summary:hover:not(:disabled) { background: var(--hjm-color-surface-alt); }
|
|
3348
|
+
.hjm-chat-message__reaction-summary:focus-visible { outline: 2px solid var(--hjm-color-focus, currentColor); outline-offset: 2px; }
|
|
3349
|
+
.hjm-chat-message__reaction-summary:disabled { opacity: 0.5; cursor: default; }
|
|
3350
|
+
/* Read-only counts (summary.readOnly): same slot, plain text, no pill surface or pointer affordance. */
|
|
3351
|
+
.hjm-chat-message__reaction-counts { display: inline-flex; align-items: center; line-height: 1; }
|
|
3352
|
+
/* Typing dots (typingIndicatorRecipe via custom properties): staggered pulse, static under reduced motion. */
|
|
3353
|
+
.hjm-typing-indicator__dot { inline-size: var(--hjm-typing-dot); block-size: var(--hjm-typing-dot); border-radius: 50%; background: var(--hjm-color-text-muted); animation: hjm-typing-pulse var(--hjm-typing-cycle) ease-in-out infinite both; }
|
|
3354
|
+
.hjm-typing-indicator[data-reduced-motion] .hjm-typing-indicator__dot { animation: none; }
|
|
3355
|
+
@media (prefers-reduced-motion: reduce) { .hjm-typing-indicator__dot { animation: none; } }
|
|
3356
|
+
@keyframes hjm-typing-pulse { 0%, 100% { opacity: var(--hjm-typing-rest); } 50% { opacity: 1; } }
|
|
3235
3357
|
/* A quoted reply heads the bubble and is divided from the answer. */
|
|
3236
3358
|
.hjm-chat-message__reply { border-block-end: 1px solid var(--hjm-color-border); padding-block-end: var(--hjm-space-xs); margin-block-end: var(--hjm-space-xs); display: flex; flex-direction: column; gap: 2px; min-inline-size: 0; }
|
|
3237
3359
|
.hjm-chat-message__quote { inline-size: 100%; border-inline: 0; border-block-start: 0; background: none; padding-inline: 0; padding-block-start: 0; color: inherit; font: inherit; text-align: start; cursor: pointer; }
|
|
@@ -3242,6 +3364,17 @@ button.hjm-list-row, a.hjm-list-row { cursor: pointer; }
|
|
|
3242
3364
|
.hjm-chat-message__media-item > img { display: block; inline-size: 100%; block-size: 100%; object-fit: cover; }
|
|
3243
3365
|
button.hjm-chat-message__media-item { cursor: pointer; }
|
|
3244
3366
|
button.hjm-chat-message__media-item:focus-visible { outline: 2px solid var(--hjm-color-focus, currentColor); outline-offset: -2px; }
|
|
3367
|
+
/* Paged media album (2026-10-18, mediaAlbumRecipe): one mounted page in the host's media width, counter row below. */
|
|
3368
|
+
.hjm-media-album { display: flex; flex-direction: column; max-inline-size: 100%; }
|
|
3369
|
+
.hjm-media-album__page { position: relative; display: block; inline-size: 100%; overflow: hidden; padding: 0; border: 0; background: var(--hjm-color-surface-alt); }
|
|
3370
|
+
/* The page wrapper fills the frame in every state; the open action is a sibling overlay so a page status inside stays reachable. */
|
|
3371
|
+
.hjm-media-album__content { inline-size: 100%; block-size: 100%; }
|
|
3372
|
+
.hjm-media-album__content > img { display: block; inline-size: 100%; block-size: 100%; object-fit: cover; }
|
|
3373
|
+
.hjm-media-album__open { position: absolute; inset: 0; z-index: 1; padding: 0; border: 0; border-radius: inherit; background: transparent; cursor: pointer; }
|
|
3374
|
+
.hjm-media-album__open:focus-visible { outline: 2px solid var(--hjm-color-focus, currentColor); outline-offset: -2px; }
|
|
3375
|
+
/* Loading / failed page (MediaAlbumPageStatus): one block centered in the frame (VQ-09); gap and padding inline from mediaAlbumRecipe.pageStatus. */
|
|
3376
|
+
.hjm-media-album__status { box-sizing: border-box; display: flex; flex-direction: column; align-items: center; justify-content: center; inline-size: 100%; block-size: 100%; text-align: center; }
|
|
3377
|
+
.hjm-media-album__controls { display: flex; align-items: center; justify-content: space-between; }
|
|
3245
3378
|
.hjm-chat-message__bubble[data-photo-only] { background: none; padding: 0; }
|
|
3246
3379
|
.hjm-chat-message__bubble[data-photo-only]::before { display: none; }
|
|
3247
3380
|
/* Only the shared default gutter narrows to the timeline gutter; "none" and "body-edge" keep their own meaning. */
|
|
@@ -3254,8 +3387,21 @@ button.hjm-chat-message__media-item:focus-visible { outline: 2px solid var(--hjm
|
|
|
3254
3387
|
.hjm-image-choice { display: flex; flex-direction: column; gap: var(--hjm-space-xs); }
|
|
3255
3388
|
.hjm-image-choice__label { font-weight: var(--hjm-text-emphasis-medium); }
|
|
3256
3389
|
.hjm-image-choice__tiles { display: flex; flex-wrap: wrap; gap: var(--hjm-image-choice-gap); }
|
|
3257
|
-
|
|
3258
|
-
|
|
3390
|
+
/* The button is a column (ring frame, optional item label) so the label shares the tap target; the ring is drawn on
|
|
3391
|
+
the inner frame (2026-10-18 showItemLabels). */
|
|
3392
|
+
.hjm-image-choice__tile { display: flex; flex-direction: column; gap: var(--hjm-image-choice-item-label-gap); inline-size: calc(var(--hjm-image-choice-size) + (var(--hjm-image-choice-ring) + var(--hjm-image-choice-offset)) * 2); padding: 0; border: 0; border-radius: calc(var(--hjm-image-choice-radius) + var(--hjm-image-choice-ring) + var(--hjm-image-choice-offset)); background: none; color: inherit; cursor: pointer; }
|
|
3393
|
+
.hjm-image-choice__ring { position: relative; display: block; inline-size: 100%; aspect-ratio: 1; padding: var(--hjm-image-choice-offset); border: var(--hjm-image-choice-ring) solid transparent; border-radius: inherit; }
|
|
3394
|
+
.hjm-image-choice__tile[data-selected] .hjm-image-choice__ring { border-color: var(--hjm-color-content-brand); }
|
|
3395
|
+
.hjm-image-choice__item-label { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; text-align: center; }
|
|
3396
|
+
/* Caption block (label lines + optional description line) has the same height in every tile of a group
|
|
3397
|
+
(resolveImageChoiceCaptionLines), so wrapped rows stay even and virtualized rows share one stride. */
|
|
3398
|
+
.hjm-image-choice__caption { display: flex; flex-direction: column; min-inline-size: 0; block-size: calc(var(--hjm-type-caption-line-height) * var(--hjm-image-choice-caption-lines)); }
|
|
3399
|
+
/* Two-line labels keep words whole (keep-all) and clamp; a single over-long word still breaks rather than overflowing. */
|
|
3400
|
+
.hjm-image-choice__item-label[data-lines="2"] { display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; line-clamp: 2; white-space: normal; word-break: keep-all; overflow-wrap: anywhere; }
|
|
3401
|
+
.hjm-image-choice__item-description { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; text-align: center; }
|
|
3402
|
+
/* virtualized: the group is its own fixed-height scroller; the inset keeps the tile focus outline inside the clip. */
|
|
3403
|
+
.hjm-image-choice__viewport { position: relative; box-sizing: border-box; overflow-y: auto; padding: var(--hjm-image-choice-viewport-inset); }
|
|
3404
|
+
.hjm-image-choice__row { position: absolute; inset-inline: 0; display: flex; gap: var(--hjm-image-choice-gap); }
|
|
3259
3405
|
.hjm-image-choice__tile:focus-visible { outline: 2px solid var(--hjm-color-focus, currentColor); outline-offset: 2px; }
|
|
3260
3406
|
.hjm-image-choice__tile:disabled { opacity: 0.5; cursor: default; }
|
|
3261
3407
|
.hjm-image-choice__image { display: block; inline-size: 100%; block-size: 100%; overflow: hidden; border-radius: var(--hjm-image-choice-radius); background: var(--hjm-color-surface); }
|
|
@@ -3303,6 +3449,8 @@ button.hjm-chat-message__media-item:focus-visible { outline: 2px solid var(--hjm
|
|
|
3303
3449
|
.hjm-comment-row__reactions:focus-visible { outline: 2px solid var(--hjm-color-focus, currentColor); outline-offset: 2px; }
|
|
3304
3450
|
.hjm-comment-row__media { align-self: flex-start; overflow: hidden; margin-block-start: 4px; }
|
|
3305
3451
|
.hjm-comment-row__media > img { display: block; inline-size: 100%; block-size: auto; }
|
|
3452
|
+
.hjm-comment-row__album { align-self: flex-start; margin-block-start: 4px; }
|
|
3453
|
+
.hjm-comment-row__panel { min-inline-size: 0; }
|
|
3306
3454
|
/* commentThreadRecipe.actionAnchor (2026-10-17 measured audit): the 44 targets centre on the identity's first line
|
|
3307
3455
|
(--hjm-comment-anchor-line, set per row), so like/more glyphs share the author line's centre instead of sitting
|
|
3308
3456
|
12px below it. When HJM's own like/more is the last control (data-edge), the whole column takes the IconButton edge
|
|
@@ -3416,6 +3564,17 @@ button.hjm-chat-message__media-item:focus-visible { outline: 2px solid var(--hjm
|
|
|
3416
3564
|
.hjm-card[data-interactive="true"] { font: inherit; color: inherit; text-align: inherit; cursor: pointer; min-inline-size: var(--hjm-control-min-touch-target); min-block-size: var(--hjm-control-min-touch-target); }
|
|
3417
3565
|
.hjm-card[data-interactive="true"]:active:not(:disabled) { opacity: var(--hjm-card-pressed-opacity); }
|
|
3418
3566
|
.hjm-card[data-interactive="true"]:disabled { opacity: var(--hjm-card-disabled-opacity); cursor: default; }
|
|
3567
|
+
/* Whole-card activation beside actions: the article keeps its semantics, a transparent button covers it, and only the
|
|
3568
|
+
action controls rise above that button, so the gaps around them still open the card. */
|
|
3569
|
+
.hjm-card[data-activation="overlay"] { position: relative; }
|
|
3570
|
+
.hjm-card__activator { position: absolute; inset: 0; z-index: 0; margin: 0; padding: 0; border: 0; border-radius: inherit; background: transparent; cursor: pointer; }
|
|
3571
|
+
.hjm-card__activator:disabled { cursor: default; }
|
|
3572
|
+
.hjm-card[data-activation="overlay"] > .hjm-card__actions { position: relative; z-index: 1; pointer-events: none; }
|
|
3573
|
+
.hjm-card[data-activation="overlay"] > .hjm-card__actions > * { pointer-events: auto; }
|
|
3574
|
+
/* Press/disabled feedback belongs to the card target (media and body); action controls keep their own states. */
|
|
3575
|
+
.hjm-card[data-activation="overlay"]:has(> .hjm-card__activator:active:not(:disabled)) > :is(.hjm-card__media, .hjm-card__body) { opacity: var(--hjm-card-pressed-opacity); }
|
|
3576
|
+
.hjm-card[data-activation="overlay"]:has(> .hjm-card__activator:disabled) > :is(.hjm-card__media, .hjm-card__body) { opacity: var(--hjm-card-disabled-opacity); }
|
|
3577
|
+
.hjm-card[data-activation="overlay"]:has(> .hjm-card__activator:focus-visible) { outline: var(--hjm-focus-width) solid var(--hjm-color-focus); outline-offset: var(--hjm-focus-offset); }
|
|
3419
3578
|
|
|
3420
3579
|
/* Full destination cards keep all names and widths stable; colors remain product semantic roles. */
|
|
3421
3580
|
.hjm-bottom-navigation[data-selection="tile"] .hjm-bottom-navigation__surface { background: var(--hjm-color-surface-accent); }
|