jfs-components 0.1.49 → 0.1.51

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.
Files changed (61) hide show
  1. package/.cursor/D2C-FLOW.md +94 -0
  2. package/.cursor/D2C-SCREEN.md +119 -0
  3. package/.cursor/commands/D2C.md +101 -0
  4. package/CHANGELOG.md +14 -0
  5. package/lib/commonjs/components/CardCTA/CardCTA.js +7 -4
  6. package/lib/commonjs/components/CardFeedback/CardFeedback.js +1 -1
  7. package/lib/commonjs/components/CategoryCard/CategoryCard.js +4 -4
  8. package/lib/commonjs/components/Checkbox/Checkbox.js +4 -6
  9. package/lib/commonjs/components/CircularProgressBarDoted/CircularProgressBarDoted.js +12 -9
  10. package/lib/commonjs/components/DonutChartSummary/DonutChartSummary.js +7 -2
  11. package/lib/commonjs/components/ProductMerchandisingCard/ProductMerchandisingCard.js +3 -1
  12. package/lib/commonjs/components/ProductOverview/ProductOverview.js +2 -2
  13. package/lib/commonjs/components/Radio/Radio.js +5 -3
  14. package/lib/commonjs/components/SavingsGoalSummary/SavingsGoalSummary.js +2 -2
  15. package/lib/commonjs/components/SegmentedControl/SegmentedControl.js +1 -1
  16. package/lib/commonjs/components/SegmentedTrack/SegmentedTrack.js +1 -1
  17. package/lib/commonjs/components/Slider/Slider.js +3 -2
  18. package/lib/commonjs/components/StatusHero/StatusHero.js +1 -1
  19. package/lib/commonjs/components/Tooltip/Tooltip.js +4 -2
  20. package/lib/commonjs/design-tokens/Coin Variables-variables-full.json +1 -1
  21. package/lib/commonjs/design-tokens/figma-modes.generated.js +31 -28
  22. package/lib/commonjs/icons/registry.js +1 -1
  23. package/lib/module/components/CardCTA/CardCTA.js +7 -4
  24. package/lib/module/components/CardFeedback/CardFeedback.js +1 -1
  25. package/lib/module/components/CategoryCard/CategoryCard.js +4 -4
  26. package/lib/module/components/Checkbox/Checkbox.js +4 -6
  27. package/lib/module/components/CircularProgressBarDoted/CircularProgressBarDoted.js +12 -9
  28. package/lib/module/components/DonutChartSummary/DonutChartSummary.js +7 -2
  29. package/lib/module/components/ProductMerchandisingCard/ProductMerchandisingCard.js +3 -1
  30. package/lib/module/components/ProductOverview/ProductOverview.js +2 -2
  31. package/lib/module/components/Radio/Radio.js +5 -3
  32. package/lib/module/components/SavingsGoalSummary/SavingsGoalSummary.js +2 -2
  33. package/lib/module/components/SegmentedControl/SegmentedControl.js +1 -1
  34. package/lib/module/components/SegmentedTrack/SegmentedTrack.js +1 -1
  35. package/lib/module/components/Slider/Slider.js +3 -2
  36. package/lib/module/components/StatusHero/StatusHero.js +1 -1
  37. package/lib/module/components/Tooltip/Tooltip.js +4 -2
  38. package/lib/module/design-tokens/Coin Variables-variables-full.json +1 -1
  39. package/lib/module/design-tokens/figma-modes.generated.js +31 -28
  40. package/lib/module/icons/registry.js +1 -1
  41. package/lib/typescript/src/design-tokens/figma-modes.generated.d.ts +4 -1
  42. package/lib/typescript/src/icons/registry.d.ts +1 -1
  43. package/package.json +4 -2
  44. package/src/components/CardCTA/CardCTA.tsx +7 -4
  45. package/src/components/CardFeedback/CardFeedback.tsx +1 -1
  46. package/src/components/CategoryCard/CategoryCard.tsx +4 -4
  47. package/src/components/Checkbox/Checkbox.tsx +4 -6
  48. package/src/components/CircularProgressBarDoted/CircularProgressBarDoted.tsx +12 -9
  49. package/src/components/DonutChartSummary/DonutChartSummary.tsx +6 -6
  50. package/src/components/ProductMerchandisingCard/ProductMerchandisingCard.tsx +3 -1
  51. package/src/components/ProductOverview/ProductOverview.tsx +2 -2
  52. package/src/components/Radio/Radio.tsx +8 -3
  53. package/src/components/SavingsGoalSummary/SavingsGoalSummary.tsx +3 -3
  54. package/src/components/SegmentedControl/SegmentedControl.tsx +1 -1
  55. package/src/components/SegmentedTrack/SegmentedTrack.tsx +1 -2
  56. package/src/components/Slider/Slider.tsx +3 -2
  57. package/src/components/StatusHero/StatusHero.tsx +1 -1
  58. package/src/components/Tooltip/Tooltip.tsx +4 -2
  59. package/src/design-tokens/Coin Variables-variables-full.json +1 -1
  60. package/src/design-tokens/figma-modes.generated.ts +31 -28
  61. package/src/icons/registry.ts +1 -1
@@ -0,0 +1,94 @@
1
+ # D2C multi-screen orchestration
2
+
3
+ Load only when scope discovery finds two or more `ScreenSpec`s. The main agent
4
+ is the orchestrator: it owns contracts, shared files, integration, and
5
+ end-to-end QA. Each implementation agent owns exactly one screen family.
6
+
7
+ ## 1. Prepare conflict-free contracts
8
+
9
+ Before launching agents:
10
+
11
+ 1. Define the transition graph and typed step model.
12
+ 2. Define shared props/callbacks, fake data, validation, timing, and persistence.
13
+ 3. Create the minimum scaffold: host/navigator, shared types, placeholders.
14
+ 4. Assign each family:
15
+ - one screen file;
16
+ - uniquely named mode file(s);
17
+ - `assets/<screen-key>/`.
18
+ 5. Only the orchestrator edits the host/shared types. Agents cannot edit other
19
+ screens or clear shared directories.
20
+
21
+ Typical recording-demo layout:
22
+
23
+ ```text
24
+ RecordingDemoScreen.tsx # orchestrator
25
+ types.ts # orchestrator
26
+ SignInScreen.tsx # Sign In agent
27
+ signInModes.json
28
+ assets/sign-in/
29
+ OtpScreen.tsx # OTP agent
30
+ otpModes.json
31
+ assets/otp/
32
+ ```
33
+
34
+ ## 2. Launch one agent per family
35
+
36
+ After shared ambiguities are resolved and the scaffold exists, launch all
37
+ independent agents in one parallel batch when possible; honor configured model
38
+ preferences. Do not create one agent per state or combine unrelated screens.
39
+
40
+ Each prompt is self-contained:
41
+
42
+ ```text
43
+ absolute repo path; platform/stack; recording-demo placement
44
+ owned files/directories + explicit do-not-edit list
45
+ original flow URL + parent node
46
+ primary node URL + all variant URLs/state meanings
47
+ purpose + relationship to preceding/following screens
48
+ shared TypeScript contract; input/output/persistence
49
+ resolved fake-data, validation, navigation, timing behavior
50
+ exact jfs-extract-modes commands + output paths
51
+ files/rules/examples to read, including .cursor/D2C-SCREEN.md
52
+ acceptance criteria + required completion summary
53
+ STOP-BEFORE-EDIT rule for material ambiguity
54
+ ```
55
+
56
+ Each agent independently executes `.cursor/D2C-SCREEN.md`, implements only its
57
+ family/local states, runs focused checks, and returns its report.
58
+
59
+ ## 3. Integrate actual deliverables
60
+
61
+ After all agents finish, inspect files—not only summaries:
62
+
63
+ 1. Confirm all placeholders are replaced and imports/modes/assets exist.
64
+ 2. Resolve conflicts, duplicates, missing assets, invalid props, and inconsistent
65
+ mode merging.
66
+ 3. Wire every transition and thread shared data/persistence.
67
+ 4. Keep variant states local to the correct family.
68
+ 5. Verify Back/Skip/Cancel/retry/resend, CTA states, and terminal paths.
69
+ 6. Keep fake flows local; do not add network/server dependencies.
70
+ 7. Re-run typecheck/lint/build; separate new failures from existing ones.
71
+
72
+ ## 4. End-to-end QA
73
+
74
+ Render the complete journey on the target platform:
75
+
76
+ - reach every terminal path from the intended start;
77
+ - test all forward, Back, Skip, and Cancel branches;
78
+ - test cross-screen validation, persistence, retry/resend, disabled/enabled
79
+ actions, transient timing, and repeated presses;
80
+ - capture every real screen and materially different state;
81
+ - verify keyboard/numpad, scrolling, sticky footers, and safe areas.
82
+
83
+ One successful screen is not proof of the flow. Fix integration differences and
84
+ recapture. If tooling is unavailable, report the exact remaining manual QA.
85
+
86
+ ## Completion report
87
+
88
+ Report briefly:
89
+
90
+ - detected families and grouped variants;
91
+ - final transition graph and shared/fake-data behavior;
92
+ - files, assets, and mode outputs per screen;
93
+ - checks, paths, and edge cases exercised;
94
+ - per-screen visual status and blockers.
@@ -0,0 +1,119 @@
1
+ # D2C per-screen execution
2
+
3
+ Load only after scope discovery provides a `ScreenSpec`. Applies to direct
4
+ single-screen work and each screen agent in a flow.
5
+
6
+ ## 1. Gather evidence
7
+
8
+ Read the Figma design-to-code skill before Figma calls.
9
+
10
+ 1. `get_design_context` for the primary node and variants needed to understand
11
+ visual/interactive differences.
12
+ 2. `get_screenshot` for the primary and materially different variants; retain
13
+ them for QA.
14
+ 3. `get_metadata` when hierarchy, visibility, assets, or duplicate names need
15
+ disambiguation.
16
+ 4. Follow Code Connect, component docs, annotations, and hidden-layer metadata.
17
+ 5. Use exact exported images/icons. Download them into the repository; never
18
+ commit expiring/localhost URLs, placeholders, hand-authored SVGs, or a new
19
+ icon package.
20
+
21
+ If MCP cannot read a required node, report the blocker and stop.
22
+
23
+ ## 2. Extract modes through Figma REST
24
+
25
+ From the consuming repository:
26
+
27
+ ```bash
28
+ npx jfs-extract-modes "<node-specific-figma-url>" --out "<unique-output>.json"
29
+ ```
30
+
31
+ Fallback:
32
+
33
+ ```bash
34
+ node node_modules/jfs-components/scripts/extract-figma-modes.js \
35
+ "<node-specific-figma-url>" --out "<unique-output>.json"
36
+ ```
37
+
38
+ Extract a variant separately if selected modes differ from the primary. The CLI
39
+ reads `FIGMA_ACCESS_TOKEN` from root `.env` (exported env wins). Never print it
40
+ or ask the user to paste it into chat. Required scope: `file_content:read`.
41
+
42
+ If missing, direct the user to `[Open .env](.env)` and add
43
+ `FIGMA_ACCESS_TOKEN=`. Creation path: Figma file browser → account menu →
44
+ Settings → Security → Personal access tokens → Generate; choose expiry and only
45
+ `file_content:read`; copy once into `.env`. Never create/overwrite it yourself.
46
+ [Official PAT docs](https://developers.figma.com/docs/rest-api/personal-access-tokens/).
47
+
48
+ Resolve modes:
49
+
50
+ 1. Start with `inheritedFromAncestors`.
51
+ 2. Collect entries for the component path and its ancestors.
52
+ 3. Merge root → leaf; deeper entries override.
53
+ 4. Match name/position; use `nodeId` for duplicates.
54
+
55
+ If `unresolved` exists, report every item/reason and stop:
56
+
57
+ - `local collection`: packaged data cannot resolve a file-local collection.
58
+ - `key not in variables JSON` / `mode not in collection`: packaged tokens stale.
59
+
60
+ ## 3. Implement
61
+
62
+ Inspect actual `jfs-components` exports/types and nearby project examples first.
63
+
64
+ - Implement one screen family; variants are local component state.
65
+ - Use user-specified fake data, validation, navigation, timing, and persistence.
66
+ - Prefer mapped components; primitives only for necessary layout.
67
+ - Apply modes to the closest represented component/subtree. Preserve parent
68
+ inheritance and child overrides; never flatten, move, substitute, or omit
69
+ selected modes.
70
+ - Match content, order, visibility, variants, spacing, and assets; omit hidden
71
+ layers.
72
+ - Never invent a component, prop, or icon.
73
+
74
+ Component contracts:
75
+
76
+ - Titles: reproduce line count with `numberOfLines`/`disableTruncation`.
77
+ - SubPage `AppBar`: trailing actions in a Fragment so action gaps apply.
78
+ - Consent + CTA `ActionFooter`: one column child:
79
+ `<View style={{ flexGrow: 1, minWidth: 0, gap: 8 }}>`.
80
+ - Multiple IMAGE fills: last fill is visually topmost.
81
+ - Icons: exact registry `ic_*` glyph when available; otherwise exact exported
82
+ asset. Use a packaged substitute only when it clearly matches.
83
+
84
+ Run focused type/lint checks.
85
+
86
+ ## 4. Visual and interaction QA
87
+
88
+ Render on the target platform. Recording-demo boots directly into its host.
89
+ Prefer `npm run simulator`, then capture device screenshots.
90
+
91
+ For the primary and every materially different variant, compare:
92
+
93
+ - component size, variant, emphasis, color, spacing, and alignment;
94
+ - text content, wrapping, and truncation;
95
+ - icons/images and visibility;
96
+ - AppBar safe area/actions;
97
+ - scrolling/below-fold content;
98
+ - keyboard/numpad and sticky footer/home-indicator clearance.
99
+
100
+ Exercise applicable behavior:
101
+
102
+ - empty/partial/complete inputs and validation boundaries;
103
+ - immutable formatting and disabled/enabled CTA;
104
+ - selection, retry/resend, persistence, transient timing, rapid presses;
105
+ - incoming/outgoing navigation callbacks.
106
+
107
+ Fix differences and recapture. If render tooling is unavailable, do not claim
108
+ visual completion; report the blocker and exact manual verification.
109
+
110
+ ## Return to orchestrator / completion report
111
+
112
+ Report briefly:
113
+
114
+ - files, mode outputs, and assets;
115
+ - effective modes;
116
+ - local states and behavior;
117
+ - navigation callbacks/data contract;
118
+ - checks and edge cases exercised;
119
+ - visual status and blockers.
@@ -0,0 +1,101 @@
1
+ # D2C — Figma to jfs-components
2
+
3
+ Build the supplied Figma node with `jfs-components`. The link may represent one
4
+ screen, states of one screen, or a complete flow. **Discover scope before
5
+ implementation.**
6
+
7
+ ## Invariants
8
+
9
+ - User-stated behavior is authoritative. Figma defines visuals and designed
10
+ states, not unspecified product logic.
11
+ - Use Figma MCP. Never recreate an unreadable design from assumptions.
12
+ - Use real package exports/props and extracted modes. Stop on unresolved modes.
13
+ - Fake demos stay local unless the user explicitly requests a service.
14
+ - This may be recorded: present a clean first implementation. Never mention
15
+ prior attempts, cached knowledge, mistakes, or “fixes.” Be concise:
16
+ discover → clarify → execute → verify.
17
+
18
+ ## 0. Input and placement
19
+
20
+ Use the Figma URL after `/D2C` or in the latest prompt; ask for it if absent.
21
+
22
+ On mobile, each root must be <Screen> wrapped in in `SafeAreaView`
23
+ (from `react-native-safe-area-context` when the project already uses it,
24
+ otherwise `react-native`) so notches and home indicators are respected — do not
25
+ rely on the host to add it.
26
+
27
+ ## 1. Discover screen families
28
+
29
+ On the linked node:
30
+
31
+ 1. Read the Figma design-to-code skill; call `get_design_context` with its
32
+ required skill logging parameter.
33
+ 2. Call `get_screenshot` for the complete overview.
34
+ 3. Call `get_metadata` to inventory visible screen-sized frames: IDs, names,
35
+ hierarchy, dimensions, order, and visibility.
36
+ 4. Inspect prototype links, annotations, titles, actions, repeated structure,
37
+ and spatial order. Never infer flow from left-to-right placement alone.
38
+
39
+ Group every frame into a **screen family**:
40
+
41
+ - Same family: same user goal/step, major layout, and data model; differences
42
+ are state (empty/filled/focused/disabled, selected, loading/success/error,
43
+ OTP progress/resend/invalid, expanded, toast/keyboard, scroll position).
44
+ - Different family: different goal/step, content model, primary interaction,
45
+ destination, or substantially different layout.
46
+ - If uncertain, inspect children/prototype links; frame names are weak evidence.
47
+
48
+ Create one internal `ScreenSpec` per family:
49
+
50
+ ```text
51
+ key + purpose
52
+ primary node ID + exact URL
53
+ variant node IDs/URLs + state meaning
54
+ incoming/outgoing transitions (Back/Skip/Cancel/retry included)f
55
+ input/output/shared data
56
+ user-specified behavior
57
+ material unknowns
58
+ ```
59
+
60
+ Before coding, briefly report the family count and grouped variants.
61
+
62
+ ## 2. Clarify once
63
+
64
+ Ask one consolidated question set only for material behavior not answered by
65
+ Figma, the prompt, or project conventions:
66
+
67
+ - validation/formatting/immutable prefixes/lengths;
68
+ - fake operation success/failure and error states;
69
+ - initial/terminal screens and Back/Skip/Cancel destinations;
70
+ - backward-navigation persistence;
71
+ - splash/loading/toast/resend/auto-advance timing;
72
+ - platform-specific behavior.
73
+
74
+ Default cosmetic details only; never invent product logic.
75
+
76
+ ## 3. Route
77
+
78
+ ### One family
79
+
80
+ Variants are local state, never separate routes.
81
+
82
+ 1. Read `.cursor/D2C-SCREEN.md`.
83
+ 2. Execute it directly for the `ScreenSpec`.
84
+
85
+ ### Two or more families
86
+
87
+ The linked node is a flow.
88
+
89
+ 1. Resolve shared material unknowns before implementation.
90
+ 2. Read `.cursor/D2C-FLOW.md`.
91
+ 3. Orchestrate one implementation agent per `ScreenSpec`.
92
+ 4. Every screen agent must read and execute `.cursor/D2C-SCREEN.md`.
93
+ 5. The orchestrator integrates and verifies the entire transition graph.
94
+
95
+ If a screen agent finds a material unknown, it stops before editing and reports
96
+ the precise question; the orchestrator asks the user and resumes it.
97
+
98
+ ## Completion
99
+
100
+ Follow the reporting contract in the loaded reference file(s). Keep the final
101
+ report factual and brief.
package/CHANGELOG.md CHANGED
@@ -4,6 +4,20 @@ 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.1.51] - 2026-07-26
8
+
9
+ - Packages the Cursor D2C playbooks with the npm release: `.cursor/commands/D2C.md`, `.cursor/D2C-FLOW.md`, and `.cursor/D2C-SCREEN.md` (replacing the removed root `D2C.md` entry in `package.json` `files`).
10
+ - D2C command — mobile roots must wrap `<Screen>` in `SafeAreaView` (no longer assumes a recording-demo host provides it).
11
+
12
+ ---
13
+
14
+ ## [0.1.50] - 2026-07-25
15
+
16
+ - Token resolution pass — remapped unresolved `getVariableByName` refs and bad mode keys against Figma Code Connect / Coin Variables (CardCTA, CategoryCard, Checkbox, CircularProgressBarDoted, DonutChartSummary, ProductMerchandisingCard, ProductOverview, Radio, SavingsGoalSummary, SegmentedControl, SegmentedTrack, Slider, Tooltip, StatusHero, CardFeedback).
17
+ - Coin Variables — repaired broken `nudge/radius` and Badge Semantic Intent System aliases; added `tooltip/radius` and `tooltip/maxWidth`.
18
+
19
+ ---
20
+
7
21
  ## [0.1.48] - 2026-07-23
8
22
 
9
23
  - `CompareTable` (fixed-width scroll mode) — selection cards pin above the scroll surface (`stickyCards`, default `true`); accordion section titles stick under the cards and replace each other as you scroll (`stickyAccordionTitles`, default `true`); gray table-header sticky is now opt-in (`stickyHeaders` default `false`). Selection cards are square (corner radius forced to `0`).
@@ -75,7 +75,8 @@ function CardCTA({
75
75
  const radius = (0, _figmaVariablesResolver.getVariableByName)('cardCTA/radius', modes);
76
76
  const borderSize = (0, _figmaVariablesResolver.getVariableByName)('cardCTA/border/size', modes);
77
77
  const borderColor = (0, _figmaVariablesResolver.getVariableByName)('cardCTA/border/color', modes);
78
- const leftPaddingH = (0, _figmaVariablesResolver.getVariableByName)('cardCTA/left-wrap/padding/horizontal', modes);
78
+ const leftPaddingLeft = (0, _figmaVariablesResolver.getVariableByName)('cardCTA/left-wrap/padding/left', modes);
79
+ const leftPaddingRight = (0, _figmaVariablesResolver.getVariableByName)('cardCTA/left-wrap/padding/right', modes);
79
80
  const leftPaddingV = (0, _figmaVariablesResolver.getVariableByName)('cardCTA/left-wrap/padding/vertical', modes);
80
81
  const leftGap = (0, _figmaVariablesResolver.getVariableByName)('cardCTA/left-wrap/gap', modes);
81
82
  const rightPaddingH = (0, _figmaVariablesResolver.getVariableByName)('cardCTA/right-wrap/padding/horizontal', modes);
@@ -221,7 +222,8 @@ function CardCTA({
221
222
  flexShrink: 1,
222
223
  flexBasis: 0,
223
224
  minWidth: 0,
224
- paddingHorizontal: leftPaddingH,
225
+ paddingLeft: leftPaddingLeft,
226
+ paddingRight: leftPaddingRight,
225
227
  paddingVertical: leftPaddingV,
226
228
  gap: leftGap,
227
229
  alignItems: 'flex-start',
@@ -253,7 +255,7 @@ function CardCTA({
253
255
  // space allows and can never collapse below its content.
254
256
  const iconCapsuleModes = {
255
257
  ...modes,
256
- 'IconCapsule / Size': 'M',
258
+ 'Icon Capsule Size': 'M',
257
259
  Emphasis: 'Medium',
258
260
  AppearanceBrand: 'Secondary'
259
261
  };
@@ -312,7 +314,8 @@ function CardCTA({
312
314
  };
313
315
  const sipWrapStyle = {
314
316
  width: '100%',
315
- paddingHorizontal: leftPaddingH,
317
+ paddingLeft: leftPaddingLeft,
318
+ paddingRight: leftPaddingRight,
316
319
  paddingVertical: leftPaddingV,
317
320
  gap: leftGap,
318
321
  alignItems: 'flex-start',
@@ -35,7 +35,7 @@ function CardFeedback({
35
35
  accessibilityLabel
36
36
  }) {
37
37
  const modes = {
38
- 'Appearance.System': 'positive',
38
+ 'AppearanceSystem': 'positive',
39
39
  'Context': 'Nudge&Alert',
40
40
  'Semantic Intent': 'System',
41
41
  ...propModes
@@ -62,10 +62,10 @@ function resolveCategoryCardTokens(modes, active) {
62
62
  const backgroundColor = active ? activeBackground : idleBackground;
63
63
  const imageSize = toNumber((0, _figmaVariablesResolver.getVariableByName)('cardTab/image/width', resolvedModes), 36);
64
64
  const imageRadius = toNumber((0, _figmaVariablesResolver.getVariableByName)('image/radius', resolvedModes), 0);
65
- const fontFamily = (0, _figmaVariablesResolver.getVariableByName)('cardTab/label/fontFamily', resolvedModes) ?? 'JioType Var';
66
- const fontSize = toNumber((0, _figmaVariablesResolver.getVariableByName)('cardTab/label/fontSize', resolvedModes), 12);
67
- const lineHeight = toNumber((0, _figmaVariablesResolver.getVariableByName)('cardTab/label/lineHeight', resolvedModes), Math.round(fontSize * 1.3));
68
- const fontWeight = toFontWeight((0, _figmaVariablesResolver.getVariableByName)('cardTab/label/fontWeight', resolvedModes), '500');
65
+ const fontFamily = (0, _figmaVariablesResolver.getVariableByName)('label/fontFamily', resolvedModes) ?? 'JioType Var';
66
+ const fontSize = toNumber((0, _figmaVariablesResolver.getVariableByName)('label/fontSize', resolvedModes), 12);
67
+ const lineHeight = toNumber((0, _figmaVariablesResolver.getVariableByName)('label/lineHeight', resolvedModes), Math.round(fontSize * 1.3));
68
+ const fontWeight = toFontWeight((0, _figmaVariablesResolver.getVariableByName)('label/fontWeight', resolvedModes), '500');
69
69
  const labelColor = (0, _figmaVariablesResolver.getVariableByName)('cardTab/label/color', resolvedModes) ?? '#000000';
70
70
  return {
71
71
  containerStyle: {
@@ -107,8 +107,8 @@ const Checkbox = /*#__PURE__*/(0, _react.forwardRef)(function Checkbox({
107
107
  const idleStroke = (0, _figmaVariablesResolver.getVariableByName)('checkbox/idle/stroke/color', modes) ?? '#666666';
108
108
  const hoverFill = (0, _figmaVariablesResolver.getVariableByName)('checkbox/hover/fill/color', modes) ?? 'rgba(0,0,0,0.1)';
109
109
  const hoverStroke = (0, _figmaVariablesResolver.getVariableByName)('checkbox/hover/stroke/color', modes) ?? '#666666';
110
- const hoverRing = (0, _figmaVariablesResolver.getVariableByName)('checkbox/hoverRing', modes) ?? 4;
111
- const hoverShadow = (0, _figmaVariablesResolver.getVariableByName)('hover/boxShadow', modes) ?? 'rgba(0,0,0,0.1)';
110
+ const hoverSpread = (0, _figmaVariablesResolver.getVariableByName)('checkbox/hover/spread/effect1', modes) ?? 4;
111
+ const hoverShadow = (0, _figmaVariablesResolver.getVariableByName)('checkbox/hover/shadow/color', modes) ?? 'rgba(0,0,0,0.1)';
112
112
  const selectedFill = (0, _figmaVariablesResolver.getVariableByName)('checkbox/selected/fill/color', modes) ?? '#cea15a';
113
113
  const selectedStroke = (0, _figmaVariablesResolver.getVariableByName)('checkbox/selected/stroke/color', modes) ?? '#0d0d0d';
114
114
  const selectedMarkColor = (0, _figmaVariablesResolver.getVariableByName)('checkbox/selected/mark/color', modes) ?? '#0f0d0a';
@@ -120,8 +120,6 @@ const Checkbox = /*#__PURE__*/(0, _react.forwardRef)(function Checkbox({
120
120
  const disabledActiveBg = (0, _figmaVariablesResolver.getVariableByName)('checkbox/disabledActive/background/color', modes) ?? '#f6d19a';
121
121
  const disabledActiveBorder = (0, _figmaVariablesResolver.getVariableByName)('checkbox/disabledActive/border/color', modes) ?? '#f6d19a';
122
122
  const disabledActiveMark = (0, _figmaVariablesResolver.getVariableByName)('checkbox/disabledActive/mark/color', modes) ?? '#474d54';
123
- const selectedHoverShadow = (0, _figmaVariablesResolver.getVariableByName)('selected/hover/boxShadow', modes) ?? 'rgba(0,0,0,0.1)';
124
- const hoverShadowSize = (0, _figmaVariablesResolver.getVariableByName)('hover/boxShadow/size', modes) ?? 4;
125
123
  const handlePress = (0, _react.useCallback)(() => {
126
124
  if (disabled) return;
127
125
  const next = !isChecked;
@@ -166,7 +164,7 @@ const Checkbox = /*#__PURE__*/(0, _react.forwardRef)(function Checkbox({
166
164
  ...base,
167
165
  backgroundColor: selectedFill,
168
166
  borderColor: selectedStroke,
169
- ...(0, _shadow.boxShadow)(`0px 0px 0px ${hoverShadowSize}px ${selectedHoverShadow}`)
167
+ ...(0, _shadow.boxShadow)(`0px 0px 0px ${hoverSpread}px ${hoverShadow}`)
170
168
  };
171
169
  }
172
170
  if (isChecked) {
@@ -189,7 +187,7 @@ const Checkbox = /*#__PURE__*/(0, _react.forwardRef)(function Checkbox({
189
187
  ...base,
190
188
  backgroundColor: hoverFill,
191
189
  borderColor: hoverStroke,
192
- ...(0, _shadow.boxShadow)(`0px 0px 0px ${hoverRing}px ${hoverShadow}`)
190
+ ...(0, _shadow.boxShadow)(`0px 0px 0px ${hoverSpread}px ${hoverShadow}`)
193
191
  };
194
192
  }
195
193
  return {
@@ -87,18 +87,21 @@ function CircularProgressBarDoted({
87
87
  const scoreTierWidth = toNumber((0, _figmaVariablesResolver.getVariableByName)('circularProgressBarDoted/scoreTier/width', modes), 116);
88
88
  const scoreTrendGap = toNumber((0, _figmaVariablesResolver.getVariableByName)('circularProgressBarDoted/scoreTrend/gap', modes), 2);
89
89
  const scoreTrendHeight = toNumber((0, _figmaVariablesResolver.getVariableByName)('circularProgressBarDoted/scoreTrend/height', modes), 24);
90
- const typographyFontFamily = (0, _figmaVariablesResolver.getVariableByName)('Typography/Font Family', modes);
91
90
  const labelColor = (0, _figmaVariablesResolver.getVariableByName)('circularProgressBarDoted/label/color', modes);
92
- const labelFontSize = toNumber((0, _figmaVariablesResolver.getVariableByName)('Typography/Size/Body/XS', modes), 12);
93
- const labelFontWeight = toFontWeight((0, _figmaVariablesResolver.getVariableByName)('Typography/Font Weight/Body Low (Regular)', modes), '400');
91
+ const labelFontSize = toNumber((0, _figmaVariablesResolver.getVariableByName)('circularProgressBarDoted/label/fontSize', modes), 12);
92
+ const labelFontFamily = (0, _figmaVariablesResolver.getVariableByName)('circularProgressBarDoted/label/fontFamily', modes);
93
+ const labelLineHeight = toNumber((0, _figmaVariablesResolver.getVariableByName)('circularProgressBarDoted/label/lineHeight', modes), 15.6);
94
+ const labelFontWeight = toFontWeight((0, _figmaVariablesResolver.getVariableByName)('circularProgressBarDoted/label/fontWeight', modes), '400');
94
95
  const scoreColor = (0, _figmaVariablesResolver.getVariableByName)('circularProgressBarDoted/scoreLabel/color', modes);
95
96
  const scoreFontSize = toNumber((0, _figmaVariablesResolver.getVariableByName)('circularProgressBarDoted/scoreLabel/fontSize', modes), 56);
96
97
  const scoreFontFamily = (0, _figmaVariablesResolver.getVariableByName)('circularProgressBarDoted/scoreLabel/fontFamily', modes);
97
98
  const scoreLineHeight = toNumber((0, _figmaVariablesResolver.getVariableByName)('circularProgressBarDoted/scoreLabel/lineHeight', modes), 56);
98
99
  const scoreFontWeight = toFontWeight((0, _figmaVariablesResolver.getVariableByName)('circularProgressBarDoted/scoreLabel/fontWeight', modes), '900');
99
100
  const tierColor = (0, _figmaVariablesResolver.getVariableByName)('circularProgressBarDoted/tierLabel/color', modes);
100
- const tierFontSize = toNumber((0, _figmaVariablesResolver.getVariableByName)('Typography/Size/Body/M', modes), 16);
101
- const tierFontWeight = toFontWeight((0, _figmaVariablesResolver.getVariableByName)('Typography/Font Weight/Body High', modes), '700');
101
+ const tierFontSize = toNumber((0, _figmaVariablesResolver.getVariableByName)('circularProgressBarDoted/tierLabel/fontSize', modes), 16);
102
+ const tierFontFamily = (0, _figmaVariablesResolver.getVariableByName)('circularProgressBarDoted/tierLabel/fontFamily', modes);
103
+ const tierLineHeight = toNumber((0, _figmaVariablesResolver.getVariableByName)('circularProgressBarDoted/tierLabel/lineHeight', modes), 20.8);
104
+ const tierFontWeight = toFontWeight((0, _figmaVariablesResolver.getVariableByName)('circularProgressBarDoted/tierLabel/fontWeight', modes), '700');
102
105
  const iconColor = (0, _figmaVariablesResolver.getVariableByName)('circularProgressBarDoted/icon/color', modes);
103
106
  const iconSize = toNumber((0, _figmaVariablesResolver.getVariableByName)('circularProgressBarDoted/icon/size', modes), 24);
104
107
  const dots = (0, _react.useMemo)(() => Array.from({
@@ -159,10 +162,10 @@ function CircularProgressBarDoted({
159
162
  };
160
163
  const computedLabelStyle = {
161
164
  color: labelColor,
162
- fontFamily: typographyFontFamily,
165
+ fontFamily: labelFontFamily,
163
166
  fontSize: labelFontSize,
164
167
  fontWeight: labelFontWeight,
165
- lineHeight: labelFontSize * 1.3,
168
+ lineHeight: labelLineHeight,
166
169
  textAlign: 'center'
167
170
  };
168
171
  const computedScoreLabelStyle = {
@@ -175,10 +178,10 @@ function CircularProgressBarDoted({
175
178
  };
176
179
  const computedTierLabelStyle = {
177
180
  color: tierColor,
178
- fontFamily: typographyFontFamily,
181
+ fontFamily: tierFontFamily,
179
182
  fontSize: tierFontSize,
180
183
  fontWeight: tierFontWeight,
181
- lineHeight: tierFontSize * 1.3,
184
+ lineHeight: tierLineHeight,
182
185
  textAlign: 'center'
183
186
  };
184
187
  const resolvedScoreLabel = String(Math.round(normalizedValue));
@@ -92,8 +92,13 @@ function DonutChartSummary({
92
92
  ...globalModes,
93
93
  ...propModes
94
94
  };
95
- const gap = (0, _figmaVariablesResolver.getVariableByName)('donutChartSummary/gap', modes) ?? 16;
96
- const legendGap = (0, _figmaVariablesResolver.getVariableByName)('donutChartSummary/legend/gap', modes) ?? 8;
95
+
96
+ // Figma DonutChartSummary (4203:51713) does not expose component-level
97
+ // gap variables — layout uses unbound 16px (donut→legend) and 8px
98
+ // (legend rows). Nested `textWrap/gap` / `metricLegendItem/gap` belong
99
+ // to child components and are not substitutes.
100
+ const gap = 16;
101
+ const legendGap = 8;
97
102
  const resolvedItems = items && items.length > 0 ? items : DEFAULT_ITEMS;
98
103
  const segments = resolvedItems.map((item, index) => ({
99
104
  key: item.key ?? `segment-${index}`,
@@ -334,7 +334,9 @@ function resolveTokens(modes) {
334
334
  const titleColor = asStr((0, _figmaVariablesResolver.getVariableByName)('productMerchandisingcard/footer/title/font/color', modes), '#ffffff');
335
335
  const titleSize = asNum((0, _figmaVariablesResolver.getVariableByName)('productMerchandisingcard/footer/title/fontsize', modes), 14);
336
336
  const titleFamily = asStr((0, _figmaVariablesResolver.getVariableByName)('productMerchandisingcard/footer/title/fontfamily', modes), 'JioType Var');
337
- const titleWeight = asStr((0, _figmaVariablesResolver.getVariableByName)('productMerchandisingcard/footer/title/fontweight', modes), '700');
337
+ // No `productMerchandisingcard/footer/title/fontweight` in Coin Variables (Figma
338
+ // binds 700). `typography/title/fontWeight/high` is 800; use body/high (=700).
339
+ const titleWeight = asStr((0, _figmaVariablesResolver.getVariableByName)('typography/body/fontWeight/high', modes), '700');
338
340
  const subtitleColor = asStr((0, _figmaVariablesResolver.getVariableByName)('productMerchandisingcard/footer/subtitle/font/color', modes), '#c5bcb5');
339
341
  const subtitleSize = asNum((0, _figmaVariablesResolver.getVariableByName)('productMerchandisingcard/footer/subtitle/fontsize', modes), 12);
340
342
  const subtitleFamily = asStr((0, _figmaVariablesResolver.getVariableByName)('productMerchandisingcard/footer/subtitle/fontfamily', modes), 'JioType Var');
@@ -35,12 +35,12 @@ const ProductOverview = ({
35
35
  const padding = (0, _figmaVariablesResolver.getVariableByName)('productOverview/padding', modes) ?? 24;
36
36
  const gap = (0, _figmaVariablesResolver.getVariableByName)('productOverview/gap', modes) ?? 12;
37
37
  const background = (0, _figmaVariablesResolver.getVariableByName)('productOverview/background', modes) ?? '#ffffff';
38
- const productNameColor = (0, _figmaVariablesResolver.getVariableByName)('productOverview/productName/color', modes) ?? '#0d0d0f';
38
+ const productNameColor = (0, _figmaVariablesResolver.getVariableByName)('text/appearance/high/color', modes) ?? '#0d0d0f';
39
39
  const productNameFontFamily = (0, _figmaVariablesResolver.getVariableByName)('productOverview/productName/fontFamily', modes) ?? 'JioType Var';
40
40
  const productNameFontSize = (0, _figmaVariablesResolver.getVariableByName)('productOverview/productName/fontSize', modes) ?? 26;
41
41
  const productNameFontWeight = (0, _figmaVariablesResolver.getVariableByName)('productOverview/productName/fontWeight', modes) ?? 900;
42
42
  const productNameLineHeight = (0, _figmaVariablesResolver.getVariableByName)('productOverview/productName/lineHeight', modes) ?? 26;
43
- const descriptionColor = (0, _figmaVariablesResolver.getVariableByName)('productOverview/description/color', modes) ?? '#1a1c1f';
43
+ const descriptionColor = (0, _figmaVariablesResolver.getVariableByName)('text/appearance/medium/color', modes) ?? '#1a1c1f';
44
44
  const descriptionFontFamily = (0, _figmaVariablesResolver.getVariableByName)('productOverview/description/fontFamily', modes) ?? 'JioType Var';
45
45
  const descriptionFontSize = (0, _figmaVariablesResolver.getVariableByName)('productOverview/description/fontSize', modes) ?? 14;
46
46
  const descriptionFontWeight = (0, _figmaVariablesResolver.getVariableByName)('productOverview/description/fontWeight', modes) ?? 500;
@@ -86,7 +86,9 @@ const Radio = exports.Radio = /*#__PURE__*/(0, _react.forwardRef)(function Radio
86
86
  }
87
87
 
88
88
  // Border Color
89
- let borderColorVar = `${prefix}/border/color`;
89
+ // Coin Variables has no `radio/focus/border/color` — focus indication is
90
+ // the yellow boxShadow ring; stroke reuses the published idle border.
91
+ let borderColorVar = visualState === 'focus' && !selected ? 'radio/idle/border/color' : `${prefix}/border/color`;
90
92
 
91
93
  // Border Width
92
94
  let borderWidthVar = `${prefix}/border/size`;
@@ -144,7 +146,6 @@ const Radio = exports.Radio = /*#__PURE__*/(0, _react.forwardRef)(function Radio
144
146
  (0, _figmaVariablesResolver.getVariableByName)('radio/selector/size');
145
147
  (0, _figmaVariablesResolver.getVariableByName)('radio/width');
146
148
  (0, _figmaVariablesResolver.getVariableByName)('radio/height');
147
- (0, _figmaVariablesResolver.getVariableByName)('radio/background/color');
148
149
  (0, _figmaVariablesResolver.getVariableByName)('radio/hover/background/color');
149
150
  (0, _figmaVariablesResolver.getVariableByName)('radio/hover/border/color');
150
151
  (0, _figmaVariablesResolver.getVariableByName)('radio/hover/boxShadow/size');
@@ -158,13 +159,14 @@ const Radio = exports.Radio = /*#__PURE__*/(0, _react.forwardRef)(function Radio
158
159
  (0, _figmaVariablesResolver.getVariableByName)('radio/hoverSelected/shadow/color');
159
160
  (0, _figmaVariablesResolver.getVariableByName)('radio/hoverSelected/selector/background/color');
160
161
  (0, _figmaVariablesResolver.getVariableByName)('radio/focus/background/color');
161
- (0, _figmaVariablesResolver.getVariableByName)('radio/focus/border/color');
162
162
  (0, _figmaVariablesResolver.getVariableByName)('radio/focus/border/size');
163
163
  (0, _figmaVariablesResolver.getVariableByName)('radio/focus/boxShadow/size');
164
164
  (0, _figmaVariablesResolver.getVariableByName)('radio/focus/shadow/color');
165
165
  (0, _figmaVariablesResolver.getVariableByName)('radio/focusSelected/background/color');
166
+ (0, _figmaVariablesResolver.getVariableByName)('radio/focusSelected/border/color');
166
167
  (0, _figmaVariablesResolver.getVariableByName)('radio/focusSelected/selector/background/color');
167
168
  (0, _figmaVariablesResolver.getVariableByName)('radio/focusSelected/border/size');
169
+ (0, _figmaVariablesResolver.getVariableByName)('radio/focusSelected/shadow/color');
168
170
  (0, _figmaVariablesResolver.getVariableByName)('radio/disabled/radio/disabled/border/size');
169
171
  (0, _figmaVariablesResolver.getVariableByName)('radio/disabled/background/color');
170
172
  (0, _figmaVariablesResolver.getVariableByName)('radio/disabled/border/color');
@@ -129,7 +129,7 @@ function SavingsGoalSummary({
129
129
  // ~1.2x so descenders never clip on native (same guard `Title` uses).
130
130
  const valueLineHeight = Math.max(valueRawLineHeight, Math.ceil(valueFontSize * 1.2));
131
131
  const valueFontWeight = String((0, _figmaVariablesResolver.getVariableByName)('savingsGoalSummary/value/fontWeight', mergedModes) ?? 900);
132
- const valueColor = (0, _figmaVariablesResolver.getVariableByName)('savingsGoalSummary/value/color', mergedModes) ?? '#0d0d0f';
132
+ const valueColor = (0, _figmaVariablesResolver.getVariableByName)('text/appearance/high/color', mergedModes) ?? '#0d0d0f';
133
133
 
134
134
  // Caption ("Credit usage") typography — `savingsGoalSummary/label/*`
135
135
  // (Figma 12 / 400). Only rendered when a `label` is supplied.
@@ -137,7 +137,7 @@ function SavingsGoalSummary({
137
137
  const labelFontFamily = (0, _figmaVariablesResolver.getVariableByName)('savingsGoalSummary/label/fontFamily', mergedModes) ?? 'JioType Var';
138
138
  const labelLineHeight = (0, _figmaVariablesResolver.getVariableByName)('savingsGoalSummary/label/lineHeight', mergedModes) ?? 16;
139
139
  const labelFontWeight = String((0, _figmaVariablesResolver.getVariableByName)('savingsGoalSummary/label/fontWeight', mergedModes) ?? 400);
140
- const labelColor = (0, _figmaVariablesResolver.getVariableByName)('savingsGoalSummary/label/color', mergedModes) ?? '#0d0d0f';
140
+ const labelColor = (0, _figmaVariablesResolver.getVariableByName)('text/appearance/medium/color', mergedModes) ?? '#1a1c1f';
141
141
  const labelNode = label == null || label === false ? null : typeof label === 'string' ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
142
142
  style: [{
143
143
  color: labelColor,
@@ -109,7 +109,7 @@ function SegmentedControl({
109
109
  }, [isControlled, onSelectionChange]);
110
110
  const gap = (0, _figmaVariablesResolver.getVariableByName)('segmentedControl/gap', modes) ?? 8;
111
111
  const background = (0, _figmaVariablesResolver.getVariableByName)('segmentedControl/background', modes) ?? '#f6f3ff';
112
- const radius = (0, _figmaVariablesResolver.getVariableByName)('segmentedControl/radius', modes) ?? 24;
112
+ const radius = (0, _figmaVariablesResolver.getVariableByName)('segment/radius', modes) ?? 20;
113
113
  const containerStyle = {
114
114
  flexDirection: 'row',
115
115
  alignItems: 'center',
@@ -96,7 +96,7 @@ function SegmentedTrack({
96
96
  ...propModes
97
97
  };
98
98
  const trackHeight = (0, _figmaVariablesResolver.getVariableByName)('segmentedTrack/height', modes) ?? 24;
99
- const trackRadius = (0, _figmaVariablesResolver.getVariableByName)('segmentedTrack/radius', modes) ?? 999;
99
+ const trackRadius = trackHeight / 2;
100
100
  const renderedSegments = renderSegments({
101
101
  segments,
102
102
  children,
@@ -391,8 +391,9 @@ function resolveTokens(modes) {
391
391
  const tooltipBackground = asStr((0, _figmaVariablesResolver.getVariableByName)('tooltip/background', modes), '#0f0d0a');
392
392
  const tooltipPaddingH = asNum((0, _figmaVariablesResolver.getVariableByName)('tooltip/padding/horizontal', modes), 12);
393
393
  const tooltipPaddingV = asNum((0, _figmaVariablesResolver.getVariableByName)('tooltip/padding/vertical', modes), 8);
394
- const tooltipRadius = asNum((0, _figmaVariablesResolver.getVariableByName)('radius', modes), 8);
395
- const tooltipMaxWidth = asNum((0, _figmaVariablesResolver.getVariableByName)('maxWidth', modes), 280);
394
+ // Not yet in Coin Variables export (Figma still binds bare local radius/maxWidth).
395
+ const tooltipRadius = asNum((0, _figmaVariablesResolver.getVariableByName)('tooltip/radius', modes), 8);
396
+ const tooltipMaxWidth = asNum((0, _figmaVariablesResolver.getVariableByName)('tooltip/maxWidth', modes), 280);
396
397
  const tipWidth = asNum((0, _figmaVariablesResolver.getVariableByName)('tooltip/tipItem/width', modes), 16);
397
398
  const tipHeight = asNum((0, _figmaVariablesResolver.getVariableByName)('tooltip/tipItem/height', modes), 8);
398
399
  const tooltipLabelColor = asStr((0, _figmaVariablesResolver.getVariableByName)('tooltip/label/color', modes), '#ffffff');
@@ -129,7 +129,7 @@ function StatusHero({
129
129
  currency: currency,
130
130
  modes: {
131
131
  ...modes,
132
- Context3: 'Balance'
132
+ Context3: 'Balance & Cards'
133
133
  }
134
134
  })]
135
135
  });