@ankhorage/surface 6.0.0 → 7.0.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/field → features/form/field/adapters/inbound}/Field.d.ts +2 -2
- package/dist/features/form/field/adapters/inbound/Field.d.ts.map +1 -0
- package/dist/features/form/field/adapters/inbound/Field.js +40 -0
- package/dist/features/form/field/adapters/inbound/Field.js.map +1 -0
- package/dist/features/form/field/public.d.ts +3 -0
- package/dist/features/form/field/public.d.ts.map +1 -0
- package/dist/features/form/field/public.js +2 -0
- package/dist/features/form/field/public.js.map +1 -0
- package/dist/{components/switch → features/form/switch/adapters/inbound}/Switch.d.ts +1 -1
- package/dist/features/form/switch/adapters/inbound/Switch.d.ts.map +1 -0
- package/dist/features/form/switch/adapters/inbound/Switch.js +52 -0
- package/dist/features/form/switch/adapters/inbound/Switch.js.map +1 -0
- package/dist/features/form/switch/public.d.ts +3 -0
- package/dist/features/form/switch/public.d.ts.map +1 -0
- package/dist/features/form/switch/public.js +2 -0
- package/dist/features/form/switch/public.js.map +1 -0
- package/dist/features/form/text-input/adapters/inbound/TextInput.d.ts.map +1 -1
- package/dist/features/form/text-input/adapters/inbound/TextInput.js +8 -4
- package/dist/features/form/text-input/adapters/inbound/TextInput.js.map +1 -1
- package/dist/features/list/adapters/inbound/List.d.ts +5 -0
- package/dist/features/list/adapters/inbound/List.d.ts.map +1 -0
- package/dist/features/list/adapters/inbound/List.js +7 -0
- package/dist/features/list/adapters/inbound/List.js.map +1 -0
- package/dist/features/list/adapters/inbound/ListItem.d.ts +5 -0
- package/dist/features/list/adapters/inbound/ListItem.d.ts.map +1 -0
- package/dist/features/list/adapters/inbound/ListItem.js +59 -0
- package/dist/features/list/adapters/inbound/ListItem.js.map +1 -0
- package/dist/features/list/public.d.ts +4 -0
- package/dist/features/list/public.d.ts.map +1 -0
- package/dist/features/list/public.js +3 -0
- package/dist/features/list/public.js.map +1 -0
- package/dist/index.d.ts +6 -12
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -6
- package/dist/index.js.map +1 -1
- package/dist/{components/field/types.d.ts → types/field.d.ts} +1 -1
- package/dist/types/field.d.ts.map +1 -0
- package/dist/types/field.js +2 -0
- package/dist/types/field.js.map +1 -0
- package/dist/types/list.d.ts +20 -0
- package/dist/types/list.d.ts.map +1 -0
- package/dist/types/list.js +2 -0
- package/dist/types/list.js.map +1 -0
- package/dist/{components/switch/types.d.ts → types/switch.d.ts} +4 -4
- package/dist/types/switch.d.ts.map +1 -0
- package/dist/types/switch.js +2 -0
- package/dist/types/switch.js.map +1 -0
- package/package.json +1 -1
- package/src/features/form/field/adapters/inbound/Field.tsx +82 -0
- package/src/features/form/field/public.ts +2 -0
- package/src/features/form/switch/adapters/inbound/Switch.tsx +123 -0
- package/src/features/form/switch/public.ts +2 -0
- package/src/features/form/text-input/adapters/inbound/TextInput.tsx +21 -5
- package/src/features/list/adapters/inbound/List.tsx +9 -0
- package/src/features/list/adapters/inbound/ListItem.tsx +128 -0
- package/src/features/list/public.test.ts +13 -0
- package/src/features/list/public.ts +3 -0
- package/src/index.test.ts +15 -11
- package/src/index.ts +6 -12
- package/src/types/list.ts +22 -0
- package/src/{components/switch/types.ts → types/switch.ts} +3 -3
- package/dist/components/field/Field.d.ts.map +0 -1
- package/dist/components/field/Field.js +0 -27
- package/dist/components/field/Field.js.map +0 -1
- package/dist/components/field/index.d.ts +0 -3
- package/dist/components/field/index.d.ts.map +0 -1
- package/dist/components/field/index.js +0 -2
- package/dist/components/field/index.js.map +0 -1
- package/dist/components/field/types.d.ts.map +0 -1
- package/dist/components/field/types.js +0 -2
- package/dist/components/field/types.js.map +0 -1
- package/dist/components/helper-text/HelperText.d.ts +0 -4
- package/dist/components/helper-text/HelperText.d.ts.map +0 -1
- package/dist/components/helper-text/HelperText.js +0 -8
- package/dist/components/helper-text/HelperText.js.map +0 -1
- package/dist/components/helper-text/index.d.ts +0 -3
- package/dist/components/helper-text/index.d.ts.map +0 -1
- package/dist/components/helper-text/index.js +0 -2
- package/dist/components/helper-text/index.js.map +0 -1
- package/dist/components/helper-text/types.d.ts +0 -9
- package/dist/components/helper-text/types.d.ts.map +0 -1
- package/dist/components/helper-text/types.js +0 -2
- package/dist/components/helper-text/types.js.map +0 -1
- package/dist/components/label/Label.d.ts +0 -4
- package/dist/components/label/Label.d.ts.map +0 -1
- package/dist/components/label/Label.js +0 -11
- package/dist/components/label/Label.js.map +0 -1
- package/dist/components/label/index.d.ts +0 -3
- package/dist/components/label/index.d.ts.map +0 -1
- package/dist/components/label/index.js +0 -2
- package/dist/components/label/index.js.map +0 -1
- package/dist/components/label/types.d.ts +0 -10
- package/dist/components/label/types.d.ts.map +0 -1
- package/dist/components/label/types.js +0 -2
- package/dist/components/label/types.js.map +0 -1
- package/dist/components/list-item/ListItem.d.ts +0 -5
- package/dist/components/list-item/ListItem.d.ts.map +0 -1
- package/dist/components/list-item/ListItem.js +0 -44
- package/dist/components/list-item/ListItem.js.map +0 -1
- package/dist/components/list-item/index.d.ts +0 -3
- package/dist/components/list-item/index.d.ts.map +0 -1
- package/dist/components/list-item/index.js +0 -2
- package/dist/components/list-item/index.js.map +0 -1
- package/dist/components/list-item/types.d.ts +0 -11
- package/dist/components/list-item/types.d.ts.map +0 -1
- package/dist/components/list-item/types.js +0 -2
- package/dist/components/list-item/types.js.map +0 -1
- package/dist/components/switch/Switch.d.ts.map +0 -1
- package/dist/components/switch/Switch.js +0 -68
- package/dist/components/switch/Switch.js.map +0 -1
- package/dist/components/switch/index.d.ts +0 -3
- package/dist/components/switch/index.d.ts.map +0 -1
- package/dist/components/switch/index.js +0 -2
- package/dist/components/switch/index.js.map +0 -1
- package/dist/components/switch/types.d.ts.map +0 -1
- package/dist/components/switch/types.js +0 -2
- package/dist/components/switch/types.js.map +0 -1
- package/dist/components/textarea/Textarea.d.ts +0 -4
- package/dist/components/textarea/Textarea.d.ts.map +0 -1
- package/dist/components/textarea/Textarea.js +0 -6
- package/dist/components/textarea/Textarea.js.map +0 -1
- package/dist/components/textarea/index.d.ts +0 -3
- package/dist/components/textarea/index.d.ts.map +0 -1
- package/dist/components/textarea/index.js +0 -2
- package/dist/components/textarea/index.js.map +0 -1
- package/dist/components/textarea/types.d.ts +0 -5
- package/dist/components/textarea/types.d.ts.map +0 -1
- package/dist/components/textarea/types.js +0 -2
- package/dist/components/textarea/types.js.map +0 -1
- package/src/components/field/Field.tsx +0 -52
- package/src/components/field/index.ts +0 -2
- package/src/components/helper-text/HelperText.tsx +0 -12
- package/src/components/helper-text/index.ts +0 -2
- package/src/components/helper-text/types.ts +0 -10
- package/src/components/label/Label.tsx +0 -23
- package/src/components/label/index.ts +0 -2
- package/src/components/label/types.ts +0 -11
- package/src/components/list-item/ListItem.tsx +0 -76
- package/src/components/list-item/index.ts +0 -2
- package/src/components/list-item/types.ts +0 -11
- package/src/components/switch/Switch.tsx +0 -113
- package/src/components/switch/index.ts +0 -2
- package/src/components/textarea/Textarea.tsx +0 -15
- package/src/components/textarea/index.ts +0 -2
- package/src/components/textarea/types.ts +0 -5
- /package/src/{components/field/types.ts → types/field.ts} +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type React from 'react';
|
|
2
|
-
import type { ControlSize } from '
|
|
3
|
-
import type { ButtonBaseProps } from '
|
|
4
|
-
import type { SurfaceColor } from '
|
|
2
|
+
import type { ControlSize } from '../internal/resolvers/resolveControlSize';
|
|
3
|
+
import type { ButtonBaseProps } from '../primitives/button-base';
|
|
4
|
+
import type { SurfaceColor } from '../surfaceColor';
|
|
5
5
|
export interface SwitchProps extends Omit<ButtonBaseProps, 'accessibilityRole' | 'accessibilityState' | 'children' | 'onPress' | 'style'> {
|
|
6
6
|
children?: React.ReactNode;
|
|
7
7
|
checked?: boolean;
|
|
@@ -12,4 +12,4 @@ export interface SwitchProps extends Omit<ButtonBaseProps, 'accessibilityRole' |
|
|
|
12
12
|
invalid?: boolean;
|
|
13
13
|
readOnly?: boolean;
|
|
14
14
|
}
|
|
15
|
-
//# sourceMappingURL=
|
|
15
|
+
//# sourceMappingURL=switch.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"switch.d.ts","sourceRoot":"","sources":["../../src/types/switch.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0CAA0C,CAAC;AAC5E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AACjE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAEpD,MAAM,WAAW,WAAY,SAAQ,IAAI,CACvC,eAAe,EACf,mBAAmB,GAAG,oBAAoB,GAAG,UAAU,GAAG,SAAS,GAAG,OAAO,CAC9E;IACC,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,eAAe,CAAC,EAAE,CAAC,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;IAC3D,KAAK,CAAC,EAAE,YAAY,CAAC;IACrB,IAAI,CAAC,EAAE,WAAW,CAAC;IACnB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"switch.js","sourceRoot":"","sources":["../../src/types/switch.ts"],"names":[],"mappings":"","sourcesContent":["import type React from 'react';\n\nimport type { ControlSize } from '../internal/resolvers/resolveControlSize';\nimport type { ButtonBaseProps } from '../primitives/button-base';\nimport type { SurfaceColor } from '../surfaceColor';\n\nexport interface SwitchProps extends Omit<\n ButtonBaseProps,\n 'accessibilityRole' | 'accessibilityState' | 'children' | 'onPress' | 'style'\n> {\n children?: React.ReactNode;\n checked?: boolean;\n defaultChecked?: boolean;\n onCheckedChange?: ((checked: boolean) => void) | undefined;\n color?: SurfaceColor;\n size?: ControlSize;\n invalid?: boolean;\n readOnly?: boolean;\n}\n"]}
|
package/package.json
CHANGED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
type ResolvedFieldPresentation,
|
|
5
|
+
resolveFieldPresentation,
|
|
6
|
+
resolveFieldState,
|
|
7
|
+
} from '../../../../../internal/resolvers';
|
|
8
|
+
import type { FieldProps } from '../../../../../types/field';
|
|
9
|
+
import { View } from '../../../../layout/public';
|
|
10
|
+
import { Text } from '../../../../typography/public';
|
|
11
|
+
|
|
12
|
+
/*** Composes a control with its label and helper or error message. */
|
|
13
|
+
export function Field({
|
|
14
|
+
children,
|
|
15
|
+
label,
|
|
16
|
+
helperText,
|
|
17
|
+
errorText,
|
|
18
|
+
required = false,
|
|
19
|
+
disabled = false,
|
|
20
|
+
invalid = false,
|
|
21
|
+
readOnly = false,
|
|
22
|
+
testID,
|
|
23
|
+
}: FieldProps) {
|
|
24
|
+
const hasErrorText = Boolean(errorText);
|
|
25
|
+
const presentation = resolveFieldPresentation(
|
|
26
|
+
resolveFieldState({ disabled, invalid: invalid || hasErrorText, readOnly }),
|
|
27
|
+
);
|
|
28
|
+
const message = hasErrorText ? errorText : helperText;
|
|
29
|
+
|
|
30
|
+
return (
|
|
31
|
+
<View gap="xs" testID={testID}>
|
|
32
|
+
{renderFieldLabel(label, required, presentation)}
|
|
33
|
+
<View>{children}</View>
|
|
34
|
+
{renderFieldMessage(message, presentation)}
|
|
35
|
+
</View>
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/*** Renders an optional field label and required indicator. */
|
|
40
|
+
function renderFieldLabel(
|
|
41
|
+
label: React.ReactNode,
|
|
42
|
+
required: boolean,
|
|
43
|
+
presentation: ResolvedFieldPresentation,
|
|
44
|
+
) {
|
|
45
|
+
if (label === undefined || label === null) return null;
|
|
46
|
+
const labelContent =
|
|
47
|
+
typeof label === 'string' || typeof label === 'number' ? (
|
|
48
|
+
<Text
|
|
49
|
+
color={presentation.labelColor}
|
|
50
|
+
emphasis={presentation.labelEmphasis}
|
|
51
|
+
variant="label"
|
|
52
|
+
weight="medium"
|
|
53
|
+
>
|
|
54
|
+
{label}
|
|
55
|
+
</Text>
|
|
56
|
+
) : (
|
|
57
|
+
label
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
return (
|
|
61
|
+
<View align="center" direction="row" gap="xs">
|
|
62
|
+
<View flex={1}>{labelContent}</View>
|
|
63
|
+
{required ? (
|
|
64
|
+
<Text color="error" variant="label" weight="medium">
|
|
65
|
+
*
|
|
66
|
+
</Text>
|
|
67
|
+
) : null}
|
|
68
|
+
</View>
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/*** Renders an optional helper or error message using field presentation semantics. */
|
|
73
|
+
function renderFieldMessage(message: React.ReactNode, presentation: ResolvedFieldPresentation) {
|
|
74
|
+
if (message === undefined || message === null || message === '') return null;
|
|
75
|
+
if (typeof message !== 'string' && typeof message !== 'number') return message;
|
|
76
|
+
|
|
77
|
+
return (
|
|
78
|
+
<Text color={presentation.helperColor} emphasis={presentation.helperEmphasis} variant="caption">
|
|
79
|
+
{message}
|
|
80
|
+
</Text>
|
|
81
|
+
);
|
|
82
|
+
}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
type InteractionState,
|
|
5
|
+
resolveFieldState,
|
|
6
|
+
resolveIndicatorSize,
|
|
7
|
+
resolveSelectionControlColors,
|
|
8
|
+
resolveSelectionControlNextChecked,
|
|
9
|
+
} from '../../../../../internal/resolvers';
|
|
10
|
+
import { useControllableState } from '../../../../../internal/useControllableState';
|
|
11
|
+
import { ButtonBase } from '../../../../../primitives/button-base';
|
|
12
|
+
import { useTheme } from '../../../../../theme/ThemeContext';
|
|
13
|
+
import type { SwitchProps } from '../../../../../types/switch';
|
|
14
|
+
import { View } from '../../../../layout/public';
|
|
15
|
+
import { Text } from '../../../../typography/public';
|
|
16
|
+
|
|
17
|
+
/*** Renders a controlled or uncontrolled accessible switch. */
|
|
18
|
+
export function Switch({
|
|
19
|
+
children,
|
|
20
|
+
checked,
|
|
21
|
+
defaultChecked = false,
|
|
22
|
+
onCheckedChange,
|
|
23
|
+
color = 'primary',
|
|
24
|
+
size = 'm',
|
|
25
|
+
disabled = false,
|
|
26
|
+
invalid = false,
|
|
27
|
+
readOnly = false,
|
|
28
|
+
accessibilityLabel,
|
|
29
|
+
testID,
|
|
30
|
+
...props
|
|
31
|
+
}: SwitchProps) {
|
|
32
|
+
const { theme } = useTheme();
|
|
33
|
+
const [isChecked, setChecked] = useControllableState<boolean>({
|
|
34
|
+
value: checked,
|
|
35
|
+
defaultValue: defaultChecked,
|
|
36
|
+
onChange: onCheckedChange,
|
|
37
|
+
});
|
|
38
|
+
const nextChecked = resolveSelectionControlNextChecked({
|
|
39
|
+
checked: isChecked,
|
|
40
|
+
disabled,
|
|
41
|
+
kind: 'switch',
|
|
42
|
+
readOnly,
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
return (
|
|
46
|
+
<ButtonBase
|
|
47
|
+
{...props}
|
|
48
|
+
accessibilityLabel={accessibilityLabel}
|
|
49
|
+
accessibilityRole="switch"
|
|
50
|
+
accessibilityState={{ checked: isChecked }}
|
|
51
|
+
disabled={disabled}
|
|
52
|
+
onPress={nextChecked === null ? undefined : () => setChecked(nextChecked)}
|
|
53
|
+
testID={testID}
|
|
54
|
+
>
|
|
55
|
+
{(interactionState) =>
|
|
56
|
+
renderSwitchContent(
|
|
57
|
+
{ children, color, disabled, invalid, isChecked, readOnly, size, theme },
|
|
58
|
+
interactionState,
|
|
59
|
+
)
|
|
60
|
+
}
|
|
61
|
+
</ButtonBase>
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
interface SwitchContentInput {
|
|
66
|
+
children: React.ReactNode;
|
|
67
|
+
color: NonNullable<SwitchProps['color']>;
|
|
68
|
+
disabled: boolean;
|
|
69
|
+
invalid: boolean;
|
|
70
|
+
isChecked: boolean;
|
|
71
|
+
readOnly: boolean;
|
|
72
|
+
size: NonNullable<SwitchProps['size']>;
|
|
73
|
+
theme: ReturnType<typeof useTheme>['theme'];
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/*** Resolves switch presentation for one interaction state and renders the visual control. */
|
|
77
|
+
function renderSwitchContent(input: SwitchContentInput, interactionState: InteractionState) {
|
|
78
|
+
const fieldState = resolveFieldState({
|
|
79
|
+
disabled: input.disabled,
|
|
80
|
+
focused: interactionState.focused,
|
|
81
|
+
invalid: input.invalid,
|
|
82
|
+
readOnly: input.readOnly,
|
|
83
|
+
});
|
|
84
|
+
const colors = resolveSelectionControlColors(input.theme, {
|
|
85
|
+
checked: input.isChecked,
|
|
86
|
+
fieldState,
|
|
87
|
+
hovered: interactionState.hovered,
|
|
88
|
+
pressed: interactionState.pressed,
|
|
89
|
+
color: input.color,
|
|
90
|
+
});
|
|
91
|
+
const indicatorSize = resolveIndicatorSize(input.size);
|
|
92
|
+
const labelEmphasis =
|
|
93
|
+
colors.labelColor === input.theme.semantics.content.muted ? 'muted' : 'default';
|
|
94
|
+
|
|
95
|
+
return (
|
|
96
|
+
<View align="center" direction="row" opacity={colors.opacity}>
|
|
97
|
+
<View
|
|
98
|
+
bg={colors.trackColor}
|
|
99
|
+
borderColor={colors.borderColor}
|
|
100
|
+
borderWidth={1}
|
|
101
|
+
height={indicatorSize.switchHeight}
|
|
102
|
+
justify="center"
|
|
103
|
+
minWidth={indicatorSize.switchWidth}
|
|
104
|
+
px={2}
|
|
105
|
+
radius="full"
|
|
106
|
+
width={indicatorSize.switchWidth}
|
|
107
|
+
>
|
|
108
|
+
<View
|
|
109
|
+
alignSelf={input.isChecked ? 'flex-end' : 'flex-start'}
|
|
110
|
+
bg={colors.thumbColor}
|
|
111
|
+
height={indicatorSize.switchThumb}
|
|
112
|
+
radius="full"
|
|
113
|
+
width={indicatorSize.switchThumb}
|
|
114
|
+
/>
|
|
115
|
+
</View>
|
|
116
|
+
{input.children ? (
|
|
117
|
+
<View ml="s">
|
|
118
|
+
<Text emphasis={labelEmphasis}>{input.children}</Text>
|
|
119
|
+
</View>
|
|
120
|
+
) : null}
|
|
121
|
+
</View>
|
|
122
|
+
);
|
|
123
|
+
}
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
Platform,
|
|
4
|
+
type StyleProp,
|
|
5
|
+
TextInput as ReactNativeTextInput,
|
|
6
|
+
type TextStyle,
|
|
7
|
+
View,
|
|
8
|
+
type ViewStyle,
|
|
9
|
+
} from 'react-native';
|
|
3
10
|
|
|
4
11
|
import { resolveFocusRingStyles } from '../../../../../internal/resolvers';
|
|
5
12
|
import { useTheme } from '../../../../../theme/ThemeContext';
|
|
@@ -39,9 +46,7 @@ export function TextInput(props: TextInputProps) {
|
|
|
39
46
|
nativeProps.onBlur?.(event);
|
|
40
47
|
}}
|
|
41
48
|
onChangeText={(nextValue) => {
|
|
42
|
-
if (interactionPolicy !== 'passive')
|
|
43
|
-
nativeProps.onChangeText?.(nextValue);
|
|
44
|
-
}
|
|
49
|
+
if (interactionPolicy !== 'passive') nativeProps.onChangeText?.(nextValue);
|
|
45
50
|
}}
|
|
46
51
|
onFocus={(event) => {
|
|
47
52
|
setFocused(true);
|
|
@@ -49,13 +54,24 @@ export function TextInput(props: TextInputProps) {
|
|
|
49
54
|
}}
|
|
50
55
|
placeholderTextColor={presentation.placeholderColor}
|
|
51
56
|
readOnly={readOnly}
|
|
52
|
-
style={
|
|
57
|
+
style={resolveInputStyle(presentation.inputStyle, nativeProps.multiline, nativeProps.style)}
|
|
53
58
|
/>
|
|
54
59
|
{renderAccessory(trailingAccessory, presentation.accessorySpacing, 'trailing')}
|
|
55
60
|
</View>
|
|
56
61
|
);
|
|
57
62
|
}
|
|
58
63
|
|
|
64
|
+
const multilineInputStyle: TextStyle = { textAlignVertical: 'top' };
|
|
65
|
+
|
|
66
|
+
/*** Resolves TextInput style composition including canonical multiline alignment. */
|
|
67
|
+
function resolveInputStyle(
|
|
68
|
+
presentationStyle: StyleProp<TextStyle>,
|
|
69
|
+
multiline: boolean | undefined,
|
|
70
|
+
style: StyleProp<TextStyle>,
|
|
71
|
+
): StyleProp<TextStyle> {
|
|
72
|
+
return [presentationStyle, multiline ? multilineInputStyle : undefined, style];
|
|
73
|
+
}
|
|
74
|
+
|
|
59
75
|
/*** Renders one optional TextInput accessory with directional spacing. */
|
|
60
76
|
function renderAccessory(
|
|
61
77
|
accessory: React.ReactNode,
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
import type { ListProps } from '../../../../types/list';
|
|
4
|
+
import { View } from '../../../layout/public';
|
|
5
|
+
|
|
6
|
+
/*** Groups list items under one neutral Surface list boundary. */
|
|
7
|
+
export function List({ children, testID }: ListProps) {
|
|
8
|
+
return <View testID={testID}>{children}</View>;
|
|
9
|
+
}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
import { ButtonBase } from '../../../../primitives/button-base';
|
|
4
|
+
import { useTheme } from '../../../../theme/ThemeContext';
|
|
5
|
+
import type { SurfaceTheme } from '../../../../theme/types';
|
|
6
|
+
import type { ListItemProps } from '../../../../types/list';
|
|
7
|
+
import { View } from '../../../layout/public';
|
|
8
|
+
import { Text } from '../../../typography/public';
|
|
9
|
+
|
|
10
|
+
/*** Renders a static or interactive list item with shared row geometry and interaction states. */
|
|
11
|
+
export function ListItem(props: ListItemProps) {
|
|
12
|
+
const { theme } = useTheme();
|
|
13
|
+
if (!props.onPress) return renderStaticListItem(props, theme);
|
|
14
|
+
return renderInteractiveListItem({ ...props, onPress: props.onPress }, theme);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/*** Renders a non-pressable list item. */
|
|
18
|
+
function renderStaticListItem(props: ListItemProps, theme: SurfaceTheme) {
|
|
19
|
+
return (
|
|
20
|
+
<ListItemContent
|
|
21
|
+
{...props}
|
|
22
|
+
backgroundColor={props.selected ? theme.semantics.selection.background : 'transparent'}
|
|
23
|
+
/>
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/*** Renders a pressable list item with shared interaction-state presentation. */
|
|
28
|
+
function renderInteractiveListItem(
|
|
29
|
+
props: ListItemProps & { onPress: NonNullable<ListItemProps['onPress']> },
|
|
30
|
+
theme: SurfaceTheme,
|
|
31
|
+
) {
|
|
32
|
+
return (
|
|
33
|
+
<ButtonBase
|
|
34
|
+
accessibilityLabel={props.accessibilityLabel}
|
|
35
|
+
accessibilityRole="button"
|
|
36
|
+
accessibilityState={{ disabled: props.disabled ?? false, selected: props.selected ?? false }}
|
|
37
|
+
disabled={props.disabled ?? false}
|
|
38
|
+
interactionPolicy={props.interactionPolicy}
|
|
39
|
+
onPress={props.onPress}
|
|
40
|
+
testID={props.testID}
|
|
41
|
+
>
|
|
42
|
+
{(state) => (
|
|
43
|
+
<ListItemContent
|
|
44
|
+
{...props}
|
|
45
|
+
backgroundColor={resolveListItemBackground(theme, {
|
|
46
|
+
hovered: state.hovered,
|
|
47
|
+
pressed: state.pressed,
|
|
48
|
+
selected: props.selected ?? false,
|
|
49
|
+
})}
|
|
50
|
+
disabled={state.disabled}
|
|
51
|
+
testID={undefined}
|
|
52
|
+
/>
|
|
53
|
+
)}
|
|
54
|
+
</ButtonBase>
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
interface ListItemBackgroundState {
|
|
59
|
+
hovered: boolean;
|
|
60
|
+
pressed: boolean;
|
|
61
|
+
selected: boolean;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
type ListItemContentProps = Omit<
|
|
65
|
+
ListItemProps,
|
|
66
|
+
'accessibilityLabel' | 'interactionPolicy' | 'onPress' | 'selected'
|
|
67
|
+
> & {
|
|
68
|
+
backgroundColor: string;
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
/*** Resolves the neutral list-item background for one interaction state. */
|
|
72
|
+
function resolveListItemBackground(theme: SurfaceTheme, state: ListItemBackgroundState) {
|
|
73
|
+
if (state.pressed) return theme.semantics.neutral.surfaceActive;
|
|
74
|
+
if (state.hovered) return theme.semantics.neutral.surfaceHover;
|
|
75
|
+
if (state.selected) return theme.semantics.selection.background;
|
|
76
|
+
return 'transparent';
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/*** Renders the shared visual row content for static and interactive list items. */
|
|
80
|
+
function ListItemContent({
|
|
81
|
+
backgroundColor,
|
|
82
|
+
children,
|
|
83
|
+
compact = false,
|
|
84
|
+
description,
|
|
85
|
+
disabled = false,
|
|
86
|
+
leading,
|
|
87
|
+
testID,
|
|
88
|
+
title,
|
|
89
|
+
trailing,
|
|
90
|
+
}: ListItemContentProps) {
|
|
91
|
+
const content = children ?? renderDefaultContent(title, description);
|
|
92
|
+
|
|
93
|
+
return (
|
|
94
|
+
<View
|
|
95
|
+
align="center"
|
|
96
|
+
bg={backgroundColor}
|
|
97
|
+
direction="row"
|
|
98
|
+
gap="m"
|
|
99
|
+
opacity={disabled ? 0.72 : 1}
|
|
100
|
+
px="m"
|
|
101
|
+
py={compact ? 's' : 'm'}
|
|
102
|
+
testID={testID}
|
|
103
|
+
>
|
|
104
|
+
{leading !== undefined ? <View>{leading}</View> : null}
|
|
105
|
+
<View flex={1}>{content}</View>
|
|
106
|
+
{trailing !== undefined ? <View>{trailing}</View> : null}
|
|
107
|
+
</View>
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/*** Renders the default title and description content when custom children are absent. */
|
|
112
|
+
function renderDefaultContent(title: React.ReactNode, description: React.ReactNode) {
|
|
113
|
+
if (title === undefined && description === undefined) return null;
|
|
114
|
+
return (
|
|
115
|
+
<View flex={1} gap="xs">
|
|
116
|
+
{title !== undefined ? (
|
|
117
|
+
<Text numberOfLines={1} variant="body" weight="medium">
|
|
118
|
+
{title}
|
|
119
|
+
</Text>
|
|
120
|
+
) : null}
|
|
121
|
+
{description !== undefined ? (
|
|
122
|
+
<Text emphasis="muted" numberOfLines={2} variant="bodySmall">
|
|
123
|
+
{description}
|
|
124
|
+
</Text>
|
|
125
|
+
) : null}
|
|
126
|
+
</View>
|
|
127
|
+
);
|
|
128
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { expect, test } from 'bun:test';
|
|
2
|
+
|
|
3
|
+
test('list capability owns List and ListItem under one feature boundary', async () => {
|
|
4
|
+
const listSource = await Bun.file('src/features/list/adapters/inbound/List.tsx').text();
|
|
5
|
+
const listItemSource = await Bun.file('src/features/list/adapters/inbound/ListItem.tsx').text();
|
|
6
|
+
|
|
7
|
+
expect(listSource).toContain('export function List');
|
|
8
|
+
expect(listItemSource).toContain('export function ListItem');
|
|
9
|
+
expect(listItemSource).toContain('interactionPolicy={props.interactionPolicy}');
|
|
10
|
+
expect(listItemSource).toContain('selected');
|
|
11
|
+
expect(listItemSource).toContain('compact');
|
|
12
|
+
expect(listItemSource).not.toContain('components/list-item');
|
|
13
|
+
});
|
package/src/index.test.ts
CHANGED
|
@@ -22,12 +22,15 @@ const expectedFeatureRootExports = [
|
|
|
22
22
|
"export { Button, IconButton } from './features/button/public';",
|
|
23
23
|
"export { Card } from './features/card/public';",
|
|
24
24
|
"export { Checkbox } from './features/form/checkbox/public';",
|
|
25
|
+
"export { Field } from './features/form/field/public';",
|
|
25
26
|
"export { Radio } from './features/form/radio/public';",
|
|
27
|
+
"export { Switch } from './features/form/switch/public';",
|
|
26
28
|
"export { TextInput } from './features/form/text-input/public';",
|
|
27
29
|
"export { Icon, SUPPORTED_ICON_PROVIDERS } from './features/icon/public';",
|
|
28
30
|
"export { Image } from './features/image/public';",
|
|
29
31
|
"export { KeyboardAvoidingView } from './features/keyboard-avoiding-view/public';",
|
|
30
32
|
"export { Divider, Grid, ScrollView, View } from './features/layout/public';",
|
|
33
|
+
"export { List, ListItem } from './features/list/public';",
|
|
31
34
|
"export { Modal } from './features/modal/public';",
|
|
32
35
|
"export { PopoverMenu } from './features/popover-menu/public';",
|
|
33
36
|
"export { Popover } from './features/popover/public';",
|
|
@@ -38,38 +41,39 @@ const expectedFeatureRootExports = [
|
|
|
38
41
|
"export { Heading, Text } from './features/typography/public';",
|
|
39
42
|
] as const;
|
|
40
43
|
|
|
41
|
-
const
|
|
42
|
-
"export { Field } from './components/field';",
|
|
43
|
-
"export { HelperText } from './components/helper-text';",
|
|
44
|
-
"export { Label } from './components/label';",
|
|
45
|
-
"export { ListItem } from './components/list-item';",
|
|
46
|
-
"export { Switch } from './components/switch';",
|
|
47
|
-
"export { Textarea } from './components/textarea';",
|
|
44
|
+
const expectedCrossCuttingRootExports = [
|
|
48
45
|
"export type { InteractionPolicy, InteractionPolicyProps } from './interactionPolicy';",
|
|
49
46
|
"export * from './core/responsive';",
|
|
50
47
|
] as const;
|
|
51
48
|
|
|
52
49
|
describe('feature-owned root barrel contract', () => {
|
|
53
|
-
it('routes
|
|
50
|
+
it('routes UI through feature-owned public facades', () => {
|
|
54
51
|
expectedFeatureRootExports.forEach((line) => expect(indexSource).toContain(line));
|
|
55
52
|
});
|
|
56
53
|
|
|
57
|
-
it('does not retain removed
|
|
54
|
+
it('does not retain removed component or layout facades and aliases', () => {
|
|
55
|
+
expect(indexSource).not.toContain("'./components/");
|
|
58
56
|
expect(indexSource).not.toContain("'./layout");
|
|
59
57
|
expect(indexSource).not.toMatch(/\bBoxProps\b/u);
|
|
60
58
|
expect(indexSource).not.toMatch(/\bContainerProps\b/u);
|
|
61
59
|
expect(indexSource).not.toMatch(/\bStackProps\b/u);
|
|
62
60
|
expect(indexSource).not.toMatch(/\bScrollAreaProps\b/u);
|
|
61
|
+
expect(indexSource).not.toMatch(/\bTextareaProps\b/u);
|
|
62
|
+
expect(indexSource).not.toMatch(/\bHelperTextProps\b/u);
|
|
63
|
+
expect(indexSource).not.toMatch(/\bLabelProps\b/u);
|
|
63
64
|
expect(indexSource).not.toMatch(/export\s*\{[^}]*\bBox\b/u);
|
|
64
65
|
expect(indexSource).not.toMatch(/export\s*\{[^}]*\bContainer\b/u);
|
|
65
66
|
expect(indexSource).not.toMatch(/export\s*\{[^}]*\bStack\b/u);
|
|
66
67
|
expect(indexSource).not.toMatch(/export\s*\{[^}]*\bScrollArea\b/u);
|
|
68
|
+
expect(indexSource).not.toMatch(/export\s*\{[^}]*\bTextarea\b/u);
|
|
69
|
+
expect(indexSource).not.toMatch(/export\s*\{[^}]*\bHelperText\b/u);
|
|
70
|
+
expect(indexSource).not.toMatch(/export\s*\{[^}]*\bLabel\b/u);
|
|
67
71
|
});
|
|
68
72
|
});
|
|
69
73
|
|
|
70
74
|
describe('remaining root barrel contract', () => {
|
|
71
|
-
it('keeps
|
|
72
|
-
|
|
75
|
+
it('keeps deliberate cross-cutting public APIs', () => {
|
|
76
|
+
expectedCrossCuttingRootExports.forEach((line) => expect(indexSource).toContain(line));
|
|
73
77
|
});
|
|
74
78
|
|
|
75
79
|
it('does not retain obsolete action-sheet, drawer, menu aliases, or navigation chrome', () => {
|
package/src/index.ts
CHANGED
|
@@ -1,15 +1,3 @@
|
|
|
1
|
-
export type { FieldProps } from './components/field';
|
|
2
|
-
export { Field } from './components/field';
|
|
3
|
-
export type { HelperTextProps } from './components/helper-text';
|
|
4
|
-
export { HelperText } from './components/helper-text';
|
|
5
|
-
export type { LabelProps } from './components/label';
|
|
6
|
-
export { Label } from './components/label';
|
|
7
|
-
export type { ListItemProps } from './components/list-item';
|
|
8
|
-
export { ListItem } from './components/list-item';
|
|
9
|
-
export type { SwitchProps } from './components/switch';
|
|
10
|
-
export { Switch } from './components/switch';
|
|
11
|
-
export type { TextareaProps } from './components/textarea';
|
|
12
|
-
export { Textarea } from './components/textarea';
|
|
13
1
|
export type { FontRuntime } from './context/FontContext';
|
|
14
2
|
export { FontProvider, useFontContext } from './context/FontContext';
|
|
15
3
|
export type { I18nInstance, TranslationRuntime, Translator } from './context/TranslationContext';
|
|
@@ -40,8 +28,12 @@ export type { CardProps } from './features/card/public';
|
|
|
40
28
|
export { Card } from './features/card/public';
|
|
41
29
|
export type { CheckboxProps } from './features/form/checkbox/public';
|
|
42
30
|
export { Checkbox } from './features/form/checkbox/public';
|
|
31
|
+
export type { FieldProps } from './features/form/field/public';
|
|
32
|
+
export { Field } from './features/form/field/public';
|
|
43
33
|
export type { RadioProps } from './features/form/radio/public';
|
|
44
34
|
export { Radio } from './features/form/radio/public';
|
|
35
|
+
export type { SwitchProps } from './features/form/switch/public';
|
|
36
|
+
export { Switch } from './features/form/switch/public';
|
|
45
37
|
export type { TextInputProps } from './features/form/text-input/public';
|
|
46
38
|
export { TextInput } from './features/form/text-input/public';
|
|
47
39
|
export type {
|
|
@@ -62,6 +54,8 @@ export type {
|
|
|
62
54
|
export { KeyboardAvoidingView } from './features/keyboard-avoiding-view/public';
|
|
63
55
|
export type { DividerProps, GridProps, ScrollViewProps, ViewProps } from './features/layout/public';
|
|
64
56
|
export { Divider, Grid, ScrollView, View } from './features/layout/public';
|
|
57
|
+
export type { ListItemProps, ListProps } from './features/list/public';
|
|
58
|
+
export { List, ListItem } from './features/list/public';
|
|
65
59
|
export type { ModalProps } from './features/modal/public';
|
|
66
60
|
export { Modal } from './features/modal/public';
|
|
67
61
|
export type {
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type React from 'react';
|
|
2
|
+
|
|
3
|
+
import type { InteractionPolicyProps } from '../interactionPolicy';
|
|
4
|
+
|
|
5
|
+
export interface ListProps {
|
|
6
|
+
children?: React.ReactNode;
|
|
7
|
+
testID?: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface ListItemProps extends InteractionPolicyProps {
|
|
11
|
+
children?: React.ReactNode;
|
|
12
|
+
title?: React.ReactNode;
|
|
13
|
+
description?: React.ReactNode;
|
|
14
|
+
leading?: React.ReactNode;
|
|
15
|
+
trailing?: React.ReactNode;
|
|
16
|
+
onPress?: (() => void) | undefined;
|
|
17
|
+
disabled?: boolean;
|
|
18
|
+
selected?: boolean;
|
|
19
|
+
compact?: boolean;
|
|
20
|
+
accessibilityLabel?: string;
|
|
21
|
+
testID?: string;
|
|
22
|
+
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type React from 'react';
|
|
2
2
|
|
|
3
|
-
import type { ControlSize } from '
|
|
4
|
-
import type { ButtonBaseProps } from '
|
|
5
|
-
import type { SurfaceColor } from '
|
|
3
|
+
import type { ControlSize } from '../internal/resolvers/resolveControlSize';
|
|
4
|
+
import type { ButtonBaseProps } from '../primitives/button-base';
|
|
5
|
+
import type { SurfaceColor } from '../surfaceColor';
|
|
6
6
|
|
|
7
7
|
export interface SwitchProps extends Omit<
|
|
8
8
|
ButtonBaseProps,
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"Field.d.ts","sourceRoot":"","sources":["../../../src/components/field/Field.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAM1B,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAE1C,8EAA8E;AAC9E,wBAAgB,KAAK,CAAC,EACpB,QAAQ,EACR,KAAK,EACL,UAAU,EACV,SAAS,EACT,QAAgB,EAChB,QAAgB,EAChB,OAAe,EACf,QAAgB,EAChB,MAAM,GACP,EAAE,UAAU,qBAgCZ"}
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { View } from '../../features/layout/public';
|
|
3
|
-
import { resolveFieldPresentation, resolveFieldState } from '../../internal/resolvers';
|
|
4
|
-
import { HelperText } from '../helper-text';
|
|
5
|
-
import { Label } from '../label';
|
|
6
|
-
/*** Composes a label, control, and helper or error message into one field. */
|
|
7
|
-
export function Field({ children, label, helperText, errorText, required = false, disabled = false, invalid = false, readOnly = false, testID, }) {
|
|
8
|
-
const hasErrorText = Boolean(errorText);
|
|
9
|
-
const fieldState = resolveFieldState({
|
|
10
|
-
disabled,
|
|
11
|
-
invalid: invalid || hasErrorText,
|
|
12
|
-
readOnly,
|
|
13
|
-
});
|
|
14
|
-
const presentation = resolveFieldPresentation(fieldState);
|
|
15
|
-
return (<View gap="xs" testID={testID}>
|
|
16
|
-
{label ? (<Label color={presentation.labelColor} emphasis={presentation.labelEmphasis} required={required}>
|
|
17
|
-
{label}
|
|
18
|
-
</Label>) : null}
|
|
19
|
-
<View>{children}</View>
|
|
20
|
-
{hasErrorText ? (<HelperText color={presentation.helperColor} emphasis={presentation.helperEmphasis}>
|
|
21
|
-
{errorText}
|
|
22
|
-
</HelperText>) : helperText ? (<HelperText color={presentation.helperColor} emphasis={presentation.helperEmphasis}>
|
|
23
|
-
{helperText}
|
|
24
|
-
</HelperText>) : null}
|
|
25
|
-
</View>);
|
|
26
|
-
}
|
|
27
|
-
//# sourceMappingURL=Field.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"Field.js","sourceRoot":"","sources":["../../../src/components/field/Field.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,EAAE,IAAI,EAAE,MAAM,8BAA8B,CAAC;AACpD,OAAO,EAAE,wBAAwB,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AACvF,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAC5C,OAAO,EAAE,KAAK,EAAE,MAAM,UAAU,CAAC;AAGjC,8EAA8E;AAC9E,MAAM,UAAU,KAAK,CAAC,EACpB,QAAQ,EACR,KAAK,EACL,UAAU,EACV,SAAS,EACT,QAAQ,GAAG,KAAK,EAChB,QAAQ,GAAG,KAAK,EAChB,OAAO,GAAG,KAAK,EACf,QAAQ,GAAG,KAAK,EAChB,MAAM,GACK;IACX,MAAM,YAAY,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;IACxC,MAAM,UAAU,GAAG,iBAAiB,CAAC;QACnC,QAAQ;QACR,OAAO,EAAE,OAAO,IAAI,YAAY;QAChC,QAAQ;KACT,CAAC,CAAC;IACH,MAAM,YAAY,GAAG,wBAAwB,CAAC,UAAU,CAAC,CAAC;IAE1D,OAAO,CACL,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAC5B;MAAA,CAAC,KAAK,CAAC,CAAC,CAAC,CACP,CAAC,KAAK,CACJ,KAAK,CAAC,CAAC,YAAY,CAAC,UAAU,CAAC,CAC/B,QAAQ,CAAC,CAAC,YAAY,CAAC,aAAa,CAAC,CACrC,QAAQ,CAAC,CAAC,QAAQ,CAAC,CAEnB;UAAA,CAAC,KAAK,CACR;QAAA,EAAE,KAAK,CAAC,CACT,CAAC,CAAC,CAAC,IAAI,CACR;MAAA,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,EAAE,IAAI,CACtB;MAAA,CAAC,YAAY,CAAC,CAAC,CAAC,CACd,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,YAAY,CAAC,WAAW,CAAC,CAAC,QAAQ,CAAC,CAAC,YAAY,CAAC,cAAc,CAAC,CACjF;UAAA,CAAC,SAAS,CACZ;QAAA,EAAE,UAAU,CAAC,CACd,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CACf,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,YAAY,CAAC,WAAW,CAAC,CAAC,QAAQ,CAAC,CAAC,YAAY,CAAC,cAAc,CAAC,CACjF;UAAA,CAAC,UAAU,CACb;QAAA,EAAE,UAAU,CAAC,CACd,CAAC,CAAC,CAAC,IAAI,CACV;IAAA,EAAE,IAAI,CAAC,CACR,CAAC;AACJ,CAAC","sourcesContent":["import React from 'react';\n\nimport { View } from '../../features/layout/public';\nimport { resolveFieldPresentation, resolveFieldState } from '../../internal/resolvers';\nimport { HelperText } from '../helper-text';\nimport { Label } from '../label';\nimport type { FieldProps } from './types';\n\n/*** Composes a label, control, and helper or error message into one field. */\nexport function Field({\n children,\n label,\n helperText,\n errorText,\n required = false,\n disabled = false,\n invalid = false,\n readOnly = false,\n testID,\n}: FieldProps) {\n const hasErrorText = Boolean(errorText);\n const fieldState = resolveFieldState({\n disabled,\n invalid: invalid || hasErrorText,\n readOnly,\n });\n const presentation = resolveFieldPresentation(fieldState);\n\n return (\n <View gap=\"xs\" testID={testID}>\n {label ? (\n <Label\n color={presentation.labelColor}\n emphasis={presentation.labelEmphasis}\n required={required}\n >\n {label}\n </Label>\n ) : null}\n <View>{children}</View>\n {hasErrorText ? (\n <HelperText color={presentation.helperColor} emphasis={presentation.helperEmphasis}>\n {errorText}\n </HelperText>\n ) : helperText ? (\n <HelperText color={presentation.helperColor} emphasis={presentation.helperEmphasis}>\n {helperText}\n </HelperText>\n ) : null}\n </View>\n );\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/field/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,YAAY,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC"}
|