@ankhorage/zora 4.4.1 → 4.5.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/CHANGELOG.md +6 -0
- package/README.md +1 -1
- package/dist/components/radio/RadioGroup.d.ts +1 -3
- package/dist/components/radio/RadioGroup.d.ts.map +1 -1
- package/dist/components/radio/RadioGroup.js +52 -40
- package/dist/components/radio/RadioGroup.js.map +1 -1
- package/dist/components/radio/RadioOptionControl.d.ts +15 -0
- package/dist/components/radio/RadioOptionControl.d.ts.map +1 -0
- package/dist/components/radio/RadioOptionControl.js +105 -0
- package/dist/components/radio/RadioOptionControl.js.map +1 -0
- package/dist/components/radio/handleRadioOptionKeyDown.d.ts +13 -0
- package/dist/components/radio/handleRadioOptionKeyDown.d.ts.map +1 -0
- package/dist/components/radio/handleRadioOptionKeyDown.js +22 -0
- package/dist/components/radio/handleRadioOptionKeyDown.js.map +1 -0
- package/dist/components/radio/meta.d.ts +38 -3
- package/dist/components/radio/meta.d.ts.map +1 -1
- package/dist/components/radio/meta.js +28 -3
- package/dist/components/radio/meta.js.map +1 -1
- package/dist/components/radio/resolveRadioOptionColors.d.ts +10 -0
- package/dist/components/radio/resolveRadioOptionColors.d.ts.map +1 -0
- package/dist/components/radio/resolveRadioOptionColors.js +27 -0
- package/dist/components/radio/resolveRadioOptionColors.js.map +1 -0
- package/dist/components/radio/types.d.ts +12 -2
- package/dist/components/radio/types.d.ts.map +1 -1
- package/dist/components/radio/types.js.map +1 -1
- package/dist/constants/keyboard.d.ts +3 -0
- package/dist/constants/keyboard.d.ts.map +1 -0
- package/dist/constants/keyboard.js +8 -0
- package/dist/constants/keyboard.js.map +1 -0
- package/package.json +1 -1
- package/src/components/radio/RadioGroup.test.ts +13 -9
- package/src/components/radio/RadioGroup.tsx +85 -111
- package/src/components/radio/RadioOptionControl.tsx +192 -0
- package/src/components/radio/handleRadioOptionKeyDown.test.ts +47 -0
- package/src/components/radio/handleRadioOptionKeyDown.ts +37 -0
- package/src/components/radio/meta.ts +28 -3
- package/src/components/radio/resolveRadioOptionColors.test.ts +29 -0
- package/src/components/radio/resolveRadioOptionColors.ts +37 -0
- package/src/components/radio/types.ts +10 -2
- package/src/constants/keyboard.ts +7 -0
- package/src/metadata/componentMeta.test.ts +1 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"meta.js","sourceRoot":"","sources":["../../../src/components/radio/meta.ts"],"names":[],"mappings":"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","sourcesContent":["import { ZORA_COLORS } from '../../internal/colorModel';\nimport type { ZoraComponentMeta } from '../../metadata';\n\nconst themeAuthoring = {\n authority: 'theme',\n scope: 'component',\n allowInstanceOverride: true,\n} as const;\n\nexport const radioMeta = {\n name: 'Radio',\n category: 'component',\n directManifestNode: false,\n allowedChildren: [],\n note: 'Composition-level radio control; author repeated single-choice UI through RadioGroup.',\n props: {},\n} as const satisfies ZoraComponentMeta;\n\nexport const radioGroupMeta = {\n name: 'RadioGroup',\n category: 'component',\n description:\n 'Single-choice group with inline or card presentation while preserving radio semantics.',\n directManifestNode: true,\n allowedChildren: [],\n blueprint: {\n label: 'Radio group',\n defaultProps: {\n value: 'option-b',\n options: [\n { value: 'option-a', label: 'First option', description: 'Supporting detail' },\n { value: 'option-b', label: 'Second option', description: 'Supporting detail' },\n { value: 'option-c', label: 'Third option', description: 'Supporting detail' },\n ],\n orientation: 'vertical',\n presentation: 'inline',\n invalid: false,\n readOnly: false,\n disabled: false,\n },\n },\n bindings: {\n props: {\n value: {\n label: 'Value',\n description: 'Currently selected option value.',\n value: { type: 'string' },\n acceptsFallback: true,\n acceptsTransforms: true,\n },\n disabled: {\n label: 'Disabled',\n description: 'Whether the complete radio group is disabled.',\n value: { type: 'boolean' },\n acceptsFallback: true,\n acceptsTransforms: true,\n },\n },\n events: {\n valueChange: {\n label: 'Value change',\n description: 'Runs when the selected radio value changes.',\n payload: {\n eventType: 'radioGroup.valueChange',\n fields: [{ path: 'value', type: 'string', label: 'Value' }],\n },\n },\n },\n },\n events: {\n valueChange: {\n label: 'Value change',\n eventType: 'radioGroup.valueChange',\n description: 'Emitted when the selected radio value changes.',\n payloadFields: [{ path: 'value', type: 'string', label: 'Value' }],\n },\n },\n props: {\n value: {\n type: 'string',\n category: 'State',\n label: 'Value',\n authoring: { authority: 'instance' },\n },\n options: {\n type: 'array',\n category: 'Content',\n label: 'Options',\n itemSchema: [\n {\n key: 'value',\n schema: {\n type: 'string',\n category: 'Content',\n label: 'Value',\n },\n },\n {\n key: 'label',\n schema: {\n type: 'string',\n category: 'Content',\n label: 'Label',\n },\n },\n {\n key: 'description',\n schema: {\n type: 'string',\n category: 'Content',\n label: 'Description',\n },\n },\n {\n key: 'disabled',\n schema: {\n type: 'boolean',\n category: 'State',\n label: 'Disabled',\n default: false,\n },\n },\n ],\n authoring: { authority: 'instance' },\n },\n orientation: {\n type: 'enum',\n category: 'Layout',\n label: 'Orientation',\n enum: ['horizontal', 'vertical'],\n default: 'vertical',\n authoring: { authority: 'instance' },\n },\n gap: {\n type: 'enum',\n category: 'Layout',\n label: 'Gap',\n enum: ['xs', 's', 'm', 'l'],\n authoring: themeAuthoring,\n },\n presentation: {\n type: 'enum',\n category: 'Style',\n label: 'Presentation',\n enum: ['inline', 'card'],\n default: 'inline',\n authoring: { authority: 'instance' },\n },\n color: {\n type: 'enum',\n category: 'Style',\n label: 'Color',\n enum: [...ZORA_COLORS],\n authoring: themeAuthoring,\n },\n size: {\n type: 'enum',\n category: 'Style',\n label: 'Size',\n enum: ['s', 'm', 'l'],\n authoring: themeAuthoring,\n },\n invalid: {\n type: 'boolean',\n category: 'State',\n label: 'Invalid',\n default: false,\n authoring: { authority: 'instance' },\n },\n readOnly: {\n type: 'boolean',\n category: 'State',\n label: 'Read only',\n default: false,\n authoring: { authority: 'instance' },\n },\n disabled: {\n type: 'boolean',\n category: 'State',\n label: 'Disabled',\n default: false,\n authoring: { authority: 'instance' },\n },\n },\n} as const satisfies ZoraComponentMeta;\n"]}
|
|
1
|
+
{"version":3,"file":"meta.js","sourceRoot":"","sources":["../../../src/components/radio/meta.ts"],"names":[],"mappings":"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","sourcesContent":["import { ZORA_COLORS } from '../../internal/colorModel';\nimport type { ZoraComponentMeta } from '../../metadata';\n\nconst themeAuthoring = {\n authority: 'theme',\n scope: 'component',\n allowInstanceOverride: true,\n} as const;\n\nexport const radioMeta = {\n name: 'Radio',\n category: 'component',\n directManifestNode: false,\n allowedChildren: [],\n note: 'Composition-level radio control; author repeated single-choice UI through RadioGroup.',\n props: {},\n} as const satisfies ZoraComponentMeta;\n\nexport const radioGroupMeta = {\n name: 'RadioGroup',\n category: 'component',\n description:\n 'Single-choice group with inline or card presentation while preserving radio semantics.',\n directManifestNode: true,\n allowedChildren: [],\n blueprint: {\n label: 'Radio button group',\n defaultProps: {\n defaultValue: 'option-b',\n options: [\n { value: 'option-a', label: 'First option', description: 'Supporting detail' },\n { value: 'option-b', label: 'Second option', description: 'Supporting detail' },\n { value: 'option-c', label: 'Third option', description: 'Supporting detail' },\n ],\n orientation: 'vertical',\n presentation: 'card',\n invalid: false,\n readOnly: false,\n disabled: false,\n },\n },\n bindings: {\n props: {\n value: {\n label: 'Value',\n description: 'Currently selected option value.',\n value: { type: 'string' },\n acceptsFallback: true,\n acceptsTransforms: true,\n },\n disabled: {\n label: 'Disabled',\n description: 'Whether the complete radio group is disabled.',\n value: { type: 'boolean' },\n acceptsFallback: true,\n acceptsTransforms: true,\n },\n },\n events: {\n valueChange: {\n label: 'Value change',\n description: 'Runs when the selected radio value changes.',\n payload: {\n eventType: 'radioGroup.valueChange',\n fields: [{ path: 'value', type: 'string', label: 'Value' }],\n },\n },\n },\n },\n events: {\n valueChange: {\n label: 'Value change',\n eventType: 'radioGroup.valueChange',\n description: 'Emitted when the selected radio value changes.',\n payloadFields: [{ path: 'value', type: 'string', label: 'Value' }],\n },\n },\n props: {\n defaultValue: {\n type: 'string',\n category: 'State',\n label: 'Initial value',\n authoring: { authority: 'instance' },\n },\n value: {\n type: 'string',\n category: 'State',\n label: 'Value',\n authoring: { authority: 'instance' },\n },\n options: {\n type: 'array',\n category: 'Content',\n label: 'Options',\n itemSchema: [\n {\n key: 'value',\n schema: {\n type: 'string',\n category: 'Content',\n label: 'Value',\n },\n },\n {\n key: 'label',\n schema: {\n type: 'string',\n category: 'Content',\n label: 'Label',\n },\n },\n {\n key: 'description',\n schema: {\n type: 'string',\n category: 'Content',\n label: 'Description',\n },\n },\n {\n key: 'iconSource',\n schema: { type: 'media', category: 'Content', label: 'Icon', mediaKinds: ['image'] },\n },\n {\n key: 'disabled',\n schema: {\n type: 'boolean',\n category: 'State',\n label: 'Disabled',\n default: false,\n },\n },\n ],\n authoring: { authority: 'instance' },\n },\n orientation: {\n type: 'enum',\n category: 'Layout',\n label: 'Orientation',\n enum: ['horizontal', 'vertical'],\n default: 'vertical',\n authoring: { authority: 'instance' },\n },\n gap: {\n type: 'enum',\n category: 'Layout',\n label: 'Gap',\n enum: ['xs', 's', 'm', 'l'],\n authoring: themeAuthoring,\n },\n presentation: {\n type: 'enum',\n category: 'Style',\n label: 'Presentation',\n enum: ['inline', 'card'],\n default: 'inline',\n authoring: { authority: 'instance' },\n },\n contentOrientation: {\n type: 'enum',\n category: 'Layout',\n label: 'Option content orientation',\n enum: ['horizontal', 'vertical'],\n default: 'horizontal',\n authoring: { authority: 'instance' },\n },\n columns: {\n type: 'enum',\n category: 'Layout',\n label: 'Option columns',\n enum: [1, 2, 3, 4],\n authoring: { authority: 'instance' },\n },\n color: {\n type: 'enum',\n category: 'Style',\n label: 'Color',\n enum: [...ZORA_COLORS],\n authoring: themeAuthoring,\n },\n size: {\n type: 'enum',\n category: 'Style',\n label: 'Size',\n enum: ['s', 'm', 'l'],\n authoring: themeAuthoring,\n },\n invalid: {\n type: 'boolean',\n category: 'State',\n label: 'Invalid',\n default: false,\n authoring: { authority: 'instance' },\n },\n readOnly: {\n type: 'boolean',\n category: 'State',\n label: 'Read only',\n default: false,\n authoring: { authority: 'instance' },\n },\n disabled: {\n type: 'boolean',\n category: 'State',\n label: 'Disabled',\n default: false,\n authoring: { authority: 'instance' },\n },\n },\n} as const satisfies ZoraComponentMeta;\n"]}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { SurfaceTheme } from '@ankhorage/surface';
|
|
2
|
+
import type { RadioGroupProps } from './types';
|
|
3
|
+
/*** Resolve selection-card decoration from the requested semantic role and field state. */
|
|
4
|
+
export declare function resolveRadioOptionColors(theme: SurfaceTheme, { color, invalid, disabled, }: Pick<RadioGroupProps<string>, 'color' | 'invalid' | 'disabled'>): {
|
|
5
|
+
accent: string;
|
|
6
|
+
onAccent: string;
|
|
7
|
+
border: string;
|
|
8
|
+
surface: string;
|
|
9
|
+
};
|
|
10
|
+
//# sourceMappingURL=resolveRadioOptionColors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolveRadioOptionColors.d.ts","sourceRoot":"","sources":["../../../src/components/radio/resolveRadioOptionColors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAiB,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEtE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAE/C,2FAA2F;AAC3F,wBAAgB,wBAAwB,CACtC,KAAK,EAAE,YAAY,EACnB,EACE,KAAiB,EACjB,OAAO,EACP,QAAQ,GACT,EAAE,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,EAAE,OAAO,GAAG,SAAS,GAAG,UAAU,CAAC;;;;;EAyBnE"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/*** Resolve selection-card decoration from the requested semantic role and field state. */
|
|
2
|
+
export function resolveRadioOptionColors(theme, { color = 'primary', invalid, disabled, }) {
|
|
3
|
+
const roles = new Map([
|
|
4
|
+
['primary', theme.semantics.action.primary],
|
|
5
|
+
['secondary', theme.semantics.secondary],
|
|
6
|
+
['tertiary', theme.semantics.accent],
|
|
7
|
+
['quaternary', theme.semantics.highlight],
|
|
8
|
+
['neutral', theme.semantics.action.neutral],
|
|
9
|
+
['danger', theme.semantics.action.danger],
|
|
10
|
+
['error', theme.semantics.error],
|
|
11
|
+
['success', theme.semantics.success],
|
|
12
|
+
['warning', theme.semantics.warning],
|
|
13
|
+
['info', theme.semantics.info],
|
|
14
|
+
]);
|
|
15
|
+
const role = roles.get(invalid ? 'error' : color) ?? theme.semantics.action.primary;
|
|
16
|
+
return {
|
|
17
|
+
accent: disabled ? theme.semantics.content.disabled : role.base,
|
|
18
|
+
onAccent: disabled ? theme.semantics.surface.disabled : role.onSolidText,
|
|
19
|
+
border: disabled
|
|
20
|
+
? theme.semantics.border.subtle
|
|
21
|
+
: invalid
|
|
22
|
+
? role.outline
|
|
23
|
+
: theme.semantics.border.default,
|
|
24
|
+
surface: disabled ? theme.semantics.surface.disabled : theme.semantics.surface.default,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=resolveRadioOptionColors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolveRadioOptionColors.js","sourceRoot":"","sources":["../../../src/components/radio/resolveRadioOptionColors.ts"],"names":[],"mappings":"AAIA,2FAA2F;AAC3F,MAAM,UAAU,wBAAwB,CACtC,KAAmB,EACnB,EACE,KAAK,GAAG,SAAS,EACjB,OAAO,EACP,QAAQ,GACwD;IAElE,MAAM,KAAK,GAAG,IAAI,GAAG,CAAwB;QAC3C,CAAC,SAAS,EAAE,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,OAAO,CAAC;QAC3C,CAAC,WAAW,EAAE,KAAK,CAAC,SAAS,CAAC,SAAS,CAAC;QACxC,CAAC,UAAU,EAAE,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC;QACpC,CAAC,YAAY,EAAE,KAAK,CAAC,SAAS,CAAC,SAAS,CAAC;QACzC,CAAC,SAAS,EAAE,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,OAAO,CAAC;QAC3C,CAAC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC;QACzC,CAAC,OAAO,EAAE,KAAK,CAAC,SAAS,CAAC,KAAK,CAAC;QAChC,CAAC,SAAS,EAAE,KAAK,CAAC,SAAS,CAAC,OAAO,CAAC;QACpC,CAAC,SAAS,EAAE,KAAK,CAAC,SAAS,CAAC,OAAO,CAAC;QACpC,CAAC,MAAM,EAAE,KAAK,CAAC,SAAS,CAAC,IAAI,CAAC;KAC/B,CAAC,CAAC;IACH,MAAM,IAAI,GAAG,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,OAAO,CAAC;IACpF,OAAO;QACL,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI;QAC/D,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW;QACxE,MAAM,EAAE,QAAQ;YACd,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,MAAM;YAC/B,CAAC,CAAC,OAAO;gBACP,CAAC,CAAC,IAAI,CAAC,OAAO;gBACd,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,OAAO;QACpC,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,OAAO,CAAC,OAAO;KACvF,CAAC;AACJ,CAAC","sourcesContent":["import type { RoleSemantics, SurfaceTheme } from '@ankhorage/surface';\n\nimport type { RadioGroupProps } from './types';\n\n/*** Resolve selection-card decoration from the requested semantic role and field state. */\nexport function resolveRadioOptionColors(\n theme: SurfaceTheme,\n {\n color = 'primary',\n invalid,\n disabled,\n }: Pick<RadioGroupProps<string>, 'color' | 'invalid' | 'disabled'>,\n) {\n const roles = new Map<string, RoleSemantics>([\n ['primary', theme.semantics.action.primary],\n ['secondary', theme.semantics.secondary],\n ['tertiary', theme.semantics.accent],\n ['quaternary', theme.semantics.highlight],\n ['neutral', theme.semantics.action.neutral],\n ['danger', theme.semantics.action.danger],\n ['error', theme.semantics.error],\n ['success', theme.semantics.success],\n ['warning', theme.semantics.warning],\n ['info', theme.semantics.info],\n ]);\n const role = roles.get(invalid ? 'error' : color) ?? theme.semantics.action.primary;\n return {\n accent: disabled ? theme.semantics.content.disabled : role.base,\n onAccent: disabled ? theme.semantics.surface.disabled : role.onSolidText,\n border: disabled\n ? theme.semantics.border.subtle\n : invalid\n ? role.outline\n : theme.semantics.border.default,\n surface: disabled ? theme.semantics.surface.disabled : theme.semantics.surface.default,\n };\n}\n"]}
|
|
@@ -1,21 +1,31 @@
|
|
|
1
1
|
import type { RadioProps as SurfaceRadioProps } from '@ankhorage/surface';
|
|
2
2
|
import type React from 'react';
|
|
3
3
|
import type { ZoraBaseProps } from '../../theme/ZoraBaseProps';
|
|
4
|
+
import type { IconProps } from '../icon';
|
|
4
5
|
export interface RadioProps extends ZoraBaseProps, Omit<SurfaceRadioProps, 'mode' | 'themeId'> {
|
|
5
6
|
}
|
|
6
7
|
export interface RadioGroupOption<TValue extends string> {
|
|
7
8
|
value: TValue;
|
|
8
9
|
label: React.ReactNode;
|
|
9
10
|
description?: React.ReactNode;
|
|
11
|
+
/** SVG media is resolved by the consuming runtime before rendering. */
|
|
12
|
+
iconSource?: Extract<IconProps, {
|
|
13
|
+
source: unknown;
|
|
14
|
+
}>['source'];
|
|
10
15
|
disabled?: boolean;
|
|
11
16
|
testID?: string;
|
|
12
17
|
}
|
|
13
18
|
export interface RadioGroupProps<TValue extends string> extends ZoraBaseProps, Pick<Omit<SurfaceRadioProps, 'mode' | 'themeId'>, 'color' | 'size' | 'invalid' | 'readOnly' | 'disabled'> {
|
|
14
|
-
value
|
|
15
|
-
|
|
19
|
+
value?: TValue;
|
|
20
|
+
defaultValue?: TValue;
|
|
21
|
+
onValueChange?: (value: TValue) => void;
|
|
16
22
|
options: readonly RadioGroupOption<TValue>[];
|
|
17
23
|
orientation?: 'horizontal' | 'vertical';
|
|
18
24
|
gap?: 'xs' | 's' | 'm' | 'l';
|
|
19
25
|
presentation?: 'inline' | 'card';
|
|
26
|
+
/** Arrangement inside a selection card, independent of the group direction. */
|
|
27
|
+
contentOrientation?: 'horizontal' | 'vertical';
|
|
28
|
+
/** Equal-width card columns; omitted columns follow orientation. */
|
|
29
|
+
columns?: 1 | 2 | 3 | 4;
|
|
20
30
|
}
|
|
21
31
|
//# sourceMappingURL=types.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/components/radio/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,IAAI,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAC1E,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/components/radio/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,IAAI,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAC1E,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAEzC,MAAM,WAAW,UAAW,SAAQ,aAAa,EAAE,IAAI,CAAC,iBAAiB,EAAE,MAAM,GAAG,SAAS,CAAC;CAAG;AAEjG,MAAM,WAAW,gBAAgB,CAAC,MAAM,SAAS,MAAM;IACrD,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,KAAK,CAAC,SAAS,CAAC;IACvB,WAAW,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC9B,uEAAuE;IACvE,UAAU,CAAC,EAAE,OAAO,CAAC,SAAS,EAAE;QAAE,MAAM,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC,QAAQ,CAAC,CAAC;IAC/D,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,eAAe,CAAC,MAAM,SAAS,MAAM,CACpD,SACE,aAAa,EACb,IAAI,CACF,IAAI,CAAC,iBAAiB,EAAE,MAAM,GAAG,SAAS,CAAC,EAC3C,OAAO,GAAG,MAAM,GAAG,SAAS,GAAG,UAAU,GAAG,UAAU,CACvD;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,OAAO,EAAE,SAAS,gBAAgB,CAAC,MAAM,CAAC,EAAE,CAAC;IAC7C,WAAW,CAAC,EAAE,YAAY,GAAG,UAAU,CAAC;IACxC,GAAG,CAAC,EAAE,IAAI,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC;IAC7B,YAAY,CAAC,EAAE,QAAQ,GAAG,MAAM,CAAC;IACjC,+EAA+E;IAC/E,kBAAkB,CAAC,EAAE,YAAY,GAAG,UAAU,CAAC;IAC/C,oEAAoE;IACpE,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;CACzB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/components/radio/types.ts"],"names":[],"mappings":"","sourcesContent":["import type { RadioProps as SurfaceRadioProps } from '@ankhorage/surface';\nimport type React from 'react';\n\nimport type { ZoraBaseProps } from '../../theme/ZoraBaseProps';\n\nexport interface RadioProps extends ZoraBaseProps, Omit<SurfaceRadioProps, 'mode' | 'themeId'> {}\n\nexport interface RadioGroupOption<TValue extends string> {\n value: TValue;\n label: React.ReactNode;\n description?: React.ReactNode;\n disabled?: boolean;\n testID?: string;\n}\n\nexport interface RadioGroupProps<TValue extends string>\n extends\n ZoraBaseProps,\n Pick<\n Omit<SurfaceRadioProps, 'mode' | 'themeId'>,\n 'color' | 'size' | 'invalid' | 'readOnly' | 'disabled'\n > {\n value
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/components/radio/types.ts"],"names":[],"mappings":"","sourcesContent":["import type { RadioProps as SurfaceRadioProps } from '@ankhorage/surface';\nimport type React from 'react';\n\nimport type { ZoraBaseProps } from '../../theme/ZoraBaseProps';\nimport type { IconProps } from '../icon';\n\nexport interface RadioProps extends ZoraBaseProps, Omit<SurfaceRadioProps, 'mode' | 'themeId'> {}\n\nexport interface RadioGroupOption<TValue extends string> {\n value: TValue;\n label: React.ReactNode;\n description?: React.ReactNode;\n /** SVG media is resolved by the consuming runtime before rendering. */\n iconSource?: Extract<IconProps, { source: unknown }>['source'];\n disabled?: boolean;\n testID?: string;\n}\n\nexport interface RadioGroupProps<TValue extends string>\n extends\n ZoraBaseProps,\n Pick<\n Omit<SurfaceRadioProps, 'mode' | 'themeId'>,\n 'color' | 'size' | 'invalid' | 'readOnly' | 'disabled'\n > {\n value?: TValue;\n defaultValue?: TValue;\n onValueChange?: (value: TValue) => void;\n options: readonly RadioGroupOption<TValue>[];\n orientation?: 'horizontal' | 'vertical';\n gap?: 'xs' | 's' | 'm' | 'l';\n presentation?: 'inline' | 'card';\n /** Arrangement inside a selection card, independent of the group direction. */\n contentOrientation?: 'horizontal' | 'vertical';\n /** Equal-width card columns; omitted columns follow orientation. */\n columns?: 1 | 2 | 3 | 4;\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"keyboard.d.ts","sourceRoot":"","sources":["../../src/constants/keyboard.ts"],"names":[],"mappings":"AAAA,6FAA6F;AAC7F,eAAO,MAAM,mBAAmB,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAK1D,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/** Shared arrow-key offsets; string keys also permit lookup of unrelated keyboard events. */
|
|
2
|
+
export const DIRECTION_MODIFIERS = new Map([
|
|
3
|
+
['ArrowRight', 1],
|
|
4
|
+
['ArrowDown', 1],
|
|
5
|
+
['ArrowLeft', -1],
|
|
6
|
+
['ArrowUp', -1],
|
|
7
|
+
]);
|
|
8
|
+
//# sourceMappingURL=keyboard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"keyboard.js","sourceRoot":"","sources":["../../src/constants/keyboard.ts"],"names":[],"mappings":"AAAA,6FAA6F;AAC7F,MAAM,CAAC,MAAM,mBAAmB,GAAgC,IAAI,GAAG,CAAC;IACtE,CAAC,YAAY,EAAE,CAAC,CAAC;IACjB,CAAC,WAAW,EAAE,CAAC,CAAC;IAChB,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;IACjB,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC;CAChB,CAAC,CAAC","sourcesContent":["/** Shared arrow-key offsets; string keys also permit lookup of unrelated keyboard events. */\nexport const DIRECTION_MODIFIERS: ReadonlyMap<string, number> = new Map([\n ['ArrowRight', 1],\n ['ArrowDown', 1],\n ['ArrowLeft', -1],\n ['ArrowUp', -1],\n]);\n"]}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ankhorage/zora",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "4.
|
|
4
|
+
"version": "4.5.0",
|
|
5
5
|
"description": "Opinionated React Native and React Native Web UI kit built on @ankhorage/surface.",
|
|
6
6
|
"homepage": "https://github.com/ankhorage/zora#readme",
|
|
7
7
|
"bugs": {
|
|
@@ -19,13 +19,17 @@ test('resolves RadioGroup theme defaults while preserving instance overrides', (
|
|
|
19
19
|
).toEqual({ gap: 'l', color: 'danger', size: 's' });
|
|
20
20
|
});
|
|
21
21
|
|
|
22
|
-
test('
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
expect(
|
|
26
|
-
expect(
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
expect(
|
|
30
|
-
|
|
22
|
+
test('icon radio options expose serializable authoring metadata', async () => {
|
|
23
|
+
const { radioGroupMeta } = await import('./meta');
|
|
24
|
+
expect(radioGroupMeta.directManifestNode).toBe(true);
|
|
25
|
+
expect(radioGroupMeta.blueprint.label).toBe('Radio button group');
|
|
26
|
+
expect(radioGroupMeta.blueprint.defaultProps.options.map((option) => option.value)).toContain(
|
|
27
|
+
radioGroupMeta.blueprint.defaultProps.defaultValue,
|
|
28
|
+
);
|
|
29
|
+
expect(
|
|
30
|
+
radioGroupMeta.props.options.itemSchema.find((field) => field.key === 'iconSource')?.schema,
|
|
31
|
+
).toMatchObject({ type: 'media', mediaKinds: ['image'] });
|
|
32
|
+
expect(radioGroupMeta.props.columns.enum).toEqual([1, 2, 3, 4]);
|
|
33
|
+
expect(radioGroupMeta.props.contentOrientation.enum).toEqual(['horizontal', 'vertical']);
|
|
34
|
+
expect(radioGroupMeta.events.valueChange.eventType).toBe('radioGroup.valueChange');
|
|
31
35
|
});
|
|
@@ -1,145 +1,117 @@
|
|
|
1
|
-
import { Radio
|
|
1
|
+
import { Radio } from '@ankhorage/surface';
|
|
2
2
|
import React from 'react';
|
|
3
|
-
import { View } from 'react-native';
|
|
3
|
+
import { StyleSheet, View } from 'react-native';
|
|
4
4
|
|
|
5
5
|
import { Stack } from '../../foundation';
|
|
6
6
|
import { useZoraThemeRecipe } from '../../theme/useZoraThemeRecipe';
|
|
7
7
|
import { withZoraThemeScope } from '../../theme/withZoraThemeScope';
|
|
8
8
|
import { Text } from '../text';
|
|
9
|
+
import { RadioOptionControl } from './RadioOptionControl';
|
|
9
10
|
import { resolveRadioGroupThemeRecipe } from './resolveRadioGroupThemeRecipe';
|
|
10
|
-
import type {
|
|
11
|
+
import type { RadioGroupProps } from './types';
|
|
11
12
|
|
|
12
|
-
/***
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
/*** Present one controlled single-choice group as inline radios or icon radio options. */
|
|
14
|
+
export const RadioGroup = withZoraThemeScope(RadioGroupInner);
|
|
15
|
+
|
|
16
|
+
/*** Resolve shared presentation once and preserve a single interaction boundary per option. */
|
|
15
17
|
function RadioGroupInner<TValue extends string>({
|
|
16
18
|
themeId: _themeId,
|
|
17
19
|
mode: _mode,
|
|
18
|
-
|
|
19
|
-
onValueChange,
|
|
20
|
-
options,
|
|
21
|
-
orientation = 'vertical',
|
|
22
|
-
gap,
|
|
23
|
-
presentation = 'inline',
|
|
24
|
-
color,
|
|
25
|
-
size,
|
|
26
|
-
invalid = false,
|
|
27
|
-
readOnly = false,
|
|
28
|
-
disabled = false,
|
|
29
|
-
testID,
|
|
30
|
-
interactionPolicy,
|
|
20
|
+
...props
|
|
31
21
|
}: RadioGroupProps<TValue>) {
|
|
32
|
-
const
|
|
22
|
+
const [localValue, setLocalValue] = React.useState(props.defaultValue);
|
|
23
|
+
const onValueChange = (next: TValue) => {
|
|
24
|
+
if (props.value === undefined) setLocalValue(next);
|
|
25
|
+
props.onValueChange?.(next);
|
|
26
|
+
};
|
|
27
|
+
const selectedProps = { ...props, value: props.value ?? localValue, onValueChange };
|
|
33
28
|
const themeFields = useZoraThemeRecipe('RadioGroup');
|
|
34
|
-
const recipe = resolveRadioGroupThemeRecipe({
|
|
29
|
+
const recipe = resolveRadioGroupThemeRecipe({ ...props, themeFields });
|
|
30
|
+
if (props.presentation !== 'card') return <RadioGroupInline {...selectedProps} {...recipe} />;
|
|
31
|
+
const columns =
|
|
32
|
+
props.columns ?? (props.orientation === 'horizontal' ? Math.max(1, props.options.length) : 1);
|
|
33
|
+
const rows = Array.from({ length: Math.ceil(props.options.length / columns) }, (_, index) =>
|
|
34
|
+
props.options.slice(index * columns, (index + 1) * columns),
|
|
35
|
+
);
|
|
36
|
+
return (
|
|
37
|
+
<View testID={props.testID} accessibilityRole="radiogroup">
|
|
38
|
+
<Stack gap={recipe.gap}>
|
|
39
|
+
{rows.map((options, index) => (
|
|
40
|
+
<Stack key={index} direction="row" gap={recipe.gap}>
|
|
41
|
+
{options.map((option) => (
|
|
42
|
+
<View key={option.value} style={styles.option}>
|
|
43
|
+
<RadioGroupItem {...selectedProps} {...recipe} option={option} />
|
|
44
|
+
</View>
|
|
45
|
+
))}
|
|
46
|
+
{Array.from({ length: columns - options.length }, (_, slot) => (
|
|
47
|
+
<View key={`empty-${slot}`} style={styles.option} />
|
|
48
|
+
))}
|
|
49
|
+
</Stack>
|
|
50
|
+
))}
|
|
51
|
+
</Stack>
|
|
52
|
+
</View>
|
|
53
|
+
);
|
|
54
|
+
}
|
|
35
55
|
|
|
56
|
+
/*** Preserve ordinary radio wrapping independently of the icon-option grid. */
|
|
57
|
+
function RadioGroupInline<TValue extends string>(props: RadioGroupProps<TValue>) {
|
|
36
58
|
return (
|
|
37
|
-
<View
|
|
38
|
-
testID={testID}
|
|
39
|
-
accessibilityRole="radiogroup"
|
|
40
|
-
style={{
|
|
41
|
-
flexDirection: isHorizontal ? 'row' : 'column',
|
|
42
|
-
flexWrap: isHorizontal ? 'wrap' : 'nowrap',
|
|
43
|
-
}}
|
|
44
|
-
>
|
|
59
|
+
<View testID={props.testID} accessibilityRole="radiogroup">
|
|
45
60
|
<Stack
|
|
46
|
-
direction={
|
|
47
|
-
gap={
|
|
48
|
-
wrap=
|
|
61
|
+
direction={props.orientation === 'horizontal' ? 'row' : 'column'}
|
|
62
|
+
gap={props.gap}
|
|
63
|
+
wrap="wrap"
|
|
49
64
|
>
|
|
50
|
-
{options.map((option) => (
|
|
51
|
-
<RadioGroupItem
|
|
52
|
-
key={option.value}
|
|
53
|
-
option={option}
|
|
54
|
-
checked={value === option.value}
|
|
55
|
-
disabled={disabled || option.disabled === true}
|
|
56
|
-
invalid={invalid}
|
|
57
|
-
readOnly={readOnly}
|
|
58
|
-
size={recipe.size}
|
|
59
|
-
color={recipe.color}
|
|
60
|
-
orientation={orientation}
|
|
61
|
-
presentation={presentation}
|
|
62
|
-
onSelect={onValueChange}
|
|
63
|
-
interactionPolicy={interactionPolicy}
|
|
64
|
-
/>
|
|
65
|
+
{props.options.map((option) => (
|
|
66
|
+
<RadioGroupItem key={option.value} {...props} option={option} />
|
|
65
67
|
))}
|
|
66
68
|
</Stack>
|
|
67
69
|
</View>
|
|
68
70
|
);
|
|
69
71
|
}
|
|
70
72
|
|
|
71
|
-
/***
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
orientation: NonNullable<RadioGroupProps<TValue>['orientation']>;
|
|
100
|
-
presentation: NonNullable<RadioGroupProps<TValue>['presentation']>;
|
|
101
|
-
onSelect: (value: TValue) => void;
|
|
102
|
-
interactionPolicy: RadioGroupProps<TValue>['interactionPolicy'];
|
|
103
|
-
}) {
|
|
104
|
-
const { theme } = useTheme();
|
|
105
|
-
const passive = interactionPolicy === 'passive';
|
|
106
|
-
const isCard = presentation === 'card';
|
|
107
|
-
|
|
73
|
+
/*** Delegate icon options to their composed radio boundary and ordinary options to Surface Radio. */
|
|
74
|
+
function RadioGroupItem<TValue extends string>(
|
|
75
|
+
props: RadioGroupProps<TValue> & {
|
|
76
|
+
option: RadioGroupProps<TValue>['options'][number];
|
|
77
|
+
},
|
|
78
|
+
) {
|
|
79
|
+
const { option, value, onValueChange, interactionPolicy, color, size } = props;
|
|
80
|
+
const checked = value === option.value;
|
|
81
|
+
const inactive = props.disabled === true || option.disabled === true;
|
|
82
|
+
const readOnly = props.readOnly === true;
|
|
83
|
+
const invalid = props.invalid === true;
|
|
84
|
+
const onSelect = () => {
|
|
85
|
+
if (!inactive && !readOnly && interactionPolicy !== 'passive' && !checked)
|
|
86
|
+
onValueChange?.(option.value);
|
|
87
|
+
};
|
|
88
|
+
if (props.presentation === 'card') {
|
|
89
|
+
return (
|
|
90
|
+
<RadioOptionControl
|
|
91
|
+
{...props}
|
|
92
|
+
checked={checked}
|
|
93
|
+
disabled={inactive}
|
|
94
|
+
readOnly={readOnly}
|
|
95
|
+
invalid={invalid}
|
|
96
|
+
layout={props.contentOrientation ?? 'horizontal'}
|
|
97
|
+
onSelect={onSelect}
|
|
98
|
+
/>
|
|
99
|
+
);
|
|
100
|
+
}
|
|
108
101
|
return (
|
|
109
102
|
<Radio
|
|
110
|
-
interactionPolicy={interactionPolicy}
|
|
111
103
|
checked={checked}
|
|
112
|
-
disabled={
|
|
113
|
-
invalid={invalid}
|
|
104
|
+
disabled={inactive}
|
|
114
105
|
readOnly={readOnly}
|
|
115
|
-
|
|
106
|
+
invalid={invalid}
|
|
107
|
+
interactionPolicy={interactionPolicy}
|
|
116
108
|
color={color}
|
|
109
|
+
size={size}
|
|
117
110
|
testID={option.testID}
|
|
118
|
-
|
|
119
|
-
isCard
|
|
120
|
-
? checked
|
|
121
|
-
? theme.semantics.selection.background
|
|
122
|
-
: theme.semantics.surface.default
|
|
123
|
-
: undefined
|
|
124
|
-
}
|
|
125
|
-
borderColor={
|
|
126
|
-
isCard
|
|
127
|
-
? checked
|
|
128
|
-
? theme.semantics.selection.border
|
|
129
|
-
: theme.semantics.border.default
|
|
130
|
-
: undefined
|
|
131
|
-
}
|
|
132
|
-
borderWidth={isCard ? 1 : undefined}
|
|
133
|
-
p={isCard ? 'm' : undefined}
|
|
134
|
-
radius={isCard ? 'l' : undefined}
|
|
135
|
-
width={isCard && orientation === 'vertical' ? '100%' : undefined}
|
|
136
|
-
onCheckedChange={(nextChecked) => {
|
|
137
|
-
if (passive) return;
|
|
138
|
-
if (nextChecked) onSelect(option.value);
|
|
139
|
-
}}
|
|
111
|
+
onCheckedChange={onSelect}
|
|
140
112
|
>
|
|
141
113
|
<Stack gap="xs">
|
|
142
|
-
<Text
|
|
114
|
+
<Text>{option.label}</Text>
|
|
143
115
|
{option.description ? (
|
|
144
116
|
<Text emphasis="muted" variant="caption">
|
|
145
117
|
{option.description}
|
|
@@ -149,3 +121,5 @@ function RadioGroupItem<TValue extends string>({
|
|
|
149
121
|
</Radio>
|
|
150
122
|
);
|
|
151
123
|
}
|
|
124
|
+
|
|
125
|
+
const styles = StyleSheet.create({ option: { flex: 1, minWidth: 0 } });
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import { useTheme } from '@ankhorage/surface';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { Platform, Pressable, StyleSheet, View } from 'react-native';
|
|
4
|
+
|
|
5
|
+
import { Icon } from '../icon';
|
|
6
|
+
import { Text } from '../text';
|
|
7
|
+
import {
|
|
8
|
+
handleRadioOptionKeyDown,
|
|
9
|
+
type RadioOptionKeyboardTarget,
|
|
10
|
+
} from './handleRadioOptionKeyDown';
|
|
11
|
+
import { resolveRadioOptionColors } from './resolveRadioOptionColors';
|
|
12
|
+
import type { RadioGroupProps } from './types';
|
|
13
|
+
|
|
14
|
+
/*** Render a selectable icon radio option with one accessible radio target and a trailing check. */
|
|
15
|
+
export function RadioOptionControl<TValue extends string>(props: RadioOptionControlProps<TValue>) {
|
|
16
|
+
const { theme } = useTheme();
|
|
17
|
+
const { option, checked, disabled, readOnly, interactionPolicy, onSelect } = props;
|
|
18
|
+
const colors = resolveRadioOptionColors(theme, props);
|
|
19
|
+
const [focused, setFocused] = React.useState(false);
|
|
20
|
+
const keyboardProps =
|
|
21
|
+
Platform.OS === 'web' && !readOnly && !disabled && interactionPolicy !== 'passive'
|
|
22
|
+
? {
|
|
23
|
+
onKeyDown: (event: React.KeyboardEvent<RadioOptionKeyboardTarget>) =>
|
|
24
|
+
handleRadioOptionKeyDown(event, onSelect),
|
|
25
|
+
}
|
|
26
|
+
: {};
|
|
27
|
+
const controlStyle = {
|
|
28
|
+
flex: 1,
|
|
29
|
+
width: '100%' as const,
|
|
30
|
+
minHeight: props.size === 'l' ? 84 : 44,
|
|
31
|
+
borderWidth: checked || focused ? 2 : 1,
|
|
32
|
+
borderColor: focused ? theme.semantics.border.focus : checked ? colors.accent : colors.border,
|
|
33
|
+
borderRadius: theme.radii.l,
|
|
34
|
+
backgroundColor: colors.surface,
|
|
35
|
+
};
|
|
36
|
+
return (
|
|
37
|
+
<Pressable
|
|
38
|
+
{...keyboardProps}
|
|
39
|
+
accessibilityRole="radio"
|
|
40
|
+
accessibilityState={{ checked, disabled }}
|
|
41
|
+
aria-checked={checked}
|
|
42
|
+
aria-disabled={disabled}
|
|
43
|
+
aria-readonly={readOnly}
|
|
44
|
+
disabled={disabled}
|
|
45
|
+
onPress={readOnly || interactionPolicy === 'passive' ? undefined : onSelect}
|
|
46
|
+
onFocus={() => setFocused(true)}
|
|
47
|
+
onBlur={() => setFocused(false)}
|
|
48
|
+
testID={option.testID}
|
|
49
|
+
style={controlStyle}
|
|
50
|
+
>
|
|
51
|
+
{(state) => <RadioOptionControlBody {...props} pressed={state.pressed} />}
|
|
52
|
+
</Pressable>
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/*** Arrange the icon, label and passive indicator within the native radio press target. */
|
|
57
|
+
function RadioOptionControlBody<TValue extends string>(
|
|
58
|
+
props: RadioOptionControlProps<TValue> & { pressed: boolean },
|
|
59
|
+
) {
|
|
60
|
+
const { theme } = useTheme();
|
|
61
|
+
const colors = resolveRadioOptionColors(theme, props);
|
|
62
|
+
const contentStyle = {
|
|
63
|
+
padding: props.size === 's' ? theme.spacing.s : props.size === 'm' ? 12 : theme.spacing.m,
|
|
64
|
+
gap:
|
|
65
|
+
props.layout === 'vertical' || !props.option.iconSource ? theme.spacing.s : theme.spacing.m,
|
|
66
|
+
...(!props.option.iconSource ? { flexDirection: 'row-reverse' as const } : {}),
|
|
67
|
+
opacity: props.disabled ? 0.5 : props.pressed ? 0.7 : 1,
|
|
68
|
+
};
|
|
69
|
+
return (
|
|
70
|
+
<View
|
|
71
|
+
style={[
|
|
72
|
+
styles.content,
|
|
73
|
+
props.layout === 'vertical' ? styles.vertical : styles.horizontal,
|
|
74
|
+
contentStyle,
|
|
75
|
+
]}
|
|
76
|
+
>
|
|
77
|
+
<RadioOptionControlContent {...props} />
|
|
78
|
+
{props.option.iconSource || props.checked ? (
|
|
79
|
+
<View style={props.layout === 'vertical' ? styles.corner : undefined}>
|
|
80
|
+
<RadioOptionControlIndicator
|
|
81
|
+
checked={props.checked}
|
|
82
|
+
accent={colors.accent}
|
|
83
|
+
onAccent={colors.onAccent}
|
|
84
|
+
/>
|
|
85
|
+
</View>
|
|
86
|
+
) : null}
|
|
87
|
+
</View>
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
interface RadioOptionControlProps<TValue extends string> extends Pick<
|
|
92
|
+
RadioGroupProps<TValue>,
|
|
93
|
+
'color' | 'size' | 'interactionPolicy'
|
|
94
|
+
> {
|
|
95
|
+
option: RadioGroupProps<TValue>['options'][number];
|
|
96
|
+
checked: boolean;
|
|
97
|
+
disabled: boolean;
|
|
98
|
+
readOnly: boolean;
|
|
99
|
+
invalid: boolean;
|
|
100
|
+
layout: 'horizontal' | 'vertical';
|
|
101
|
+
onSelect: () => void;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/*** Keep decoration passive while allowing labels to wrap at narrow widths and large text sizes. */
|
|
105
|
+
function RadioOptionControlContent<TValue extends string>({
|
|
106
|
+
option,
|
|
107
|
+
layout,
|
|
108
|
+
size,
|
|
109
|
+
color,
|
|
110
|
+
invalid,
|
|
111
|
+
disabled,
|
|
112
|
+
}: RadioOptionControlProps<TValue>) {
|
|
113
|
+
const { theme } = useTheme();
|
|
114
|
+
const colors = resolveRadioOptionColors(theme, { color, invalid, disabled });
|
|
115
|
+
return (
|
|
116
|
+
<>
|
|
117
|
+
{option.iconSource ? (
|
|
118
|
+
<View accessibilityElementsHidden importantForAccessibility="no-hide-descendants">
|
|
119
|
+
<Icon source={option.iconSource} size={size === 'l' ? 36 : 28} color={colors.accent} />
|
|
120
|
+
</View>
|
|
121
|
+
) : null}
|
|
122
|
+
<View style={layout === 'horizontal' ? styles.label : styles.centerLabel}>
|
|
123
|
+
<Text
|
|
124
|
+
variant={size === 'l' ? 'body' : 'bodySmall'}
|
|
125
|
+
weight="semiBold"
|
|
126
|
+
align={layout === 'vertical' || !option.iconSource ? 'center' : 'left'}
|
|
127
|
+
>
|
|
128
|
+
{option.label}
|
|
129
|
+
</Text>
|
|
130
|
+
{option.description ? (
|
|
131
|
+
<Text
|
|
132
|
+
emphasis="muted"
|
|
133
|
+
variant="bodySmall"
|
|
134
|
+
align={layout === 'vertical' || !option.iconSource ? 'center' : 'left'}
|
|
135
|
+
>
|
|
136
|
+
{option.description}
|
|
137
|
+
</Text>
|
|
138
|
+
) : null}
|
|
139
|
+
</View>
|
|
140
|
+
</>
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/*** Draw a passive check using themed geometry without requiring an application media asset. */
|
|
145
|
+
function RadioOptionControlIndicator({
|
|
146
|
+
checked,
|
|
147
|
+
accent,
|
|
148
|
+
onAccent,
|
|
149
|
+
}: {
|
|
150
|
+
checked: boolean;
|
|
151
|
+
accent: string;
|
|
152
|
+
onAccent: string;
|
|
153
|
+
}) {
|
|
154
|
+
const indicatorStyle = { backgroundColor: checked ? accent : 'transparent' };
|
|
155
|
+
return (
|
|
156
|
+
<View
|
|
157
|
+
accessibilityElementsHidden
|
|
158
|
+
importantForAccessibility="no-hide-descendants"
|
|
159
|
+
style={[styles.indicator, indicatorStyle]}
|
|
160
|
+
>
|
|
161
|
+
{checked ? <View style={[styles.check, { borderColor: onAccent }]} /> : null}
|
|
162
|
+
</View>
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
const styles = StyleSheet.create({
|
|
167
|
+
content: { gap: 16, flex: 1, minWidth: 0 },
|
|
168
|
+
horizontal: { flexDirection: 'row', alignItems: 'center' },
|
|
169
|
+
vertical: {
|
|
170
|
+
flexDirection: 'column',
|
|
171
|
+
alignItems: 'center',
|
|
172
|
+
justifyContent: 'center',
|
|
173
|
+
paddingTop: 24,
|
|
174
|
+
},
|
|
175
|
+
label: { flex: 1, minWidth: 0, gap: 4 },
|
|
176
|
+
centerLabel: { alignSelf: 'stretch', gap: 4 },
|
|
177
|
+
corner: { position: 'absolute', right: 8, top: 8 },
|
|
178
|
+
indicator: {
|
|
179
|
+
width: 24,
|
|
180
|
+
height: 24,
|
|
181
|
+
borderRadius: 12,
|
|
182
|
+
alignItems: 'center',
|
|
183
|
+
justifyContent: 'center',
|
|
184
|
+
},
|
|
185
|
+
check: {
|
|
186
|
+
width: 7,
|
|
187
|
+
height: 12,
|
|
188
|
+
borderRightWidth: 2.5,
|
|
189
|
+
borderBottomWidth: 2.5,
|
|
190
|
+
transform: [{ rotate: '45deg' }, { translateY: -2 }],
|
|
191
|
+
},
|
|
192
|
+
});
|