@hjmds/react-native 1.18.0 → 1.19.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/README.md +8 -8
- package/dist/actions.d.ts +3 -23
- package/dist/actions.d.ts.map +1 -1
- package/dist/actions.js +7 -10
- package/dist/actions.js.map +1 -1
- package/dist/agreement.d.ts +1 -7
- package/dist/agreement.d.ts.map +1 -1
- package/dist/agreement.js +21 -15
- package/dist/agreement.js.map +1 -1
- package/dist/asset.d.ts +2 -13
- package/dist/asset.d.ts.map +1 -1
- package/dist/asset.js +4 -7
- package/dist/asset.js.map +1 -1
- package/dist/bottom-info.d.ts +1 -7
- package/dist/bottom-info.d.ts.map +1 -1
- package/dist/bottom-info.js +2 -4
- package/dist/bottom-info.js.map +1 -1
- package/dist/carousel-motion.d.ts +1 -0
- package/dist/carousel-motion.d.ts.map +1 -1
- package/dist/carousel-motion.js +5 -3
- package/dist/carousel-motion.js.map +1 -1
- package/dist/carousel.d.ts +1 -7
- package/dist/carousel.d.ts.map +1 -1
- package/dist/carousel.js +14 -6
- package/dist/carousel.js.map +1 -1
- package/dist/collapsible.d.ts +1 -7
- package/dist/collapsible.d.ts.map +1 -1
- package/dist/collapsible.js +4 -4
- package/dist/collapsible.js.map +1 -1
- package/dist/data-display.d.ts +19 -153
- package/dist/data-display.d.ts.map +1 -1
- package/dist/data-display.js +73 -90
- package/dist/data-display.js.map +1 -1
- package/dist/date-entry.d.ts +1 -0
- package/dist/date-entry.d.ts.map +1 -1
- package/dist/date-entry.js +22 -20
- package/dist/date-entry.js.map +1 -1
- package/dist/date-picker.d.ts +1 -7
- package/dist/date-picker.d.ts.map +1 -1
- package/dist/date-picker.js +19 -11
- package/dist/date-picker.js.map +1 -1
- package/dist/duration-field.d.ts +1 -1
- package/dist/duration-field.d.ts.map +1 -1
- package/dist/duration-field.js +11 -9
- package/dist/duration-field.js.map +1 -1
- package/dist/evidence.d.ts +1 -1
- package/dist/evidence.js +1 -1
- package/dist/feedback.d.ts +8 -88
- package/dist/feedback.d.ts.map +1 -1
- package/dist/feedback.js +72 -62
- package/dist/feedback.js.map +1 -1
- package/dist/field-group.d.ts +3 -2
- package/dist/field-group.d.ts.map +1 -1
- package/dist/field-group.js +7 -4
- package/dist/field-group.js.map +1 -1
- package/dist/file-picker.d.ts +1 -7
- package/dist/file-picker.d.ts.map +1 -1
- package/dist/file-picker.js +21 -11
- package/dist/file-picker.js.map +1 -1
- package/dist/forms.d.ts +6 -21
- package/dist/forms.d.ts.map +1 -1
- package/dist/forms.js +29 -35
- package/dist/forms.js.map +1 -1
- package/dist/gravity-letters.d.ts.map +1 -1
- package/dist/gravity-letters.js +13 -5
- package/dist/gravity-letters.js.map +1 -1
- package/dist/grid-reveal.d.ts.map +1 -1
- package/dist/grid-reveal.js +10 -2
- package/dist/grid-reveal.js.map +1 -1
- package/dist/heading.d.ts +1 -7
- package/dist/heading.d.ts.map +1 -1
- package/dist/heading.js +1 -4
- package/dist/heading.js.map +1 -1
- package/dist/image-viewer.d.ts.map +1 -1
- package/dist/image-viewer.js +2 -1
- package/dist/image-viewer.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/inline-confirm.d.ts.map +1 -1
- package/dist/inline-confirm.js +5 -1
- package/dist/inline-confirm.js.map +1 -1
- package/dist/inputs.d.ts +4 -71
- package/dist/inputs.d.ts.map +1 -1
- package/dist/inputs.js +25 -50
- package/dist/inputs.js.map +1 -1
- package/dist/internal/accessible-focus.d.ts +3 -0
- package/dist/internal/accessible-focus.d.ts.map +1 -0
- package/dist/internal/accessible-focus.js +15 -0
- package/dist/internal/accessible-focus.js.map +1 -0
- package/dist/internal/diagnostics.d.ts +7 -0
- package/dist/internal/diagnostics.d.ts.map +1 -0
- package/dist/internal/diagnostics.js +20 -0
- package/dist/internal/diagnostics.js.map +1 -0
- package/dist/internal/document-resource.d.ts.map +1 -1
- package/dist/internal/document-resource.js +2 -2
- package/dist/internal/document-resource.js.map +1 -1
- package/dist/internal/spinner.d.ts +1 -7
- package/dist/internal/spinner.d.ts.map +1 -1
- package/dist/internal/spinner.js +2 -4
- package/dist/internal/spinner.js.map +1 -1
- package/dist/masonry.d.ts.map +1 -1
- package/dist/masonry.js +2 -1
- package/dist/masonry.js.map +1 -1
- package/dist/mentions.d.ts +1 -7
- package/dist/mentions.d.ts.map +1 -1
- package/dist/mentions.js +11 -7
- package/dist/mentions.js.map +1 -1
- package/dist/navigation.d.ts +4 -74
- package/dist/navigation.d.ts.map +1 -1
- package/dist/navigation.js +81 -43
- package/dist/navigation.js.map +1 -1
- package/dist/number-field.d.ts +1 -21
- package/dist/number-field.d.ts.map +1 -1
- package/dist/number-field.js +6 -5
- package/dist/number-field.js.map +1 -1
- package/dist/overlays.d.ts +7 -16
- package/dist/overlays.d.ts.map +1 -1
- package/dist/overlays.js +220 -213
- package/dist/overlays.js.map +1 -1
- package/dist/primitives.d.ts +3 -18
- package/dist/primitives.d.ts.map +1 -1
- package/dist/primitives.js +8 -10
- package/dist/primitives.js.map +1 -1
- package/dist/provider-button.d.ts +1 -7
- package/dist/provider-button.d.ts.map +1 -1
- package/dist/provider-button.js +1 -4
- package/dist/provider-button.js.map +1 -1
- package/dist/provider.d.ts.map +1 -1
- package/dist/provider.js +9 -1
- package/dist/provider.js.map +1 -1
- package/dist/saved-items.d.ts.map +1 -1
- package/dist/saved-items.js +6 -1
- package/dist/saved-items.js.map +1 -1
- package/dist/screen-flows.d.ts +1 -2
- package/dist/screen-flows.d.ts.map +1 -1
- package/dist/screen-flows.js +60 -16
- package/dist/screen-flows.js.map +1 -1
- package/dist/screens.d.ts.map +1 -1
- package/dist/screens.js +21 -10
- package/dist/screens.js.map +1 -1
- package/dist/sheet-gesture.d.ts.map +1 -1
- package/dist/sheet-gesture.js +6 -3
- package/dist/sheet-gesture.js.map +1 -1
- package/dist/slider.d.ts +1 -21
- package/dist/slider.d.ts.map +1 -1
- package/dist/slider.js +3 -5
- package/dist/slider.js.map +1 -1
- package/dist/sortable.d.ts.map +1 -1
- package/dist/sortable.js +2 -1
- package/dist/sortable.js.map +1 -1
- package/dist/status-text.d.ts +17 -0
- package/dist/status-text.d.ts.map +1 -0
- package/dist/status-text.js +18 -0
- package/dist/status-text.js.map +1 -0
- package/dist/steps.d.ts +1 -7
- package/dist/steps.d.ts.map +1 -1
- package/dist/steps.js +2 -4
- package/dist/steps.js.map +1 -1
- package/dist/swipe-actions.d.ts.map +1 -1
- package/dist/swipe-actions.js +13 -2
- package/dist/swipe-actions.js.map +1 -1
- package/dist/tags-input.d.ts +1 -7
- package/dist/tags-input.d.ts.map +1 -1
- package/dist/tags-input.js +2 -4
- package/dist/tags-input.js.map +1 -1
- package/dist/toggle-group.d.ts +1 -7
- package/dist/toggle-group.d.ts.map +1 -1
- package/dist/toggle-group.js +10 -5
- package/dist/toggle-group.js.map +1 -1
- package/dist/top.d.ts +1 -7
- package/dist/top.d.ts.map +1 -1
- package/dist/top.js +1 -4
- package/dist/top.js.map +1 -1
- package/dist/transfer-list.d.ts +2 -8
- package/dist/transfer-list.d.ts.map +1 -1
- package/dist/transfer-list.js +30 -11
- package/dist/transfer-list.js.map +1 -1
- package/dist/upload-item.d.ts +1 -7
- package/dist/upload-item.d.ts.map +1 -1
- package/dist/upload-item.js +2 -4
- package/dist/upload-item.js.map +1 -1
- package/dist/virtual-list.d.ts.map +1 -1
- package/dist/virtual-list.js +2 -1
- package/dist/virtual-list.js.map +1 -1
- package/docs/liquid-toast.md +9 -0
- package/package.json +9 -3
- package/dist/internal/deprecated-style.d.ts +0 -8
- package/dist/internal/deprecated-style.d.ts.map +0 -1
- package/dist/internal/deprecated-style.js +0 -34
- package/dist/internal/deprecated-style.js.map +0 -1
package/dist/data-display.js
CHANGED
|
@@ -1,25 +1,25 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { assertNoRemovedStyleProps } from "./internal/diagnostics.js";
|
|
2
3
|
import { resolveAvatarInitials } from "@hjmds/design-contracts/avatar-fallback";
|
|
3
4
|
import { resolveColorReference } from "@hjmds/design-contracts/color-references";
|
|
4
5
|
import { fontWeight, glyph, radius, spacing } from "@hjmds/design-contracts/foundations";
|
|
5
6
|
import { resolveDescriptionListColumnCount, resolveDescriptionListDescriptor, } from "@hjmds/design-contracts/components/description-list";
|
|
6
7
|
import { resolveStatisticDescriptor, validateStatisticGroup, } from "@hjmds/design-contracts/components/statistic";
|
|
7
8
|
import { resolveTagDescriptor, resolveTagPresentation, tagRecipe, } from "@hjmds/design-contracts/components/tag";
|
|
8
|
-
import { warnDeprecatedStyleProps } from "./internal/deprecated-style.js";
|
|
9
9
|
import { cardRecipe } from "@hjmds/design-contracts/components/card";
|
|
10
10
|
import { imageRecipe, nativeResizeModes, resolveImageAspectRatio, resolveImageDescriptor, resolveImageFallbackAccessibilityLabel, } from "@hjmds/design-contracts/components/image";
|
|
11
11
|
import { resolveTimelineDescriptor, timelineRecipe, } from "@hjmds/design-contracts/components/timeline";
|
|
12
12
|
import { surfaceDefaults, surfaceGeometry } from "@hjmds/design-contracts/recipes/base";
|
|
13
13
|
import { accordionRecipe, counterBadgeRecipe, badgeRecipe, listRecipe, formatCounterBadgeCount, listRowRecipe, statisticRecipe, } from "@hjmds/design-contracts/recipes";
|
|
14
|
-
import { Children, isValidElement, useEffect, useMemo, useRef, useState, } from "react";
|
|
14
|
+
import { Children, isValidElement, useEffect, useLayoutEffect, useMemo, useRef, useState, } from "react";
|
|
15
15
|
import { Image as NativeImage, LayoutAnimation, Pressable, StyleSheet, View, useWindowDimensions, } from "react-native";
|
|
16
16
|
import { useControllableState } from "./internal/state.js";
|
|
17
17
|
import { minimumTargetStyle } from "./internal/styles.js";
|
|
18
18
|
import { webDisclosureProps, webOnly } from "./internal/web-a11y.js";
|
|
19
19
|
import { Surface, Text, } from "./primitives.js";
|
|
20
20
|
import { useHjmNativeTheme } from "./provider.js";
|
|
21
|
-
export function Badge({ label, tone = badgeRecipe.defaults.tone, size = badgeRecipe.defaults.size, variant = badgeRecipe.defaults.variant, leading, accessibilityLabel,
|
|
22
|
-
|
|
21
|
+
export function Badge({ label, tone = badgeRecipe.defaults.tone, size = badgeRecipe.defaults.size, variant = badgeRecipe.defaults.variant, leading, accessibilityLabel, layoutStyle, ...props }) {
|
|
22
|
+
assertNoRemovedStyleProps("Badge", props, ["style", "labelStyle"]);
|
|
23
23
|
const theme = useHjmNativeTheme();
|
|
24
24
|
const presentation = badgeRecipe.tones[tone];
|
|
25
25
|
const metrics = badgeRecipe.sizes[size];
|
|
@@ -49,17 +49,15 @@ export function Badge({ label, tone = badgeRecipe.defaults.tone, size = badgeRec
|
|
|
49
49
|
minHeight: metrics.minHeight,
|
|
50
50
|
paddingHorizontal: metrics.paddingHorizontal,
|
|
51
51
|
},
|
|
52
|
-
style,
|
|
53
52
|
layoutStyle,
|
|
54
53
|
], children: [leading === undefined ? null : (_jsx(View, { accessibilityElementsHidden: true, accessible: false, importantForAccessibility: "no-hide-descendants", children: leading })), _jsx(Text, { accessible: false, align: "center", emphasis: "strong", style: [
|
|
55
54
|
{
|
|
56
55
|
color: resolveColorReference(outlined ? presentation.outlineContent : presentation.content, theme.palette),
|
|
57
56
|
},
|
|
58
|
-
labelStyle,
|
|
59
57
|
], variant: metrics.textVariant, children: label })] }));
|
|
60
58
|
}
|
|
61
|
-
export function Tag({ children, tone, accessibilityLabel, layoutStyle,
|
|
62
|
-
|
|
59
|
+
export function Tag({ children, tone, accessibilityLabel, layoutStyle, ...props }) {
|
|
60
|
+
assertNoRemovedStyleProps("Tag", props, ["style", "labelStyle"]);
|
|
63
61
|
const theme = useHjmNativeTheme();
|
|
64
62
|
const resolvedLabel = children;
|
|
65
63
|
if (resolvedLabel === undefined) {
|
|
@@ -84,9 +82,8 @@ export function Tag({ children, tone, accessibilityLabel, layoutStyle, style, la
|
|
|
84
82
|
minHeight: tagRecipe.size.minHeight,
|
|
85
83
|
paddingHorizontal: tagRecipe.size.paddingHorizontal,
|
|
86
84
|
},
|
|
87
|
-
style,
|
|
88
85
|
layoutStyle,
|
|
89
|
-
], children: _jsx(Text, { align: "center", emphasis: "medium", style: [{ color: presentation.content }
|
|
86
|
+
], children: _jsx(Text, { align: "center", emphasis: "medium", style: [{ color: presentation.content }], variant: tagRecipe.size.textVariant, children: descriptor.label }) }));
|
|
90
87
|
}
|
|
91
88
|
export function Card({ children, title, description, leading, media, actions, selected = cardRecipe.defaults.selected, onActivate, disabled = false, accessibilityLabel, accessibilityHint, tone = cardRecipe.defaults.tone, bordered = cardRecipe.defaults.bordered, padding = cardRecipe.defaults.padding, layoutStyle, radius: cornerRadius = surfaceDefaults.radius, ...props }) {
|
|
92
89
|
const { environment, tokens } = useHjmNativeTheme();
|
|
@@ -120,9 +117,9 @@ export function Card({ children, title, description, leading, media, actions, se
|
|
|
120
117
|
opacity: disabled ? cardRecipe.interaction.disabledOpacity : pressed ? cardRecipe.interaction.pressedOpacity : 1,
|
|
121
118
|
}, layoutStyle], children: frame });
|
|
122
119
|
}
|
|
123
|
-
export function ListRow({ title, description, leading, trailing, titleMetadata, trailingAction, trailingText, metadataLabel, trailingLabel, onPress, accessibilityLabel, accessibilityHint, disabled = false, density = listRowRecipe.defaults.density, selected: selectedProp, leadingShape = "square", layoutStyle, leadingStyle, contentStyle,
|
|
120
|
+
export function ListRow({ title, tone = listRowRecipe.defaults.tone, description, leading, trailing, titleMetadata, trailingAction, trailingText, metadataLabel, trailingLabel, onPress, accessibilityLabel, accessibilityHint, disabled = false, density = listRowRecipe.defaults.density, loading = false, loadingLabel, selected: selectedProp, leadingShape = "square", layoutStyle, leadingStyle, contentStyle, titleRowStyle, trailingStyle, trailingActionStyle, containerProps, accessibilityState, ...forwarded }) {
|
|
121
|
+
assertNoRemovedStyleProps("ListRow", forwarded, ["titleStyle", "descriptionStyle"]);
|
|
124
122
|
const { hjmTitleEmphasis, ...props } = forwarded;
|
|
125
|
-
warnDeprecatedStyleProps("ListRow", { titleStyle, descriptionStyle }, "density/selected and the listRowRecipe typography for appearance");
|
|
126
123
|
const theme = useHjmNativeTheme();
|
|
127
124
|
const metrics = listRowRecipe.density[density];
|
|
128
125
|
const interactive = onPress !== undefined;
|
|
@@ -155,6 +152,15 @@ export function ListRow({ title, description, leading, trailing, titleMetadata,
|
|
|
155
152
|
width: listRowRecipe.leadingSize,
|
|
156
153
|
...(leadingRadius === null ? {} : { borderRadius: theme.tokens.radius[leadingRadius] }),
|
|
157
154
|
};
|
|
155
|
+
if (loading) {
|
|
156
|
+
// Search and other collections share ListRow geometry instead of approximating it with
|
|
157
|
+
// loose Skeletons. Never mount placeholder actions or forward touch handlers while loading.
|
|
158
|
+
const placeholder = { backgroundColor: theme.colors.surfaceAlt, borderRadius: theme.tokens.radius.sm };
|
|
159
|
+
return _jsxs(View, { testID: props.testID, onLayout: props.onLayout, accessible: Boolean(loadingLabel), accessibilityRole: "progressbar", accessibilityLabel: loadingLabel, accessibilityState: { busy: true }, importantForAccessibility: loadingLabel ? "yes" : "no-hide-descendants", style: [{ alignItems: "center", flexDirection: "row", direction: theme.environment.direction,
|
|
160
|
+
gap: listRowRecipe.gap, minHeight: visualState.minHeight,
|
|
161
|
+
paddingHorizontal: metrics.paddingHorizontal, paddingVertical: metrics.paddingVertical,
|
|
162
|
+
borderWidth: 1, borderColor: "transparent" }, layoutStyle], children: [leading ? _jsx(View, { style: [placeholder, leadingFrameStyle] }) : null, _jsxs(View, { style: { flex: 1, minWidth: 0, gap: spacing.xxs }, children: [_jsx(View, { style: [placeholder, { width: `${listRowRecipe.loading.titleWidthPercent}%`, height: theme.tokens.typography[listRowRecipe.title.textVariant].lineHeight }] }), description ? _jsx(View, { style: [placeholder, { width: `${listRowRecipe.loading.descriptionWidthPercent}%`, height: theme.tokens.typography[listRowRecipe.description.textVariant].lineHeight }] }) : null] }), trailing || trailingText ? _jsx(View, { style: [placeholder, { width: listRowRecipe.loading.trailingWidth, height: theme.tokens.typography[listRowRecipe.trailing.textVariant].lineHeight }] }) : null] });
|
|
163
|
+
}
|
|
158
164
|
const rowContent = (_jsxs(_Fragment, { children: [leading ? (_jsx(View, { accessible: interactive ? false : undefined, importantForAccessibility: interactive ? "no-hide-descendants" : "auto", style: [leadingFrameStyle, leadingStyle], children: leading })) : null, _jsxs(View, { style: [{ flex: 1, gap: spacing.xxs, minWidth: 0 }, contentStyle], children: [_jsxs(View, { style: [
|
|
159
165
|
{
|
|
160
166
|
alignItems: "center",
|
|
@@ -166,14 +172,12 @@ export function ListRow({ title, description, leading, trailing, titleMetadata,
|
|
|
166
172
|
titleRowStyle,
|
|
167
173
|
], children: [_jsx(Text, { style: [
|
|
168
174
|
{
|
|
169
|
-
color: resolveColorReference(listRowRecipe.
|
|
175
|
+
color: resolveColorReference(listRowRecipe.tones[tone].titleColor, theme.palette),
|
|
170
176
|
flexShrink: 1,
|
|
171
177
|
fontWeight: hjmTitleEmphasis === "regular" ? fontWeight.regular : listRowRecipe.title.fontWeight,
|
|
172
178
|
},
|
|
173
|
-
titleStyle,
|
|
174
179
|
], variant: listRowRecipe.title.textVariant, children: title }), resolvedMetadata === undefined ? null : (_jsx(View, { accessible: interactive ? false : undefined, importantForAccessibility: interactive ? "no-hide-descendants" : "auto", children: resolvedMetadata }))] }), description ? (_jsx(Text, { style: [
|
|
175
180
|
{ color: resolveColorReference(listRowRecipe.description.color, theme.palette) },
|
|
176
|
-
descriptionStyle,
|
|
177
181
|
], variant: listRowRecipe.description.textVariant, children: description })) : null] }), trailingText || trailing ? (_jsx(View, { accessible: interactive ? false : undefined, importantForAccessibility: interactive ? "no-hide-descendants" : "auto", style: [{ flexShrink: 0 }, trailingStyle], children: trailingText ? (_jsx(Text, { style: { color: resolveColorReference(listRowRecipe.trailing.textColor, theme.palette) }, variant: listRowRecipe.trailing.textVariant, children: trailingText })) : trailing })) : null] }));
|
|
178
182
|
const contentStyleFor = (pressed) => [
|
|
179
183
|
minimumTargetStyle,
|
|
@@ -223,10 +227,9 @@ export function ListRow({ title, description, leading, trailing, titleMetadata,
|
|
|
223
227
|
trailingActionStyle,
|
|
224
228
|
], children: trailingAction })] }));
|
|
225
229
|
}
|
|
226
|
-
export function Avatar({ source, renderImage, name, initials, renderFallback, size = 44, decorative = false, accessibilityLabel,
|
|
230
|
+
export function Avatar({ source, renderImage, name, initials, renderFallback, size = 44, decorative = false, accessibilityLabel, layoutStyle, }) {
|
|
227
231
|
if (!Number.isFinite(size) || size < 24)
|
|
228
232
|
throw new RangeError("Avatar size must be at least 24");
|
|
229
|
-
warnDeprecatedStyleProps("Avatar", { style, imageStyle }, "layoutStyle for placement and size/renderFallback for appearance");
|
|
230
233
|
const { colors } = useHjmNativeTheme();
|
|
231
234
|
const sourceKey = source === undefined ? "none" : resolveImageSourceKey(source);
|
|
232
235
|
const [failedSource, setFailedSource] = useState(null);
|
|
@@ -259,55 +262,55 @@ export function Avatar({ source, renderImage, name, initials, renderFallback, si
|
|
|
259
262
|
overflow: "hidden",
|
|
260
263
|
width: size,
|
|
261
264
|
},
|
|
262
|
-
style,
|
|
263
265
|
layoutStyle,
|
|
264
266
|
], children: source !== undefined && !failed ? (renderImage ? (_jsx(View, { accessible: false, accessibilityElementsHidden: true, importantForAccessibility: "no-hide-descendants", style: { height: size, width: size }, children: renderImage({ source, size, onError: failImage,
|
|
265
|
-
fallback: renderFallback?.({ size, decorative: true }) ?? _jsx(Text, { align: "center", style: { color: colors.contentBrand }, variant: "label", children: fallback }) }) })) : (_jsx(NativeImage, { accessible: false, onError: failImage, source: source, style: [{ height: size, width: size }
|
|
267
|
+
fallback: renderFallback?.({ size, decorative: true }) ?? _jsx(Text, { align: "center", style: { color: colors.contentBrand }, variant: "label", children: fallback }) }) })) : (_jsx(NativeImage, { accessible: false, onError: failImage, source: source, style: [{ height: size, width: size }] }))) : (_jsx(View, { accessible: false, accessibilityElementsHidden: true, importantForAccessibility: "no-hide-descendants", children: renderFallback?.({ size, decorative: true }) ?? _jsx(Text, { align: "center", style: { color: colors.contentBrand }, variant: "label", children: fallback }) })) }));
|
|
266
268
|
}
|
|
267
|
-
export function Divider({ orientation = "horizontal", inset = 0,
|
|
269
|
+
export function Divider({ orientation = "horizontal", inset = 0, layoutStyle }) {
|
|
268
270
|
if (!Number.isFinite(inset) || inset < 0)
|
|
269
271
|
throw new RangeError("Divider inset must be non-negative");
|
|
270
|
-
warnDeprecatedStyleProps("Divider", { style }, "layoutStyle for placement and orientation/inset for appearance");
|
|
271
272
|
const { colors } = useHjmNativeTheme();
|
|
272
273
|
return (_jsx(View, { accessible: false, style: [
|
|
273
274
|
orientation === "horizontal"
|
|
274
275
|
? { backgroundColor: colors.border, height: 1, marginHorizontal: inset, width: "auto" }
|
|
275
276
|
: { alignSelf: "stretch", backgroundColor: colors.border, marginVertical: inset, width: 1 },
|
|
276
|
-
style,
|
|
277
277
|
layoutStyle,
|
|
278
278
|
] }));
|
|
279
279
|
}
|
|
280
280
|
// UI control labels keep the ui font even when their metric variant is body; content still uses reading.
|
|
281
|
-
export function Accordion({ label, items, expandedValues, defaultExpandedValues = [], onExpandedValuesChange, multiple = accordionRecipe.defaults.allowsMultipleExpanded, density = accordionRecipe.defaults.density, renderIndicator,
|
|
282
|
-
warnDeprecatedStyleProps("Accordion", { style, itemStyle, triggerStyle, titleStyle, indicatorStyle, panelStyle }, "layoutStyle for placement and density/renderIndicator for appearance");
|
|
281
|
+
export function Accordion({ label, items, expandedValues, defaultExpandedValues = [], onExpandedValuesChange, multiple = accordionRecipe.defaults.allowsMultipleExpanded, density = accordionRecipe.defaults.density, renderIndicator, layoutStyle, }) {
|
|
283
282
|
if (items.length === 0)
|
|
284
283
|
throw new Error("Accordion requires at least one item");
|
|
285
284
|
const itemValues = new Set(items.map((item) => item.value));
|
|
286
285
|
if (itemValues.size !== items.length)
|
|
287
286
|
throw new TypeError("Accordion values must be unique");
|
|
288
|
-
const initial = expandedValues ?? defaultExpandedValues;
|
|
289
|
-
if (initial.some((value) => !itemValues.has(value))) {
|
|
290
|
-
throw new RangeError("Accordion expanded values must match items");
|
|
291
|
-
}
|
|
292
|
-
if (!multiple && initial.length > 1) {
|
|
293
|
-
throw new RangeError("Accordion only accepts one expanded value unless multiple is true");
|
|
294
|
-
}
|
|
295
287
|
const theme = useHjmNativeTheme();
|
|
296
288
|
const metrics = accordionRecipe.density[density];
|
|
297
289
|
const indicatorColor = resolveColorReference(accordionRecipe.indicator.color, theme.palette);
|
|
298
|
-
const [
|
|
290
|
+
const [storedExpanded, setExpanded] = useControllableState({
|
|
299
291
|
...(expandedValues === undefined ? {} : { value: expandedValues }),
|
|
300
292
|
defaultValue: defaultExpandedValues,
|
|
301
293
|
...(onExpandedValuesChange === undefined ? {} : { onChange: onExpandedValuesChange }),
|
|
302
294
|
});
|
|
303
|
-
|
|
295
|
+
const committed = useRef(false);
|
|
296
|
+
const expanded = expandedValues === undefined && committed.current ? storedExpanded.filter(value => itemValues.has(value)) : storedExpanded;
|
|
297
|
+
if (expanded.some(value => !itemValues.has(value)))
|
|
298
|
+
throw new RangeError("Accordion expanded values must match items");
|
|
299
|
+
if (!multiple && expanded.length > 1)
|
|
300
|
+
throw new RangeError("Accordion only accepts one expanded value unless multiple is true");
|
|
301
|
+
useLayoutEffect(() => {
|
|
302
|
+
committed.current = true;
|
|
303
|
+
// Retire expansion with the deleted item instead of reopening it when its key returns.
|
|
304
|
+
if (expanded.length !== storedExpanded.length)
|
|
305
|
+
setExpanded(expanded);
|
|
306
|
+
}, [expanded, storedExpanded, setExpanded]);
|
|
307
|
+
return (_jsx(View, { accessibilityLabel: label, accessibilityRole: "list", style: [layoutStyle], children: items.map((item) => {
|
|
304
308
|
const isExpanded = expanded.includes(item.value);
|
|
305
309
|
return (_jsxs(View, { style: [
|
|
306
310
|
{
|
|
307
311
|
borderBottomColor: resolveColorReference(accordionRecipe.divider, theme.palette),
|
|
308
312
|
borderBottomWidth: 1,
|
|
309
313
|
},
|
|
310
|
-
itemStyle,
|
|
311
314
|
], children: [_jsxs(Pressable, { accessibilityHint: item.accessibilityHint, accessibilityLabel: item.accessibilityLabel ?? item.title, accessibilityRole: "button", accessibilityState: { disabled: item.disabled === true, expanded: isExpanded }, ...webOnly(webDisclosureProps(isExpanded, item.disabled === true)), disabled: item.disabled, onPress: () => {
|
|
312
315
|
if (!theme.environment.reducedMotion) {
|
|
313
316
|
LayoutAnimation.configureNext({
|
|
@@ -338,14 +341,12 @@ export function Accordion({ label, items, expandedValues, defaultExpandedValues
|
|
|
338
341
|
paddingHorizontal: accordionRecipe.paddingHorizontal,
|
|
339
342
|
paddingVertical: metrics.paddingVertical,
|
|
340
343
|
},
|
|
341
|
-
triggerStyle,
|
|
342
344
|
], children: [_jsxs(View, { style: { flex: 1, gap: spacing.xxs }, children: [_jsx(Text, { fontRole: "ui", style: [
|
|
343
345
|
{
|
|
344
346
|
color: resolveColorReference(accordionRecipe.title.color, theme.palette),
|
|
345
347
|
fontWeight: accordionRecipe.title.fontWeight,
|
|
346
348
|
},
|
|
347
|
-
|
|
348
|
-
], variant: accordionRecipe.title.textVariant, children: item.title }), item.description ? _jsx(Text, { tone: "muted", variant: "caption", children: item.description }) : null] }), _jsx(View, { accessible: false, style: indicatorStyle, children: renderIndicator ? (renderIndicator({
|
|
349
|
+
], variant: accordionRecipe.title.textVariant, children: item.title }), item.description ? _jsx(Text, { tone: "muted", variant: "caption", children: item.description }) : null] }), _jsx(View, { accessible: false, children: renderIndicator ? (renderIndicator({
|
|
349
350
|
value: item.value,
|
|
350
351
|
expanded: isExpanded,
|
|
351
352
|
disabled: item.disabled === true,
|
|
@@ -356,12 +357,11 @@ export function Accordion({ label, items, expandedValues, defaultExpandedValues
|
|
|
356
357
|
paddingBottom: accordionRecipe.panel.paddingBottom,
|
|
357
358
|
paddingStart: accordionRecipe.panel.paddingInlineStart,
|
|
358
359
|
},
|
|
359
|
-
panelStyle,
|
|
360
360
|
], children: item.content })) : null] }, item.value));
|
|
361
361
|
}) }));
|
|
362
362
|
}
|
|
363
|
-
export function DescriptionList({ label, descriptor, availableWidth,
|
|
364
|
-
|
|
363
|
+
export function DescriptionList({ label, descriptor, availableWidth, layoutStyle, onLayout, ...props }) {
|
|
364
|
+
assertNoRemovedStyleProps("DescriptionList", props, ["style", "itemStyle"]);
|
|
365
365
|
const resolved = resolveDescriptionListDescriptor(descriptor);
|
|
366
366
|
const { width: windowWidth } = useWindowDimensions();
|
|
367
367
|
const { environment } = useHjmNativeTheme();
|
|
@@ -388,9 +388,8 @@ export function DescriptionList({ label, descriptor, availableWidth, style, item
|
|
|
388
388
|
flexWrap: "wrap",
|
|
389
389
|
gap: spacing.sm,
|
|
390
390
|
},
|
|
391
|
-
style,
|
|
392
391
|
layoutStyle,
|
|
393
|
-
], children: resolved.items.map((item) => (_jsxs(View, { accessibilityLabel: `${item.label}, ${item.value}`, accessible: true, style: [{ gap: spacing.xxs, width: itemWidth }
|
|
392
|
+
], children: resolved.items.map((item) => (_jsxs(View, { accessibilityLabel: `${item.label}, ${item.value}`, accessible: true, style: [{ gap: spacing.xxs, width: itemWidth }], children: [_jsx(Text, { accessible: false, tone: "muted", variant: "label", children: item.label }), _jsx(Text, { accessible: false, tone: "primary", children: item.value })] }, item.id))) }));
|
|
394
393
|
}
|
|
395
394
|
function resolveImageSourceKey(source) {
|
|
396
395
|
if (typeof source === "number")
|
|
@@ -415,27 +414,32 @@ export function Image(imageProps) {
|
|
|
415
414
|
const resolvedDecorative = descriptor.decorative;
|
|
416
415
|
const resolvedAccessibilityLabel = descriptor.decorative ? undefined : descriptor.accessibilityLabel;
|
|
417
416
|
const resolvedResizeMode = nativeResizeModes[descriptor.fit];
|
|
418
|
-
const sourceKey = `src:${descriptor.src}`;
|
|
419
417
|
const source = useMemo(() => sourceAdapter?.(descriptor) ?? { uri: descriptor.src }, [descriptor.accessibilityLabel, descriptor.decorative, descriptor.fit,
|
|
420
418
|
descriptor.height, descriptor.src, descriptor.width, sourceAdapter]);
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
419
|
+
// Auth/cache changes can create a new request at the same URL. Compare the
|
|
420
|
+
// resolved source contents, not the inline adapter function's identity.
|
|
421
|
+
const sourceKey = JSON.stringify([descriptor.src, resolveImageSourceKey(source)]);
|
|
422
|
+
// Match the Web image lifecycle: a replaced/unmounted host cannot publish
|
|
423
|
+
// results, including an old A request after the product changes A→B→A.
|
|
424
|
+
const generation = useMemo(() => ({}), [sourceKey]);
|
|
425
|
+
const activeGeneration = useRef(generation);
|
|
426
|
+
useLayoutEffect(() => {
|
|
427
|
+
activeGeneration.current = generation;
|
|
428
|
+
return () => { activeGeneration.current = null; };
|
|
429
|
+
}, [generation]);
|
|
430
|
+
const [state, setState] = useState({ generation, status: "loading" });
|
|
431
|
+
const status = state.generation === generation ? state.status : "loading";
|
|
428
432
|
const reportLoad = (event) => {
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
433
|
+
if (activeGeneration.current !== generation)
|
|
434
|
+
return;
|
|
435
|
+
setState({ generation, status: "loaded" });
|
|
432
436
|
onLoadStatusChange?.("loaded");
|
|
433
437
|
onLoad?.(event);
|
|
434
438
|
};
|
|
435
439
|
const reportError = (event) => {
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
440
|
+
if (activeGeneration.current !== generation)
|
|
441
|
+
return;
|
|
442
|
+
setState({ generation, status: "error" });
|
|
439
443
|
onLoadStatusChange?.("error");
|
|
440
444
|
onError?.(event);
|
|
441
445
|
};
|
|
@@ -529,15 +533,15 @@ const styles = StyleSheet.create({
|
|
|
529
533
|
width: glyph.lg,
|
|
530
534
|
},
|
|
531
535
|
});
|
|
532
|
-
export function CounterBadge({ count, accessibilityLabel, max = counterBadgeRecipe.defaults.max, tone = counterBadgeRecipe.defaults.tone, size = counterBadgeRecipe.defaults.size, variant = counterBadgeRecipe.defaults.variant,
|
|
533
|
-
warnDeprecatedStyleProps("CounterBadge", { style }, "layoutStyle for placement and tone/size/variant for appearance");
|
|
536
|
+
export function CounterBadge({ count, accessibilityLabel, max = counterBadgeRecipe.defaults.max, tone = counterBadgeRecipe.defaults.tone, size = counterBadgeRecipe.defaults.size, variant = counterBadgeRecipe.defaults.variant, layoutStyle, }) {
|
|
534
537
|
if (accessibilityLabel !== undefined && !accessibilityLabel.trim()) {
|
|
535
538
|
throw new TypeError("CounterBadge accessibilityLabel must not be empty");
|
|
536
539
|
}
|
|
540
|
+
// A zero count hides the badge, but must not change its Hook call order.
|
|
541
|
+
const { colors } = useHjmNativeTheme();
|
|
537
542
|
const visibleLabel = formatCounterBadgeCount(count, max);
|
|
538
543
|
if (visibleLabel === null)
|
|
539
544
|
return null;
|
|
540
|
-
const { colors } = useHjmNativeTheme();
|
|
541
545
|
const presentation = {
|
|
542
546
|
danger: { background: colors.dangerFill, content: colors.onDanger },
|
|
543
547
|
brand: { background: colors.primary, content: colors.onPrimary },
|
|
@@ -557,13 +561,12 @@ export function CounterBadge({ count, accessibilityLabel, max = counterBadgeReci
|
|
|
557
561
|
minWidth: metrics.minWidth,
|
|
558
562
|
paddingHorizontal: metrics.paddingHorizontal,
|
|
559
563
|
},
|
|
560
|
-
style,
|
|
561
564
|
layoutStyle,
|
|
562
565
|
], children: _jsx(Text, { accessible: false, align: "center", style: { color: presentation[tone].content, fontWeight: "700" }, variant: "caption", children: visibleLabel }) }));
|
|
563
566
|
}
|
|
564
567
|
/** Semantic list container that owns separator rhythm around composed rows. */
|
|
565
|
-
export function List({ label, children, separator = listRecipe.defaults.separator, appearance = "plain",
|
|
566
|
-
|
|
568
|
+
export function List({ label, children, separator = listRecipe.defaults.separator, appearance = "plain", layoutStyle, ...props }) {
|
|
569
|
+
assertNoRemovedStyleProps("List", props, ["style"]);
|
|
567
570
|
const { colors, environment, tokens } = useHjmNativeTheme();
|
|
568
571
|
const items = Children.toArray(children);
|
|
569
572
|
const separatorContract = listRecipe.separators[separator];
|
|
@@ -580,7 +583,6 @@ export function List({ label, children, separator = listRecipe.defaults.separato
|
|
|
580
583
|
}
|
|
581
584
|
: {}),
|
|
582
585
|
},
|
|
583
|
-
style,
|
|
584
586
|
layoutStyle,
|
|
585
587
|
], children: items.map((item, index) => (_jsxs(View, { children: [item, separatorContract && index < items.length - 1 ? (_jsx(View, { accessible: false, style: {
|
|
586
588
|
backgroundColor: colors.border,
|
|
@@ -590,21 +592,10 @@ export function List({ label, children, separator = listRecipe.defaults.separato
|
|
|
590
592
|
} })) : null] }, isValidElement(item) && item.key !== null ? item.key : `hjm-list-${index}`))) }));
|
|
591
593
|
}
|
|
592
594
|
export function Statistic(props) {
|
|
593
|
-
warnDeprecatedStyleProps("Statistic", {
|
|
594
|
-
style: props.style,
|
|
595
|
-
labelStyle: props.labelStyle,
|
|
596
|
-
valueStyle: props.valueStyle,
|
|
597
|
-
affixStyle: props.affixStyle,
|
|
598
|
-
trendStyle: props.trendStyle,
|
|
599
|
-
hintStyle: props.hintStyle,
|
|
600
|
-
}, "layoutStyle for placement and density/presentation for appearance");
|
|
601
595
|
return renderStatistic(props);
|
|
602
596
|
}
|
|
603
|
-
// StatisticGroup
|
|
604
|
-
|
|
605
|
-
// keeps those internal values from being reported as caller misuse of Statistic.style. A private
|
|
606
|
-
// prop on the public component was rejected because it would leak into the exported type.
|
|
607
|
-
function renderStatistic({ descriptor, density = "comfortable", presentation = "plain", contextLabel, accessibilityLabel, composeAccessibilityLabel, renderTrendMark, style, labelStyle, valueStyle, affixStyle, trendStyle, hintStyle, layoutStyle, }) {
|
|
597
|
+
// StatisticGroup reuses this renderer with its calculated layout width.
|
|
598
|
+
function renderStatistic({ descriptor, density = "comfortable", presentation = "plain", contextLabel, accessibilityLabel, composeAccessibilityLabel, renderTrendMark, layoutStyle, }) {
|
|
608
599
|
const resolved = resolveStatisticDescriptor(descriptor);
|
|
609
600
|
const theme = useHjmNativeTheme();
|
|
610
601
|
const densityContract = statisticRecipe.density[density];
|
|
@@ -643,14 +634,12 @@ function renderStatistic({ descriptor, density = "comfortable", presentation = "
|
|
|
643
634
|
minWidth: 0,
|
|
644
635
|
padding: densityContract.padding,
|
|
645
636
|
},
|
|
646
|
-
style,
|
|
647
637
|
layoutStyle,
|
|
648
638
|
], children: [_jsx(Text, { accessible: false, style: [
|
|
649
639
|
{
|
|
650
640
|
color: resolveColorReference(statisticRecipe.label.color, theme.palette),
|
|
651
641
|
fontWeight: statisticRecipe.label.fontWeight,
|
|
652
642
|
},
|
|
653
|
-
labelStyle,
|
|
654
643
|
], variant: densityContract.labelVariant, children: resolved.label }), _jsxs(View, { accessible: false, style: {
|
|
655
644
|
alignItems: "baseline",
|
|
656
645
|
direction: theme.environment.direction,
|
|
@@ -663,7 +652,6 @@ function renderStatistic({ descriptor, density = "comfortable", presentation = "
|
|
|
663
652
|
color: resolveColorReference(statisticRecipe.affix.color, theme.palette),
|
|
664
653
|
fontWeight: statisticRecipe.affix.fontWeight,
|
|
665
654
|
},
|
|
666
|
-
affixStyle,
|
|
667
655
|
], variant: statisticRecipe.affix.textVariant, children: resolved.prefix })) : null, _jsx(Text, { accessible: false, style: [
|
|
668
656
|
{
|
|
669
657
|
color: resolveColorReference(statisticRecipe.value.color, theme.palette),
|
|
@@ -671,13 +659,11 @@ function renderStatistic({ descriptor, density = "comfortable", presentation = "
|
|
|
671
659
|
fontVariant: ["tabular-nums"],
|
|
672
660
|
fontWeight: statisticRecipe.value.fontWeight,
|
|
673
661
|
},
|
|
674
|
-
valueStyle,
|
|
675
662
|
], variant: densityContract.valueVariant, children: resolved.value }), resolved.suffix ? (_jsx(Text, { accessible: false, style: [
|
|
676
663
|
{
|
|
677
664
|
color: resolveColorReference(statisticRecipe.affix.color, theme.palette),
|
|
678
665
|
fontWeight: statisticRecipe.affix.fontWeight,
|
|
679
666
|
},
|
|
680
|
-
affixStyle,
|
|
681
667
|
], variant: statisticRecipe.affix.textVariant, children: resolved.suffix })) : null] }), resolved.trend ? (_jsxs(View, { accessible: false, style: {
|
|
682
668
|
alignItems: "center",
|
|
683
669
|
flexDirection: "row",
|
|
@@ -690,14 +676,12 @@ function renderStatistic({ descriptor, density = "comfortable", presentation = "
|
|
|
690
676
|
flexShrink: 1,
|
|
691
677
|
fontWeight: statisticRecipe.trend.fontWeight,
|
|
692
678
|
},
|
|
693
|
-
trendStyle,
|
|
694
679
|
], variant: statisticRecipe.trend.textVariant, children: resolved.trend.label })] })) : null, resolved.hint ? (_jsx(Text, { accessible: false, style: [
|
|
695
680
|
{ color: resolveColorReference(statisticRecipe.hint.color, theme.palette) },
|
|
696
|
-
hintStyle,
|
|
697
681
|
], variant: statisticRecipe.hint.textVariant, children: resolved.hint })) : null] }));
|
|
698
682
|
}
|
|
699
|
-
export function StatisticGroup({ label, descriptor, availableWidth, density, presentation, composeAccessibilityLabel, renderTrendMark,
|
|
700
|
-
|
|
683
|
+
export function StatisticGroup({ label, descriptor, availableWidth, density, presentation, composeAccessibilityLabel, renderTrendMark, layoutStyle, onLayout, ...props }) {
|
|
684
|
+
assertNoRemovedStyleProps("StatisticGroup", props, ["style", "itemStyle"]);
|
|
701
685
|
validateStatisticGroup(descriptor);
|
|
702
686
|
const { width: windowWidth } = useWindowDimensions();
|
|
703
687
|
const { environment } = useHjmNativeTheme();
|
|
@@ -736,20 +720,19 @@ export function StatisticGroup({ label, descriptor, availableWidth, density, pre
|
|
|
736
720
|
flexWrap: "wrap",
|
|
737
721
|
gap: statisticRecipe.group.gap,
|
|
738
722
|
},
|
|
739
|
-
style,
|
|
740
723
|
layoutStyle,
|
|
741
|
-
], children: descriptor.items.map((item, index) => (_jsx(StatisticGroupItem, { contextLabel: label, descriptor: item, ...(composeAccessibilityLabel === undefined ? {} : { composeAccessibilityLabel }), ...(density === undefined ? {} : { density }), ...(presentation === undefined ? {} : { presentation }), ...(renderTrendMark === undefined ? {} : { renderTrendMark }), layoutStyle: { width: index >= finalRowStart ? finalRowItemWidth : itemWidth }
|
|
724
|
+
], children: descriptor.items.map((item, index) => (_jsx(StatisticGroupItem, { contextLabel: label, descriptor: item, ...(composeAccessibilityLabel === undefined ? {} : { composeAccessibilityLabel }), ...(density === undefined ? {} : { density }), ...(presentation === undefined ? {} : { presentation }), ...(renderTrendMark === undefined ? {} : { renderTrendMark }), layoutStyle: { width: index >= finalRowStart ? finalRowItemWidth : itemWidth } }, item.id))) }));
|
|
742
725
|
}
|
|
743
726
|
/** Group cell: same render as Statistic without attributing the group's styles to the caller. */
|
|
744
727
|
function StatisticGroupItem(props) {
|
|
745
728
|
return renderStatistic(props);
|
|
746
729
|
}
|
|
747
730
|
/** Ordered record of completed events; unlike Steps it has no current cursor. */
|
|
748
|
-
export function Timeline({ items, composeAccessibleName,
|
|
749
|
-
|
|
731
|
+
export function Timeline({ items, composeAccessibleName, layoutStyle, ...props }) {
|
|
732
|
+
assertNoRemovedStyleProps("Timeline", props, ["style"]);
|
|
750
733
|
const theme = useHjmNativeTheme();
|
|
751
734
|
const resolved = resolveTimelineDescriptor({ items }, { composeAccessibleName });
|
|
752
|
-
return (_jsx(View, { ...props, style: [{ gap: timelineRecipe.gap },
|
|
735
|
+
return (_jsx(View, { ...props, style: [{ gap: timelineRecipe.gap }, layoutStyle], children: resolved.map((item, index) => {
|
|
753
736
|
const tone = timelineRecipe.dot.tones[item.tone];
|
|
754
737
|
const accessibilityLabel = [
|
|
755
738
|
item.accessibleName,
|