@castui/cast-ui 4.1.1 → 4.2.1
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 +129 -19
- package/dist/components/Alert/Alert.d.ts +40 -0
- package/dist/components/Alert/Alert.js +71 -0
- package/dist/components/Alert/index.d.ts +1 -0
- package/dist/components/Alert/index.js +5 -0
- package/dist/components/Avatar/Avatar.d.ts +31 -0
- package/dist/components/Avatar/Avatar.js +55 -0
- package/dist/components/Avatar/index.d.ts +1 -0
- package/dist/components/Avatar/index.js +5 -0
- package/dist/components/Badge/Badge.d.ts +41 -0
- package/dist/components/Badge/Badge.js +71 -0
- package/dist/components/Badge/index.d.ts +1 -0
- package/dist/components/Badge/index.js +5 -0
- package/dist/components/Button/Button.d.ts +0 -1
- package/dist/components/Button/Button.js +21 -19
- package/dist/components/Button/index.d.ts +0 -1
- package/dist/components/Button/index.js +5 -2
- package/dist/components/Card/Card.d.ts +41 -0
- package/dist/components/Card/Card.js +91 -0
- package/dist/components/Card/index.d.ts +1 -0
- package/dist/components/Card/index.js +5 -0
- package/dist/components/Checkbox/Checkbox.d.ts +32 -0
- package/dist/components/Checkbox/Checkbox.js +107 -0
- package/dist/components/Checkbox/index.d.ts +1 -0
- package/dist/components/Checkbox/index.js +5 -0
- package/dist/components/Chip/Chip.d.ts +46 -0
- package/dist/components/Chip/Chip.js +82 -0
- package/dist/components/Chip/index.d.ts +1 -0
- package/dist/components/Chip/index.js +5 -0
- package/dist/components/Dialog/Dialog.d.ts +0 -1
- package/dist/components/Dialog/Dialog.js +33 -26
- package/dist/components/Dialog/index.d.ts +0 -1
- package/dist/components/Dialog/index.js +6 -2
- package/dist/components/Divider/Divider.d.ts +22 -0
- package/dist/components/Divider/Divider.js +19 -0
- package/dist/components/Divider/index.d.ts +1 -0
- package/dist/components/Divider/index.js +5 -0
- package/dist/components/Icon/Icon.d.ts +26 -9
- package/dist/components/Icon/Icon.js +16 -6
- package/dist/components/Icon/index.d.ts +0 -1
- package/dist/components/Icon/index.js +5 -2
- package/dist/components/Input/Input.d.ts +62 -0
- package/dist/components/Input/Input.js +141 -0
- package/dist/components/Input/index.d.ts +1 -0
- package/dist/components/Input/index.js +5 -0
- package/dist/components/List/List.d.ts +58 -0
- package/dist/components/List/List.js +116 -0
- package/dist/components/List/index.d.ts +1 -0
- package/dist/components/List/index.js +8 -0
- package/dist/components/Popover/Popover.d.ts +34 -0
- package/dist/components/Popover/Popover.js +62 -0
- package/dist/components/Popover/index.d.ts +1 -0
- package/dist/components/Popover/index.js +5 -0
- package/dist/components/Radio/Radio.d.ts +52 -0
- package/dist/components/Radio/Radio.js +127 -0
- package/dist/components/Radio/index.d.ts +1 -0
- package/dist/components/Radio/index.js +6 -0
- package/dist/components/Select/Select.d.ts +0 -1
- package/dist/components/Select/Select.js +114 -96
- package/dist/components/Select/index.d.ts +0 -1
- package/dist/components/Select/index.js +10 -2
- package/dist/components/Skeleton/Skeleton.d.ts +33 -0
- package/dist/components/Skeleton/Skeleton.js +66 -0
- package/dist/components/Skeleton/index.d.ts +1 -0
- package/dist/components/Skeleton/index.js +5 -0
- package/dist/components/Toast/Toast.d.ts +35 -0
- package/dist/components/Toast/Toast.js +79 -0
- package/dist/components/Toast/index.d.ts +1 -0
- package/dist/components/Toast/index.js +5 -0
- package/dist/components/Toggle/Toggle.d.ts +31 -0
- package/dist/components/Toggle/Toggle.js +91 -0
- package/dist/components/Toggle/index.d.ts +1 -0
- package/dist/components/Toggle/index.js +5 -0
- package/dist/components/Tooltip/Tooltip.d.ts +34 -0
- package/dist/components/Tooltip/Tooltip.js +67 -0
- package/dist/components/Tooltip/index.d.ts +1 -0
- package/dist/components/Tooltip/index.js +5 -0
- package/dist/index.d.ts +17 -3
- package/dist/index.js +81 -7
- package/dist/theme/ThemeContext.d.ts +24 -8
- package/dist/theme/ThemeContext.js +41 -22
- package/dist/theme/index.d.ts +1 -2
- package/dist/theme/index.js +8 -3
- package/dist/theme/themes.d.ts +0 -1
- package/dist/theme/themes.js +214 -2
- package/dist/theme/types.d.ts +183 -1
- package/dist/theme/types.js +2 -2
- package/dist/tokens/colors.d.ts +294 -26
- package/dist/tokens/colors.js +324 -99
- package/dist/tokens/index.d.ts +1 -2
- package/dist/tokens/index.js +29 -3
- package/dist/tokens/typography.d.ts +0 -1
- package/dist/tokens/typography.js +13 -11
- package/package.json +13 -2
- package/dist/components/Button/Button.d.ts.map +0 -1
- package/dist/components/Button/Button.js.map +0 -1
- package/dist/components/Button/index.d.ts.map +0 -1
- package/dist/components/Button/index.js.map +0 -1
- package/dist/components/Dialog/Dialog.d.ts.map +0 -1
- package/dist/components/Dialog/Dialog.js.map +0 -1
- package/dist/components/Dialog/index.d.ts.map +0 -1
- package/dist/components/Dialog/index.js.map +0 -1
- package/dist/components/Icon/Icon.d.ts.map +0 -1
- package/dist/components/Icon/Icon.js.map +0 -1
- package/dist/components/Icon/index.d.ts.map +0 -1
- package/dist/components/Icon/index.js.map +0 -1
- package/dist/components/Select/Select.d.ts.map +0 -1
- package/dist/components/Select/Select.js.map +0 -1
- package/dist/components/Select/index.d.ts.map +0 -1
- package/dist/components/Select/index.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/theme/ThemeContext.d.ts.map +0 -1
- package/dist/theme/ThemeContext.js.map +0 -1
- package/dist/theme/index.d.ts.map +0 -1
- package/dist/theme/index.js.map +0 -1
- package/dist/theme/themes.d.ts.map +0 -1
- package/dist/theme/themes.js.map +0 -1
- package/dist/theme/types.d.ts.map +0 -1
- package/dist/theme/types.js.map +0 -1
- package/dist/tokens/colors.d.ts.map +0 -1
- package/dist/tokens/colors.js.map +0 -1
- package/dist/tokens/index.d.ts.map +0 -1
- package/dist/tokens/index.js.map +0 -1
- package/dist/tokens/typography.d.ts.map +0 -1
- package/dist/tokens/typography.js.map +0 -1
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Card — surface container for grouped content with optional media, header,
|
|
3
|
+
* body, and actions.
|
|
4
|
+
*
|
|
5
|
+
* Maps to the Figma <Card> component (node 307:3346):
|
|
6
|
+
* size → small | default | large (drives padding, gap, type scale)
|
|
7
|
+
* variant → outline (1px border) | elevated (border + drop shadow)
|
|
8
|
+
*
|
|
9
|
+
* Each content slot mirrors a Figma boolean (hasImage / hasIcon / hasSubtitle
|
|
10
|
+
* / hasBody / hasActions): the slot renders only when its prop is provided.
|
|
11
|
+
* Padding + gap come from the density theme's `card` tokens (size × density).
|
|
12
|
+
*/
|
|
13
|
+
import React from 'react';
|
|
14
|
+
import { type ViewStyle, type StyleProp } from 'react-native';
|
|
15
|
+
export type CardSize = 'small' | 'default' | 'large';
|
|
16
|
+
export type CardVariant = 'outline' | 'elevated';
|
|
17
|
+
export type CardProps = {
|
|
18
|
+
/** Size variant — controls padding, gap, and typography scale. */
|
|
19
|
+
size?: CardSize;
|
|
20
|
+
/** Visual style — outline (border) or elevated (border + shadow). */
|
|
21
|
+
variant?: CardVariant;
|
|
22
|
+
/** Media area rendered at the top (e.g. an <Image>). */
|
|
23
|
+
image?: React.ReactNode;
|
|
24
|
+
/** Header leading icon — Material Symbols name string or a ReactNode. */
|
|
25
|
+
icon?: string | React.ReactNode;
|
|
26
|
+
/** Card title. */
|
|
27
|
+
title?: string;
|
|
28
|
+
/** Supporting subtitle below the title. */
|
|
29
|
+
subtitle?: string;
|
|
30
|
+
/** Body description text. */
|
|
31
|
+
body?: string;
|
|
32
|
+
/** Action row content (e.g. Buttons), right-aligned at the bottom. */
|
|
33
|
+
actions?: React.ReactNode;
|
|
34
|
+
/** Additional custom content rendered in the body, after `body`. */
|
|
35
|
+
children?: React.ReactNode;
|
|
36
|
+
/** Style override for the outer container. */
|
|
37
|
+
style?: StyleProp<ViewStyle>;
|
|
38
|
+
/** Accessibility label for the card. */
|
|
39
|
+
accessibilityLabel?: string;
|
|
40
|
+
};
|
|
41
|
+
export declare function Card({ size, variant, image, icon, title: titleText, subtitle, body: bodyText, actions, children, style, accessibilityLabel, }: CardProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Card = Card;
|
|
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 Icon_1 = require("../Icon");
|
|
8
|
+
const tokens_1 = require("../../tokens");
|
|
9
|
+
/** Maps card size → title typography scale */
|
|
10
|
+
const TITLE_SCALE = {
|
|
11
|
+
small: 'sm',
|
|
12
|
+
default: 'md',
|
|
13
|
+
large: 'lg',
|
|
14
|
+
};
|
|
15
|
+
/** Maps card size → body/subtitle typography scale */
|
|
16
|
+
const BODY_SCALE = {
|
|
17
|
+
small: 'sm',
|
|
18
|
+
default: 'md',
|
|
19
|
+
large: 'lg',
|
|
20
|
+
};
|
|
21
|
+
/** shadow/lg — elevated card drop shadow */
|
|
22
|
+
const SHADOW_WEB = {
|
|
23
|
+
boxShadow: '0px 10px 15px -3px rgba(0,0,0,0.08), 0px 4px 6px -4px rgba(0,0,0,0.04)',
|
|
24
|
+
};
|
|
25
|
+
const SHADOW_NATIVE = {
|
|
26
|
+
shadowColor: '#000000',
|
|
27
|
+
shadowOffset: { width: 0, height: 10 },
|
|
28
|
+
shadowOpacity: 0.08,
|
|
29
|
+
shadowRadius: 15,
|
|
30
|
+
elevation: 8,
|
|
31
|
+
};
|
|
32
|
+
function Card({ size = 'default', variant = 'outline', image, icon, title: titleText, subtitle, body: bodyText, actions, children, style, accessibilityLabel, }) {
|
|
33
|
+
const { components, scheme } = (0, theme_1.useTheme)();
|
|
34
|
+
const surfaceTokens = scheme.surface;
|
|
35
|
+
const textTokens = scheme.text;
|
|
36
|
+
const TITLE_FG = scheme.intents.neutral.default.default.fg;
|
|
37
|
+
const tokens = components.card;
|
|
38
|
+
const sizeTokens = tokens[size];
|
|
39
|
+
const titleTokens = tokens_1.title[TITLE_SCALE[size]];
|
|
40
|
+
const bodyTokens = tokens_1.body[BODY_SCALE[size]];
|
|
41
|
+
const resolvedIcon = typeof icon === 'string' ? ((0, jsx_runtime_1.jsx)(Icon_1.Icon, { name: icon, size: sizeTokens.iconSize, color: TITLE_FG })) : (icon);
|
|
42
|
+
const hasHeader = !!(resolvedIcon || titleText || subtitle);
|
|
43
|
+
return ((0, jsx_runtime_1.jsxs)(react_native_1.View, { accessibilityLabel: accessibilityLabel, style: [
|
|
44
|
+
{
|
|
45
|
+
backgroundColor: surfaceTokens.overlay.bg,
|
|
46
|
+
borderRadius: tokens.borderRadius,
|
|
47
|
+
borderWidth: 1,
|
|
48
|
+
borderColor: surfaceTokens.overlay.border,
|
|
49
|
+
overflow: 'hidden',
|
|
50
|
+
...(variant === 'elevated'
|
|
51
|
+
? react_native_1.Platform.OS === 'web'
|
|
52
|
+
? SHADOW_WEB
|
|
53
|
+
: SHADOW_NATIVE
|
|
54
|
+
: {}),
|
|
55
|
+
},
|
|
56
|
+
style,
|
|
57
|
+
], children: [image ? ((0, jsx_runtime_1.jsx)(react_native_1.View, { style: { height: sizeTokens.imageHeight, width: '100%' }, children: image })) : null, (0, jsx_runtime_1.jsxs)(react_native_1.View, { style: { padding: sizeTokens.padding, gap: sizeTokens.gap }, children: [hasHeader ? ((0, jsx_runtime_1.jsxs)(react_native_1.View, { style: {
|
|
58
|
+
flexDirection: 'row',
|
|
59
|
+
alignItems: 'flex-start',
|
|
60
|
+
gap: sizeTokens.gap,
|
|
61
|
+
}, children: [resolvedIcon ? ((0, jsx_runtime_1.jsx)(react_native_1.View, { accessibilityElementsHidden: true, importantForAccessibility: "no", style: {
|
|
62
|
+
width: sizeTokens.iconSize,
|
|
63
|
+
height: sizeTokens.iconSize,
|
|
64
|
+
}, children: resolvedIcon })) : null, titleText || subtitle ? ((0, jsx_runtime_1.jsxs)(react_native_1.View, { style: { flex: 1 }, children: [titleText ? ((0, jsx_runtime_1.jsx)(react_native_1.Text, { style: {
|
|
65
|
+
fontFamily: tokens_1.fontFamily.sans,
|
|
66
|
+
fontWeight: tokens_1.fontWeight.medium,
|
|
67
|
+
fontSize: titleTokens.fontSize,
|
|
68
|
+
lineHeight: titleTokens.lineHeight,
|
|
69
|
+
letterSpacing: titleTokens.letterSpacing,
|
|
70
|
+
color: TITLE_FG,
|
|
71
|
+
}, selectable: false, children: titleText })) : null, subtitle ? ((0, jsx_runtime_1.jsx)(react_native_1.Text, { style: {
|
|
72
|
+
fontFamily: tokens_1.fontFamily.sans,
|
|
73
|
+
fontWeight: tokens_1.fontWeight.regular,
|
|
74
|
+
fontSize: bodyTokens.fontSize,
|
|
75
|
+
lineHeight: bodyTokens.lineHeight,
|
|
76
|
+
letterSpacing: bodyTokens.letterSpacing,
|
|
77
|
+
color: textTokens.description,
|
|
78
|
+
}, selectable: false, children: subtitle })) : null] })) : null] })) : null, bodyText ? ((0, jsx_runtime_1.jsx)(react_native_1.Text, { style: {
|
|
79
|
+
fontFamily: tokens_1.fontFamily.sans,
|
|
80
|
+
fontWeight: tokens_1.fontWeight.regular,
|
|
81
|
+
fontSize: bodyTokens.fontSize,
|
|
82
|
+
lineHeight: bodyTokens.lineHeight,
|
|
83
|
+
letterSpacing: bodyTokens.letterSpacing,
|
|
84
|
+
color: textTokens.description,
|
|
85
|
+
}, selectable: false, children: bodyText })) : null, children, actions ? ((0, jsx_runtime_1.jsx)(react_native_1.View, { style: {
|
|
86
|
+
flexDirection: 'row',
|
|
87
|
+
justifyContent: 'flex-end',
|
|
88
|
+
alignItems: 'center',
|
|
89
|
+
gap: sizeTokens.gap,
|
|
90
|
+
}, children: actions })) : null] })] }));
|
|
91
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { Card, type CardProps, type CardSize, type CardVariant } from './Card';
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Checkbox — binary (or tri-state) choice control.
|
|
3
|
+
*
|
|
4
|
+
* Maps to the Figma <Checkbox> component (node 275:5919):
|
|
5
|
+
* checked → false | true | indeterminate
|
|
6
|
+
* size → small | default | large
|
|
7
|
+
* state → default | hover | focus | disabled (interaction-driven)
|
|
8
|
+
*
|
|
9
|
+
* Indicator and icon sizes come from the density theme's `checkbox` tokens
|
|
10
|
+
* (sizes track the `size` prop; gap tracks density). Colours come from the
|
|
11
|
+
* active theme scheme's `checkbox` set + the focus-ring colour.
|
|
12
|
+
*/
|
|
13
|
+
import { type ViewStyle, type StyleProp } from 'react-native';
|
|
14
|
+
export type CheckboxSize = 'small' | 'default' | 'large';
|
|
15
|
+
export type CheckboxChecked = boolean | 'indeterminate';
|
|
16
|
+
export type CheckboxProps = {
|
|
17
|
+
/** Checked state — true, false, or 'indeterminate'. */
|
|
18
|
+
checked?: CheckboxChecked;
|
|
19
|
+
/** Change handler — receives the next boolean checked value. */
|
|
20
|
+
onChange?: (checked: boolean) => void;
|
|
21
|
+
/** Optional label rendered beside the indicator. */
|
|
22
|
+
children?: string;
|
|
23
|
+
/** Size variant — controls indicator + icon size. */
|
|
24
|
+
size?: CheckboxSize;
|
|
25
|
+
/** Disables interaction and applies muted styling. */
|
|
26
|
+
disabled?: boolean;
|
|
27
|
+
/** Style override for the outer row. */
|
|
28
|
+
style?: StyleProp<ViewStyle>;
|
|
29
|
+
/** Accessibility label — falls back to the label text. */
|
|
30
|
+
accessibilityLabel?: string;
|
|
31
|
+
};
|
|
32
|
+
export declare function Checkbox({ checked, onChange, children, size, disabled, style, accessibilityLabel, }: CheckboxProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Checkbox = Checkbox;
|
|
4
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
5
|
+
/**
|
|
6
|
+
* Checkbox — binary (or tri-state) choice control.
|
|
7
|
+
*
|
|
8
|
+
* Maps to the Figma <Checkbox> component (node 275:5919):
|
|
9
|
+
* checked → false | true | indeterminate
|
|
10
|
+
* size → small | default | large
|
|
11
|
+
* state → default | hover | focus | disabled (interaction-driven)
|
|
12
|
+
*
|
|
13
|
+
* Indicator and icon sizes come from the density theme's `checkbox` tokens
|
|
14
|
+
* (sizes track the `size` prop; gap tracks density). Colours come from the
|
|
15
|
+
* active theme scheme's `checkbox` set + the focus-ring colour.
|
|
16
|
+
*/
|
|
17
|
+
const react_1 = require("react");
|
|
18
|
+
const react_native_1 = require("react-native");
|
|
19
|
+
const theme_1 = require("../../theme");
|
|
20
|
+
const Icon_1 = require("../Icon");
|
|
21
|
+
const tokens_1 = require("../../tokens");
|
|
22
|
+
/** Maps checkbox size → label typography scale */
|
|
23
|
+
const LABEL_SCALE = {
|
|
24
|
+
small: 'sm',
|
|
25
|
+
default: 'md',
|
|
26
|
+
large: 'lg',
|
|
27
|
+
};
|
|
28
|
+
function Checkbox({ checked = false, onChange, children, size = 'default', disabled = false, style, accessibilityLabel, }) {
|
|
29
|
+
const { components, scheme } = (0, theme_1.useTheme)();
|
|
30
|
+
const checkboxColors = scheme.checkbox;
|
|
31
|
+
const tokens = components.checkbox;
|
|
32
|
+
const sizeTokens = tokens[size];
|
|
33
|
+
const labelTokens = tokens_1.label[LABEL_SCALE[size]];
|
|
34
|
+
const [isHovered, setIsHovered] = (0, react_1.useState)(false);
|
|
35
|
+
const [isFocused, setIsFocused] = (0, react_1.useState)(false);
|
|
36
|
+
const isIndeterminate = checked === 'indeterminate';
|
|
37
|
+
const isChecked = checked === true;
|
|
38
|
+
const isOn = isChecked || isIndeterminate;
|
|
39
|
+
const handlePress = (0, react_1.useCallback)(() => {
|
|
40
|
+
if (!disabled)
|
|
41
|
+
onChange?.(!isChecked);
|
|
42
|
+
}, [disabled, onChange, isChecked]);
|
|
43
|
+
// Resolve indicator fill + border based on state.
|
|
44
|
+
// Priority: disabled > focus > (checked) > hover > default
|
|
45
|
+
let boxBg;
|
|
46
|
+
let boxBorderColor;
|
|
47
|
+
let boxBorderWidth;
|
|
48
|
+
if (disabled) {
|
|
49
|
+
boxBg = checkboxColors.box.disabled.bg;
|
|
50
|
+
boxBorderColor = checkboxColors.box.disabled.border;
|
|
51
|
+
boxBorderWidth = tokens_1.controlTokens.borderWidth;
|
|
52
|
+
}
|
|
53
|
+
else if (isOn) {
|
|
54
|
+
boxBg = checkboxColors.box.checked.bg;
|
|
55
|
+
boxBorderColor = isFocused
|
|
56
|
+
? scheme.focusRing.color
|
|
57
|
+
: checkboxColors.box.checked.border;
|
|
58
|
+
boxBorderWidth = isFocused ? tokens.focusRingWidth : 0;
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
boxBg = checkboxColors.box.uncheckedDefault.bg;
|
|
62
|
+
if (isFocused) {
|
|
63
|
+
boxBorderColor = scheme.focusRing.color;
|
|
64
|
+
boxBorderWidth = tokens.focusRingWidth;
|
|
65
|
+
}
|
|
66
|
+
else if (isHovered) {
|
|
67
|
+
boxBorderColor = checkboxColors.box.uncheckedHover.border;
|
|
68
|
+
boxBorderWidth = tokens_1.controlTokens.borderWidth;
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
boxBorderColor = checkboxColors.box.uncheckedDefault.border;
|
|
72
|
+
boxBorderWidth = tokens_1.controlTokens.borderWidth;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
const glyphColor = disabled
|
|
76
|
+
? checkboxColors.icon.disabled
|
|
77
|
+
: checkboxColors.icon.default;
|
|
78
|
+
return ((0, jsx_runtime_1.jsxs)(react_native_1.Pressable, { onPress: handlePress, disabled: disabled, onHoverIn: () => setIsHovered(true), onHoverOut: () => setIsHovered(false), onFocus: () => setIsFocused(true), onBlur: () => setIsFocused(false), accessibilityRole: "checkbox", accessibilityLabel: accessibilityLabel || children, accessibilityState: {
|
|
79
|
+
checked: isIndeterminate ? 'mixed' : isChecked,
|
|
80
|
+
disabled,
|
|
81
|
+
}, style: [
|
|
82
|
+
{
|
|
83
|
+
flexDirection: 'row',
|
|
84
|
+
alignItems: 'flex-start',
|
|
85
|
+
gap: tokens.gap,
|
|
86
|
+
},
|
|
87
|
+
style,
|
|
88
|
+
], children: [(0, jsx_runtime_1.jsx)(react_native_1.View, { style: {
|
|
89
|
+
width: sizeTokens.indicatorSize,
|
|
90
|
+
height: sizeTokens.indicatorSize,
|
|
91
|
+
borderRadius: tokens.borderRadius,
|
|
92
|
+
backgroundColor: boxBg,
|
|
93
|
+
borderWidth: boxBorderWidth,
|
|
94
|
+
borderColor: boxBorderColor,
|
|
95
|
+
alignItems: 'center',
|
|
96
|
+
justifyContent: 'center',
|
|
97
|
+
}, children: isChecked ? ((0, jsx_runtime_1.jsx)(Icon_1.Icon, { name: "check", size: sizeTokens.iconSize, color: glyphColor })) : isIndeterminate ? ((0, jsx_runtime_1.jsx)(Icon_1.Icon, { name: "remove", size: sizeTokens.iconSize, color: glyphColor })) : null }), children ? ((0, jsx_runtime_1.jsx)(react_native_1.Text, { style: {
|
|
98
|
+
fontFamily: tokens_1.fontFamily.sans,
|
|
99
|
+
fontWeight: tokens_1.fontWeight.medium,
|
|
100
|
+
fontSize: labelTokens.fontSize,
|
|
101
|
+
lineHeight: labelTokens.lineHeight,
|
|
102
|
+
letterSpacing: labelTokens.letterSpacing,
|
|
103
|
+
color: disabled
|
|
104
|
+
? checkboxColors.label.disabled
|
|
105
|
+
: checkboxColors.label.default,
|
|
106
|
+
}, selectable: false, children: children })) : null] }));
|
|
107
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { Checkbox, type CheckboxProps, type CheckboxSize, type CheckboxChecked, } from './Checkbox';
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Chip — compact, interactive pill for filters, selections, and tokens.
|
|
3
|
+
*
|
|
4
|
+
* Maps to the Figma <Chip> component (node 307:3479):
|
|
5
|
+
* intent → neutral | brand | danger
|
|
6
|
+
* variant → outline (bordered) | subtle (tinted)
|
|
7
|
+
* size → small | default | large
|
|
8
|
+
* state → default | hover | active | disabled (interaction-driven)
|
|
9
|
+
*
|
|
10
|
+
* Spacing/icon sizes come from the density theme's `chip` tokens (padding/gap
|
|
11
|
+
* vary by size AND density; icon size tracks the `size` prop). Colours map
|
|
12
|
+
* directly onto the semantic intent system:
|
|
13
|
+
* outline → intent default (white/tinted bg + border)
|
|
14
|
+
* subtle → intent subtle (transparent bg/border)
|
|
15
|
+
* The `selected` state renders the intent's active colours.
|
|
16
|
+
*/
|
|
17
|
+
import React from 'react';
|
|
18
|
+
import { type ViewStyle, type StyleProp, type GestureResponderEvent } from 'react-native';
|
|
19
|
+
import type { IntentName } from '../../tokens';
|
|
20
|
+
export type ChipSize = 'small' | 'default' | 'large';
|
|
21
|
+
export type ChipVariant = 'outline' | 'subtle';
|
|
22
|
+
export type ChipProps = {
|
|
23
|
+
/** The chip label text. */
|
|
24
|
+
children: string;
|
|
25
|
+
/** Semantic intent — drives the colour scheme. */
|
|
26
|
+
intent?: IntentName;
|
|
27
|
+
/** Surface treatment — outline (bordered) or subtle (tinted). */
|
|
28
|
+
variant?: ChipVariant;
|
|
29
|
+
/** Size variant — controls padding, gap, and typography scale. */
|
|
30
|
+
size?: ChipSize;
|
|
31
|
+
/** Selected state — renders the intent's active colours. */
|
|
32
|
+
selected?: boolean;
|
|
33
|
+
/** Disables interaction and applies muted styling. */
|
|
34
|
+
disabled?: boolean;
|
|
35
|
+
/** Leading icon — Material Symbols name string or a ReactNode. */
|
|
36
|
+
leadingIcon?: string | React.ReactNode;
|
|
37
|
+
/** Press handler — makes the chip selectable. */
|
|
38
|
+
onPress?: (e: GestureResponderEvent) => void;
|
|
39
|
+
/** Remove handler — renders a trailing close button when provided. */
|
|
40
|
+
onRemove?: () => void;
|
|
41
|
+
/** Outer style — use for positioning (margin, flex, alignSelf). */
|
|
42
|
+
style?: StyleProp<ViewStyle>;
|
|
43
|
+
/** Accessibility label — falls back to the label text. */
|
|
44
|
+
accessibilityLabel?: string;
|
|
45
|
+
};
|
|
46
|
+
export declare function Chip({ children, intent, variant, size, selected, disabled, leadingIcon, onPress, onRemove, style, accessibilityLabel, }: ChipProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Chip = Chip;
|
|
4
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
5
|
+
/**
|
|
6
|
+
* Chip — compact, interactive pill for filters, selections, and tokens.
|
|
7
|
+
*
|
|
8
|
+
* Maps to the Figma <Chip> component (node 307:3479):
|
|
9
|
+
* intent → neutral | brand | danger
|
|
10
|
+
* variant → outline (bordered) | subtle (tinted)
|
|
11
|
+
* size → small | default | large
|
|
12
|
+
* state → default | hover | active | disabled (interaction-driven)
|
|
13
|
+
*
|
|
14
|
+
* Spacing/icon sizes come from the density theme's `chip` tokens (padding/gap
|
|
15
|
+
* vary by size AND density; icon size tracks the `size` prop). Colours map
|
|
16
|
+
* directly onto the semantic intent system:
|
|
17
|
+
* outline → intent default (white/tinted bg + border)
|
|
18
|
+
* subtle → intent subtle (transparent bg/border)
|
|
19
|
+
* The `selected` state renders the intent's active colours.
|
|
20
|
+
*/
|
|
21
|
+
const react_1 = require("react");
|
|
22
|
+
const react_native_1 = require("react-native");
|
|
23
|
+
const theme_1 = require("../../theme");
|
|
24
|
+
const tokens_1 = require("../../tokens");
|
|
25
|
+
const Icon_1 = require("../Icon");
|
|
26
|
+
// ---------------------------------------------------------------------------
|
|
27
|
+
// Constants
|
|
28
|
+
// ---------------------------------------------------------------------------
|
|
29
|
+
/** Maps chip size → label typography scale */
|
|
30
|
+
const LABEL_SCALE = {
|
|
31
|
+
small: 'sm',
|
|
32
|
+
default: 'md',
|
|
33
|
+
large: 'lg',
|
|
34
|
+
};
|
|
35
|
+
// ---------------------------------------------------------------------------
|
|
36
|
+
// Component
|
|
37
|
+
// ---------------------------------------------------------------------------
|
|
38
|
+
function Chip({ children, intent = 'neutral', variant = 'outline', size = 'default', selected = false, disabled = false, leadingIcon, onPress, onRemove, style, accessibilityLabel, }) {
|
|
39
|
+
const { components, scheme } = (0, theme_1.useTheme)();
|
|
40
|
+
const intentColors = scheme.intents;
|
|
41
|
+
const disabledColors = scheme.disabled;
|
|
42
|
+
const sizeTokens = components.chip[size];
|
|
43
|
+
const labelTokens = tokens_1.label[LABEL_SCALE[size]];
|
|
44
|
+
const [isHovered, setIsHovered] = (0, react_1.useState)(false);
|
|
45
|
+
const prominence = variant === 'outline' ? 'default' : 'subtle';
|
|
46
|
+
// Resolve colours. Priority: disabled > selected/pressed > hover > default
|
|
47
|
+
const resolveColors = (0, react_1.useCallback)((pressed) => {
|
|
48
|
+
if (disabled)
|
|
49
|
+
return disabledColors;
|
|
50
|
+
const states = intentColors[intent][prominence];
|
|
51
|
+
if (selected || pressed)
|
|
52
|
+
return states.active;
|
|
53
|
+
if (isHovered)
|
|
54
|
+
return states.hover;
|
|
55
|
+
return states.default;
|
|
56
|
+
}, [disabled, intent, prominence, selected, isHovered, intentColors, disabledColors]);
|
|
57
|
+
const isInteractive = !disabled && (onPress != null || onRemove != null);
|
|
58
|
+
return ((0, jsx_runtime_1.jsx)(react_native_1.Pressable, { onPress: onPress, disabled: disabled || onPress == null, onHoverIn: () => setIsHovered(true), onHoverOut: () => setIsHovered(false), accessibilityRole: onPress ? 'button' : 'text', accessibilityLabel: accessibilityLabel || children, accessibilityState: { disabled, selected }, style: style, children: ({ pressed }) => {
|
|
59
|
+
const colors = resolveColors(pressed && isInteractive);
|
|
60
|
+
const resolvedLeading = typeof leadingIcon === 'string' ? ((0, jsx_runtime_1.jsx)(Icon_1.Icon, { name: leadingIcon, size: sizeTokens.iconSize, color: colors.fg })) : (leadingIcon);
|
|
61
|
+
return ((0, jsx_runtime_1.jsxs)(react_native_1.View, { style: {
|
|
62
|
+
flexDirection: 'row',
|
|
63
|
+
alignItems: 'center',
|
|
64
|
+
justifyContent: 'center',
|
|
65
|
+
alignSelf: 'flex-start',
|
|
66
|
+
gap: sizeTokens.gap,
|
|
67
|
+
paddingHorizontal: sizeTokens.paddingX,
|
|
68
|
+
paddingVertical: sizeTokens.paddingY,
|
|
69
|
+
borderRadius: components.chip.borderRadius,
|
|
70
|
+
borderWidth: tokens_1.controlTokens.borderWidth,
|
|
71
|
+
borderColor: colors.border,
|
|
72
|
+
backgroundColor: colors.bg,
|
|
73
|
+
}, children: [resolvedLeading ? ((0, jsx_runtime_1.jsx)(react_native_1.View, { accessibilityElementsHidden: true, importantForAccessibility: "no", style: { width: sizeTokens.iconSize, height: sizeTokens.iconSize }, children: resolvedLeading })) : null, (0, jsx_runtime_1.jsx)(react_native_1.Text, { style: {
|
|
74
|
+
fontFamily: tokens_1.fontFamily.sans,
|
|
75
|
+
fontWeight: tokens_1.fontWeight.medium,
|
|
76
|
+
fontSize: labelTokens.fontSize,
|
|
77
|
+
lineHeight: labelTokens.lineHeight,
|
|
78
|
+
letterSpacing: labelTokens.letterSpacing,
|
|
79
|
+
color: colors.fg,
|
|
80
|
+
}, selectable: false, children: children }), onRemove ? ((0, jsx_runtime_1.jsx)(react_native_1.Pressable, { onPress: disabled ? undefined : onRemove, disabled: disabled, hitSlop: 6, accessibilityRole: "button", accessibilityLabel: `Remove ${children}`, style: { width: sizeTokens.iconSize, height: sizeTokens.iconSize }, children: (0, jsx_runtime_1.jsx)(Icon_1.Icon, { name: "close", size: sizeTokens.iconSize, color: colors.fg }) })) : null] }));
|
|
81
|
+
} }));
|
|
82
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { Chip, type ChipProps, type ChipSize, type ChipVariant } from './Chip';
|
|
@@ -54,4 +54,3 @@ export type DialogProps = DialogContentProps & {
|
|
|
54
54
|
*/
|
|
55
55
|
export declare function DialogContent({ title: titleText, description, icon, size, children, primaryAction, secondaryAction, style, accessibilityLabel, }: DialogContentProps): import("react/jsx-runtime").JSX.Element;
|
|
56
56
|
export declare function Dialog({ open, onClose, ...contentProps }: DialogProps): import("react/jsx-runtime").JSX.Element;
|
|
57
|
-
//# sourceMappingURL=Dialog.d.ts.map
|
|
@@ -1,9 +1,13 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DialogContent = DialogContent;
|
|
4
|
+
exports.Dialog = Dialog;
|
|
5
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
6
|
+
const react_native_1 = require("react-native");
|
|
7
|
+
const theme_1 = require("../../theme");
|
|
8
|
+
const Button_1 = require("../Button");
|
|
9
|
+
const Icon_1 = require("../Icon");
|
|
10
|
+
const tokens_1 = require("../../tokens");
|
|
7
11
|
// ---------------------------------------------------------------------------
|
|
8
12
|
// Constants
|
|
9
13
|
// ---------------------------------------------------------------------------
|
|
@@ -48,57 +52,60 @@ const SHADOW_NATIVE = {
|
|
|
48
52
|
* Use this for static display (e.g., Storybook visual stories)
|
|
49
53
|
* or when building custom overlay implementations.
|
|
50
54
|
*/
|
|
51
|
-
|
|
52
|
-
const { components, colors } = useTheme();
|
|
55
|
+
function DialogContent({ title: titleText, description, icon, size = 'default', children, primaryAction, secondaryAction, style, accessibilityLabel, }) {
|
|
56
|
+
const { components, colors, scheme } = (0, theme_1.useTheme)();
|
|
57
|
+
const surfaceTokens = scheme.surface;
|
|
58
|
+
const textTokens = scheme.text;
|
|
53
59
|
const sizeTokens = components.dialog[size];
|
|
54
|
-
const titleTokens = title[TYPO_SCALE[size]];
|
|
55
|
-
const bodyTokens = body[TYPO_SCALE[size]];
|
|
60
|
+
const titleTokens = tokens_1.title[TYPO_SCALE[size]];
|
|
61
|
+
const bodyTokens = tokens_1.body[TYPO_SCALE[size]];
|
|
56
62
|
const buttonSize = BUTTON_SIZE[size];
|
|
57
63
|
const fgColor = colors.neutral.default.default.fg;
|
|
58
|
-
const resolvedIcon = typeof icon === 'string' ? (
|
|
64
|
+
const resolvedIcon = typeof icon === 'string' ? ((0, jsx_runtime_1.jsx)(Icon_1.Icon, { name: icon, size: sizeTokens.iconSize, color: fgColor })) : (icon);
|
|
59
65
|
const hasActions = primaryAction || secondaryAction;
|
|
60
|
-
return (
|
|
66
|
+
return ((0, jsx_runtime_1.jsxs)(react_native_1.View, { accessibilityRole: "alert", accessibilityLabel: accessibilityLabel || titleText, style: [
|
|
61
67
|
{
|
|
62
68
|
width: DIALOG_WIDTH[size],
|
|
63
69
|
maxWidth: '100%',
|
|
64
70
|
backgroundColor: surfaceTokens.overlay.bg,
|
|
65
|
-
borderWidth: controlTokens.borderWidth,
|
|
71
|
+
borderWidth: tokens_1.controlTokens.borderWidth,
|
|
66
72
|
borderColor: surfaceTokens.overlay.border,
|
|
67
73
|
borderRadius: surfaceTokens.overlay.borderRadius,
|
|
68
74
|
padding: sizeTokens.padding,
|
|
69
75
|
gap: sizeTokens.gap,
|
|
70
|
-
...(Platform.OS === 'web' ? SHADOW_WEB : SHADOW_NATIVE),
|
|
76
|
+
...(react_native_1.Platform.OS === 'web' ? SHADOW_WEB : SHADOW_NATIVE),
|
|
71
77
|
},
|
|
72
78
|
style,
|
|
73
|
-
], children: [
|
|
74
|
-
fontFamily: fontFamily.sans,
|
|
75
|
-
fontWeight: fontWeight.medium,
|
|
79
|
+
], children: [(0, jsx_runtime_1.jsxs)(react_native_1.View, { style: { gap: TITLE_DESC_GAP }, children: [(0, jsx_runtime_1.jsxs)(react_native_1.View, { style: { gap: HEADER_ICON_GAP }, children: [resolvedIcon, (0, jsx_runtime_1.jsx)(react_native_1.Text, { accessibilityRole: "header", style: {
|
|
80
|
+
fontFamily: tokens_1.fontFamily.sans,
|
|
81
|
+
fontWeight: tokens_1.fontWeight.medium,
|
|
76
82
|
fontSize: titleTokens.fontSize,
|
|
77
83
|
lineHeight: titleTokens.lineHeight,
|
|
78
84
|
letterSpacing: titleTokens.letterSpacing,
|
|
79
85
|
color: fgColor,
|
|
80
|
-
}, children: titleText })] }), description ? (
|
|
81
|
-
fontFamily: fontFamily.sans,
|
|
82
|
-
fontWeight: fontWeight.regular,
|
|
86
|
+
}, children: titleText })] }), description ? ((0, jsx_runtime_1.jsx)(react_native_1.Text, { style: {
|
|
87
|
+
fontFamily: tokens_1.fontFamily.sans,
|
|
88
|
+
fontWeight: tokens_1.fontWeight.regular,
|
|
83
89
|
fontSize: bodyTokens.fontSize,
|
|
84
90
|
lineHeight: bodyTokens.lineHeight,
|
|
85
91
|
letterSpacing: bodyTokens.letterSpacing,
|
|
86
92
|
color: textTokens.description,
|
|
87
|
-
}, children: description })) : null] }), children, hasActions ? (
|
|
93
|
+
}, children: description })) : null] }), children, hasActions ? ((0, jsx_runtime_1.jsxs)(react_native_1.View, { style: {
|
|
88
94
|
flexDirection: 'row',
|
|
89
95
|
justifyContent: 'flex-end',
|
|
90
96
|
gap: sizeTokens.gap,
|
|
91
|
-
}, children: [secondaryAction ? (
|
|
97
|
+
}, children: [secondaryAction ? ((0, jsx_runtime_1.jsx)(Button_1.Button, { intent: "neutral", prominence: "default", size: buttonSize, onPress: secondaryAction.onPress, children: secondaryAction.label })) : null, primaryAction ? ((0, jsx_runtime_1.jsx)(Button_1.Button, { intent: "brand", prominence: "bold", size: buttonSize, onPress: primaryAction.onPress, children: primaryAction.label })) : null] })) : null] }));
|
|
92
98
|
}
|
|
93
99
|
// ---------------------------------------------------------------------------
|
|
94
100
|
// Dialog — full modal with backdrop
|
|
95
101
|
// ---------------------------------------------------------------------------
|
|
96
|
-
|
|
97
|
-
|
|
102
|
+
function Dialog({ open, onClose, ...contentProps }) {
|
|
103
|
+
const { scheme } = (0, theme_1.useTheme)();
|
|
104
|
+
const overlayTokens = scheme.overlay;
|
|
105
|
+
return ((0, jsx_runtime_1.jsx)(react_native_1.Modal, { visible: open, transparent: true, animationType: "fade", onRequestClose: onClose, children: (0, jsx_runtime_1.jsx)(react_native_1.Pressable, { onPress: onClose, accessibilityRole: "button", accessibilityLabel: "Close dialog", style: {
|
|
98
106
|
flex: 1,
|
|
99
107
|
backgroundColor: `rgba(0, 0, 0, ${overlayTokens.scrimOpacity})`,
|
|
100
108
|
justifyContent: 'center',
|
|
101
109
|
alignItems: 'center',
|
|
102
|
-
}, children:
|
|
110
|
+
}, children: (0, jsx_runtime_1.jsx)(react_native_1.Pressable, { onPress: (e) => e.stopPropagation(), accessibilityRole: "none", style: { maxWidth: '90%' }, children: (0, jsx_runtime_1.jsx)(DialogContent, { ...contentProps }) }) }) }));
|
|
103
111
|
}
|
|
104
|
-
//# sourceMappingURL=Dialog.js.map
|
|
@@ -1,2 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DialogContent = exports.Dialog = void 0;
|
|
4
|
+
var Dialog_1 = require("./Dialog");
|
|
5
|
+
Object.defineProperty(exports, "Dialog", { enumerable: true, get: function () { return Dialog_1.Dialog; } });
|
|
6
|
+
Object.defineProperty(exports, "DialogContent", { enumerable: true, get: function () { return Dialog_1.DialogContent; } });
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Divider — a thin rule separating content, horizontally or vertically.
|
|
3
|
+
*
|
|
4
|
+
* Maps to the Figma <Divider> component (node 307:3571):
|
|
5
|
+
* orientation → horizontal | vertical
|
|
6
|
+
*
|
|
7
|
+
* The line uses the overlay border colour (surface/overlay/border) at the
|
|
8
|
+
* control border width (1px) — both constant across densities. A horizontal
|
|
9
|
+
* divider stretches to its container's width; a vertical divider stretches to
|
|
10
|
+
* its container's height (give the parent a defined cross-axis size).
|
|
11
|
+
*/
|
|
12
|
+
import { type ViewStyle, type StyleProp } from 'react-native';
|
|
13
|
+
export type DividerOrientation = 'horizontal' | 'vertical';
|
|
14
|
+
export type DividerProps = {
|
|
15
|
+
/** Line direction. */
|
|
16
|
+
orientation?: DividerOrientation;
|
|
17
|
+
/** Line colour — defaults to the overlay border token. */
|
|
18
|
+
color?: string;
|
|
19
|
+
/** Style override — e.g. margins or an explicit length. */
|
|
20
|
+
style?: StyleProp<ViewStyle>;
|
|
21
|
+
};
|
|
22
|
+
export declare function Divider({ orientation, color, style, }: DividerProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Divider = Divider;
|
|
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
|
+
function Divider({ orientation = 'horizontal', color, style, }) {
|
|
9
|
+
const { scheme } = (0, theme_1.useTheme)();
|
|
10
|
+
const resolvedColor = color ?? scheme.surface.overlay.border;
|
|
11
|
+
const isVertical = orientation === 'vertical';
|
|
12
|
+
return ((0, jsx_runtime_1.jsx)(react_native_1.View, { accessibilityElementsHidden: true, importantForAccessibility: "no-hide-descendants", style: [
|
|
13
|
+
isVertical
|
|
14
|
+
? { alignSelf: 'stretch', width: tokens_1.controlTokens.borderWidth }
|
|
15
|
+
: { alignSelf: 'stretch', height: tokens_1.controlTokens.borderWidth },
|
|
16
|
+
{ backgroundColor: resolvedColor },
|
|
17
|
+
style,
|
|
18
|
+
] }));
|
|
19
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { Divider, type DividerProps, type DividerOrientation } from './Divider';
|