@castui/cast-ui 4.7.0 → 4.8.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 +6 -0
- package/dist/components/Accordion/Accordion.d.ts +80 -0
- package/dist/components/Accordion/Accordion.js +157 -0
- package/dist/components/Accordion/index.d.ts +1 -0
- package/dist/components/Accordion/index.js +6 -0
- package/dist/components/AppBar/AppBar.d.ts +47 -0
- package/dist/components/AppBar/AppBar.js +47 -0
- package/dist/components/AppBar/index.d.ts +1 -0
- package/dist/components/AppBar/index.js +5 -0
- package/dist/components/Autocomplete/Autocomplete.d.ts +70 -0
- package/dist/components/Autocomplete/Autocomplete.js +249 -0
- package/dist/components/Autocomplete/index.d.ts +1 -0
- package/dist/components/Autocomplete/index.js +5 -0
- package/dist/components/Backdrop/Backdrop.d.ts +32 -0
- package/dist/components/Backdrop/Backdrop.js +74 -0
- package/dist/components/Backdrop/index.d.ts +1 -0
- package/dist/components/Backdrop/index.js +5 -0
- package/dist/components/BottomSheet/BottomSheet.d.ts +50 -0
- package/dist/components/BottomSheet/BottomSheet.js +159 -0
- package/dist/components/BottomSheet/index.d.ts +1 -0
- package/dist/components/BottomSheet/index.js +6 -0
- package/dist/components/Breadcrumbs/Breadcrumbs.d.ts +63 -0
- package/dist/components/Breadcrumbs/Breadcrumbs.js +143 -0
- package/dist/components/Breadcrumbs/index.d.ts +1 -0
- package/dist/components/Breadcrumbs/index.js +6 -0
- package/dist/components/CodeBlock/CodeBlock.d.ts +42 -0
- package/dist/components/CodeBlock/CodeBlock.js +110 -0
- package/dist/components/CodeBlock/index.d.ts +1 -0
- package/dist/components/CodeBlock/index.js +5 -0
- package/dist/components/Drawer/Drawer.d.ts +51 -0
- package/dist/components/Drawer/Drawer.js +168 -0
- package/dist/components/Drawer/index.d.ts +1 -0
- package/dist/components/Drawer/index.js +6 -0
- package/dist/components/Link/Link.d.ts +51 -0
- package/dist/components/Link/Link.js +73 -0
- package/dist/components/Link/index.d.ts +1 -0
- package/dist/components/Link/index.js +5 -0
- package/dist/components/Menu/Menu.d.ts +91 -0
- package/dist/components/Menu/Menu.js +211 -0
- package/dist/components/Menu/index.d.ts +1 -0
- package/dist/components/Menu/index.js +9 -0
- package/dist/components/Slider/Slider.d.ts +47 -0
- package/dist/components/Slider/Slider.js +132 -0
- package/dist/components/Slider/index.d.ts +1 -0
- package/dist/components/Slider/index.js +5 -0
- package/dist/components/SpeedDial/SpeedDial.d.ts +72 -0
- package/dist/components/SpeedDial/SpeedDial.js +189 -0
- package/dist/components/SpeedDial/index.d.ts +1 -0
- package/dist/components/SpeedDial/index.js +6 -0
- package/dist/components/Table/Table.d.ts +74 -0
- package/dist/components/Table/Table.js +176 -0
- package/dist/components/Table/index.d.ts +1 -0
- package/dist/components/Table/index.js +9 -0
- package/dist/components/ToggleButtonGroup/ToggleButtonGroup.d.ts +69 -0
- package/dist/components/ToggleButtonGroup/ToggleButtonGroup.js +158 -0
- package/dist/components/ToggleButtonGroup/index.d.ts +1 -0
- package/dist/components/ToggleButtonGroup/index.js +6 -0
- package/dist/index.d.ts +16 -2
- package/dist/index.js +49 -2
- package/dist/theme/ThemeContext.d.ts +8 -1
- package/dist/theme/ThemeContext.js +7 -4
- package/dist/theme/applyCastTheme.d.ts +75 -0
- package/dist/theme/applyCastTheme.js +95 -0
- package/dist/theme/index.d.ts +2 -1
- package/dist/theme/index.js +3 -1
- package/dist/theme/themes.js +177 -0
- package/dist/theme/types.d.ts +177 -0
- package/dist/tokens/colors.d.ts +44 -0
- package/dist/tokens/colors.js +47 -1
- package/dist/tokens/index.d.ts +1 -1
- package/dist/tokens/index.js +4 -1
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
<img src="https://raw.githubusercontent.com/Connagh/cast-ui/main/logo.png" alt="Cast UI" width="300" />
|
|
3
3
|
</p>
|
|
4
4
|
|
|
5
|
+
<p align="center">
|
|
6
|
+
<a href="https://www.npmjs.com/package/@castui/cast-ui"><img src="https://img.shields.io/npm/v/@castui/cast-ui.svg" alt="npm version" /></a>
|
|
7
|
+
<a href="https://www.npmjs.com/package/@castui/cast-ui"><img src="https://img.shields.io/npm/dm/@castui/cast-ui.svg" alt="npm downloads" /></a>
|
|
8
|
+
<a href="https://github.com/Connagh/cast-ui/blob/main/LICENSE"><img src="https://img.shields.io/npm/l/@castui/cast-ui.svg" alt="license" /></a>
|
|
9
|
+
</p>
|
|
10
|
+
|
|
5
11
|
A cross-platform component library for React Native. One set of components
|
|
6
12
|
that works on iOS, Android, and the web.
|
|
7
13
|
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Accordion — a stack of expandable sections, flush/divided style.
|
|
3
|
+
*
|
|
4
|
+
* Compound component. `<Accordion>` owns which items are open and how they
|
|
5
|
+
* coordinate; `<AccordionItem>` is one section with a header and collapsible
|
|
6
|
+
* content. They communicate through context, so a consumer writes:
|
|
7
|
+
*
|
|
8
|
+
* <Accordion type="single" defaultValue="shipping">
|
|
9
|
+
* <AccordionItem value="shipping" title="Shipping">
|
|
10
|
+
* Free delivery on orders over £50.
|
|
11
|
+
* </AccordionItem>
|
|
12
|
+
* <AccordionItem value="returns" title="Returns" leadingIcon="undo">
|
|
13
|
+
* Return any item within 30 days.
|
|
14
|
+
* </AccordionItem>
|
|
15
|
+
* <AccordionItem value="legacy" title="Archived" disabled>
|
|
16
|
+
* Hidden content.
|
|
17
|
+
* </AccordionItem>
|
|
18
|
+
* </Accordion>
|
|
19
|
+
*
|
|
20
|
+
* Maps 1:1 to the Figma <Accordion> component:
|
|
21
|
+
* type → single | multiple (single opens one section at a time)
|
|
22
|
+
* size → small | default | large (header padding, gap, typography)
|
|
23
|
+
* AccordionItem state=open → expanded; state=disabled → disabled;
|
|
24
|
+
* state=hover → runtime onHoverIn (not a prop)
|
|
25
|
+
*
|
|
26
|
+
* Accordion is neutral only. The header label uses scheme.text.primary (disabled
|
|
27
|
+
* uses scheme.disabled.fg). The chevron (chevron_right, rotated 90deg when open)
|
|
28
|
+
* and the optional leadingIcon render through <Icon> at the named size keyed by
|
|
29
|
+
* the `size` prop and take the same colour as the label. The header hover and
|
|
30
|
+
* press backgrounds reuse the neutral subtle intent. The divider between items is
|
|
31
|
+
* the overlay border colour (like <Divider>) at the control border width.
|
|
32
|
+
*
|
|
33
|
+
* Tokens: `gap` / `paddingX` / `paddingY` are density spacing from
|
|
34
|
+
* `components.accordion[size]`. No new colour tokens.
|
|
35
|
+
*/
|
|
36
|
+
import React from 'react';
|
|
37
|
+
import { type StyleProp, type ViewStyle } from 'react-native';
|
|
38
|
+
export type AccordionSize = 'small' | 'default' | 'large';
|
|
39
|
+
export type AccordionType = 'single' | 'multiple';
|
|
40
|
+
export type AccordionProps = {
|
|
41
|
+
/** 'single' opens one section at a time; 'multiple' opens any number. */
|
|
42
|
+
type?: AccordionType;
|
|
43
|
+
/**
|
|
44
|
+
* Controlled open value(s). A string for `type="single"`, a string array for
|
|
45
|
+
* `type="multiple"`. Provide with `onValueChange` for a controlled accordion.
|
|
46
|
+
*/
|
|
47
|
+
value?: string | string[];
|
|
48
|
+
/** Uncontrolled initial open value(s). Same shape rules as `value`. */
|
|
49
|
+
defaultValue?: string | string[];
|
|
50
|
+
/** Called with the next open value(s) when a section toggles. */
|
|
51
|
+
onValueChange?: (value: string | string[]) => void;
|
|
52
|
+
/** Size variant — header padding, gap, and typography. */
|
|
53
|
+
size?: AccordionSize;
|
|
54
|
+
/** For `type="single"`, allow closing the open section. Defaults to true. */
|
|
55
|
+
collapsible?: boolean;
|
|
56
|
+
/** `<AccordionItem>` children. */
|
|
57
|
+
children: React.ReactNode;
|
|
58
|
+
/** Outer style — use for positioning (margin, width, alignSelf). */
|
|
59
|
+
style?: StyleProp<ViewStyle>;
|
|
60
|
+
/** Accessibility label for the group. */
|
|
61
|
+
accessibilityLabel?: string;
|
|
62
|
+
};
|
|
63
|
+
export type AccordionItemProps = {
|
|
64
|
+
/** Unique value identifying this section. */
|
|
65
|
+
value: string;
|
|
66
|
+
/** The header label text. */
|
|
67
|
+
title: string;
|
|
68
|
+
/** Icon before the title — Material Symbols name string or a ReactNode. */
|
|
69
|
+
leadingIcon?: string | React.ReactNode;
|
|
70
|
+
/** Disables interaction and applies muted styling. */
|
|
71
|
+
disabled?: boolean;
|
|
72
|
+
/** The collapsible content. A string is wrapped in <Text> automatically. */
|
|
73
|
+
children: React.ReactNode;
|
|
74
|
+
/** Outer style — applied to the item container. */
|
|
75
|
+
style?: StyleProp<ViewStyle>;
|
|
76
|
+
/** Accessibility label — falls back to the title text. */
|
|
77
|
+
accessibilityLabel?: string;
|
|
78
|
+
};
|
|
79
|
+
export declare function AccordionItem({ value, title, leadingIcon, disabled, children, style, accessibilityLabel, }: AccordionItemProps): import("react/jsx-runtime").JSX.Element;
|
|
80
|
+
export declare function Accordion({ type, value, defaultValue, onValueChange, size, collapsible, children, style, accessibilityLabel, }: AccordionProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AccordionItem = AccordionItem;
|
|
4
|
+
exports.Accordion = Accordion;
|
|
5
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
6
|
+
/**
|
|
7
|
+
* Accordion — a stack of expandable sections, flush/divided style.
|
|
8
|
+
*
|
|
9
|
+
* Compound component. `<Accordion>` owns which items are open and how they
|
|
10
|
+
* coordinate; `<AccordionItem>` is one section with a header and collapsible
|
|
11
|
+
* content. They communicate through context, so a consumer writes:
|
|
12
|
+
*
|
|
13
|
+
* <Accordion type="single" defaultValue="shipping">
|
|
14
|
+
* <AccordionItem value="shipping" title="Shipping">
|
|
15
|
+
* Free delivery on orders over £50.
|
|
16
|
+
* </AccordionItem>
|
|
17
|
+
* <AccordionItem value="returns" title="Returns" leadingIcon="undo">
|
|
18
|
+
* Return any item within 30 days.
|
|
19
|
+
* </AccordionItem>
|
|
20
|
+
* <AccordionItem value="legacy" title="Archived" disabled>
|
|
21
|
+
* Hidden content.
|
|
22
|
+
* </AccordionItem>
|
|
23
|
+
* </Accordion>
|
|
24
|
+
*
|
|
25
|
+
* Maps 1:1 to the Figma <Accordion> component:
|
|
26
|
+
* type → single | multiple (single opens one section at a time)
|
|
27
|
+
* size → small | default | large (header padding, gap, typography)
|
|
28
|
+
* AccordionItem state=open → expanded; state=disabled → disabled;
|
|
29
|
+
* state=hover → runtime onHoverIn (not a prop)
|
|
30
|
+
*
|
|
31
|
+
* Accordion is neutral only. The header label uses scheme.text.primary (disabled
|
|
32
|
+
* uses scheme.disabled.fg). The chevron (chevron_right, rotated 90deg when open)
|
|
33
|
+
* and the optional leadingIcon render through <Icon> at the named size keyed by
|
|
34
|
+
* the `size` prop and take the same colour as the label. The header hover and
|
|
35
|
+
* press backgrounds reuse the neutral subtle intent. The divider between items is
|
|
36
|
+
* the overlay border colour (like <Divider>) at the control border width.
|
|
37
|
+
*
|
|
38
|
+
* Tokens: `gap` / `paddingX` / `paddingY` are density spacing from
|
|
39
|
+
* `components.accordion[size]`. No new colour tokens.
|
|
40
|
+
*/
|
|
41
|
+
const react_1 = require("react");
|
|
42
|
+
const react_native_1 = require("react-native");
|
|
43
|
+
const theme_1 = require("../../theme");
|
|
44
|
+
const tokens_1 = require("../../tokens");
|
|
45
|
+
const Text_1 = require("../Text");
|
|
46
|
+
const Icon_1 = require("../Icon");
|
|
47
|
+
const AccordionCtx = (0, react_1.createContext)(null);
|
|
48
|
+
function useAccordionContext(component) {
|
|
49
|
+
const ctx = (0, react_1.useContext)(AccordionCtx);
|
|
50
|
+
if (!ctx) {
|
|
51
|
+
throw new Error(`<${component}> must be used within <Accordion>`);
|
|
52
|
+
}
|
|
53
|
+
return ctx;
|
|
54
|
+
}
|
|
55
|
+
// ---------------------------------------------------------------------------
|
|
56
|
+
// Constants
|
|
57
|
+
// ---------------------------------------------------------------------------
|
|
58
|
+
/** Header label typography scale (medium weight title). */
|
|
59
|
+
const HEADER_TYPE = {
|
|
60
|
+
small: 'title-sm',
|
|
61
|
+
default: 'title-md',
|
|
62
|
+
large: 'title-lg',
|
|
63
|
+
};
|
|
64
|
+
/** Content body typography scale. */
|
|
65
|
+
const CONTENT_TYPE = {
|
|
66
|
+
small: 'body-sm',
|
|
67
|
+
default: 'body-md',
|
|
68
|
+
large: 'body-lg',
|
|
69
|
+
};
|
|
70
|
+
/** Normalise a value/defaultValue prop into an array of open values. */
|
|
71
|
+
function toOpenArray(v, type) {
|
|
72
|
+
if (v === undefined || v === null)
|
|
73
|
+
return [];
|
|
74
|
+
const arr = Array.isArray(v) ? v : [v];
|
|
75
|
+
const cleaned = arr.filter((x) => x !== '');
|
|
76
|
+
return type === 'single' ? cleaned.slice(0, 1) : cleaned;
|
|
77
|
+
}
|
|
78
|
+
// ---------------------------------------------------------------------------
|
|
79
|
+
// AccordionItem
|
|
80
|
+
// ---------------------------------------------------------------------------
|
|
81
|
+
function AccordionItem({ value, title, leadingIcon, disabled = false, children, style, accessibilityLabel, }) {
|
|
82
|
+
const { openValues, toggle, size } = useAccordionContext('AccordionItem');
|
|
83
|
+
const { components, colors, scheme } = (0, theme_1.useTheme)();
|
|
84
|
+
const [isHovered, setIsHovered] = (0, react_1.useState)(false);
|
|
85
|
+
const sizeTokens = components.accordion[size];
|
|
86
|
+
const isOpen = openValues.includes(value);
|
|
87
|
+
// Chevron rotation: chevron_right (0deg) rotates to point down (90deg) when open.
|
|
88
|
+
const spin = (0, react_1.useRef)(new react_native_1.Animated.Value(isOpen ? 1 : 0)).current;
|
|
89
|
+
(0, react_1.useEffect)(() => {
|
|
90
|
+
react_native_1.Animated.timing(spin, {
|
|
91
|
+
toValue: isOpen ? 1 : 0,
|
|
92
|
+
duration: 160,
|
|
93
|
+
easing: react_native_1.Easing.inOut(react_native_1.Easing.ease),
|
|
94
|
+
useNativeDriver: true,
|
|
95
|
+
}).start();
|
|
96
|
+
}, [isOpen, spin]);
|
|
97
|
+
const rotate = spin.interpolate({
|
|
98
|
+
inputRange: [0, 1],
|
|
99
|
+
outputRange: ['0deg', '90deg'],
|
|
100
|
+
});
|
|
101
|
+
const labelFg = disabled ? scheme.disabled.fg : scheme.text.primary;
|
|
102
|
+
const resolvedLeading = typeof leadingIcon === 'string' ? ((0, jsx_runtime_1.jsx)(Icon_1.Icon, { name: leadingIcon, size: size, color: labelFg })) : (leadingIcon ?? null);
|
|
103
|
+
const content = typeof children === 'string' ? ((0, jsx_runtime_1.jsx)(Text_1.Text, { type: CONTENT_TYPE[size], color: scheme.text.description, children: children })) : (children);
|
|
104
|
+
return ((0, jsx_runtime_1.jsxs)(react_native_1.View, { style: [
|
|
105
|
+
{
|
|
106
|
+
borderBottomWidth: tokens_1.controlTokens.borderWidth,
|
|
107
|
+
borderBottomColor: scheme.surface.overlay.border,
|
|
108
|
+
},
|
|
109
|
+
style,
|
|
110
|
+
], children: [(0, jsx_runtime_1.jsx)(react_native_1.Pressable, { onPress: () => {
|
|
111
|
+
if (!disabled)
|
|
112
|
+
toggle(value);
|
|
113
|
+
}, disabled: disabled, onHoverIn: () => setIsHovered(true), onHoverOut: () => setIsHovered(false), accessibilityRole: "button", accessibilityLabel: accessibilityLabel || title, accessibilityState: { expanded: isOpen, disabled }, children: ({ pressed }) => {
|
|
114
|
+
const headerBg = disabled
|
|
115
|
+
? 'transparent'
|
|
116
|
+
: pressed
|
|
117
|
+
? colors.neutral.subtle.active.bg
|
|
118
|
+
: isHovered
|
|
119
|
+
? colors.neutral.subtle.hover.bg
|
|
120
|
+
: 'transparent';
|
|
121
|
+
return ((0, jsx_runtime_1.jsxs)(react_native_1.View, { style: {
|
|
122
|
+
flexDirection: 'row',
|
|
123
|
+
alignItems: 'center',
|
|
124
|
+
gap: sizeTokens.gap,
|
|
125
|
+
paddingHorizontal: sizeTokens.paddingX,
|
|
126
|
+
paddingVertical: sizeTokens.paddingY,
|
|
127
|
+
backgroundColor: headerBg,
|
|
128
|
+
}, children: [resolvedLeading, (0, jsx_runtime_1.jsx)(Text_1.Text, { type: HEADER_TYPE[size], color: labelFg, selectable: false, style: { flex: 1 }, children: title }), (0, jsx_runtime_1.jsx)(react_native_1.Animated.View, { pointerEvents: "none", style: { transform: [{ rotate }] }, children: (0, jsx_runtime_1.jsx)(Icon_1.Icon, { name: "chevron_right", size: size, color: labelFg }) })] }));
|
|
129
|
+
} }), isOpen ? ((0, jsx_runtime_1.jsx)(react_native_1.View, { style: {
|
|
130
|
+
paddingHorizontal: sizeTokens.paddingX,
|
|
131
|
+
paddingBottom: sizeTokens.paddingY,
|
|
132
|
+
}, children: content })) : null] }));
|
|
133
|
+
}
|
|
134
|
+
// ---------------------------------------------------------------------------
|
|
135
|
+
// Accordion
|
|
136
|
+
// ---------------------------------------------------------------------------
|
|
137
|
+
function Accordion({ type = 'single', value, defaultValue, onValueChange, size = 'default', collapsible = true, children, style, accessibilityLabel, }) {
|
|
138
|
+
const isControlled = value !== undefined;
|
|
139
|
+
const [internal, setInternal] = (0, react_1.useState)(() => toOpenArray(defaultValue, type));
|
|
140
|
+
const openValues = toOpenArray(isControlled ? value : internal, type);
|
|
141
|
+
const toggle = (item) => {
|
|
142
|
+
let next;
|
|
143
|
+
if (type === 'multiple') {
|
|
144
|
+
next = openValues.includes(item)
|
|
145
|
+
? openValues.filter((x) => x !== item)
|
|
146
|
+
: [...openValues, item];
|
|
147
|
+
}
|
|
148
|
+
else {
|
|
149
|
+
const isOpen = openValues.includes(item);
|
|
150
|
+
next = isOpen ? (collapsible ? [] : openValues) : [item];
|
|
151
|
+
}
|
|
152
|
+
if (!isControlled)
|
|
153
|
+
setInternal(next);
|
|
154
|
+
onValueChange?.(type === 'multiple' ? next : (next[0] ?? ''));
|
|
155
|
+
};
|
|
156
|
+
return ((0, jsx_runtime_1.jsx)(AccordionCtx.Provider, { value: { openValues, toggle, size }, children: (0, jsx_runtime_1.jsx)(react_native_1.View, { accessibilityRole: "none", accessibilityLabel: accessibilityLabel, style: [{ alignSelf: 'stretch' }, style], children: children }) }));
|
|
157
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { Accordion, AccordionItem, type AccordionProps, type AccordionItemProps, type AccordionSize, type AccordionType, } from './Accordion';
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AccordionItem = exports.Accordion = void 0;
|
|
4
|
+
var Accordion_1 = require("./Accordion");
|
|
5
|
+
Object.defineProperty(exports, "Accordion", { enumerable: true, get: function () { return Accordion_1.Accordion; } });
|
|
6
|
+
Object.defineProperty(exports, "AccordionItem", { enumerable: true, get: function () { return Accordion_1.AccordionItem; } });
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AppBar — a top bar with a leading control, a title, and trailing actions.
|
|
3
|
+
*
|
|
4
|
+
* Maps 1:1 to the Figma <App Bar> component:
|
|
5
|
+
* intent → neutral | brand | danger
|
|
6
|
+
* prominence → default | bold | subtle
|
|
7
|
+
* size → small | default | large (padding, gap, title scale)
|
|
8
|
+
* align → start | center (title alignment)
|
|
9
|
+
*
|
|
10
|
+
* Colour comes from the intent system, like Button. prominence picks the
|
|
11
|
+
* surface: bold is a filled bar (intent bg, white text), default is a plain bar
|
|
12
|
+
* with a bottom divider, subtle is transparent. The title and the leadingIcon
|
|
13
|
+
* inherit the bar foreground; trailing actions are a free slot, so colour them
|
|
14
|
+
* to match on a bold bar. The bar hugs its content height from the padding, so
|
|
15
|
+
* there is no fixed height token. Spacing varies by density; the title scale by
|
|
16
|
+
* size. Fonts are consumer-loaded.
|
|
17
|
+
*/
|
|
18
|
+
import React from 'react';
|
|
19
|
+
import { type StyleProp, type ViewStyle, type GestureResponderEvent } from 'react-native';
|
|
20
|
+
import type { IntentName, ProminenceName } from '../../tokens';
|
|
21
|
+
export type AppBarSize = 'small' | 'default' | 'large';
|
|
22
|
+
export type AppBarAlign = 'start' | 'center';
|
|
23
|
+
export type AppBarProps = {
|
|
24
|
+
/** The bar title. */
|
|
25
|
+
title: string;
|
|
26
|
+
/** Standard leading control icon (menu / back). Auto-coloured + pressable. */
|
|
27
|
+
leadingIcon?: string;
|
|
28
|
+
/** Press handler for the leading icon. */
|
|
29
|
+
onLeadingPress?: (e: GestureResponderEvent) => void;
|
|
30
|
+
/** Custom leading slot. Wins over leadingIcon. */
|
|
31
|
+
leading?: React.ReactNode;
|
|
32
|
+
/** Trailing actions slot. */
|
|
33
|
+
trailing?: React.ReactNode;
|
|
34
|
+
/** Semantic intent. */
|
|
35
|
+
intent?: IntentName;
|
|
36
|
+
/** Visual weight — bold (filled), default (divider), subtle (transparent). */
|
|
37
|
+
prominence?: ProminenceName;
|
|
38
|
+
/** Size variant — padding, gap, and title scale. */
|
|
39
|
+
size?: AppBarSize;
|
|
40
|
+
/** Title alignment. Defaults to start. */
|
|
41
|
+
align?: AppBarAlign;
|
|
42
|
+
/** Outer style. */
|
|
43
|
+
style?: StyleProp<ViewStyle>;
|
|
44
|
+
/** Accessibility label — falls back to the title. */
|
|
45
|
+
accessibilityLabel?: string;
|
|
46
|
+
};
|
|
47
|
+
export declare function AppBar({ title, leadingIcon, onLeadingPress, leading, trailing, intent, prominence, size, align, style, accessibilityLabel, }: AppBarProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AppBar = AppBar;
|
|
4
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
5
|
+
const react_native_1 = require("react-native");
|
|
6
|
+
const theme_1 = require("../../theme");
|
|
7
|
+
const tokens_1 = require("../../tokens");
|
|
8
|
+
const Text_1 = require("../Text");
|
|
9
|
+
const Icon_1 = require("../Icon");
|
|
10
|
+
// ---------------------------------------------------------------------------
|
|
11
|
+
// Constants
|
|
12
|
+
// ---------------------------------------------------------------------------
|
|
13
|
+
/** Maps size → title typography scale (Text component `type`). */
|
|
14
|
+
const TITLE_TYPE = {
|
|
15
|
+
small: 'title-sm',
|
|
16
|
+
default: 'title-md',
|
|
17
|
+
large: 'title-lg',
|
|
18
|
+
};
|
|
19
|
+
/** Maps size → named Icon scale for the leading control. */
|
|
20
|
+
const ICON_SIZE = {
|
|
21
|
+
small: 'default',
|
|
22
|
+
default: 'large',
|
|
23
|
+
large: 'large',
|
|
24
|
+
};
|
|
25
|
+
// ---------------------------------------------------------------------------
|
|
26
|
+
// Component
|
|
27
|
+
// ---------------------------------------------------------------------------
|
|
28
|
+
function AppBar({ title, leadingIcon, onLeadingPress, leading, trailing, intent = 'neutral', prominence = 'default', size = 'default', align = 'start', style, accessibilityLabel, }) {
|
|
29
|
+
const { components, colors } = (0, theme_1.useTheme)();
|
|
30
|
+
const tokens = components.appBar[size];
|
|
31
|
+
const barColors = colors[intent][prominence].default;
|
|
32
|
+
const resolvedLeading = leading ??
|
|
33
|
+
(leadingIcon ? ((0, jsx_runtime_1.jsx)(react_native_1.Pressable, { onPress: onLeadingPress, accessibilityRole: "button", accessibilityLabel: "Navigation", hitSlop: 8, children: (0, jsx_runtime_1.jsx)(Icon_1.Icon, { name: leadingIcon, size: ICON_SIZE[size], color: barColors.fg }) })) : null);
|
|
34
|
+
return ((0, jsx_runtime_1.jsxs)(react_native_1.View, { accessibilityRole: "header", accessibilityLabel: accessibilityLabel || title, style: [
|
|
35
|
+
{
|
|
36
|
+
flexDirection: 'row',
|
|
37
|
+
alignItems: 'center',
|
|
38
|
+
gap: tokens.gap,
|
|
39
|
+
paddingHorizontal: tokens.paddingX,
|
|
40
|
+
paddingVertical: tokens.paddingY,
|
|
41
|
+
backgroundColor: barColors.bg,
|
|
42
|
+
borderBottomWidth: tokens_1.controlTokens.borderWidth,
|
|
43
|
+
borderBottomColor: barColors.border,
|
|
44
|
+
},
|
|
45
|
+
style,
|
|
46
|
+
], children: [resolvedLeading, (0, jsx_runtime_1.jsx)(Text_1.Text, { type: TITLE_TYPE[size], color: barColors.fg, numberOfLines: 1, selectable: false, style: { flex: 1, textAlign: align === 'center' ? 'center' : 'left' }, children: title }), trailing ? ((0, jsx_runtime_1.jsx)(react_native_1.View, { style: { flexDirection: 'row', alignItems: 'center', gap: tokens.gap }, children: trailing })) : null] }));
|
|
47
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { AppBar, type AppBarProps, type AppBarSize, type AppBarAlign } from './AppBar';
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Autocomplete — a text field that filters a list of options as you type.
|
|
3
|
+
*
|
|
4
|
+
* Maps 1:1 to the Figma <Autocomplete> component:
|
|
5
|
+
* size → small | default | large
|
|
6
|
+
* state → default | hover | focus | error | disabled
|
|
7
|
+
* option state → default | hover | selected | disabled
|
|
8
|
+
*
|
|
9
|
+
* Autocomplete is the Select combobox specialised for client-side filtering. Its
|
|
10
|
+
* field is an Input, so it reuses the input tokens; its options are
|
|
11
|
+
* value-selection rows, so it reuses the select tokens and the
|
|
12
|
+
* scheme.select.option colours. It introduces no new tokens. Type to filter the
|
|
13
|
+
* options by label, press one to select it, or clear the field.
|
|
14
|
+
*
|
|
15
|
+
* value is controlled with value/onValueChange (null = nothing selected) or
|
|
16
|
+
* uncontrolled with defaultValue. Pass a filterOptions function to change how
|
|
17
|
+
* matching works. Fonts are consumer-loaded.
|
|
18
|
+
*/
|
|
19
|
+
import React from 'react';
|
|
20
|
+
import { type StyleProp, type ViewStyle } from 'react-native';
|
|
21
|
+
export type AutocompleteSize = 'small' | 'default' | 'large';
|
|
22
|
+
export type AutocompleteOption = {
|
|
23
|
+
/** Unique value. */
|
|
24
|
+
value: string;
|
|
25
|
+
/** Display label — also what the filter matches against. */
|
|
26
|
+
label: string;
|
|
27
|
+
/** Supporting text below the label. */
|
|
28
|
+
description?: string;
|
|
29
|
+
/** Leading icon — Material Symbols name or a ReactNode. */
|
|
30
|
+
icon?: string | React.ReactNode;
|
|
31
|
+
/** Disables this option. */
|
|
32
|
+
disabled?: boolean;
|
|
33
|
+
};
|
|
34
|
+
export type AutocompleteProps = {
|
|
35
|
+
/** The options to choose from. */
|
|
36
|
+
options: AutocompleteOption[];
|
|
37
|
+
/** Selected value (controlled). null = nothing selected. */
|
|
38
|
+
value?: string | null;
|
|
39
|
+
/** Initial value (uncontrolled). */
|
|
40
|
+
defaultValue?: string | null;
|
|
41
|
+
/** Selection change handler. */
|
|
42
|
+
onValueChange?: (value: string | null) => void;
|
|
43
|
+
/** Called with the input text as it changes. */
|
|
44
|
+
onInputChange?: (text: string) => void;
|
|
45
|
+
/** Field label above the input. */
|
|
46
|
+
label?: string;
|
|
47
|
+
/** Helper or error text below the input. */
|
|
48
|
+
helperText?: string;
|
|
49
|
+
/** Placeholder when empty. */
|
|
50
|
+
placeholder?: string;
|
|
51
|
+
/** Leading icon in the field. */
|
|
52
|
+
leadingIcon?: string | React.ReactNode;
|
|
53
|
+
/** Size variant. */
|
|
54
|
+
size?: AutocompleteSize;
|
|
55
|
+
/** Disables the field. */
|
|
56
|
+
disabled?: boolean;
|
|
57
|
+
/** Error state — danger border + red helper text. */
|
|
58
|
+
error?: boolean;
|
|
59
|
+
/** Show a clear button when there is input. Defaults to true. */
|
|
60
|
+
clearable?: boolean;
|
|
61
|
+
/** Text shown when no option matches. Defaults to "No options". */
|
|
62
|
+
noOptionsText?: string;
|
|
63
|
+
/** Override the default case-insensitive label filter. */
|
|
64
|
+
filterOptions?: (options: AutocompleteOption[], query: string) => AutocompleteOption[];
|
|
65
|
+
/** Style override for the outer container. */
|
|
66
|
+
style?: StyleProp<ViewStyle>;
|
|
67
|
+
/** Accessibility label — falls back to the label prop. */
|
|
68
|
+
accessibilityLabel?: string;
|
|
69
|
+
};
|
|
70
|
+
export declare function Autocomplete({ options, value: controlledValue, defaultValue, onValueChange, onInputChange, label: fieldLabel, helperText, placeholder, leadingIcon, size, disabled, error, clearable, noOptionsText, filterOptions, style, accessibilityLabel, }: AutocompleteProps): import("react/jsx-runtime").JSX.Element;
|