@sincpro/mobile-ui 1.0.1 → 1.1.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/README.md +572 -229
- package/dist/Actions/Actions.Button.d.ts +7 -2
- package/dist/Actions/Actions.Button.js +23 -10
- package/dist/Actions/Actions.FAB.d.ts +3 -1
- package/dist/Actions/Actions.FAB.js +7 -3
- package/dist/Actions/Actions.FilterButton.d.ts +10 -2
- package/dist/Actions/Actions.FilterButton.js +21 -6
- package/dist/Actions/Actions.IconButton.d.ts +5 -2
- package/dist/Actions/Actions.IconButton.js +7 -3
- package/dist/Actions/index.d.ts +2 -2
- package/dist/Actions/index.js +1 -1
- package/dist/Dialog/Dialog.ActionSheet.d.ts +2 -1
- package/dist/Dialog/Dialog.ActionSheet.js +15 -5
- package/dist/Dialog/Dialog.Confirmation.js +3 -3
- package/dist/Dialog/Dialog.NativeSheet.d.ts +10 -0
- package/dist/Dialog/Dialog.NativeSheet.js +21 -0
- package/dist/Dialog/Dialog.Sheet.d.ts +5 -1
- package/dist/Dialog/Dialog.Sheet.js +14 -8
- package/dist/Display/Display.CopyableText.d.ts +9 -2
- package/dist/Display/Display.CopyableText.js +75 -7
- package/dist/Display/Display.Icon.js +2 -1
- package/dist/Display/Display.KeyValue.d.ts +11 -4
- package/dist/Display/Display.KeyValue.js +6 -4
- package/dist/Display/Display.ListGroup.d.ts +23 -0
- package/dist/Display/Display.ListGroup.js +17 -0
- package/dist/Display/Display.ListItem.d.ts +16 -2
- package/dist/Display/Display.ListItem.js +25 -8
- package/dist/Display/Display.SectionHeader.d.ts +11 -1
- package/dist/Display/Display.SectionHeader.js +11 -2
- package/dist/Display/Display.SwipeableRow.d.ts +3 -1
- package/dist/Display/Display.SwipeableRow.js +3 -3
- package/dist/Display/index.d.ts +4 -0
- package/dist/Display/index.js +2 -0
- package/dist/Feedback/Feedback.Banner.js +1 -1
- package/dist/Feedback/Feedback.EmptyState.d.ts +2 -1
- package/dist/Feedback/Feedback.EmptyState.js +2 -2
- package/dist/Feedback/Feedback.Error.d.ts +3 -1
- package/dist/Feedback/Feedback.Error.js +4 -3
- package/dist/Form/Form.Checkbox.d.ts +4 -1
- package/dist/Form/Form.Checkbox.js +2 -2
- package/dist/Form/Form.DatePicker.d.ts +2 -1
- package/dist/Form/Form.DatePicker.js +4 -3
- package/dist/Form/Form.FilterButton.d.ts +1 -1
- package/dist/Form/Form.Input.d.ts +5 -3
- package/dist/Form/Form.Input.js +2 -2
- package/dist/Form/Form.KeyboardForm.d.ts +11 -0
- package/dist/Form/Form.KeyboardForm.js +9 -0
- package/dist/Form/Form.KeyboardToolbar.d.ts +21 -0
- package/dist/Form/Form.KeyboardToolbar.js +70 -0
- package/dist/Form/Form.Select.d.ts +3 -1
- package/dist/Form/Form.Select.js +23 -10
- package/dist/Form/index.d.ts +6 -0
- package/dist/Form/index.js +4 -0
- package/dist/Navigation/Navigation.AppBar.d.ts +6 -2
- package/dist/Navigation/Navigation.AppBar.js +7 -7
- package/dist/Navigation/Navigation.BottomNav.d.ts +3 -1
- package/dist/Navigation/Navigation.BottomNav.js +9 -5
- package/dist/Navigation/Navigation.RowItem.d.ts +1 -1
- package/dist/Navigation/Navigation.RowItem.js +2 -2
- package/dist/Navigation/Navigation.SearchBar.d.ts +6 -1
- package/dist/Navigation/Navigation.SearchBar.js +29 -8
- package/dist/Navigation/Navigation.SearchSuggestions.d.ts +14 -0
- package/dist/Navigation/Navigation.SearchSuggestions.js +7 -0
- package/dist/Navigation/Navigation.SegmentedControl.d.ts +3 -1
- package/dist/Navigation/Navigation.SegmentedControl.js +2 -1
- package/dist/Navigation/index.d.ts +6 -2
- package/dist/Navigation/index.js +2 -0
- package/dist/Typography/Typography.Heading.js +1 -1
- package/dist/Typography/Typography.SelectableText.d.ts +10 -0
- package/dist/Typography/Typography.SelectableText.js +16 -0
- package/dist/Typography/Typography.Text.js +4 -20
- package/dist/Typography/index.d.ts +3 -0
- package/dist/Typography/index.js +3 -0
- package/dist/layouts/AuthContainer.d.ts +4 -1
- package/dist/layouts/AuthContainer.js +3 -3
- package/dist/primitives/BaseButton.d.ts +7 -2
- package/dist/primitives/BaseButton.js +19 -5
- package/dist/theme/typography.d.ts +16 -1
- package/dist/theme/typography.js +19 -0
- package/dist/utils/criteria.d.ts +56 -0
- package/dist/utils/criteria.js +99 -0
- package/dist/utils/reorder.d.ts +4 -0
- package/dist/utils/reorder.js +32 -0
- package/dist/views/AuthFormView.d.ts +4 -1
- package/dist/views/AuthFormView.js +2 -2
- package/dist/views/FormViewV2.d.ts +7 -2
- package/dist/views/FormViewV2.js +35 -16
- package/dist/views/ListViewV2.d.ts +9 -6
- package/dist/views/ListViewV2.js +34 -21
- package/dist/widgets/CollectionOptions.d.ts +15 -0
- package/dist/widgets/CollectionOptions.js +127 -0
- package/dist/widgets/FilterBar.d.ts +21 -0
- package/dist/widgets/FilterBar.js +14 -0
- package/dist/widgets/FilterBuilder.d.ts +10 -0
- package/dist/widgets/FilterBuilder.js +115 -0
- package/dist/widgets/QueryChoice.d.ts +10 -0
- package/dist/widgets/QueryChoice.js +13 -0
- package/dist/widgets/ReorderableList.d.ts +51 -0
- package/dist/widgets/ReorderableList.js +138 -0
- package/dist/widgets/index.d.ts +4 -0
- package/dist/widgets/index.js +3 -0
- package/package.json +15 -1
package/dist/Form/Form.Select.js
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "nativewind/jsx-runtime";
|
|
2
2
|
import Icon from "../Display/Display.Icon.js";
|
|
3
3
|
import Pressable from "../primitives/Pressable.js";
|
|
4
|
-
import {
|
|
4
|
+
import { themeToVars, useTheme } from "../theme/index.js";
|
|
5
5
|
import { cn } from "../theme/tw.js";
|
|
6
6
|
import { Typography } from "../Typography/index.js";
|
|
7
|
+
import { vars } from "nativewind";
|
|
7
8
|
import { useEffect, useRef, useState } from "react";
|
|
8
|
-
import { Animated, Modal,
|
|
9
|
+
import { Animated, Modal, ScrollView, View } from "react-native";
|
|
9
10
|
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
|
10
|
-
function Select({ options, value, onChange, label, placeholder = "Seleccionar…", title, disabled = false, className, testID, }) {
|
|
11
|
+
function Select({ options, value, onChange, label, placeholder = "Seleccionar…", title, disabled = false, accessibleSizing = false, className, testID, showCloseButton = accessibleSizing, }) {
|
|
12
|
+
const theme = useTheme();
|
|
11
13
|
const insets = useSafeAreaInsets();
|
|
12
14
|
const [open, setOpen] = useState(false);
|
|
13
15
|
const selected = options.find((o) => o.value === value) ?? null;
|
|
@@ -26,16 +28,27 @@ function Select({ options, value, onChange, label, placeholder = "Seleccionar…
|
|
|
26
28
|
translateY.setValue(800);
|
|
27
29
|
}
|
|
28
30
|
}, [open, translateY]);
|
|
29
|
-
return (_jsxs(View, { className: cn("gap-1", className), testID: testID, children: [label ? (_jsx(Typography.Text, { className: "font-medium text-text-primary", variant: "bodySmall", children: label })) : null, _jsxs(Pressable, { accessibilityHint: "Abre la lista de opciones", accessibilityLabel: label
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
31
|
+
return (_jsxs(View, { className: cn("gap-1", className), testID: testID, children: [label ? (_jsx(Typography.Text, { className: "font-medium text-text-primary", variant: "bodySmall", children: label })) : null, _jsxs(Pressable, { accessibilityHint: "Abre la lista de opciones", accessibilityLabel: label
|
|
32
|
+
? `${label}: ${selected?.label ?? placeholder}`
|
|
33
|
+
: (selected?.label ?? placeholder), accessibilityRole: "button", accessibilityState: { disabled, expanded: open }, className: cn("flex-row items-center justify-between rounded-lg border border-input bg-bg-card px-3", accessibleSizing ? "min-h-[48px]" : "min-h-[44px]"), disabled: disabled, onPress: () => setOpen(true), children: [_jsx(Typography.Text, { className: cn("flex-1 text-sm", selected ? "text-text-primary" : "text-text-tertiary"), numberOfLines: accessibleSizing ? undefined : 1, style: accessibleSizing ? { paddingVertical: 12 } : undefined, children: selected ? selected.label : placeholder }), _jsx(Icon, { color: theme.icon.secondary, name: "chevron-down", size: 18 })] }), _jsx(Modal, { animationType: "none", onRequestClose: () => setOpen(false), presentationStyle: "overFullScreen", transparent: true, visible: open, children: _jsxs(View, { className: "flex-1 justify-end", children: [_jsx(View, { accessibilityElementsHidden: true, className: "absolute inset-0 bg-black/50", importantForAccessibility: "no-hide-descendants", onResponderRelease: () => setOpen(false), onStartShouldSetResponder: () => true }), _jsxs(Animated.View, { accessibilityViewIsModal: true, className: "rounded-t-3xl", importantForAccessibility: "yes", onAccessibilityEscape: () => setOpen(false), style: [
|
|
34
|
+
vars(themeToVars(theme)),
|
|
35
|
+
{
|
|
36
|
+
transform: [{ translateY }],
|
|
37
|
+
maxHeight: "70%",
|
|
38
|
+
backgroundColor: theme.bg.card,
|
|
39
|
+
paddingBottom: insets.bottom + 8,
|
|
40
|
+
},
|
|
41
|
+
], children: [_jsx(View, { className: "items-center pt-3 pb-1", children: _jsx(View, { className: "w-10 h-1 rounded-full bg-border-strong" }) }), title || showCloseButton ? (_jsxs(View, { className: "flex-row items-center justify-between px-4", children: [_jsx(Typography.Text, { accessibilityRole: "header", className: "flex-1 text-text-primary py-2", semibold: true, variant: "body", children: title ?? label ?? "Seleccionar" }), showCloseButton ? (_jsx(Pressable, { accessibilityLabel: "Cerrar opciones", onPress: () => setOpen(false), style: {
|
|
42
|
+
minWidth: 48,
|
|
43
|
+
minHeight: 48,
|
|
44
|
+
justifyContent: "center",
|
|
45
|
+
alignItems: "center",
|
|
46
|
+
}, children: _jsx(Typography.Text, { className: "text-text-accent", variant: "bodySmall", children: "Cerrar" }) })) : null] })) : null, _jsx(ScrollView, { children: options.map((option) => {
|
|
34
47
|
const isSelected = option.value === value;
|
|
35
48
|
return (_jsxs(Pressable, { accessibilityRole: "menuitem", accessibilityState: { selected: isSelected }, className: "flex-row items-center justify-between px-4 py-3 border-b border-border-light", onPress: () => {
|
|
36
49
|
onChange(option.value);
|
|
37
50
|
setOpen(false);
|
|
38
|
-
}, children: [_jsx(Typography.Text, { className: cn("flex-1 text-sm", isSelected ? "text-text-accent font-semibold" : "text-text-primary"), children: option.label }), isSelected ? (_jsx(Icon, { color: theme.text.accent, name: "checkmark", size: 18 })) : null] }, String(option.value)));
|
|
39
|
-
}) })] }) }) })
|
|
51
|
+
}, style: accessibleSizing ? { minHeight: 48 } : undefined, children: [_jsx(Typography.Text, { className: cn("flex-1 text-sm", isSelected ? "text-text-accent font-semibold" : "text-text-primary"), children: option.label }), isSelected ? (_jsx(Icon, { color: theme.text.accent, name: "checkmark", size: 18 })) : null] }, String(option.value)));
|
|
52
|
+
}) })] })] }) })] }));
|
|
40
53
|
}
|
|
41
54
|
export default Select;
|
package/dist/Form/index.d.ts
CHANGED
|
@@ -11,6 +11,8 @@ import { FilterButtonGroup } from "./Form.FilterButton.js";
|
|
|
11
11
|
import FractionalQuantityInput from "./Form.FractionalQuantityInput.js";
|
|
12
12
|
import IconButton from "./Form.IconButton.js";
|
|
13
13
|
import Input from "./Form.Input.js";
|
|
14
|
+
import KeyboardForm from "./Form.KeyboardForm.js";
|
|
15
|
+
import KeyboardToolbar from "./Form.KeyboardToolbar.js";
|
|
14
16
|
import MonetaryInput from "./Form.MonetaryInput.js";
|
|
15
17
|
import PinInput from "./Form.PinInput.js";
|
|
16
18
|
import QuantitySelector from "./Form.QuantitySelector.js";
|
|
@@ -23,6 +25,8 @@ export declare const Form: {
|
|
|
23
25
|
TextInput: import("react").FC<import("./Form.TextInput.js").TextInputFProps>;
|
|
24
26
|
Input: typeof Input;
|
|
25
27
|
InputField: import("react").FC<import("./Form.InputField.js").InputFieldProps>;
|
|
28
|
+
KeyboardForm: typeof KeyboardForm;
|
|
29
|
+
KeyboardToolbar: typeof KeyboardToolbar;
|
|
26
30
|
Button: import("react").FC<import("./Form.Button.js").ButtonProps> & {
|
|
27
31
|
Icon: import("react").FC<import("./Form.Button.js").ButtonIconProps>;
|
|
28
32
|
};
|
|
@@ -50,4 +54,6 @@ export declare const Form: {
|
|
|
50
54
|
FilterButtonGroup: typeof FilterButtonGroup;
|
|
51
55
|
};
|
|
52
56
|
export { type DropdownOption };
|
|
57
|
+
export type { KeyboardFormProps } from "./Form.KeyboardForm.js";
|
|
58
|
+
export type { KeyboardToolbarAction, KeyboardToolbarProps, } from "./Form.KeyboardToolbar.js";
|
|
53
59
|
export default Form;
|
package/dist/Form/index.js
CHANGED
|
@@ -13,6 +13,8 @@ import FractionalQuantityInput from "./Form.FractionalQuantityInput.js";
|
|
|
13
13
|
import IconButton from "./Form.IconButton.js";
|
|
14
14
|
import Input from "./Form.Input.js";
|
|
15
15
|
import InputField from "./Form.InputField.js";
|
|
16
|
+
import KeyboardForm from "./Form.KeyboardForm.js";
|
|
17
|
+
import KeyboardToolbar from "./Form.KeyboardToolbar.js";
|
|
16
18
|
import MonetaryInput from "./Form.MonetaryInput.js";
|
|
17
19
|
import PasswordInput from "./Form.PasswordInput.js";
|
|
18
20
|
import PinInput from "./Form.PinInput.js";
|
|
@@ -27,6 +29,8 @@ export const Form = {
|
|
|
27
29
|
TextInput,
|
|
28
30
|
Input,
|
|
29
31
|
InputField,
|
|
32
|
+
KeyboardForm,
|
|
33
|
+
KeyboardToolbar,
|
|
30
34
|
Button: ButtonWithIcon,
|
|
31
35
|
IconButton,
|
|
32
36
|
PasswordInput,
|
|
@@ -16,6 +16,8 @@ export interface AppBarActionProps {
|
|
|
16
16
|
onDark?: boolean;
|
|
17
17
|
/** Drop the contained surface → bare icon/text (iOS-style plain back/action). */
|
|
18
18
|
bare?: boolean;
|
|
19
|
+
/** Increase the action target to 48 points. */
|
|
20
|
+
accessibleSizing?: boolean;
|
|
19
21
|
testID?: string;
|
|
20
22
|
}
|
|
21
23
|
/**
|
|
@@ -23,7 +25,7 @@ export interface AppBarActionProps {
|
|
|
23
25
|
* (merge of Material 3 state-layer + iOS 26 contained button). Optional badge.
|
|
24
26
|
* With `label`, renders a text pill CTA instead (for "Editar"/"Nuevo"/"Guardar").
|
|
25
27
|
*/
|
|
26
|
-
declare function AppBarAction({ icon, label, onPress, badge, accessibilityLabel, tone, onDark, bare, testID, }: AppBarActionProps): import("react").JSX.Element;
|
|
28
|
+
declare function AppBarAction({ icon, label, onPress, badge, accessibilityLabel, tone, onDark, bare, accessibleSizing, testID, }: AppBarActionProps): import("react").JSX.Element;
|
|
27
29
|
export interface AppBarProps {
|
|
28
30
|
title?: string;
|
|
29
31
|
subtitle?: string;
|
|
@@ -47,6 +49,8 @@ export interface AppBarProps {
|
|
|
47
49
|
border?: boolean;
|
|
48
50
|
/** Reserves the status-bar space (insets.top). `false` to embed/demo. */
|
|
49
51
|
safeArea?: boolean;
|
|
52
|
+
/** Increase the back-action target to 48 points. */
|
|
53
|
+
accessibleSizing?: boolean;
|
|
50
54
|
/**
|
|
51
55
|
* [large variant] Extra top padding (px) above the large title row.
|
|
52
56
|
* Default is 8. Use ~16–24 on root/home screens without a back button.
|
|
@@ -109,7 +113,7 @@ export interface AppBarBackground {
|
|
|
109
113
|
* a `subheader` slot (for SearchBar/Segmented below the title), and a `large` variant.
|
|
110
114
|
* Replaces the gradient look of `Navigation.Header`/`ScreenHeader`.
|
|
111
115
|
*/
|
|
112
|
-
declare function AppBar({ title, subtitle, onBack, leading, actions, subheader, variant, tone, accentBar, backVariant, border, safeArea, topSpacing, background, bottomDivider, className, testID, }: AppBarProps): import("react").JSX.Element;
|
|
116
|
+
declare function AppBar({ title, subtitle, onBack, leading, actions, subheader, variant, tone, accentBar, backVariant, border, safeArea, accessibleSizing, topSpacing, background, bottomDivider, className, testID, }: AppBarProps): import("react").JSX.Element;
|
|
113
117
|
declare const AppBarWithAction: typeof AppBar & {
|
|
114
118
|
Action: typeof AppBarAction;
|
|
115
119
|
};
|
|
@@ -15,7 +15,7 @@ const HERO_DARK_FALLBACK = "#0E1714";
|
|
|
15
15
|
* (merge of Material 3 state-layer + iOS 26 contained button). Optional badge.
|
|
16
16
|
* With `label`, renders a text pill CTA instead (for "Editar"/"Nuevo"/"Guardar").
|
|
17
17
|
*/
|
|
18
|
-
function AppBarAction({ icon, label, onPress, badge, accessibilityLabel, tone = "plain", onDark = false, bare = false, testID, }) {
|
|
18
|
+
function AppBarAction({ icon, label, onPress, badge, accessibilityLabel, tone = "plain", onDark = false, bare = false, accessibleSizing = false, testID, }) {
|
|
19
19
|
const theme = useTheme();
|
|
20
20
|
const bg = bare
|
|
21
21
|
? "transparent"
|
|
@@ -35,7 +35,7 @@ function AppBarAction({ icon, label, onPress, badge, accessibilityLabel, tone =
|
|
|
35
35
|
// primary/secondary header actions like "Editar", "Nuevo", "Guardar".
|
|
36
36
|
if (label) {
|
|
37
37
|
return (_jsxs(Pressable, { accessibilityLabel: accessibilityLabel ?? label, accessibilityRole: "button", className: "flex-row items-center justify-center gap-1.5", hitSlop: 6, onPress: onPress, style: {
|
|
38
|
-
height: 36,
|
|
38
|
+
height: accessibleSizing ? 48 : 36,
|
|
39
39
|
paddingHorizontal: 14,
|
|
40
40
|
borderRadius: 999,
|
|
41
41
|
backgroundColor: bg,
|
|
@@ -43,8 +43,8 @@ function AppBarAction({ icon, label, onPress, badge, accessibilityLabel, tone =
|
|
|
43
43
|
}, testID: testID, children: [icon ? _jsx(Icon, { color: iconColor, name: icon, size: 16 }) : null, _jsx(Typography.Text, { semibold: true, style: { color: iconColor }, variant: "bodySmall", children: label })] }));
|
|
44
44
|
}
|
|
45
45
|
return (_jsxs(Pressable, { accessibilityLabel: accessibilityLabel, accessibilityRole: "button", className: "items-center justify-center", hitSlop: 6, onPress: onPress, style: {
|
|
46
|
-
width: 40,
|
|
47
|
-
height: 40,
|
|
46
|
+
width: accessibleSizing ? 48 : 40,
|
|
47
|
+
height: accessibleSizing ? 48 : 40,
|
|
48
48
|
borderRadius: 12,
|
|
49
49
|
backgroundColor: bg,
|
|
50
50
|
...(showBorder ? { borderWidth: 1, borderColor: theme.border.light } : null),
|
|
@@ -56,7 +56,7 @@ function AppBarAction({ icon, label, onPress, badge, accessibilityLabel, tone =
|
|
|
56
56
|
* a `subheader` slot (for SearchBar/Segmented below the title), and a `large` variant.
|
|
57
57
|
* Replaces the gradient look of `Navigation.Header`/`ScreenHeader`.
|
|
58
58
|
*/
|
|
59
|
-
function AppBar({ title, subtitle, onBack, leading, actions, subheader, variant = "default", tone = "default", accentBar = false, backVariant = "contained", border = true, safeArea = true, topSpacing, background, bottomDivider, className, testID, }) {
|
|
59
|
+
function AppBar({ title, subtitle, onBack, leading, actions, subheader, variant = "default", tone = "default", accentBar = false, backVariant = "contained", border = true, safeArea = true, accessibleSizing = false, topSpacing, background, bottomDivider, className, testID, }) {
|
|
60
60
|
const theme = useTheme();
|
|
61
61
|
const insets = useSafeAreaInsets();
|
|
62
62
|
const centered = variant === "center";
|
|
@@ -106,13 +106,13 @@ function AppBar({ title, subtitle, onBack, leading, actions, subheader, variant
|
|
|
106
106
|
? { borderBottomLeftRadius: 24, borderBottomRightRadius: 24, overflow: "hidden" }
|
|
107
107
|
: null),
|
|
108
108
|
...(showShadow ? theme.shadow.md : null),
|
|
109
|
-
}, testID: testID, children: [hasBackground ? (_jsx(GradientSurface, { colors: background.colors, end: background.end, padding: "none", preset: background.surface ?? "warm", radius: "none", start: background.start, style: StyleSheet.absoluteFill })) : gradient ? (_jsx(GradientSurface, { colors: theme.gradient.accent, padding: "none", radius: "none", style: StyleSheet.absoluteFill })) : null, background?.pattern ? (_jsx(Pattern, { color: background.patternColor ?? "#FFFFFF", kind: background.pattern, opacity: background.patternOpacity ?? 0.18 })) : null, showTopBar ? (_jsxs(View, { className: "flex-row items-center px-3 gap-2 min-h-[56px]", children: [_jsxs(View, { className: "flex-row items-center gap-2", style: { minWidth: 38 }, children: [onBack ? (_jsx(AppBarAction, { accessibilityLabel: "Volver", bare: backVariant === "plain", icon: "chevron-back", onDark: dark || gradient || hasBackground, onPress: onBack })) : null, leading] }), _jsxs(View, { className: cn("flex-1", centered && "items-center"), children: [title ? (_jsx(Typography.Text, { className: colored ? "" : "text-text-primary", numberOfLines: 1, semibold: true, style: titleStyle, variant: "subtitle", children: title })) : null, subtitle ? (_jsx(Typography.Text, { className: colored ? "" : "text-text-secondary", numberOfLines: 1, style: subtitleStyle, variant: "caption", children: subtitle })) : null] }), _jsx(View, { className: "flex-row items-center justify-end gap-2", style: { minWidth: 38 }, children: actions })] })) : null, large && title ? (_jsxs(View, { className: cn("flex-row px-4 pb-3", largeHasNav ? "items-center gap-2" : ""), style: { paddingTop: topSpacing != null ? topSpacing : 8 }, children: [onBack ? (_jsx(AppBarAction, { accessibilityLabel: "Volver", bare: backVariant === "plain", icon: "chevron-back", onDark: dark || gradient || hasBackground, onPress: onBack })) : null, leading, accentBar && !largeHasNav ? (_jsx(View, { style: {
|
|
109
|
+
}, testID: testID, children: [hasBackground ? (_jsx(GradientSurface, { colors: background.colors, end: background.end, padding: "none", preset: background.surface ?? "warm", radius: "none", start: background.start, style: StyleSheet.absoluteFill })) : gradient ? (_jsx(GradientSurface, { colors: theme.gradient.accent, padding: "none", radius: "none", style: StyleSheet.absoluteFill })) : null, background?.pattern ? (_jsx(Pattern, { color: background.patternColor ?? "#FFFFFF", kind: background.pattern, opacity: background.patternOpacity ?? 0.18 })) : null, showTopBar ? (_jsxs(View, { className: "flex-row items-center px-3 gap-2 min-h-[56px]", children: [_jsxs(View, { className: "flex-row items-center gap-2", style: { minWidth: 38 }, children: [onBack ? (_jsx(AppBarAction, { accessibilityLabel: "Volver", accessibleSizing: accessibleSizing, bare: backVariant === "plain", icon: "chevron-back", onDark: dark || gradient || hasBackground, onPress: onBack })) : null, leading] }), _jsxs(View, { className: cn("flex-1", centered && "items-center"), children: [title ? (_jsx(Typography.Text, { accessibilityRole: "header", className: colored ? "" : "text-text-primary", numberOfLines: 1, semibold: true, style: titleStyle, variant: "subtitle", children: title })) : null, subtitle ? (_jsx(Typography.Text, { className: colored ? "" : "text-text-secondary", numberOfLines: 1, style: subtitleStyle, variant: "caption", children: subtitle })) : null] }), _jsx(View, { className: "flex-row items-center justify-end gap-2", style: { minWidth: 38 }, children: actions })] })) : null, large && title ? (_jsxs(View, { className: cn("flex-row px-4 pb-3", largeHasNav ? "items-center gap-2" : ""), style: { paddingTop: topSpacing != null ? topSpacing : 8 }, children: [onBack ? (_jsx(AppBarAction, { accessibilityLabel: "Volver", accessibleSizing: accessibleSizing, bare: backVariant === "plain", icon: "chevron-back", onDark: dark || gradient || hasBackground, onPress: onBack })) : null, leading, accentBar && !largeHasNav ? (_jsx(View, { style: {
|
|
110
110
|
width: 4,
|
|
111
111
|
marginRight: 10,
|
|
112
112
|
marginVertical: 2,
|
|
113
113
|
borderRadius: 999,
|
|
114
114
|
backgroundColor: theme.accent,
|
|
115
|
-
} })) : null, _jsxs(View, { className: "flex-1", children: [_jsx(Typography.Text, { className: colored ? "" : "text-text-primary", style: titleStyle, variant: "h2", children: title }), subtitle ? (_jsx(Typography.Text, { className: colored ? "" : "text-text-secondary", style: subtitleStyle, variant: "bodySmall", children: subtitle })) : null] }), actions ? (_jsx(View, { className: cn("flex-row items-center justify-end gap-2 pl-2", largeHasNav ? "" : "self-center"), children: actions })) : null] })) : null, subheader ? _jsx(View, { className: "px-3 pb-3 pt-0.5", children: subheader }) : null, showWave ? (_jsx(View, { style: {
|
|
115
|
+
} })) : null, _jsxs(View, { className: "flex-1", children: [_jsx(Typography.Text, { accessibilityRole: "header", className: colored ? "" : "text-text-primary", style: titleStyle, variant: "h2", children: title }), subtitle ? (_jsx(Typography.Text, { className: colored ? "" : "text-text-secondary", style: subtitleStyle, variant: "bodySmall", children: subtitle })) : null] }), actions ? (_jsx(View, { className: cn("flex-row items-center justify-end gap-2 pl-2", largeHasNav ? "" : "self-center"), children: actions })) : null] })) : null, subheader ? _jsx(View, { className: "px-3 pb-3 pt-0.5", children: subheader }) : null, showWave ? (_jsx(View, { style: {
|
|
116
116
|
height: 24,
|
|
117
117
|
backgroundColor: theme.bg.page,
|
|
118
118
|
borderTopLeftRadius: 24,
|
|
@@ -44,6 +44,8 @@ export interface BottomNavProps {
|
|
|
44
44
|
bordered?: boolean;
|
|
45
45
|
/** Token for the active color. `primary` (default) or `accent` (e.g. green CTA brand). */
|
|
46
46
|
activeColor?: "primary" | "accent";
|
|
47
|
+
/** Increase each tab's target to at least 48 points. */
|
|
48
|
+
accessibleSizing?: boolean;
|
|
47
49
|
className?: string;
|
|
48
50
|
testID?: string;
|
|
49
51
|
}
|
|
@@ -52,6 +54,6 @@ export interface BottomNavProps {
|
|
|
52
54
|
* `shape` (bar/floating), `tone` (light/dark), `indicator` (none/pill/pill-text/bar/glow),
|
|
53
55
|
* `showLabels`, `centerAction` (FAB), `activeColor`. Replaces the legacy `TabNavigatorLayout`.
|
|
54
56
|
*/
|
|
55
|
-
declare function BottomNav({ items, value, onChange, showLabels, centerAction, safeArea, shape, tone, indicator, bordered, activeColor, className, testID, }: BottomNavProps): import("react").JSX.Element;
|
|
57
|
+
declare function BottomNav({ items, value, onChange, showLabels, centerAction, safeArea, shape, tone, indicator, bordered, activeColor, accessibleSizing, className, testID, }: BottomNavProps): import("react").JSX.Element;
|
|
56
58
|
export default BottomNav;
|
|
57
59
|
export { BottomNav };
|
|
@@ -16,7 +16,7 @@ function resolveDarkSurface(theme) {
|
|
|
16
16
|
* `shape` (bar/floating), `tone` (light/dark), `indicator` (none/pill/pill-text/bar/glow),
|
|
17
17
|
* `showLabels`, `centerAction` (FAB), `activeColor`. Replaces the legacy `TabNavigatorLayout`.
|
|
18
18
|
*/
|
|
19
|
-
function BottomNav({ items, value, onChange, showLabels = true, centerAction, safeArea = true, shape = "bar", tone = "light", indicator = "none", bordered = true, activeColor = "primary", className, testID, }) {
|
|
19
|
+
function BottomNav({ items, value, onChange, showLabels = true, centerAction, safeArea = true, shape = "bar", tone = "light", indicator = "none", bordered = true, activeColor = "primary", accessibleSizing = false, className, testID, }) {
|
|
20
20
|
const insets = useSafeAreaInsets();
|
|
21
21
|
const theme = useTheme();
|
|
22
22
|
const dark = tone === "dark";
|
|
@@ -52,9 +52,13 @@ function BottomNav({ items, value, onChange, showLabels = true, centerAction, sa
|
|
|
52
52
|
// Variant A — extended pill with text (active = horizontal pill, inactive = icon only).
|
|
53
53
|
if (indicator === "pill-text") {
|
|
54
54
|
if (active) {
|
|
55
|
-
return (_jsxs(Pressable, { accessibilityLabel: item.label ?? item.key, accessibilityRole: "tab", accessibilityState: { selected: true }, className: "flex-row items-center px-4 py-2", onPress: () => onChange(item.key), style: {
|
|
55
|
+
return (_jsxs(Pressable, { accessibilityLabel: item.label ?? item.key, accessibilityRole: "tab", accessibilityState: { selected: true }, className: "flex-row items-center px-4 py-2", onPress: () => onChange(item.key), style: {
|
|
56
|
+
borderRadius: 999,
|
|
57
|
+
backgroundColor: activeTint,
|
|
58
|
+
...(accessibleSizing ? { minHeight: 48, minWidth: 48 } : null),
|
|
59
|
+
}, children: [renderIconNode(item, true, onActive), item.label ? (_jsx(Typography.Text, { semibold: true, style: { color: onActive, fontSize: 13, marginLeft: 8 }, children: item.label })) : null] }, item.key));
|
|
56
60
|
}
|
|
57
|
-
return (_jsx(Pressable, { accessibilityLabel: item.label ?? item.key, accessibilityRole: "tab", className: "items-center justify-center px-3 py-2", onPress: () => onChange(item.key), children: renderIconNode(item, false, inactiveColor) }, item.key));
|
|
61
|
+
return (_jsx(Pressable, { accessibilityLabel: item.label ?? item.key, accessibilityRole: "tab", className: "items-center justify-center px-3 py-2", onPress: () => onChange(item.key), style: accessibleSizing ? { minHeight: 48, minWidth: 48 } : undefined, children: renderIconNode(item, false, inactiveColor) }, item.key));
|
|
58
62
|
}
|
|
59
63
|
// Variants none / pill / bar / glow — vertical icon + optional indicator + optional label.
|
|
60
64
|
const inPill = indicator === "pill" && active;
|
|
@@ -70,7 +74,7 @@ function BottomNav({ items, value, onChange, showLabels = true, centerAction, sa
|
|
|
70
74
|
labelColor = theme.text.inverse;
|
|
71
75
|
else if (active)
|
|
72
76
|
labelColor = brandText;
|
|
73
|
-
return (_jsxs(Pressable, { accessibilityLabel: item.label ?? item.key, accessibilityRole: "tab", accessibilityState: { selected: active }, className: "flex-1 items-center justify-center py-1.5", onPress: () => onChange(item.key), children: [indicator === "bar" && active ? (_jsx(View, { style: {
|
|
77
|
+
return (_jsxs(Pressable, { accessibilityLabel: item.label ?? item.key, accessibilityRole: "tab", accessibilityState: { selected: active }, className: "flex-1 items-center justify-center py-1.5", onPress: () => onChange(item.key), style: accessibleSizing ? { minHeight: 48, minWidth: 48 } : undefined, children: [indicator === "bar" && active ? (_jsx(View, { style: {
|
|
74
78
|
position: "absolute",
|
|
75
79
|
top: 0,
|
|
76
80
|
width: 26,
|
|
@@ -112,7 +116,7 @@ function BottomNav({ items, value, onChange, showLabels = true, centerAction, sa
|
|
|
112
116
|
content = items.map(renderItem);
|
|
113
117
|
}
|
|
114
118
|
const justify = indicator === "pill-text" ? "justify-around" : "";
|
|
115
|
-
return (_jsx(View, { className: cn("flex-row items-center", justify, className), style: containerStyle, testID: testID, children: content }));
|
|
119
|
+
return (_jsx(View, { accessibilityRole: "tablist", className: cn("flex-row items-center", justify, className), style: containerStyle, testID: testID, children: content }));
|
|
116
120
|
}
|
|
117
121
|
export default BottomNav;
|
|
118
122
|
export { BottomNav };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { IRowItemProps } from "../views/types/IListView.js";
|
|
2
|
-
declare function RowItem({ item, className }: IRowItemProps<any> & {
|
|
2
|
+
declare function RowItem({ item, className, onPress, readonly, }: IRowItemProps<any> & {
|
|
3
3
|
className?: string;
|
|
4
4
|
}): import("react").JSX.Element;
|
|
5
5
|
export default RowItem;
|
|
@@ -2,10 +2,10 @@ import { jsx as _jsx, jsxs as _jsxs } from "nativewind/jsx-runtime";
|
|
|
2
2
|
import { cn } from "../theme/tw.js";
|
|
3
3
|
import { Typography } from "../Typography/index.js";
|
|
4
4
|
import { TouchableOpacity, View } from "react-native";
|
|
5
|
-
function RowItem({ item, className }) {
|
|
5
|
+
function RowItem({ item, className, onPress = item.onPress, readonly = item.readonly, }) {
|
|
6
6
|
function rowContent() {
|
|
7
7
|
return (_jsxs(View, { className: "flex-1", children: [_jsx(Typography.Text, { className: "flex-1", variant: "title", children: item.rowTitle }), _jsx(Typography.Text, { className: "mt-0.5 text-text-secondary", variant: "bodySmall", children: item.rowSubtitle })] }));
|
|
8
8
|
}
|
|
9
|
-
return
|
|
9
|
+
return readonly ? (_jsx(View, { className: cn("flex-row items-center py-2.5", className), children: rowContent() })) : (_jsx(TouchableOpacity, { className: cn("flex-row items-center py-2.5", className), onPress: onPress, children: rowContent() }));
|
|
10
10
|
}
|
|
11
11
|
export default RowItem;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type SearchSuggestionsProps } from "./Navigation.SearchSuggestions.js";
|
|
1
2
|
export interface SearchBarProps {
|
|
2
3
|
value: string;
|
|
3
4
|
onChangeText: (value: string) => void;
|
|
@@ -9,10 +10,14 @@ export interface SearchBarProps {
|
|
|
9
10
|
onPress?: () => void;
|
|
10
11
|
className?: string;
|
|
11
12
|
testID?: string;
|
|
13
|
+
accessibleSizing?: boolean;
|
|
14
|
+
accessibilityLabel?: string;
|
|
15
|
+
clearAccessibilityLabel?: string;
|
|
16
|
+
suggestions?: SearchSuggestionsProps;
|
|
12
17
|
}
|
|
13
18
|
/**
|
|
14
19
|
* **Pill** search bar (rounded-full), 2026 style (merge of Material 3 + iOS 26).
|
|
15
20
|
* Use `editable={false}` + `onPress` for a trigger that navigates to the search screen.
|
|
16
21
|
*/
|
|
17
|
-
declare function SearchBar({ value, onChangeText, placeholder, onSubmit, onClear, autoFocus, editable, onPress, className, testID, }: SearchBarProps): import("react").JSX.Element;
|
|
22
|
+
declare function SearchBar({ value, onChangeText, placeholder, onSubmit, onClear, autoFocus, editable, onPress, className, testID, accessibleSizing, accessibilityLabel, clearAccessibilityLabel, suggestions, }: SearchBarProps): import("react").JSX.Element;
|
|
18
23
|
export default SearchBar;
|
|
@@ -1,28 +1,49 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "nativewind/jsx-runtime";
|
|
2
2
|
import Icon from "../Display/Display.Icon.js";
|
|
3
|
+
import SearchSuggestions from "./Navigation.SearchSuggestions.js";
|
|
3
4
|
import Pressable from "../primitives/Pressable.js";
|
|
4
|
-
import {
|
|
5
|
+
import { useTheme } from "../theme/index.js";
|
|
5
6
|
import { cn } from "../theme/tw.js";
|
|
7
|
+
import { resolveTextFontFamily, typographyVariants, } from "../theme/typography.js";
|
|
6
8
|
import { Typography } from "../Typography/index.js";
|
|
7
9
|
import { useState } from "react";
|
|
8
|
-
import { TextInput, View } from "react-native";
|
|
10
|
+
import { Keyboard, TextInput, View } from "react-native";
|
|
9
11
|
/**
|
|
10
12
|
* **Pill** search bar (rounded-full), 2026 style (merge of Material 3 + iOS 26).
|
|
11
13
|
* Use `editable={false}` + `onPress` for a trigger that navigates to the search screen.
|
|
12
14
|
*/
|
|
13
|
-
function SearchBar({ value, onChangeText, placeholder = "Buscar", onSubmit, onClear, autoFocus, editable = true, onPress, className, testID, }) {
|
|
15
|
+
function SearchBar({ value, onChangeText, placeholder = "Buscar", onSubmit, onClear, autoFocus, editable = true, onPress, className, testID, accessibleSizing = false, accessibilityLabel, clearAccessibilityLabel = "Limpiar", suggestions, }) {
|
|
16
|
+
const theme = useTheme();
|
|
14
17
|
const [focused, setFocused] = useState(false);
|
|
15
18
|
const body = (_jsxs(View, { className: cn("flex-row items-center gap-2 rounded-full px-4", focused ? "bg-bg-card" : "bg-bg-muted", className), style: {
|
|
16
|
-
height: 44,
|
|
19
|
+
...(accessibleSizing ? { minHeight: 48 } : { height: 44 }),
|
|
17
20
|
borderWidth: 1,
|
|
18
21
|
borderColor: focused ? theme.border.focus : "transparent",
|
|
19
|
-
}, children: [_jsx(Icon, { color: focused ? theme.border.focus : theme.icon.tertiary, name: "search", size: 18 }), editable ? (_jsx(TextInput, { autoFocus: autoFocus, className: "flex-1 text-
|
|
22
|
+
}, children: [_jsx(View, { accessibilityElementsHidden: true, importantForAccessibility: "no-hide-descendants", children: _jsx(Icon, { color: focused ? theme.border.focus : theme.icon.tertiary, name: "search", size: 18 }) }), editable ? (_jsx(TextInput, { accessibilityLabel: accessibilityLabel ?? placeholder, autoFocus: autoFocus, className: cn("flex-1 text-text-primary", !accessibleSizing && "text-sm"), onBlur: () => setFocused(false), onChangeText: onChangeText, onFocus: () => setFocused(true), onSubmitEditing: (e) => onSubmit?.(e.nativeEvent.text), placeholder: placeholder, placeholderTextColor: theme.text.tertiary, returnKeyType: "search", selectionColor: theme.primary, style: accessibleSizing
|
|
23
|
+
? {
|
|
24
|
+
...typographyVariants.bodyReadable,
|
|
25
|
+
fontFamily: resolveTextFontFamily("bodyReadable"),
|
|
26
|
+
minHeight: 48,
|
|
27
|
+
paddingVertical: 8,
|
|
28
|
+
}
|
|
29
|
+
: undefined, testID: testID ? `${testID}-input` : undefined, underlineColorAndroid: "transparent", value: value })) : (_jsx(Typography.Text, { className: cn("flex-1 text-text-tertiary", !accessibleSizing && "text-sm"), numberOfLines: accessibleSizing ? undefined : 1, variant: accessibleSizing ? "bodyReadable" : "body", children: value || placeholder })), editable && value.length > 0 ? (_jsx(Pressable, { accessibilityLabel: clearAccessibilityLabel, hitSlop: 8, onPress: () => {
|
|
20
30
|
onChangeText("");
|
|
21
31
|
onClear?.();
|
|
22
|
-
},
|
|
32
|
+
}, style: accessibleSizing
|
|
33
|
+
? {
|
|
34
|
+
minHeight: 48,
|
|
35
|
+
minWidth: 48,
|
|
36
|
+
alignItems: "center",
|
|
37
|
+
justifyContent: "center",
|
|
38
|
+
}
|
|
39
|
+
: undefined, children: _jsx(Icon, { color: theme.icon.tertiary, name: "close-circle", size: 18 }) })) : null] }));
|
|
23
40
|
if (!editable && onPress) {
|
|
24
|
-
return (_jsx(Pressable, { accessibilityLabel: placeholder, accessibilityRole: "search", onPress: onPress, testID: testID, children: body }));
|
|
41
|
+
return (_jsx(Pressable, { accessibilityLabel: accessibilityLabel ?? placeholder, accessibilityRole: "search", onPress: onPress, testID: testID, children: body }));
|
|
25
42
|
}
|
|
26
|
-
return
|
|
43
|
+
return (_jsxs(View, { testID: testID, children: [body, focused && suggestions ? (_jsx(SearchSuggestions, { ...suggestions, onSelect: (suggestion) => {
|
|
44
|
+
suggestions.onSelect(suggestion);
|
|
45
|
+
setFocused(false);
|
|
46
|
+
Keyboard.dismiss();
|
|
47
|
+
} })) : null] }));
|
|
27
48
|
}
|
|
28
49
|
export default SearchBar;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface SearchSuggestion {
|
|
2
|
+
id: string;
|
|
3
|
+
label: string;
|
|
4
|
+
description?: string;
|
|
5
|
+
}
|
|
6
|
+
export interface SearchSuggestionsProps {
|
|
7
|
+
items: readonly SearchSuggestion[];
|
|
8
|
+
onSelect: (suggestion: SearchSuggestion) => void;
|
|
9
|
+
loading?: boolean;
|
|
10
|
+
error?: string;
|
|
11
|
+
onRetry?: () => void;
|
|
12
|
+
emptyLabel?: string;
|
|
13
|
+
}
|
|
14
|
+
export default function SearchSuggestions({ items, onSelect, loading, error, onRetry, emptyLabel, }: SearchSuggestionsProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "nativewind/jsx-runtime";
|
|
2
|
+
import Pressable from "../primitives/Pressable.js";
|
|
3
|
+
import { Typography } from "../Typography/index.js";
|
|
4
|
+
import { View } from "react-native";
|
|
5
|
+
export default function SearchSuggestions({ items, onSelect, loading, error, onRetry, emptyLabel = "Sin sugerencias", }) {
|
|
6
|
+
return (_jsx(View, { className: "gap-1 border-b border-border-light py-2", children: loading ? (_jsx(Typography.Text, { accessibilityLiveRegion: "polite", children: "Buscando sugerencias\u2026" })) : error ? (_jsxs(_Fragment, { children: [_jsx(Typography.Text, { accessibilityLiveRegion: "polite", className: "text-danger", children: error }), onRetry ? (_jsx(Pressable, { onPress: onRetry, style: { minHeight: 48, justifyContent: "center" }, children: _jsx(Typography.Text, { className: "text-text-accent", children: "Reintentar sugerencias" }) })) : null] })) : !items.length ? (_jsx(Typography.Text, { accessibilityLiveRegion: "polite", className: "text-text-secondary", children: emptyLabel })) : (items.map((item) => (_jsxs(Pressable, { accessibilityLabel: item.description ? `${item.label}. ${item.description}` : item.label, className: "px-3 py-2", onPress: () => onSelect(item), style: { minHeight: 48, justifyContent: "center" }, children: [_jsx(Typography.Text, { variant: "bodyReadable", children: item.label }), item.description ? (_jsx(Typography.Text, { className: "text-text-secondary", variant: "bodyLarge", children: item.description })) : null] }, item.id)))) }));
|
|
7
|
+
}
|
|
@@ -20,9 +20,11 @@ export interface SegmentedControlProps<T extends string> {
|
|
|
20
20
|
* - `"left"` — icon inline left of the label (compact, single-line).
|
|
21
21
|
*/
|
|
22
22
|
iconLayout?: "top" | "left";
|
|
23
|
+
/** Increase each option's target to at least 48 points. */
|
|
24
|
+
accessibleSizing?: boolean;
|
|
23
25
|
className?: string;
|
|
24
26
|
testID?: string;
|
|
25
27
|
}
|
|
26
|
-
declare function SegmentedControl<T extends string>({ options, value, onChange, iconLayout, className, testID, }: SegmentedControlProps<T>): import("react").JSX.Element;
|
|
28
|
+
declare function SegmentedControl<T extends string>({ options, value, onChange, iconLayout, accessibleSizing, className, testID, }: SegmentedControlProps<T>): import("react").JSX.Element;
|
|
27
29
|
export default SegmentedControl;
|
|
28
30
|
export { SegmentedControl };
|
|
@@ -4,7 +4,7 @@ import { useTheme } from "../theme/index.js";
|
|
|
4
4
|
import { cn } from "../theme/tw.js";
|
|
5
5
|
import { Typography } from "../Typography/index.js";
|
|
6
6
|
import { TouchableOpacity, View } from "react-native";
|
|
7
|
-
function SegmentedControl({ options, value, onChange, iconLayout = "top", className, testID, }) {
|
|
7
|
+
function SegmentedControl({ options, value, onChange, iconLayout = "top", accessibleSizing = false, className, testID, }) {
|
|
8
8
|
const theme = useTheme();
|
|
9
9
|
const hasIcons = options.some((o) => o.icon || o.customIcon);
|
|
10
10
|
return (_jsx(View, { accessibilityRole: "tablist", className: cn("flex-row bg-bg-muted rounded-lg p-1 gap-1", className), testID: testID, children: options.map((option) => {
|
|
@@ -14,6 +14,7 @@ function SegmentedControl({ options, value, onChange, iconLayout = "top", classN
|
|
|
14
14
|
const inline = hasIcons && iconLayout === "left";
|
|
15
15
|
return (_jsxs(TouchableOpacity, { accessibilityLabel: option.label, accessibilityRole: "tab", accessibilityState: { selected }, activeOpacity: 0.7, onPress: () => onChange(option.value), style: {
|
|
16
16
|
flex: 1,
|
|
17
|
+
minHeight: accessibleSizing ? 48 : undefined,
|
|
17
18
|
flexDirection: inline ? "row" : "column",
|
|
18
19
|
alignItems: "center",
|
|
19
20
|
justifyContent: "center",
|
|
@@ -6,19 +6,23 @@ import Menu from "./Navigation.Menu.js";
|
|
|
6
6
|
import { MenuSection } from "./Navigation.MenuSection.js";
|
|
7
7
|
import RowItem from "./Navigation.RowItem.js";
|
|
8
8
|
import SearchBar from "./Navigation.SearchBar.js";
|
|
9
|
+
import SearchSuggestions from "./Navigation.SearchSuggestions.js";
|
|
9
10
|
import SegmentedControl from "./Navigation.SegmentedControl.js";
|
|
10
11
|
import Steps from "./Navigation.Steps.js";
|
|
11
12
|
import TabIcon from "./Navigation.TabIcon.js";
|
|
12
13
|
export type { AppBarBackground } from "./Navigation.AppBar.js";
|
|
13
14
|
export type { MenuSectionProps } from "./Navigation.MenuSection.js";
|
|
15
|
+
export type { SearchBarProps } from "./Navigation.SearchBar.js";
|
|
16
|
+
export type { SearchSuggestion, SearchSuggestionsProps, } from "./Navigation.SearchSuggestions.js";
|
|
14
17
|
export declare const Navigation: {
|
|
15
|
-
AppBar: (({ title, subtitle, onBack, leading, actions, subheader, variant, tone, accentBar, backVariant, border, safeArea, topSpacing, background, bottomDivider, className, testID, }: import("./Navigation.AppBar.js").AppBarProps) => import("react").JSX.Element) & {
|
|
16
|
-
Action: ({ icon, label, onPress, badge, accessibilityLabel, tone, onDark, bare, testID, }: import("./Navigation.AppBar.js").AppBarActionProps) => import("react").JSX.Element;
|
|
18
|
+
AppBar: (({ title, subtitle, onBack, leading, actions, subheader, variant, tone, accentBar, backVariant, border, safeArea, accessibleSizing, topSpacing, background, bottomDivider, className, testID, }: import("./Navigation.AppBar.js").AppBarProps) => import("react").JSX.Element) & {
|
|
19
|
+
Action: ({ icon, label, onPress, badge, accessibilityLabel, tone, onDark, bare, accessibleSizing, testID, }: import("./Navigation.AppBar.js").AppBarActionProps) => import("react").JSX.Element;
|
|
17
20
|
};
|
|
18
21
|
BottomNav: typeof BottomNav;
|
|
19
22
|
CollapsingHeader: typeof CollapsingHeader;
|
|
20
23
|
FloatingBar: typeof FloatingBar;
|
|
21
24
|
SearchBar: typeof SearchBar;
|
|
25
|
+
SearchSuggestions: typeof SearchSuggestions;
|
|
22
26
|
Header: ({ title, logo, logoSource, backButton, handleBackButton, className, }: import("./Navigation.Header.js").HeaderProps) => import("react").JSX.Element;
|
|
23
27
|
HeaderToolbar: typeof HeaderToolbar;
|
|
24
28
|
TabItem: import("react").FC<import("./Navigation.TabItem.js").TabIconProps>;
|
package/dist/Navigation/index.js
CHANGED
|
@@ -8,6 +8,7 @@ import Menu from "./Navigation.Menu.js";
|
|
|
8
8
|
import { MenuSection } from "./Navigation.MenuSection.js";
|
|
9
9
|
import RowItem from "./Navigation.RowItem.js";
|
|
10
10
|
import SearchBar from "./Navigation.SearchBar.js";
|
|
11
|
+
import SearchSuggestions from "./Navigation.SearchSuggestions.js";
|
|
11
12
|
import SegmentedControl from "./Navigation.SegmentedControl.js";
|
|
12
13
|
import Steps from "./Navigation.Steps.js";
|
|
13
14
|
import TabIcon from "./Navigation.TabIcon.js";
|
|
@@ -19,6 +20,7 @@ export const Navigation = {
|
|
|
19
20
|
CollapsingHeader,
|
|
20
21
|
FloatingBar,
|
|
21
22
|
SearchBar,
|
|
23
|
+
SearchSuggestions,
|
|
22
24
|
Header,
|
|
23
25
|
HeaderToolbar,
|
|
24
26
|
TabItem,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx } from "nativewind/jsx-runtime";
|
|
2
2
|
import { AppText } from "./Typography.Text.js";
|
|
3
3
|
const Heading = ({ variant = "h1", ...props }) => {
|
|
4
|
-
return _jsx(AppText, { variant: variant, ...props });
|
|
4
|
+
return _jsx(AppText, { accessibilityRole: "header", variant: variant, ...props });
|
|
5
5
|
};
|
|
6
6
|
export default Heading;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { typographyVariants } from "../theme/typography.js";
|
|
2
|
+
import { type TextInputProps } from "react-native";
|
|
3
|
+
export type SelectableTextProps = Pick<TextInputProps, "accessibilityLabel" | "testID" | "style" | "allowFontScaling" | "onSelectionChange"> & {
|
|
4
|
+
value: string;
|
|
5
|
+
variant?: keyof typeof typographyVariants;
|
|
6
|
+
semibold?: boolean;
|
|
7
|
+
className?: string;
|
|
8
|
+
};
|
|
9
|
+
declare function SelectableText({ value, variant, semibold, className, style, ...props }: SelectableTextProps): import("react").JSX.Element;
|
|
10
|
+
export default SelectableText;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { jsx as _jsx } from "nativewind/jsx-runtime";
|
|
2
|
+
import { cn } from "../theme/tw.js";
|
|
3
|
+
import { resolveTextFontFamily, typographyVariants, } from "../theme/typography.js";
|
|
4
|
+
import { TextInput } from "react-native";
|
|
5
|
+
function SelectableText({ value, variant = "body", semibold = false, className, style, ...props }) {
|
|
6
|
+
return (_jsx(TextInput, { ...props, className: cn("text-text-primary", className), editable: false, multiline: true, readOnly: true, scrollEnabled: false, showSoftInputOnFocus: false, style: [
|
|
7
|
+
typographyVariants[variant],
|
|
8
|
+
{
|
|
9
|
+
fontFamily: resolveTextFontFamily(variant, false, semibold),
|
|
10
|
+
padding: 0,
|
|
11
|
+
textAlignVertical: "top",
|
|
12
|
+
},
|
|
13
|
+
style,
|
|
14
|
+
], underlineColorAndroid: "transparent", value: value }));
|
|
15
|
+
}
|
|
16
|
+
export default SelectableText;
|
|
@@ -1,31 +1,15 @@
|
|
|
1
1
|
import { jsx as _jsx } from "nativewind/jsx-runtime";
|
|
2
2
|
import { cn } from "../theme/tw.js";
|
|
3
|
-
import {
|
|
4
|
-
import { Text } from "react-native";
|
|
3
|
+
import { resolveTextFontFamily, Typography, } from "../theme/typography.js";
|
|
4
|
+
import { StyleSheet, Text } from "react-native";
|
|
5
5
|
function AppText({ variant = "body", color, bold = false, italic = false, underline = false, align = "left", transform = "none", semibold = false, style, className, children, ...props }) {
|
|
6
6
|
const baseStyle = Typography.variants[variant];
|
|
7
7
|
const textClassName = cn("text-text-primary", align === "center" && "text-center", align === "right" && "text-right", align === "justify" && "text-justify", transform === "uppercase" && "uppercase", transform === "lowercase" && "lowercase", transform === "capitalize" && "capitalize", underline && "underline", italic && "italic", className);
|
|
8
|
-
// Resolve the family LIVE from the configurable registry by the variant's role, so
|
|
9
|
-
// `configureFonts(...)` (app/Storybook) takes effect. Falls back to the variant's baked
|
|
10
|
-
// family if a role is somehow missing.
|
|
11
|
-
const variantFamily = fontFamilies[variantFontRole[variant]] ?? baseStyle.fontFamily;
|
|
12
|
-
// `bold`/`semibold` map to the IBM Plex Sans weights — but NOT when the active family is a
|
|
13
|
-
// branded face (a configured title face, or IBM Plex Mono): those carry their own weight, so
|
|
14
|
-
// forcing Plex Sans would erase the typeface. Keep the variant's family for those.
|
|
15
|
-
const isBrandedFace = typeof variantFamily === "string" &&
|
|
16
|
-
!variantFamily.startsWith("Inter_") &&
|
|
17
|
-
!variantFamily.startsWith("IBMPlexSans_");
|
|
18
8
|
const textStyle = {
|
|
19
9
|
...baseStyle,
|
|
20
10
|
...(color ? { color } : {}),
|
|
21
|
-
fontFamily:
|
|
22
|
-
|
|
23
|
-
: bold
|
|
24
|
-
? fontFamilies.extraBold
|
|
25
|
-
: semibold
|
|
26
|
-
? fontFamilies.semiBold
|
|
27
|
-
: variantFamily,
|
|
28
|
-
...(Array.isArray(style) ? Object.assign({}, ...style) : style),
|
|
11
|
+
fontFamily: resolveTextFontFamily(variant, bold, semibold),
|
|
12
|
+
...StyleSheet.flatten(style),
|
|
29
13
|
};
|
|
30
14
|
return (_jsx(Text, { className: textClassName, style: textStyle, ...props, children: children }));
|
|
31
15
|
}
|
|
@@ -1,7 +1,10 @@
|
|
|
1
|
+
import SelectableText from "./Typography.SelectableText.js";
|
|
1
2
|
import { AppText } from "./Typography.Text.js";
|
|
2
3
|
export declare const Typography: {
|
|
3
4
|
Text: typeof AppText;
|
|
4
5
|
Heading: import("react").FC<import("./Typography.Heading.js").TypographyProps>;
|
|
6
|
+
SelectableText: typeof SelectableText;
|
|
5
7
|
};
|
|
6
8
|
export { AppText };
|
|
9
|
+
export { SelectableText };
|
|
7
10
|
export default Typography;
|
package/dist/Typography/index.js
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import Heading from "./Typography.Heading.js";
|
|
2
|
+
import SelectableText from "./Typography.SelectableText.js";
|
|
2
3
|
import { AppText } from "./Typography.Text.js";
|
|
3
4
|
export const Typography = {
|
|
4
5
|
Text: AppText,
|
|
5
6
|
Heading,
|
|
7
|
+
SelectableText,
|
|
6
8
|
};
|
|
7
9
|
export { AppText };
|
|
10
|
+
export { SelectableText };
|
|
8
11
|
export default Typography;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type KeyboardFormProps } from "../Form/Form.KeyboardForm.js";
|
|
1
2
|
import type { AppBarBackground } from "../Navigation/Navigation.AppBar.js";
|
|
2
3
|
import { ReactNode } from "react";
|
|
3
4
|
interface AuthContainerProps {
|
|
@@ -5,11 +6,13 @@ interface AuthContainerProps {
|
|
|
5
6
|
children: ReactNode;
|
|
6
7
|
onBackPress?: () => void;
|
|
7
8
|
className?: string;
|
|
9
|
+
keyboardToolbar?: boolean;
|
|
10
|
+
keyboardFormProps?: Omit<KeyboardFormProps, "children" | "toolbar">;
|
|
8
11
|
/** Gradient + optional texture surface for the header area. Defaults to the `warm`
|
|
9
12
|
* preset. Set `background.pattern` to opt-in a texture (`dots` / `grid` /
|
|
10
13
|
* `diagonals`); compose `<Display.Pattern kind="mesh" />` outside if you want the
|
|
11
14
|
* brand symbol. */
|
|
12
15
|
background?: AppBarBackground;
|
|
13
16
|
}
|
|
14
|
-
declare function AuthContainer({ header, children, onBackPress, background, className, }: AuthContainerProps): import("react").JSX.Element;
|
|
17
|
+
declare function AuthContainer({ header, children, onBackPress, background, className, keyboardToolbar, keyboardFormProps, }: AuthContainerProps): import("react").JSX.Element;
|
|
15
18
|
export default AuthContainer;
|