jfs-components 0.1.50 → 0.1.54
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/.cursor/D2C-FLOW.md +94 -0
- package/.cursor/D2C-SCREEN.md +119 -0
- package/.cursor/commands/D2C.md +101 -0
- package/CHANGELOG.md +18 -0
- package/lib/commonjs/components/ActionFooter/ActionFooter.js +319 -135
- package/lib/commonjs/components/Badge/Badge.js +20 -1
- package/lib/commonjs/components/Button/Button.js +139 -47
- package/lib/commonjs/components/ButtonGroup/ButtonGroup.js +1 -1
- package/lib/commonjs/components/Card/Card.js +151 -112
- package/lib/commonjs/components/Card/assets/gold-logo-mark.png +0 -0
- package/lib/commonjs/components/CategoryCard/CategoryCard.js +97 -63
- package/lib/commonjs/components/CategoryCard/assets/sample.png +0 -0
- package/lib/commonjs/components/CheckboxItem/CheckboxItem.js +59 -10
- package/lib/commonjs/components/ExpandableCheckbox/ExpandableCheckbox.js +132 -49
- package/lib/commonjs/components/HelloJioInput/HelloJioInput.js +56 -14
- package/lib/commonjs/components/IconCapsule/IconCapsule.js +1 -1
- package/lib/commonjs/components/MetricData/MetricData.js +26 -13
- package/lib/commonjs/components/MoneyValue/MoneyValue.js +1 -1
- package/lib/commonjs/components/Nudge/Nudge.js +1 -1
- package/lib/commonjs/components/PdpCcCard/PdpCcCard.js +47 -91
- package/lib/commonjs/components/PlanComparisonCard/PlanComparisonCard.js +52 -45
- package/lib/commonjs/components/PortfolioHero/PortfolioHero.js +1 -1
- package/lib/commonjs/components/Slider/Slider.js +3 -3
- package/lib/commonjs/components/TextInput/TextInput.js +26 -8
- package/lib/commonjs/components/Tooltip/Tooltip.js +3 -5
- package/lib/commonjs/components/index.js +7 -1
- package/lib/commonjs/design-tokens/Coin Variables-variables-full.json +1 -1
- package/lib/commonjs/design-tokens/figma-modes.generated.js +13 -13
- package/lib/commonjs/icons/registry.js +1 -1
- package/lib/module/components/ActionFooter/ActionFooter.js +322 -138
- package/lib/module/components/Badge/Badge.js +20 -1
- package/lib/module/components/Button/Button.js +140 -48
- package/lib/module/components/ButtonGroup/ButtonGroup.js +1 -1
- package/lib/module/components/Card/Card.js +152 -114
- package/lib/module/components/Card/assets/gold-logo-mark.png +0 -0
- package/lib/module/components/CategoryCard/CategoryCard.js +97 -63
- package/lib/module/components/CategoryCard/assets/sample.png +0 -0
- package/lib/module/components/CheckboxItem/CheckboxItem.js +59 -10
- package/lib/module/components/ExpandableCheckbox/ExpandableCheckbox.js +135 -52
- package/lib/module/components/HelloJioInput/HelloJioInput.js +56 -14
- package/lib/module/components/IconCapsule/IconCapsule.js +1 -1
- package/lib/module/components/MetricData/MetricData.js +26 -14
- package/lib/module/components/MoneyValue/MoneyValue.js +1 -1
- package/lib/module/components/Nudge/Nudge.js +1 -1
- package/lib/module/components/PdpCcCard/PdpCcCard.js +48 -92
- package/lib/module/components/PlanComparisonCard/PlanComparisonCard.js +52 -45
- package/lib/module/components/PortfolioHero/PortfolioHero.js +1 -1
- package/lib/module/components/Slider/Slider.js +3 -3
- package/lib/module/components/TextInput/TextInput.js +27 -9
- package/lib/module/components/Tooltip/Tooltip.js +3 -5
- package/lib/module/components/index.js +1 -1
- package/lib/module/design-tokens/Coin Variables-variables-full.json +1 -1
- package/lib/module/design-tokens/figma-modes.generated.js +13 -13
- package/lib/module/icons/registry.js +1 -1
- package/lib/typescript/src/components/ActionFooter/ActionFooter.d.ts +50 -21
- package/lib/typescript/src/components/Button/Button.d.ts +24 -1
- package/lib/typescript/src/components/ButtonGroup/ButtonGroup.d.ts +2 -2
- package/lib/typescript/src/components/Card/Card.d.ts +54 -25
- package/lib/typescript/src/components/CategoryCard/CategoryCard.d.ts +29 -12
- package/lib/typescript/src/components/CheckboxItem/CheckboxItem.d.ts +27 -9
- package/lib/typescript/src/components/ExpandableCheckbox/ExpandableCheckbox.d.ts +37 -12
- package/lib/typescript/src/components/IconCapsule/IconCapsule.d.ts +1 -1
- package/lib/typescript/src/components/MetricData/MetricData.d.ts +7 -5
- package/lib/typescript/src/components/PdpCcCard/PdpCcCard.d.ts +16 -6
- package/lib/typescript/src/components/PlanComparisonCard/PlanComparisonCard.d.ts +9 -2
- package/lib/typescript/src/components/index.d.ts +2 -2
- package/lib/typescript/src/icons/registry.d.ts +1 -1
- package/package.json +4 -2
- package/src/components/ActionFooter/ActionFooter.tsx +375 -141
- package/src/components/Badge/Badge.tsx +21 -1
- package/src/components/Button/Button.tsx +192 -44
- package/src/components/ButtonGroup/ButtonGroup.tsx +2 -2
- package/src/components/Card/Card.tsx +370 -212
- package/src/components/Card/assets/gold-logo-mark.png +0 -0
- package/src/components/CategoryCard/CategoryCard.tsx +130 -84
- package/src/components/CategoryCard/assets/sample.png +0 -0
- package/src/components/CheckboxItem/CheckboxItem.tsx +72 -12
- package/src/components/ExpandableCheckbox/ExpandableCheckbox.tsx +186 -67
- package/src/components/HelloJioInput/HelloJioInput.tsx +58 -17
- package/src/components/IconCapsule/IconCapsule.tsx +1 -1
- package/src/components/MetricData/MetricData.tsx +39 -22
- package/src/components/MoneyValue/MoneyValue.tsx +1 -1
- package/src/components/Nudge/Nudge.tsx +1 -1
- package/src/components/PdpCcCard/PdpCcCard.tsx +41 -92
- package/src/components/PlanComparisonCard/PlanComparisonCard.tsx +73 -58
- package/src/components/PortfolioHero/PortfolioHero.tsx +1 -1
- package/src/components/Slider/Slider.tsx +3 -3
- package/src/components/TextInput/TextInput.tsx +26 -9
- package/src/components/Tooltip/Tooltip.tsx +3 -5
- package/src/components/index.ts +9 -2
- package/src/design-tokens/Coin Variables-variables-full.json +1 -1
- package/src/design-tokens/figma-modes.generated.ts +13 -13
- package/src/icons/registry.ts +1 -1
|
@@ -15,6 +15,26 @@ import GlassFill from '../../utils/GlassFill/GlassFill'
|
|
|
15
15
|
|
|
16
16
|
export type BadgeType = 'default' | 'glass'
|
|
17
17
|
|
|
18
|
+
/**
|
|
19
|
+
* Figma still binds `badge/color/label`, but that alias is broken for
|
|
20
|
+
* `Semantic Intent=System` + `Emphasis=High` (missing VariableID:2811:2401).
|
|
21
|
+
* Use the published tokens that the chain is supposed to land on:
|
|
22
|
+
* - Brand → `Emphasis/badge/brand/fg`
|
|
23
|
+
* - System + High → `Emphasis/badge/high/fg Copy` (AppearanceSystem)
|
|
24
|
+
* - System + Medium/Low → `Emphasis/badge/system/fg`
|
|
25
|
+
*/
|
|
26
|
+
function badgeLabelColorToken(modes: Modes): string {
|
|
27
|
+
const intent = modes['Semantic Intent'] ?? 'Brand'
|
|
28
|
+
const emphasis = modes.Emphasis ?? 'High'
|
|
29
|
+
if (intent === 'System' && emphasis === 'High') {
|
|
30
|
+
return 'Emphasis/badge/high/fg Copy'
|
|
31
|
+
}
|
|
32
|
+
if (intent === 'System') {
|
|
33
|
+
return 'Emphasis/badge/system/fg'
|
|
34
|
+
}
|
|
35
|
+
return 'Emphasis/badge/brand/fg'
|
|
36
|
+
}
|
|
37
|
+
|
|
18
38
|
export type BadgeProps = {
|
|
19
39
|
/** Visible label text shown inside the badge */
|
|
20
40
|
label?: string
|
|
@@ -91,7 +111,7 @@ function Badge({
|
|
|
91
111
|
(getVariableByName('badge/glass/color/label', modes) as string)
|
|
92
112
|
const labelColor = isGlass
|
|
93
113
|
? glassLabelColor
|
|
94
|
-
: (getVariableByName(
|
|
114
|
+
: (getVariableByName(badgeLabelColorToken(modes), modes) as string)
|
|
95
115
|
const fontSize =
|
|
96
116
|
Number(getVariableByName('badge/label/fontSize', modes) as unknown)
|
|
97
117
|
const fontFamily =
|
|
@@ -13,11 +13,20 @@ import {
|
|
|
13
13
|
import { getVariableByName } from '../../design-tokens/figma-variables-resolver'
|
|
14
14
|
import { usePressableWebSupport, type SafePressableProps, type WebAccessibilityProps } from '../../utils/web-platform-utils'
|
|
15
15
|
import { EMPTY_MODES } from '../../utils/react-utils'
|
|
16
|
+
import GlassFill from '../../utils/GlassFill/GlassFill'
|
|
16
17
|
import Icon from '../../icons/Icon'
|
|
17
18
|
import Skeleton from '../../skeleton/Skeleton'
|
|
18
19
|
import { useSkeleton } from '../../skeleton/SkeletonGroup'
|
|
19
20
|
import type { Modes } from '../../design-tokens'
|
|
20
21
|
|
|
22
|
+
/**
|
|
23
|
+
* Figma `Type` property on Button.
|
|
24
|
+
* - `'default'` — solid token-colored pill (hugs content)
|
|
25
|
+
* - `'glass'` — frosted translucent pill backed by {@link GlassFill}
|
|
26
|
+
* - `'fixed'` — solid pill constrained by `button/maxWidth`
|
|
27
|
+
*/
|
|
28
|
+
export type ButtonType = 'default' | 'glass' | 'fixed'
|
|
29
|
+
|
|
21
30
|
export type ButtonProps = SafePressableProps & {
|
|
22
31
|
label?: string;
|
|
23
32
|
children?: React.ReactNode;
|
|
@@ -45,6 +54,22 @@ export type ButtonProps = SafePressableProps & {
|
|
|
45
54
|
* Takes precedence over `trailing` if both are provided.
|
|
46
55
|
*/
|
|
47
56
|
icon?: string;
|
|
57
|
+
/**
|
|
58
|
+
* Visual/layout type matching the Figma `Type` property. Defaults to
|
|
59
|
+
* `'default'`. `'glass'` also activates when `modes['Button type'] === 'glass'`.
|
|
60
|
+
*/
|
|
61
|
+
type?: ButtonType;
|
|
62
|
+
/**
|
|
63
|
+
* Glass-only override for the translucent overlay color painted over the live
|
|
64
|
+
* blur. Defaults to the resolved `button/background` token under
|
|
65
|
+
* `Button type=glass`. Ignored for non-glass types.
|
|
66
|
+
*/
|
|
67
|
+
glassOverlayColor?: string;
|
|
68
|
+
/**
|
|
69
|
+
* Glass-only override for blur intensity on the 0–100 scale. Defaults to the
|
|
70
|
+
* `blur/minimal` token. Ignored for non-glass types.
|
|
71
|
+
*/
|
|
72
|
+
glassIntensity?: number;
|
|
48
73
|
modes?: Modes;
|
|
49
74
|
onPress?: () => void;
|
|
50
75
|
disabled?: boolean;
|
|
@@ -115,6 +140,8 @@ const NO_WRAP_LABEL_STYLE: TextStyle = {
|
|
|
115
140
|
// ---------------------------------------------------------------------------
|
|
116
141
|
|
|
117
142
|
interface ButtonTokens {
|
|
143
|
+
isGlass: boolean;
|
|
144
|
+
isFixed: boolean;
|
|
118
145
|
container: ViewStyle;
|
|
119
146
|
baseLabel: TextStyle;
|
|
120
147
|
hoverContainer: ViewStyle | null;
|
|
@@ -126,28 +153,101 @@ interface ButtonTokens {
|
|
|
126
153
|
pressedIconColor: string;
|
|
127
154
|
iconSize: number;
|
|
128
155
|
accessoryOffset: number;
|
|
156
|
+
/** Idle glass overlay (token `button/background` under Button type=glass). */
|
|
157
|
+
glassOverlayIdle: string;
|
|
158
|
+
glassOverlayHover: string | null;
|
|
159
|
+
glassOverlayPressed: string;
|
|
160
|
+
/** `blur/minimal` mapped to GlassFill's 0–100 intensity scale. */
|
|
161
|
+
glassBlurIntensity: number;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
type ButtonInteractiveState = 'Idle' | 'Hover' | 'Pressed' | 'Disabled'
|
|
165
|
+
|
|
166
|
+
const BUTTON_STATE_VALUES = new Set<string>(['Idle', 'Hover', 'Pressed', 'Disabled'])
|
|
167
|
+
const SOLID_STATE_COLLECTION = 'Button / State'
|
|
168
|
+
const GLASS_STATE_COLLECTION = 'Button Glass State'
|
|
169
|
+
|
|
170
|
+
function resolveIsGlass(type: ButtonType, modes: Modes): boolean {
|
|
171
|
+
return type === 'glass' || modes['Button type'] === 'glass'
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Pick Idle/Hover/Pressed/Disabled from the active state collection, falling
|
|
176
|
+
* back to the sibling collection when callers pass the other key (e.g. glass
|
|
177
|
+
* buttons that still send `Button / State`). Never treats a collection name
|
|
178
|
+
* as a mode value.
|
|
179
|
+
*/
|
|
180
|
+
function pickButtonInteractiveState(
|
|
181
|
+
modes: Modes,
|
|
182
|
+
isGlass: boolean,
|
|
183
|
+
): ButtonInteractiveState {
|
|
184
|
+
const primary = isGlass ? GLASS_STATE_COLLECTION : SOLID_STATE_COLLECTION
|
|
185
|
+
const sibling = isGlass ? SOLID_STATE_COLLECTION : GLASS_STATE_COLLECTION
|
|
186
|
+
const candidate = modes[primary] ?? modes[sibling]
|
|
187
|
+
if (typeof candidate === 'string' && BUTTON_STATE_VALUES.has(candidate)) {
|
|
188
|
+
return candidate as ButtonInteractiveState
|
|
189
|
+
}
|
|
190
|
+
return 'Idle'
|
|
129
191
|
}
|
|
130
192
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
const
|
|
138
|
-
const
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
193
|
+
/** Write a valid interactive state onto the correct collection for glass/solid. */
|
|
194
|
+
function withButtonInteractiveState(
|
|
195
|
+
modes: Modes,
|
|
196
|
+
isGlass: boolean,
|
|
197
|
+
state: ButtonInteractiveState,
|
|
198
|
+
): Modes {
|
|
199
|
+
const collection = isGlass ? GLASS_STATE_COLLECTION : SOLID_STATE_COLLECTION
|
|
200
|
+
const sibling = isGlass ? SOLID_STATE_COLLECTION : GLASS_STATE_COLLECTION
|
|
201
|
+
const { [sibling]: _dropSibling, ...rest } = modes
|
|
202
|
+
return { ...rest, [collection]: state }
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
function resolveButtonTokens(
|
|
206
|
+
modes: Modes,
|
|
207
|
+
disabled: boolean,
|
|
208
|
+
type: ButtonType,
|
|
209
|
+
): ButtonTokens {
|
|
210
|
+
const isGlass = resolveIsGlass(type, modes)
|
|
211
|
+
const isFixed = type === 'fixed'
|
|
212
|
+
|
|
213
|
+
// Inject the Button type mode so token aliases (background/foreground) resolve
|
|
214
|
+
// to the glass palette. Callers can also drive glass solely via modes.
|
|
215
|
+
const effectiveModes: Modes = isGlass
|
|
216
|
+
? { ...modes, 'Button type': 'glass' }
|
|
217
|
+
: modes
|
|
218
|
+
|
|
219
|
+
// Glass interactive states live on `Button Glass State`; solid on `Button / State`.
|
|
220
|
+
// Map Idle/Hover/Pressed/Disabled values through — never assign a collection name.
|
|
221
|
+
const idleState: ButtonInteractiveState =
|
|
222
|
+
disabled && isGlass ? 'Disabled' : pickButtonInteractiveState(effectiveModes, isGlass)
|
|
223
|
+
const idleModes = withButtonInteractiveState(effectiveModes, isGlass, idleState)
|
|
224
|
+
|
|
225
|
+
const backgroundColor = getVariableByName('button/background', idleModes)
|
|
226
|
+
const borderColor = getVariableByName('button/border/color', idleModes)
|
|
227
|
+
const borderWidth = getVariableByName('button/border/size', idleModes)
|
|
228
|
+
const radius = getVariableByName('button/radius', idleModes)
|
|
229
|
+
const paddingHorizontal = getVariableByName('button/padding/horizontal', idleModes)
|
|
230
|
+
const paddingVertical = getVariableByName('button/padding/vertical', idleModes)
|
|
231
|
+
const gap = getVariableByName('button/gap', idleModes)
|
|
232
|
+
const maxWidth = getVariableByName('button/maxWidth', idleModes)
|
|
233
|
+
|
|
234
|
+
const fontFamily = getVariableByName('button/fontFamily', idleModes)
|
|
235
|
+
const fontWeightValue = getVariableByName('button/fontWeight', idleModes)
|
|
142
236
|
const fontWeight = typeof fontWeightValue === 'number' ? fontWeightValue.toString() : fontWeightValue
|
|
143
|
-
const lineHeight = getVariableByName('button/lineHeight',
|
|
144
|
-
const fontSize = getVariableByName('button/fontSize',
|
|
145
|
-
const textColor = getVariableByName('button/foreground',
|
|
146
|
-
const iconSize = (getVariableByName('button/icon/size',
|
|
147
|
-
|
|
148
|
-
//
|
|
149
|
-
|
|
150
|
-
|
|
237
|
+
const lineHeight = getVariableByName('button/lineHeight', idleModes)
|
|
238
|
+
const fontSize = getVariableByName('button/fontSize', idleModes)
|
|
239
|
+
const textColor = getVariableByName('button/foreground', idleModes)
|
|
240
|
+
const iconSize = (getVariableByName('button/icon/size', idleModes) ?? 18) as number
|
|
241
|
+
|
|
242
|
+
// Figma `blur/minimal` (px radius) -> GlassFill's 0–100 intensity scale.
|
|
243
|
+
const glassBlurIntensity = Math.max(
|
|
244
|
+
0,
|
|
245
|
+
Math.min(100, Math.round(Number(getVariableByName('blur/minimal', idleModes) ?? 29))),
|
|
246
|
+
)
|
|
247
|
+
|
|
248
|
+
// Pressed tokens are always resolved so the Pressable `style` callback /
|
|
249
|
+
// glass overlay can apply the pressed visual without a modes recompute.
|
|
250
|
+
const pressedModes = withButtonInteractiveState(effectiveModes, isGlass, 'Pressed')
|
|
151
251
|
const pressedBg = getVariableByName('button/background', pressedModes)
|
|
152
252
|
const pressedBorderColor = getVariableByName('button/border/color', pressedModes)
|
|
153
253
|
const pressedTextColor = (getVariableByName('button/foreground', pressedModes)) as string
|
|
@@ -156,15 +256,22 @@ function resolveButtonTokens(modes: Modes, disabled: boolean): ButtonTokens {
|
|
|
156
256
|
// ~3 token lookups + an object spread per render on every Button.
|
|
157
257
|
let hoverContainer: ViewStyle | null = null
|
|
158
258
|
let hoverTextColor: string | null = null
|
|
259
|
+
let glassOverlayHover: string | null = null
|
|
159
260
|
if (IS_WEB) {
|
|
160
|
-
const hoverModes =
|
|
261
|
+
const hoverModes = withButtonInteractiveState(effectiveModes, isGlass, 'Hover')
|
|
161
262
|
const hoverBg = getVariableByName('button/background', hoverModes)
|
|
162
263
|
const hoverBorderColor = getVariableByName('button/border/color', hoverModes)
|
|
163
264
|
hoverTextColor = (getVariableByName('button/foreground', hoverModes)) as string
|
|
164
|
-
|
|
265
|
+
glassOverlayHover = hoverBg as string
|
|
266
|
+
// Glass keeps the host transparent; hover only retints the GlassFill overlay.
|
|
267
|
+
hoverContainer = isGlass
|
|
268
|
+
? null
|
|
269
|
+
: { backgroundColor: hoverBg as string, borderColor: hoverBorderColor as string }
|
|
165
270
|
}
|
|
166
271
|
|
|
167
272
|
return {
|
|
273
|
+
isGlass,
|
|
274
|
+
isFixed,
|
|
168
275
|
container: {
|
|
169
276
|
...containerLayoutStyle,
|
|
170
277
|
paddingHorizontal: paddingHorizontal as number,
|
|
@@ -172,9 +279,14 @@ function resolveButtonTokens(modes: Modes, disabled: boolean): ButtonTokens {
|
|
|
172
279
|
borderRadius: radius as number,
|
|
173
280
|
borderWidth: (borderWidth ?? 1) as number,
|
|
174
281
|
borderColor: borderColor as string,
|
|
175
|
-
|
|
282
|
+
// Glass: transparent host so GlassFill shows through. Fixed: clamp width.
|
|
283
|
+
backgroundColor: isGlass ? 'transparent' : (backgroundColor as string),
|
|
176
284
|
gap: gap as number,
|
|
177
|
-
|
|
285
|
+
// Glass disabled uses Button Glass State=Disabled foreground tokens —
|
|
286
|
+
// don't also apply the solid-button opacity fade.
|
|
287
|
+
opacity: disabled && !isGlass ? 0.5 : 1,
|
|
288
|
+
...(isGlass ? { overflow: 'hidden' as const } : null),
|
|
289
|
+
...(isFixed && maxWidth != null ? { maxWidth: maxWidth as number } : null),
|
|
178
290
|
},
|
|
179
291
|
baseLabel: {
|
|
180
292
|
color: textColor as string,
|
|
@@ -184,10 +296,12 @@ function resolveButtonTokens(modes: Modes, disabled: boolean): ButtonTokens {
|
|
|
184
296
|
lineHeight: lineHeight as number,
|
|
185
297
|
},
|
|
186
298
|
hoverContainer,
|
|
187
|
-
pressedContainer:
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
299
|
+
pressedContainer: isGlass
|
|
300
|
+
? {}
|
|
301
|
+
: {
|
|
302
|
+
backgroundColor: pressedBg as string,
|
|
303
|
+
borderColor: pressedBorderColor as string,
|
|
304
|
+
},
|
|
191
305
|
hoverTextColor,
|
|
192
306
|
pressedTextColor,
|
|
193
307
|
baseIconColor: textColor as string,
|
|
@@ -195,6 +309,10 @@ function resolveButtonTokens(modes: Modes, disabled: boolean): ButtonTokens {
|
|
|
195
309
|
pressedIconColor: pressedTextColor,
|
|
196
310
|
iconSize,
|
|
197
311
|
accessoryOffset: (gap as number) / 2,
|
|
312
|
+
glassOverlayIdle: backgroundColor as string,
|
|
313
|
+
glassOverlayHover,
|
|
314
|
+
glassOverlayPressed: pressedBg as string,
|
|
315
|
+
glassBlurIntensity,
|
|
198
316
|
}
|
|
199
317
|
}
|
|
200
318
|
|
|
@@ -240,6 +358,9 @@ function ButtonImpl({
|
|
|
240
358
|
leading,
|
|
241
359
|
trailing,
|
|
242
360
|
icon,
|
|
361
|
+
type = 'default',
|
|
362
|
+
glassOverlayColor,
|
|
363
|
+
glassIntensity,
|
|
243
364
|
modes = EMPTY_MODES,
|
|
244
365
|
onPress,
|
|
245
366
|
disabled = false,
|
|
@@ -271,8 +392,8 @@ function ButtonImpl({
|
|
|
271
392
|
userHandlersRef.current.onHoverOut = (rest as any)?.onHoverOut
|
|
272
393
|
|
|
273
394
|
const tokens = useMemo(
|
|
274
|
-
() => resolveButtonTokens(modes, disabled),
|
|
275
|
-
[modes, disabled]
|
|
395
|
+
() => resolveButtonTokens(modes, disabled, type),
|
|
396
|
+
[modes, disabled, type]
|
|
276
397
|
)
|
|
277
398
|
|
|
278
399
|
// Skeleton context — read unconditionally so React's hook order stays
|
|
@@ -412,6 +533,26 @@ function ButtonImpl({
|
|
|
412
533
|
)
|
|
413
534
|
}
|
|
414
535
|
|
|
536
|
+
const body = (
|
|
537
|
+
<>
|
|
538
|
+
{leading ? (
|
|
539
|
+
<View style={leadingAccessoryStyle}>
|
|
540
|
+
{leading}
|
|
541
|
+
</View>
|
|
542
|
+
) : null}
|
|
543
|
+
{content}
|
|
544
|
+
{icon ? (
|
|
545
|
+
<View style={trailingAccessoryStyle}>
|
|
546
|
+
<Icon name={icon} size={tokens.iconSize} color={activeIconColor} accessibilityElementsHidden={true} importantForAccessibility="no" />
|
|
547
|
+
</View>
|
|
548
|
+
) : trailing ? (
|
|
549
|
+
<View style={trailingAccessoryStyle}>
|
|
550
|
+
{trailing}
|
|
551
|
+
</View>
|
|
552
|
+
) : null}
|
|
553
|
+
</>
|
|
554
|
+
)
|
|
555
|
+
|
|
415
556
|
return (
|
|
416
557
|
<Pressable
|
|
417
558
|
accessibilityRole="button"
|
|
@@ -431,21 +572,28 @@ function ButtonImpl({
|
|
|
431
572
|
style={styleCallback}
|
|
432
573
|
{...webProps}
|
|
433
574
|
>
|
|
434
|
-
{
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
575
|
+
{tokens.isGlass
|
|
576
|
+
? ({ pressed }: PressableStateCallbackType) => {
|
|
577
|
+
const overlayColor =
|
|
578
|
+
glassOverlayColor ??
|
|
579
|
+
(pressed && !disabled
|
|
580
|
+
? tokens.glassOverlayPressed
|
|
581
|
+
: isHovered && !disabled && tokens.glassOverlayHover
|
|
582
|
+
? tokens.glassOverlayHover
|
|
583
|
+
: tokens.glassOverlayIdle)
|
|
584
|
+
return (
|
|
585
|
+
<>
|
|
586
|
+
<GlassFill
|
|
587
|
+
tint="light"
|
|
588
|
+
intensity={glassIntensity ?? tokens.glassBlurIntensity}
|
|
589
|
+
overlayColor={overlayColor}
|
|
590
|
+
androidTintWash={false}
|
|
591
|
+
/>
|
|
592
|
+
{body}
|
|
593
|
+
</>
|
|
594
|
+
)
|
|
595
|
+
}
|
|
596
|
+
: body}
|
|
449
597
|
</Pressable>
|
|
450
598
|
)
|
|
451
599
|
}
|
|
@@ -16,7 +16,7 @@ export type ButtonGroupProps = {
|
|
|
16
16
|
*/
|
|
17
17
|
children?: React.ReactNode;
|
|
18
18
|
/**
|
|
19
|
-
* Mode configuration for design tokens (e.g., {"Button / Size": "M", "
|
|
19
|
+
* Mode configuration for design tokens (e.g., {"Button / Size": "M", "Emphasis": "High"})
|
|
20
20
|
* These modes are passed down to all child components.
|
|
21
21
|
*/
|
|
22
22
|
modes?: Modes;
|
|
@@ -37,7 +37,7 @@ export type ButtonGroupProps = {
|
|
|
37
37
|
* @component
|
|
38
38
|
* @example
|
|
39
39
|
* ```jsx
|
|
40
|
-
* <ButtonGroup modes={{"
|
|
40
|
+
* <ButtonGroup modes={{"Color Mode": "Light"}}>
|
|
41
41
|
* <IconButton iconName="ic_qr_code" />
|
|
42
42
|
* <Button label="Pay" />
|
|
43
43
|
* </ButtonGroup>
|