jfs-components 0.0.84 → 0.0.86
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/CHANGELOG.md +36 -0
- package/lib/commonjs/components/AllocationComparisonChart/AllocationComparisonChart.js +299 -0
- package/lib/commonjs/components/AppBar/AppBar.js +36 -22
- package/lib/commonjs/components/AreaLineChart/AreaLineChart.js +866 -0
- package/lib/commonjs/components/AreaLineChart/chartMath.js +252 -0
- package/lib/commonjs/components/Attached/Attached.js +34 -4
- package/lib/commonjs/components/BubbleChart/BubbleChart.js +191 -0
- package/lib/commonjs/components/BubbleChart/bubblePacking.js +378 -0
- package/lib/commonjs/components/ClusterBubble/ClusterBubble.js +272 -0
- package/lib/commonjs/components/FullscreenModal/FullscreenModal.js +52 -89
- package/lib/commonjs/components/MetricLegendItem/MetricLegendItem.js +7 -1
- package/lib/commonjs/components/index.js +34 -0
- package/lib/commonjs/design-tokens/Coin Variables-variables-full.json +1 -1
- package/lib/commonjs/icons/registry.js +1 -1
- package/lib/module/components/AllocationComparisonChart/AllocationComparisonChart.js +293 -0
- package/lib/module/components/AppBar/AppBar.js +36 -22
- package/lib/module/components/AreaLineChart/AreaLineChart.js +859 -0
- package/lib/module/components/AreaLineChart/chartMath.js +242 -0
- package/lib/module/components/Attached/Attached.js +34 -4
- package/lib/module/components/BubbleChart/BubbleChart.js +185 -0
- package/lib/module/components/BubbleChart/bubblePacking.js +370 -0
- package/lib/module/components/ClusterBubble/ClusterBubble.js +267 -0
- package/lib/module/components/FullscreenModal/FullscreenModal.js +53 -90
- package/lib/module/components/MetricLegendItem/MetricLegendItem.js +7 -1
- package/lib/module/components/index.js +4 -0
- package/lib/module/design-tokens/Coin Variables-variables-full.json +1 -1
- package/lib/module/icons/registry.js +1 -1
- package/lib/typescript/src/components/AllocationComparisonChart/AllocationComparisonChart.d.ts +118 -0
- package/lib/typescript/src/components/AreaLineChart/AreaLineChart.d.ts +212 -0
- package/lib/typescript/src/components/AreaLineChart/chartMath.d.ts +90 -0
- package/lib/typescript/src/components/BubbleChart/BubbleChart.d.ts +81 -0
- package/lib/typescript/src/components/BubbleChart/bubblePacking.d.ts +83 -0
- package/lib/typescript/src/components/ClusterBubble/ClusterBubble.d.ts +76 -0
- package/lib/typescript/src/components/FullscreenModal/FullscreenModal.d.ts +21 -25
- package/lib/typescript/src/components/MetricLegendItem/MetricLegendItem.d.ts +7 -1
- package/lib/typescript/src/components/index.d.ts +4 -0
- package/lib/typescript/src/icons/registry.d.ts +1 -1
- package/package.json +1 -1
- package/src/components/AllocationComparisonChart/AllocationComparisonChart.tsx +450 -0
- package/src/components/AppBar/AppBar.tsx +37 -24
- package/src/components/AreaLineChart/AreaLineChart.tsx +1161 -0
- package/src/components/AreaLineChart/chartMath.ts +265 -0
- package/src/components/Attached/Attached.tsx +36 -5
- package/src/components/BubbleChart/BubbleChart.tsx +319 -0
- package/src/components/BubbleChart/bubblePacking.ts +397 -0
- package/src/components/ClusterBubble/ClusterBubble.tsx +359 -0
- package/src/components/FullscreenModal/FullscreenModal.tsx +61 -119
- package/src/components/MetricLegendItem/MetricLegendItem.tsx +20 -6
- package/src/components/index.ts +4 -0
- package/src/design-tokens/Coin Variables-variables-full.json +1 -1
- package/src/icons/registry.ts +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,42 @@ All notable changes to this project are documented in this file.
|
|
|
4
4
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
|
6
6
|
|
|
7
|
+
## [0.0.86] - 2026-06-04
|
|
8
|
+
|
|
9
|
+
- Added `AllocationComparisonChart` — vertical pill bars comparing current vs recommended allocation with optional baseline overlay and dashed marker.
|
|
10
|
+
- `FullscreenModal` — removed parallax; hero media scrolls with content and height follows media aspect ratio.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## [0.0.85] - 2026-06-03
|
|
15
|
+
|
|
16
|
+
- Added `AreaLineChart` — multi-series area/line chart with grid, axes, legend, goal pin, and interactive tooltip; exports `useChart` and compound `ChartGrid` / `ChartXAxis` / `ChartYAxis` / `GoalPin` parts.
|
|
17
|
+
- Added `BubbleChart` — packed bubble cluster layout with sqrt-scaled sizes and collision-aware label placement.
|
|
18
|
+
- Added `ClusterBubble` — single data-viz bubble with inside/outside/auto label placement.
|
|
19
|
+
- `AppBar` — SubPage middle slot uses full-height flex overlay (fixes Android vertical misalignment).
|
|
20
|
+
- `Attached` — token-driven outside border ring on the badge slot.
|
|
21
|
+
- `MetricLegendItem` — new `indicatorShape` prop (`dot` | `line`).
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## [0.0.84] - 2026-06-02
|
|
26
|
+
|
|
27
|
+
- Added `Spinner` — animated three-segment loading indicator with gravity-based motion and reduced-motion support.
|
|
28
|
+
- Added 12 icons: `ArrowUp`/`ArrowDown`, chevron-in-circle variants, OS nav icons, `SignIn`/`SignOut`.
|
|
29
|
+
- `AppBar` — SubPage middle slot absolutely centered; new `middleSlotWidth` prop.
|
|
30
|
+
- `Attached` — `badgeSize` / `badgeRadius` to enforce a fixed badge box and clip content.
|
|
31
|
+
- `Checkbox` — 44 pt touch target via `hitSlop` instead of oversized visual box.
|
|
32
|
+
- `Drawer` / `FullscreenModal` — `keyboardShouldPersistTaps="handled"` on scroll content.
|
|
33
|
+
- `DropdownInput` — Android popup positioning fix; `menuOffset` defaults to `formField/gap`.
|
|
34
|
+
- `ExpandableCheckbox` — single-line label/checkbox vertical alignment on Android.
|
|
35
|
+
- `FormField` / `MessageField` — input wrapper reverted to `View`.
|
|
36
|
+
- `TextInput` — native uses `View` wrapper for reliable Android focus; web keeps Pressable tap-to-focus.
|
|
37
|
+
- `PaymentFeedback` — `AppearanceSystem` via `modes` drives default capsule color.
|
|
38
|
+
- `PlanComparisonCard` — 1.8fr/1fr flex grid; removed `labelColumnFlex`.
|
|
39
|
+
- `ListItem` — `leading` no longer defaults to `IconCapsule`; omit/`null` renders nothing.
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
7
43
|
## [0.0.79] - 2026-05-30
|
|
8
44
|
|
|
9
45
|
- Added `Attached` — positions a badge over main content at nine anchor points (corners, edges, center).
|
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = void 0;
|
|
7
|
+
var _react = _interopRequireDefault(require("react"));
|
|
8
|
+
var _reactNative = require("react-native");
|
|
9
|
+
var _reactNativeSvg = _interopRequireWildcard(require("react-native-svg"));
|
|
10
|
+
var _figmaVariablesResolver = require("../../design-tokens/figma-variables-resolver");
|
|
11
|
+
var _JFSThemeProvider = require("../../design-tokens/JFSThemeProvider");
|
|
12
|
+
var _reactUtils = require("../../utils/react-utils");
|
|
13
|
+
var _MetricLegendItem = _interopRequireDefault(require("../MetricLegendItem/MetricLegendItem"));
|
|
14
|
+
var _jsxRuntime = require("react/jsx-runtime");
|
|
15
|
+
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
|
|
16
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
17
|
+
/**
|
|
18
|
+
* One vertical pill in the {@link AllocationComparisonChartProps.data} array.
|
|
19
|
+
*
|
|
20
|
+
* Each segment renders a single bar whose **height encodes `value`** (the
|
|
21
|
+
* "current" reading) and, when supplied, a **`baseline`** overlay drawn from
|
|
22
|
+
* the bottom up with a dashed marker line (the "recommended" reading). Both
|
|
23
|
+
* are measured against the same shared scale so bars and baselines are
|
|
24
|
+
* directly comparable across segments.
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
const DEFAULT_DATA = [{
|
|
28
|
+
label: 'Small & Mid',
|
|
29
|
+
value: 65,
|
|
30
|
+
baseline: 35
|
|
31
|
+
}, {
|
|
32
|
+
label: 'Large',
|
|
33
|
+
value: 25
|
|
34
|
+
}, {
|
|
35
|
+
label: 'Others',
|
|
36
|
+
value: 10
|
|
37
|
+
}];
|
|
38
|
+
const toNumber = (value, fallback) => {
|
|
39
|
+
if (typeof value === 'number') {
|
|
40
|
+
return Number.isFinite(value) ? value : fallback;
|
|
41
|
+
}
|
|
42
|
+
if (typeof value === 'string') {
|
|
43
|
+
const parsed = Number(value);
|
|
44
|
+
return Number.isFinite(parsed) ? parsed : fallback;
|
|
45
|
+
}
|
|
46
|
+
return fallback;
|
|
47
|
+
};
|
|
48
|
+
const toFontWeight = (value, fallback) => {
|
|
49
|
+
if (typeof value === 'number') {
|
|
50
|
+
return String(value);
|
|
51
|
+
}
|
|
52
|
+
if (typeof value === 'string') {
|
|
53
|
+
return value;
|
|
54
|
+
}
|
|
55
|
+
return fallback;
|
|
56
|
+
};
|
|
57
|
+
const isShown = node => node !== undefined && node !== null && node !== false;
|
|
58
|
+
/**
|
|
59
|
+
* Internal: one vertical pill column (the Figma "Segment Indicator"). Not
|
|
60
|
+
* exported — the ergonomic public unit is the chart driven by `data`. The
|
|
61
|
+
* `segmentIndicator/*` token names are mirrored here so design ↔ code token
|
|
62
|
+
* alignment is preserved.
|
|
63
|
+
*/
|
|
64
|
+
function SegmentBar({
|
|
65
|
+
segment,
|
|
66
|
+
barHeightPx,
|
|
67
|
+
baselineHeightPx,
|
|
68
|
+
baselineLabel,
|
|
69
|
+
showMarker,
|
|
70
|
+
theme
|
|
71
|
+
}) {
|
|
72
|
+
const {
|
|
73
|
+
barWidth,
|
|
74
|
+
pillRadius,
|
|
75
|
+
gap,
|
|
76
|
+
currentColor,
|
|
77
|
+
baselineColor,
|
|
78
|
+
lineColor,
|
|
79
|
+
lineSize,
|
|
80
|
+
labelStyle
|
|
81
|
+
} = theme;
|
|
82
|
+
const fillColor = segment.color ?? currentColor;
|
|
83
|
+
const overlayColor = segment.baselineColor ?? baselineColor;
|
|
84
|
+
const showValueLabel = isShown(segment.valueLabel);
|
|
85
|
+
const hasBaseline = baselineHeightPx !== null && baselineHeightPx > 0;
|
|
86
|
+
const overlayHeight = hasBaseline ? Math.min(baselineHeightPx, barHeightPx) : 0;
|
|
87
|
+
const overlayRadius = Math.min(pillRadius, barWidth / 2, overlayHeight / 2);
|
|
88
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
89
|
+
style: {
|
|
90
|
+
flex: 1,
|
|
91
|
+
alignItems: 'center',
|
|
92
|
+
justifyContent: 'flex-end',
|
|
93
|
+
gap
|
|
94
|
+
},
|
|
95
|
+
accessibilityLabel: segment.accessibilityLabel,
|
|
96
|
+
children: [showValueLabel ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
97
|
+
numberOfLines: 1,
|
|
98
|
+
style: labelStyle,
|
|
99
|
+
children: segment.valueLabel
|
|
100
|
+
}) : null, /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
101
|
+
style: {
|
|
102
|
+
width: barWidth,
|
|
103
|
+
height: Math.max(barHeightPx, 1),
|
|
104
|
+
borderRadius: pillRadius,
|
|
105
|
+
backgroundColor: fillColor,
|
|
106
|
+
position: 'relative'
|
|
107
|
+
},
|
|
108
|
+
children: hasBaseline ? /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
|
|
109
|
+
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
110
|
+
style: {
|
|
111
|
+
position: 'absolute',
|
|
112
|
+
left: 0,
|
|
113
|
+
right: 0,
|
|
114
|
+
bottom: 0,
|
|
115
|
+
height: overlayHeight,
|
|
116
|
+
backgroundColor: overlayColor,
|
|
117
|
+
borderBottomLeftRadius: overlayRadius,
|
|
118
|
+
borderBottomRightRadius: overlayRadius
|
|
119
|
+
}
|
|
120
|
+
}), showMarker ? /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
121
|
+
style: {
|
|
122
|
+
position: 'absolute',
|
|
123
|
+
left: 0,
|
|
124
|
+
bottom: overlayHeight,
|
|
125
|
+
height: 0,
|
|
126
|
+
flexDirection: 'row',
|
|
127
|
+
alignItems: 'center'
|
|
128
|
+
},
|
|
129
|
+
pointerEvents: "none",
|
|
130
|
+
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNativeSvg.default, {
|
|
131
|
+
width: barWidth,
|
|
132
|
+
height: Math.max(lineSize, 1),
|
|
133
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNativeSvg.Line, {
|
|
134
|
+
x1: 0,
|
|
135
|
+
y1: Math.max(lineSize, 1) / 2,
|
|
136
|
+
x2: barWidth,
|
|
137
|
+
y2: Math.max(lineSize, 1) / 2,
|
|
138
|
+
stroke: lineColor,
|
|
139
|
+
strokeWidth: lineSize,
|
|
140
|
+
strokeDasharray: "2 2"
|
|
141
|
+
})
|
|
142
|
+
}), isShown(baselineLabel) ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
143
|
+
numberOfLines: 1,
|
|
144
|
+
style: [labelStyle, {
|
|
145
|
+
marginLeft: 6
|
|
146
|
+
}],
|
|
147
|
+
children: baselineLabel
|
|
148
|
+
}) : null]
|
|
149
|
+
}) : null]
|
|
150
|
+
}) : null
|
|
151
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
152
|
+
numberOfLines: 1,
|
|
153
|
+
style: labelStyle,
|
|
154
|
+
children: segment.label
|
|
155
|
+
})]
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* `AllocationComparisonChart` plots a row of vertical pill bars that compare a
|
|
161
|
+
* **current** reading (each bar's height) against an optional **recommended**
|
|
162
|
+
* baseline (a filled overlay drawn from the bottom up, marked with a dashed
|
|
163
|
+
* line). Every bar and baseline shares a single scale, so heights are directly
|
|
164
|
+
* comparable across segments — no axes required.
|
|
165
|
+
*
|
|
166
|
+
* The chart is driven entirely by the `data` array: each entry pairs a
|
|
167
|
+
* `value`, an optional `baseline` and its `label`, so a bar can never drift
|
|
168
|
+
* out of sync with its caption or its baseline marker.
|
|
169
|
+
*
|
|
170
|
+
* Colors, fonts, spacing and the pill radius resolve from the Figma
|
|
171
|
+
* `segmentIndicator/*`, `metricLegendItem/*` and `allocationComparisonChart/*`
|
|
172
|
+
* tokens via the `modes` prop.
|
|
173
|
+
*
|
|
174
|
+
* @component
|
|
175
|
+
*/
|
|
176
|
+
function AllocationComparisonChart({
|
|
177
|
+
data = DEFAULT_DATA,
|
|
178
|
+
max,
|
|
179
|
+
height = 154,
|
|
180
|
+
barWidth,
|
|
181
|
+
showLegend = true,
|
|
182
|
+
valueLegendLabel = 'Current',
|
|
183
|
+
baselineLegendLabel = 'Recommended',
|
|
184
|
+
formatValue = value => `${value}%`,
|
|
185
|
+
modes: propModes = _reactUtils.EMPTY_MODES,
|
|
186
|
+
style,
|
|
187
|
+
chartStyle,
|
|
188
|
+
legendStyle,
|
|
189
|
+
accessibilityLabel
|
|
190
|
+
}) {
|
|
191
|
+
const {
|
|
192
|
+
modes: globalModes
|
|
193
|
+
} = (0, _JFSThemeProvider.useTokens)();
|
|
194
|
+
const modes = _react.default.useMemo(() => ({
|
|
195
|
+
...globalModes,
|
|
196
|
+
...propModes
|
|
197
|
+
}), [globalModes, propModes]);
|
|
198
|
+
const trackWidth = toNumber((0, _figmaVariablesResolver.getVariableByName)('segmentIndicator/track/width', modes), 28);
|
|
199
|
+
const resolvedBarWidth = barWidth ?? trackWidth;
|
|
200
|
+
const radiusToken = toNumber((0, _figmaVariablesResolver.getVariableByName)('segmentIndicator/indicator/radius', modes), 99999);
|
|
201
|
+
const pillRadius = Math.min(radiusToken, resolvedBarWidth / 2);
|
|
202
|
+
const gap = toNumber((0, _figmaVariablesResolver.getVariableByName)('segmentIndicator/gap', modes), 4);
|
|
203
|
+
const chartGap = toNumber((0, _figmaVariablesResolver.getVariableByName)('allocationComparisonChart/gap', modes), 8);
|
|
204
|
+
const currentColor = (0, _figmaVariablesResolver.getVariableByName)('segmentIndicator/indicator/background', modes) ?? '#5d00b5';
|
|
205
|
+
const baselineColor = (0, _figmaVariablesResolver.getVariableByName)('segmentIndicator/indicator/foreground', modes) ?? '#b84fbd';
|
|
206
|
+
const lineColor = (0, _figmaVariablesResolver.getVariableByName)('segmentIndicator/indicator/line/color', modes) ?? '#ffffff';
|
|
207
|
+
const lineSize = toNumber((0, _figmaVariablesResolver.getVariableByName)('segmentIndicator/indicator/line/size', modes), 1);
|
|
208
|
+
const foreground = (0, _figmaVariablesResolver.getVariableByName)('segmentIndicator/foreground', modes) ?? '#0c0d10';
|
|
209
|
+
const fontFamily = (0, _figmaVariablesResolver.getVariableByName)('segmentIndicator/fontFamily', modes) ?? 'JioType Var';
|
|
210
|
+
const fontSize = toNumber((0, _figmaVariablesResolver.getVariableByName)('segmentIndicator/fontSize', modes), 12);
|
|
211
|
+
const lineHeight = toNumber((0, _figmaVariablesResolver.getVariableByName)('segmentIndicator/lineHeight', modes), 12);
|
|
212
|
+
const fontWeight = toFontWeight((0, _figmaVariablesResolver.getVariableByName)('segmentIndicator/fontWeight', modes), '400');
|
|
213
|
+
const labelStyle = {
|
|
214
|
+
color: foreground,
|
|
215
|
+
fontFamily,
|
|
216
|
+
fontSize,
|
|
217
|
+
lineHeight,
|
|
218
|
+
fontWeight,
|
|
219
|
+
textAlign: 'center'
|
|
220
|
+
};
|
|
221
|
+
const computedMax = max ?? data.reduce((acc, seg) => Math.max(acc, seg.value, seg.baseline ?? 0), 0);
|
|
222
|
+
const safeMax = computedMax > 0 ? computedMax : 1;
|
|
223
|
+
const firstBaselineIndex = data.findIndex(seg => typeof seg.baseline === 'number');
|
|
224
|
+
const hasAnyBaseline = firstBaselineIndex !== -1;
|
|
225
|
+
const theme = {
|
|
226
|
+
barWidth: resolvedBarWidth,
|
|
227
|
+
pillRadius,
|
|
228
|
+
gap,
|
|
229
|
+
currentColor,
|
|
230
|
+
baselineColor,
|
|
231
|
+
lineColor,
|
|
232
|
+
lineSize,
|
|
233
|
+
labelStyle
|
|
234
|
+
};
|
|
235
|
+
const defaultAccessibilityLabel = accessibilityLabel ?? `Allocation comparison of ${data.length} segment${data.length === 1 ? '' : 's'}: ` + data.map(seg => {
|
|
236
|
+
const label = typeof seg.label === 'string' ? seg.label : 'segment';
|
|
237
|
+
const base = typeof seg.baseline === 'number' ? `, recommended ${seg.baseline}` : '';
|
|
238
|
+
return `${label} ${seg.value}${base}`;
|
|
239
|
+
}).join('; ');
|
|
240
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
241
|
+
style: [{
|
|
242
|
+
width: '100%'
|
|
243
|
+
}, style],
|
|
244
|
+
accessibilityLabel: defaultAccessibilityLabel,
|
|
245
|
+
children: [showLegend ? /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
246
|
+
style: [{
|
|
247
|
+
flexDirection: 'row',
|
|
248
|
+
alignItems: 'center',
|
|
249
|
+
gap: 8,
|
|
250
|
+
marginBottom: chartGap
|
|
251
|
+
}, legendStyle],
|
|
252
|
+
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_MetricLegendItem.default, {
|
|
253
|
+
label: valueLegendLabel,
|
|
254
|
+
indicatorColor: currentColor,
|
|
255
|
+
modes: modes,
|
|
256
|
+
style: {
|
|
257
|
+
flexGrow: 0,
|
|
258
|
+
flexShrink: 1
|
|
259
|
+
}
|
|
260
|
+
}), hasAnyBaseline ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_MetricLegendItem.default, {
|
|
261
|
+
label: baselineLegendLabel,
|
|
262
|
+
indicatorColor: baselineColor,
|
|
263
|
+
modes: modes,
|
|
264
|
+
style: {
|
|
265
|
+
flexGrow: 0,
|
|
266
|
+
flexShrink: 1
|
|
267
|
+
}
|
|
268
|
+
}) : null]
|
|
269
|
+
}) : null, /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
270
|
+
accessibilityRole: "image",
|
|
271
|
+
style: [{
|
|
272
|
+
flexDirection: 'row',
|
|
273
|
+
alignItems: 'flex-end',
|
|
274
|
+
gap: 8,
|
|
275
|
+
width: '100%'
|
|
276
|
+
}, chartStyle],
|
|
277
|
+
children: data.map((segment, index) => {
|
|
278
|
+
const ratio = Math.max(0, Math.min(1, segment.value / safeMax));
|
|
279
|
+
const barHeightPx = Math.max(0, height * ratio);
|
|
280
|
+
const baselineHeightPx = typeof segment.baseline === 'number' ? Math.max(0, Math.min(1, segment.baseline / safeMax)) * height : null;
|
|
281
|
+
const baselineLabel = segment.baselineLabel === undefined ? typeof segment.baseline === 'number' ? formatValue(segment.baseline) : undefined : segment.baselineLabel;
|
|
282
|
+
const resolvedSegment = {
|
|
283
|
+
...segment,
|
|
284
|
+
valueLabel: segment.valueLabel === undefined ? formatValue(segment.value) : segment.valueLabel
|
|
285
|
+
};
|
|
286
|
+
const showMarker = segment.showMarker ?? index === firstBaselineIndex;
|
|
287
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsx)(SegmentBar, {
|
|
288
|
+
segment: resolvedSegment,
|
|
289
|
+
barHeightPx: barHeightPx,
|
|
290
|
+
baselineHeightPx: baselineHeightPx,
|
|
291
|
+
baselineLabel: baselineLabel,
|
|
292
|
+
showMarker: showMarker,
|
|
293
|
+
theme: theme
|
|
294
|
+
}, segment.key ?? `segment-${index}`);
|
|
295
|
+
})
|
|
296
|
+
})]
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
var _default = exports.default = AllocationComparisonChart;
|
|
@@ -139,21 +139,31 @@ function AppBar({
|
|
|
139
139
|
justifyContent: hasInFlowMiddle ? 'flex-start' : 'space-between'
|
|
140
140
|
};
|
|
141
141
|
|
|
142
|
-
// Absolutely-
|
|
143
|
-
// `left
|
|
144
|
-
//
|
|
145
|
-
//
|
|
146
|
-
|
|
142
|
+
// Absolutely-positioned overlay for the SubPage middle slot. Instead of
|
|
143
|
+
// centering a fixed-height box with `top/left: 50%` + transform (which on
|
|
144
|
+
// Android resolves the percentage against an intermediate, content-driven
|
|
145
|
+
// parent height and lands a few px too high), the overlay STRETCHES to fill
|
|
146
|
+
// the whole bar (`top/bottom/left/right: 0`) and centers its content with
|
|
147
|
+
// flexbox. This uses the exact same full-height vertical reference as the
|
|
148
|
+
// leading/actions row (`alignItems: 'center'`), so the middle content always
|
|
149
|
+
// sits on the same line as the back arrow and end slot on every platform.
|
|
150
|
+
const subPageMiddleOverlayStyle = {
|
|
147
151
|
position: 'absolute',
|
|
148
|
-
top:
|
|
149
|
-
left:
|
|
152
|
+
top: 0,
|
|
153
|
+
left: 0,
|
|
154
|
+
right: 0,
|
|
155
|
+
bottom: 0,
|
|
156
|
+
flexDirection: 'row',
|
|
157
|
+
alignItems: 'center',
|
|
158
|
+
justifyContent: 'center'
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
// Fixed-width clipping box (mirrors the Figma "slot wrap" geometry): keeps the
|
|
162
|
+
// middle content from bleeding under the leading/actions slots while staying
|
|
163
|
+
// centered within the overlay above.
|
|
164
|
+
const subPageMiddleBoxStyle = {
|
|
150
165
|
width: middleSlotWidth,
|
|
151
166
|
height: SUBPAGE_MIDDLE_HEIGHT,
|
|
152
|
-
transform: [{
|
|
153
|
-
translateX: -middleSlotWidth / 2
|
|
154
|
-
}, {
|
|
155
|
-
translateY: -SUBPAGE_MIDDLE_HEIGHT / 2
|
|
156
|
-
}],
|
|
157
167
|
flexDirection: 'row',
|
|
158
168
|
alignItems: 'center',
|
|
159
169
|
justifyContent: 'center',
|
|
@@ -188,19 +198,23 @@ function AppBar({
|
|
|
188
198
|
style: actionsStyle,
|
|
189
199
|
children: processedActions
|
|
190
200
|
}), isSub && processedMiddle && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
191
|
-
style:
|
|
201
|
+
style: subPageMiddleOverlayStyle,
|
|
192
202
|
pointerEvents: "box-none",
|
|
193
203
|
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
194
|
-
style:
|
|
195
|
-
flex: 1,
|
|
196
|
-
minWidth: 1,
|
|
197
|
-
height: '100%',
|
|
198
|
-
flexDirection: 'row',
|
|
199
|
-
alignItems: 'center',
|
|
200
|
-
justifyContent: 'center'
|
|
201
|
-
},
|
|
204
|
+
style: subPageMiddleBoxStyle,
|
|
202
205
|
pointerEvents: "box-none",
|
|
203
|
-
children:
|
|
206
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
207
|
+
style: {
|
|
208
|
+
flex: 1,
|
|
209
|
+
minWidth: 1,
|
|
210
|
+
height: '100%',
|
|
211
|
+
flexDirection: 'row',
|
|
212
|
+
alignItems: 'center',
|
|
213
|
+
justifyContent: 'center'
|
|
214
|
+
},
|
|
215
|
+
pointerEvents: "box-none",
|
|
216
|
+
children: processedMiddle
|
|
217
|
+
})
|
|
204
218
|
})
|
|
205
219
|
})]
|
|
206
220
|
});
|