@castui/cast-ui 4.6.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.
Files changed (78) hide show
  1. package/README.md +6 -0
  2. package/dist/components/Accordion/Accordion.d.ts +80 -0
  3. package/dist/components/Accordion/Accordion.js +157 -0
  4. package/dist/components/Accordion/index.d.ts +1 -0
  5. package/dist/components/Accordion/index.js +6 -0
  6. package/dist/components/AppBar/AppBar.d.ts +47 -0
  7. package/dist/components/AppBar/AppBar.js +47 -0
  8. package/dist/components/AppBar/index.d.ts +1 -0
  9. package/dist/components/AppBar/index.js +5 -0
  10. package/dist/components/Autocomplete/Autocomplete.d.ts +70 -0
  11. package/dist/components/Autocomplete/Autocomplete.js +249 -0
  12. package/dist/components/Autocomplete/index.d.ts +1 -0
  13. package/dist/components/Autocomplete/index.js +5 -0
  14. package/dist/components/Backdrop/Backdrop.d.ts +32 -0
  15. package/dist/components/Backdrop/Backdrop.js +74 -0
  16. package/dist/components/Backdrop/index.d.ts +1 -0
  17. package/dist/components/Backdrop/index.js +5 -0
  18. package/dist/components/BottomSheet/BottomSheet.d.ts +50 -0
  19. package/dist/components/BottomSheet/BottomSheet.js +159 -0
  20. package/dist/components/BottomSheet/index.d.ts +1 -0
  21. package/dist/components/BottomSheet/index.js +6 -0
  22. package/dist/components/Breadcrumbs/Breadcrumbs.d.ts +63 -0
  23. package/dist/components/Breadcrumbs/Breadcrumbs.js +143 -0
  24. package/dist/components/Breadcrumbs/index.d.ts +1 -0
  25. package/dist/components/Breadcrumbs/index.js +6 -0
  26. package/dist/components/CodeBlock/CodeBlock.d.ts +42 -0
  27. package/dist/components/CodeBlock/CodeBlock.js +110 -0
  28. package/dist/components/CodeBlock/index.d.ts +1 -0
  29. package/dist/components/CodeBlock/index.js +5 -0
  30. package/dist/components/Drawer/Drawer.d.ts +51 -0
  31. package/dist/components/Drawer/Drawer.js +168 -0
  32. package/dist/components/Drawer/index.d.ts +1 -0
  33. package/dist/components/Drawer/index.js +6 -0
  34. package/dist/components/Link/Link.d.ts +51 -0
  35. package/dist/components/Link/Link.js +73 -0
  36. package/dist/components/Link/index.d.ts +1 -0
  37. package/dist/components/Link/index.js +5 -0
  38. package/dist/components/Menu/Menu.d.ts +91 -0
  39. package/dist/components/Menu/Menu.js +211 -0
  40. package/dist/components/Menu/index.d.ts +1 -0
  41. package/dist/components/Menu/index.js +9 -0
  42. package/dist/components/Slider/Slider.d.ts +47 -0
  43. package/dist/components/Slider/Slider.js +132 -0
  44. package/dist/components/Slider/index.d.ts +1 -0
  45. package/dist/components/Slider/index.js +5 -0
  46. package/dist/components/SpeedDial/SpeedDial.d.ts +72 -0
  47. package/dist/components/SpeedDial/SpeedDial.js +189 -0
  48. package/dist/components/SpeedDial/index.d.ts +1 -0
  49. package/dist/components/SpeedDial/index.js +6 -0
  50. package/dist/components/Spinner/Spinner.d.ts +42 -0
  51. package/dist/components/Spinner/Spinner.js +77 -0
  52. package/dist/components/Spinner/index.d.ts +1 -0
  53. package/dist/components/Spinner/index.js +5 -0
  54. package/dist/components/Table/Table.d.ts +74 -0
  55. package/dist/components/Table/Table.js +176 -0
  56. package/dist/components/Table/index.d.ts +1 -0
  57. package/dist/components/Table/index.js +9 -0
  58. package/dist/components/Tabs/Tabs.d.ts +1 -1
  59. package/dist/components/Tabs/Tabs.js +5 -2
  60. package/dist/components/ToggleButtonGroup/ToggleButtonGroup.d.ts +69 -0
  61. package/dist/components/ToggleButtonGroup/ToggleButtonGroup.js +158 -0
  62. package/dist/components/ToggleButtonGroup/index.d.ts +1 -0
  63. package/dist/components/ToggleButtonGroup/index.js +6 -0
  64. package/dist/index.d.ts +17 -2
  65. package/dist/index.js +51 -2
  66. package/dist/theme/ThemeContext.d.ts +8 -1
  67. package/dist/theme/ThemeContext.js +7 -4
  68. package/dist/theme/applyCastTheme.d.ts +75 -0
  69. package/dist/theme/applyCastTheme.js +95 -0
  70. package/dist/theme/index.d.ts +2 -1
  71. package/dist/theme/index.js +3 -1
  72. package/dist/theme/themes.js +192 -0
  73. package/dist/theme/types.d.ts +192 -0
  74. package/dist/tokens/colors.d.ts +48 -0
  75. package/dist/tokens/colors.js +49 -1
  76. package/dist/tokens/index.d.ts +1 -1
  77. package/dist/tokens/index.js +4 -1
  78. package/package.json +2 -1
@@ -0,0 +1,63 @@
1
+ /**
2
+ * Breadcrumbs — a trail showing where the user is in a hierarchy.
3
+ *
4
+ * Compound component. <Breadcrumbs> lays out the row and draws a separator
5
+ * between items; <Breadcrumb> is one entry. The last item (or any item with
6
+ * `current`) renders as plain text; the rest are pressable links.
7
+ *
8
+ * <Breadcrumbs>
9
+ * <Breadcrumb onPress={goHome}>Home</Breadcrumb>
10
+ * <Breadcrumb onPress={goLibrary}>Library</Breadcrumb>
11
+ * <Breadcrumb current>This page</Breadcrumb>
12
+ * </Breadcrumbs>
13
+ *
14
+ * Maps 1:1 to the Figma <Breadcrumbs> component:
15
+ * size → small | default | large (typography + icon size + gap)
16
+ * separator → the glyph or string drawn between items (default chevron_right)
17
+ *
18
+ * Colours: link items use the brand subtle fg and text/primary on hover; the
19
+ * current item uses text/primary; separators use text/description; disabled
20
+ * uses the shared disabled fg. The one spacing token is breadcrumbs/{size}/gap
21
+ * (density-varying), used as the row gap between every item and separator, and
22
+ * as the gap between a leading icon and its label. Labels render through the
23
+ * shared <Text> component, so Breadcrumbs inherits the type ramp.
24
+ */
25
+ import React from 'react';
26
+ import { type StyleProp, type ViewStyle, type GestureResponderEvent } from 'react-native';
27
+ export type BreadcrumbsSize = 'small' | 'default' | 'large';
28
+ export type BreadcrumbsProps = {
29
+ /** `<Breadcrumb>` children. */
30
+ children: React.ReactNode;
31
+ /**
32
+ * Separator between items. A Material Symbols name (e.g. "chevron_right") is
33
+ * drawn as an icon; any other string (e.g. "/") is drawn as text. A ReactNode
34
+ * is rendered as-is. Defaults to "chevron_right".
35
+ */
36
+ separator?: string | React.ReactNode;
37
+ /** Size variant — typography scale, icon size, and gap. */
38
+ size?: BreadcrumbsSize;
39
+ /** Outer style. */
40
+ style?: StyleProp<ViewStyle>;
41
+ /** Accessibility label for the trail. */
42
+ accessibilityLabel?: string;
43
+ };
44
+ export type BreadcrumbProps = {
45
+ /** The item text. */
46
+ children: string;
47
+ /** Press handler — omit on the current item. */
48
+ onPress?: (e: GestureResponderEvent) => void;
49
+ /** Marks this as the current page — renders as plain text, not a link. */
50
+ current?: boolean;
51
+ /** Disables the link. */
52
+ disabled?: boolean;
53
+ /** Icon before the label — Material Symbols name string or a ReactNode. */
54
+ leadingIcon?: string | React.ReactNode;
55
+ /** Destination URL. Renders a real anchor on web; informational on native. */
56
+ href?: string;
57
+ /** Accessibility label — falls back to the item text. */
58
+ accessibilityLabel?: string;
59
+ /** Internal: set by <Breadcrumbs> on the final item. */
60
+ __isLast?: boolean;
61
+ };
62
+ export declare function Breadcrumb({ children, onPress, current, disabled, leadingIcon, href, accessibilityLabel, __isLast, }: BreadcrumbProps): import("react/jsx-runtime").JSX.Element;
63
+ export declare function Breadcrumbs({ children, separator, size, style, accessibilityLabel, }: BreadcrumbsProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,143 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.Breadcrumb = Breadcrumb;
37
+ exports.Breadcrumbs = Breadcrumbs;
38
+ const jsx_runtime_1 = require("react/jsx-runtime");
39
+ /**
40
+ * Breadcrumbs — a trail showing where the user is in a hierarchy.
41
+ *
42
+ * Compound component. <Breadcrumbs> lays out the row and draws a separator
43
+ * between items; <Breadcrumb> is one entry. The last item (or any item with
44
+ * `current`) renders as plain text; the rest are pressable links.
45
+ *
46
+ * <Breadcrumbs>
47
+ * <Breadcrumb onPress={goHome}>Home</Breadcrumb>
48
+ * <Breadcrumb onPress={goLibrary}>Library</Breadcrumb>
49
+ * <Breadcrumb current>This page</Breadcrumb>
50
+ * </Breadcrumbs>
51
+ *
52
+ * Maps 1:1 to the Figma <Breadcrumbs> component:
53
+ * size → small | default | large (typography + icon size + gap)
54
+ * separator → the glyph or string drawn between items (default chevron_right)
55
+ *
56
+ * Colours: link items use the brand subtle fg and text/primary on hover; the
57
+ * current item uses text/primary; separators use text/description; disabled
58
+ * uses the shared disabled fg. The one spacing token is breadcrumbs/{size}/gap
59
+ * (density-varying), used as the row gap between every item and separator, and
60
+ * as the gap between a leading icon and its label. Labels render through the
61
+ * shared <Text> component, so Breadcrumbs inherits the type ramp.
62
+ */
63
+ const react_1 = __importStar(require("react"));
64
+ const react_native_1 = require("react-native");
65
+ const theme_1 = require("../../theme");
66
+ const Text_1 = require("../Text");
67
+ const Icon_1 = require("../Icon");
68
+ const BreadcrumbsCtx = (0, react_1.createContext)(null);
69
+ function useBreadcrumbsContext(component) {
70
+ const ctx = (0, react_1.useContext)(BreadcrumbsCtx);
71
+ if (!ctx) {
72
+ throw new Error(`<${component}> must be used within <Breadcrumbs>`);
73
+ }
74
+ return ctx;
75
+ }
76
+ // ---------------------------------------------------------------------------
77
+ // Constants
78
+ // ---------------------------------------------------------------------------
79
+ /** Maps size → label typography scale (Text component `type`). */
80
+ const LABEL_TYPE = {
81
+ small: 'body-sm',
82
+ default: 'body-md',
83
+ large: 'body-lg',
84
+ };
85
+ /** Maps size → named Icon scale for separators and leading icons. */
86
+ const ICON_SIZE = {
87
+ small: 'xs',
88
+ default: 'small',
89
+ large: 'default',
90
+ };
91
+ /** A bare lowercase/underscore token is treated as a Material Symbols name. */
92
+ const isSymbolName = (s) => /^[a-z0-9_]+$/.test(s);
93
+ // ---------------------------------------------------------------------------
94
+ // Breadcrumb
95
+ // ---------------------------------------------------------------------------
96
+ function Breadcrumb({ children, onPress, current = false, disabled = false, leadingIcon, href, accessibilityLabel, __isLast = false, }) {
97
+ const { size, gap } = useBreadcrumbsContext('Breadcrumb');
98
+ const { colors, scheme } = (0, theme_1.useTheme)();
99
+ const [isHovered, setIsHovered] = (0, react_1.useState)(false);
100
+ const isCurrent = current || __isLast;
101
+ const linkFg = colors.brand.subtle.default.fg;
102
+ const fg = disabled
103
+ ? scheme.disabled.fg
104
+ : isCurrent
105
+ ? scheme.text.primary
106
+ : isHovered
107
+ ? scheme.text.primary
108
+ : linkFg;
109
+ const showUnderline = !isCurrent && !disabled && isHovered;
110
+ const resolvedIcon = typeof leadingIcon === 'string' ? ((0, jsx_runtime_1.jsx)(Icon_1.Icon, { name: leadingIcon, size: ICON_SIZE[size], color: fg })) : (leadingIcon);
111
+ const content = ((0, jsx_runtime_1.jsxs)(react_native_1.View, { style: { flexDirection: 'row', alignItems: 'center', gap }, children: [resolvedIcon, (0, jsx_runtime_1.jsx)(Text_1.Text, { type: LABEL_TYPE[size], color: fg, selectable: false, style: { textDecorationLine: showUnderline ? 'underline' : 'none' }, children: children })] }));
112
+ if (isCurrent) {
113
+ return ((0, jsx_runtime_1.jsx)(react_native_1.View, { accessibilityRole: "text", accessibilityState: { selected: true }, accessibilityLabel: accessibilityLabel || children, ...{ 'aria-current': 'page' }, children: content }));
114
+ }
115
+ const hrefProps = href ? { href } : {};
116
+ return ((0, jsx_runtime_1.jsx)(react_native_1.Pressable, { ...hrefProps, onPress: disabled ? undefined : onPress, disabled: disabled, onHoverIn: () => setIsHovered(true), onHoverOut: () => setIsHovered(false), accessibilityRole: "link", accessibilityLabel: accessibilityLabel || children, accessibilityState: { disabled }, children: content }));
117
+ }
118
+ // ---------------------------------------------------------------------------
119
+ // Breadcrumbs
120
+ // ---------------------------------------------------------------------------
121
+ function Breadcrumbs({ children, separator = 'chevron_right', size = 'default', style, accessibilityLabel, }) {
122
+ const { components, scheme } = (0, theme_1.useTheme)();
123
+ const { gap } = components.breadcrumbs[size];
124
+ const items = react_1.default.Children.toArray(children).filter(Boolean);
125
+ const lastIndex = items.length - 1;
126
+ const separatorNode = typeof separator === 'string' ? (isSymbolName(separator) ? ((0, jsx_runtime_1.jsx)(Icon_1.Icon, { name: separator, size: ICON_SIZE[size], color: scheme.text.description })) : ((0, jsx_runtime_1.jsx)(Text_1.Text, { type: LABEL_TYPE[size], color: scheme.text.description, selectable: false, children: separator }))) : (separator);
127
+ const rendered = [];
128
+ items.forEach((child, i) => {
129
+ rendered.push(react_1.default.cloneElement(child, { key: `item-${i}`, __isLast: i === lastIndex }));
130
+ if (i < lastIndex) {
131
+ rendered.push((0, jsx_runtime_1.jsx)(react_native_1.View, { pointerEvents: "none", accessibilityElementsHidden: true, importantForAccessibility: "no-hide-descendants", children: separatorNode }, `sep-${i}`));
132
+ }
133
+ });
134
+ return ((0, jsx_runtime_1.jsx)(BreadcrumbsCtx.Provider, { value: { size, gap }, children: (0, jsx_runtime_1.jsx)(react_native_1.View, { accessibilityLabel: accessibilityLabel || 'Breadcrumb', style: [
135
+ {
136
+ flexDirection: 'row',
137
+ alignItems: 'center',
138
+ flexWrap: 'wrap',
139
+ gap,
140
+ },
141
+ style,
142
+ ], children: rendered }) }));
143
+ }
@@ -0,0 +1 @@
1
+ export { Breadcrumbs, Breadcrumb, type BreadcrumbsProps, type BreadcrumbProps, type BreadcrumbsSize, } from './Breadcrumbs';
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Breadcrumb = exports.Breadcrumbs = void 0;
4
+ var Breadcrumbs_1 = require("./Breadcrumbs");
5
+ Object.defineProperty(exports, "Breadcrumbs", { enumerable: true, get: function () { return Breadcrumbs_1.Breadcrumbs; } });
6
+ Object.defineProperty(exports, "Breadcrumb", { enumerable: true, get: function () { return Breadcrumbs_1.Breadcrumb; } });
@@ -0,0 +1,42 @@
1
+ /**
2
+ * CodeBlock — a block of monospaced code on a subtle surface.
3
+ *
4
+ * Maps 1:1 to the Figma <CodeBlock> component (code-block):
5
+ * size → small | default | large (padding, gap, mono type scale)
6
+ *
7
+ * Renders code in JetBrains Mono via the mono font family. An optional header
8
+ * row shows a title/filename and a language tag; an optional copy button copies
9
+ * the code. Copy uses the web Clipboard API when available, so the package keeps
10
+ * zero dependencies, and always calls the `onCopy` callback so a native host can
11
+ * wire its own clipboard. Optional line numbers render in a muted gutter. Long
12
+ * lines scroll horizontally rather than wrapping.
13
+ *
14
+ * Colours: the surface is surface/subtle with the shared overlay border; code
15
+ * text is text/primary; the gutter, title, language tag, and copy icon use
16
+ * text/description. Tokens: code-block/{size}/{padding,gap} (density-varying)
17
+ * and a constant code-block/border-radius. Typography uses the body scale in the
18
+ * mono family, constant across densities. Fonts are consumer-loaded.
19
+ */
20
+ import { type StyleProp, type ViewStyle } from 'react-native';
21
+ export type CodeBlockSize = 'small' | 'default' | 'large';
22
+ export type CodeBlockProps = {
23
+ /** The code to display. Newlines split into lines. */
24
+ children: string;
25
+ /** Size variant — controls padding, gap, and the mono type scale. */
26
+ size?: CodeBlockSize;
27
+ /** Language tag shown in the header (e.g. "tsx"). Display only. */
28
+ language?: string;
29
+ /** Title/filename shown in the header. */
30
+ title?: string;
31
+ /** Show the copy button. Defaults to true. */
32
+ showCopy?: boolean;
33
+ /** Show a line-number gutter. Defaults to false. */
34
+ showLineNumbers?: boolean;
35
+ /** Called with the code when the copy button is pressed. */
36
+ onCopy?: (code: string) => void;
37
+ /** Outer style — use for positioning (margin, width, alignSelf). */
38
+ style?: StyleProp<ViewStyle>;
39
+ /** Accessibility label. */
40
+ accessibilityLabel?: string;
41
+ };
42
+ export declare function CodeBlock({ children, size, language, title, showCopy, showLineNumbers, onCopy, style, accessibilityLabel, }: CodeBlockProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,110 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CodeBlock = CodeBlock;
4
+ const jsx_runtime_1 = require("react/jsx-runtime");
5
+ /**
6
+ * CodeBlock — a block of monospaced code on a subtle surface.
7
+ *
8
+ * Maps 1:1 to the Figma <CodeBlock> component (code-block):
9
+ * size → small | default | large (padding, gap, mono type scale)
10
+ *
11
+ * Renders code in JetBrains Mono via the mono font family. An optional header
12
+ * row shows a title/filename and a language tag; an optional copy button copies
13
+ * the code. Copy uses the web Clipboard API when available, so the package keeps
14
+ * zero dependencies, and always calls the `onCopy` callback so a native host can
15
+ * wire its own clipboard. Optional line numbers render in a muted gutter. Long
16
+ * lines scroll horizontally rather than wrapping.
17
+ *
18
+ * Colours: the surface is surface/subtle with the shared overlay border; code
19
+ * text is text/primary; the gutter, title, language tag, and copy icon use
20
+ * text/description. Tokens: code-block/{size}/{padding,gap} (density-varying)
21
+ * and a constant code-block/border-radius. Typography uses the body scale in the
22
+ * mono family, constant across densities. Fonts are consumer-loaded.
23
+ */
24
+ const react_1 = require("react");
25
+ const react_native_1 = require("react-native");
26
+ const theme_1 = require("../../theme");
27
+ const tokens_1 = require("../../tokens");
28
+ const Icon_1 = require("../Icon");
29
+ // ---------------------------------------------------------------------------
30
+ // Constants
31
+ // ---------------------------------------------------------------------------
32
+ /** Maps size → body typography scale (rendered in the mono family). */
33
+ const MONO_SCALE = {
34
+ small: tokens_1.body.sm,
35
+ default: tokens_1.body.md,
36
+ large: tokens_1.body.lg,
37
+ };
38
+ /** How long the "copied" check stays visible. */
39
+ const COPIED_RESET_MS = 1500;
40
+ // ---------------------------------------------------------------------------
41
+ // Component
42
+ // ---------------------------------------------------------------------------
43
+ function CodeBlock({ children, size = 'default', language, title, showCopy = true, showLineNumbers = false, onCopy, style, accessibilityLabel, }) {
44
+ const { components, scheme } = (0, theme_1.useTheme)();
45
+ const tokens = components.codeBlock[size];
46
+ const radius = components.codeBlock.borderRadius;
47
+ const mono = MONO_SCALE[size];
48
+ const [copied, setCopied] = (0, react_1.useState)(false);
49
+ const handleCopy = (0, react_1.useCallback)(() => {
50
+ try {
51
+ if (typeof navigator !== 'undefined' &&
52
+ navigator.clipboard &&
53
+ typeof navigator.clipboard.writeText === 'function') {
54
+ navigator.clipboard.writeText(children);
55
+ }
56
+ }
57
+ catch {
58
+ // Clipboard unavailable (native / insecure context) — onCopy still fires.
59
+ }
60
+ onCopy?.(children);
61
+ setCopied(true);
62
+ setTimeout(() => setCopied(false), COPIED_RESET_MS);
63
+ }, [children, onCopy]);
64
+ const lines = children.split('\n');
65
+ const gutterDigits = String(lines.length).length;
66
+ const codeTextStyle = {
67
+ fontFamily: tokens_1.fontFamily.mono,
68
+ fontWeight: tokens_1.fontWeight.regular,
69
+ fontSize: mono.fontSize,
70
+ lineHeight: mono.lineHeight,
71
+ color: scheme.text.primary,
72
+ };
73
+ const showHeader = Boolean(title) || Boolean(language) || showCopy;
74
+ return ((0, jsx_runtime_1.jsxs)(react_native_1.View, { accessibilityLabel: accessibilityLabel || title || 'Code block', style: [
75
+ {
76
+ backgroundColor: scheme.surface.subtle,
77
+ borderWidth: 1,
78
+ borderColor: scheme.surface.overlay.border,
79
+ borderRadius: radius,
80
+ padding: tokens.padding,
81
+ gap: tokens.gap,
82
+ },
83
+ style,
84
+ ], children: [showHeader ? ((0, jsx_runtime_1.jsxs)(react_native_1.View, { style: {
85
+ flexDirection: 'row',
86
+ alignItems: 'center',
87
+ justifyContent: 'space-between',
88
+ gap: tokens.gap,
89
+ }, children: [(0, jsx_runtime_1.jsxs)(react_native_1.View, { style: { flexDirection: 'row', alignItems: 'center', gap: tokens.gap, flexShrink: 1 }, children: [title ? ((0, jsx_runtime_1.jsx)(react_native_1.Text, { numberOfLines: 1, style: {
90
+ fontFamily: tokens_1.fontFamily.mono,
91
+ fontWeight: tokens_1.fontWeight.medium,
92
+ fontSize: tokens_1.body.sm.fontSize,
93
+ lineHeight: tokens_1.body.sm.lineHeight,
94
+ color: scheme.text.description,
95
+ }, children: title })) : null, language ? ((0, jsx_runtime_1.jsx)(react_native_1.Text, { style: {
96
+ fontFamily: tokens_1.fontFamily.mono,
97
+ fontWeight: tokens_1.fontWeight.medium,
98
+ fontSize: tokens_1.caption.fontSize,
99
+ lineHeight: tokens_1.caption.lineHeight,
100
+ letterSpacing: tokens_1.caption.letterSpacing,
101
+ color: scheme.text.description,
102
+ textTransform: 'uppercase',
103
+ }, children: language })) : null] }), showCopy ? ((0, jsx_runtime_1.jsx)(react_native_1.Pressable, { onPress: handleCopy, accessibilityRole: "button", accessibilityLabel: copied ? 'Copied' : 'Copy code', hitSlop: 8, children: (0, jsx_runtime_1.jsx)(Icon_1.Icon, { name: copied ? 'check' : 'content_copy', size: "small", color: copied ? scheme.text.primary : scheme.text.description }) })) : null] })) : null, (0, jsx_runtime_1.jsx)(react_native_1.ScrollView, { horizontal: true, showsHorizontalScrollIndicator: false, bounces: false, children: showLineNumbers ? ((0, jsx_runtime_1.jsx)(react_native_1.View, { children: lines.map((line, i) => ((0, jsx_runtime_1.jsxs)(react_native_1.View, { style: { flexDirection: 'row' }, children: [(0, jsx_runtime_1.jsx)(react_native_1.Text, { selectable: false, style: {
104
+ ...codeTextStyle,
105
+ color: scheme.text.description,
106
+ textAlign: 'right',
107
+ minWidth: gutterDigits * (mono.fontSize * 0.62),
108
+ marginRight: tokens.gap,
109
+ }, children: String(i + 1) }), (0, jsx_runtime_1.jsx)(react_native_1.Text, { selectable: true, style: codeTextStyle, children: line.length ? line : ' ' })] }, i))) })) : ((0, jsx_runtime_1.jsx)(react_native_1.Text, { selectable: true, style: codeTextStyle, children: children })) })] }));
110
+ }
@@ -0,0 +1 @@
1
+ export { CodeBlock, type CodeBlockProps, type CodeBlockSize } from './CodeBlock';
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CodeBlock = void 0;
4
+ var CodeBlock_1 = require("./CodeBlock");
5
+ Object.defineProperty(exports, "CodeBlock", { enumerable: true, get: function () { return CodeBlock_1.CodeBlock; } });
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Drawer — a panel that slides in from an edge of the screen.
3
+ *
4
+ * Maps to the Figma <Drawer> component. Like BottomSheet, but anchored to any
5
+ * edge: left and right give a vertical side panel (default 320 wide, full
6
+ * height); top and bottom give a horizontal panel (full width, hugging content
7
+ * up to ~90% of the screen). Spacing (padding, gap) comes from the density
8
+ * theme. The panel is square (no corner radius), like a standard edge drawer,
9
+ * with a single border and shadow on the inner edge.
10
+ *
11
+ * Interaction model matches BottomSheet: slide in on open, slide out on close,
12
+ * the scrim fades with it. There is no finger dragging, so web and native behave
13
+ * the same. Dismiss by pressing the scrim (when enabled) or calling onClose.
14
+ *
15
+ * Structure: scrim backdrop -> panel (optional title + scrolling content). The
16
+ * panel surface reuses the shared overlay tokens; the scrim reuses
17
+ * overlay.scrimOpacity. Fonts are consumer-loaded (Inter).
18
+ *
19
+ * Exports:
20
+ * Drawer — full modal (scrim + animated panel)
21
+ * DrawerContent — just the panel, for inline use or static stories
22
+ */
23
+ import React from 'react';
24
+ import { type ViewStyle, type StyleProp } from 'react-native';
25
+ export type DrawerAnchor = 'left' | 'right' | 'top' | 'bottom';
26
+ export type DrawerContentProps = {
27
+ /** Which edge the panel is anchored to. Defaults to "left". */
28
+ anchor?: DrawerAnchor;
29
+ /** Heading shown above the content. Optional. */
30
+ title?: string;
31
+ /** Panel content. */
32
+ children?: React.ReactNode;
33
+ /** Style override for the panel (e.g. set a custom width). */
34
+ style?: StyleProp<ViewStyle>;
35
+ /** Accessibility label. Falls back to the title. */
36
+ accessibilityLabel?: string;
37
+ };
38
+ export type DrawerProps = DrawerContentProps & {
39
+ /** Controls visibility. */
40
+ open: boolean;
41
+ /** Called when the scrim is pressed or the panel requests close. */
42
+ onClose?: () => void;
43
+ /** Dismiss when the scrim is pressed. Defaults to true. */
44
+ closeOnBackdropPress?: boolean;
45
+ };
46
+ /**
47
+ * The panel rendered inline. No modal, no scrim, no animation. Use this for
48
+ * static display (Storybook visual stories) or custom overlay implementations.
49
+ */
50
+ export declare function DrawerContent({ anchor, title: titleText, children, style, accessibilityLabel, }: DrawerContentProps): import("react/jsx-runtime").JSX.Element;
51
+ export declare function Drawer({ open, onClose, closeOnBackdropPress, anchor, ...contentProps }: DrawerProps): import("react/jsx-runtime").JSX.Element | null;
@@ -0,0 +1,168 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DrawerContent = DrawerContent;
4
+ exports.Drawer = Drawer;
5
+ const jsx_runtime_1 = require("react/jsx-runtime");
6
+ /**
7
+ * Drawer — a panel that slides in from an edge of the screen.
8
+ *
9
+ * Maps to the Figma <Drawer> component. Like BottomSheet, but anchored to any
10
+ * edge: left and right give a vertical side panel (default 320 wide, full
11
+ * height); top and bottom give a horizontal panel (full width, hugging content
12
+ * up to ~90% of the screen). Spacing (padding, gap) comes from the density
13
+ * theme. The panel is square (no corner radius), like a standard edge drawer,
14
+ * with a single border and shadow on the inner edge.
15
+ *
16
+ * Interaction model matches BottomSheet: slide in on open, slide out on close,
17
+ * the scrim fades with it. There is no finger dragging, so web and native behave
18
+ * the same. Dismiss by pressing the scrim (when enabled) or calling onClose.
19
+ *
20
+ * Structure: scrim backdrop -> panel (optional title + scrolling content). The
21
+ * panel surface reuses the shared overlay tokens; the scrim reuses
22
+ * overlay.scrimOpacity. Fonts are consumer-loaded (Inter).
23
+ *
24
+ * Exports:
25
+ * Drawer — full modal (scrim + animated panel)
26
+ * DrawerContent — just the panel, for inline use or static stories
27
+ */
28
+ const react_1 = require("react");
29
+ const react_native_1 = require("react-native");
30
+ const theme_1 = require("../../theme");
31
+ const tokens_1 = require("../../tokens");
32
+ // ---------------------------------------------------------------------------
33
+ // Constants
34
+ // ---------------------------------------------------------------------------
35
+ /** Default width of a left/right panel. Override via `style`. */
36
+ const DEFAULT_WIDTH = 320;
37
+ /** Top/bottom panels never grow past this share of the screen height. */
38
+ const MAX_HEIGHT_RATIO = 0.9;
39
+ /** Animation timing. */
40
+ const DURATION = 240;
41
+ /** react-native-web does not support the native animation driver. */
42
+ const USE_NATIVE_DRIVER = react_native_1.Platform.OS !== 'web';
43
+ const SHADOW_WEB = {
44
+ boxShadow: '0px 0px 6px rgba(0,0,0,0.04), 0px 0px 15px rgba(0,0,0,0.08)',
45
+ };
46
+ const SHADOW_NATIVE = {
47
+ shadowColor: '#000000',
48
+ shadowOffset: { width: 0, height: 0 },
49
+ shadowOpacity: 0.12,
50
+ shadowRadius: 15,
51
+ elevation: 16,
52
+ };
53
+ const isHorizontal = (a) => a === 'left' || a === 'right';
54
+ // ---------------------------------------------------------------------------
55
+ // DrawerContent — the panel, without modal/scrim/animation
56
+ // ---------------------------------------------------------------------------
57
+ /**
58
+ * The panel rendered inline. No modal, no scrim, no animation. Use this for
59
+ * static display (Storybook visual stories) or custom overlay implementations.
60
+ */
61
+ function DrawerContent({ anchor = 'left', title: titleText, children, style, accessibilityLabel, }) {
62
+ const { components, scheme } = (0, theme_1.useTheme)();
63
+ const tokens = components.drawer;
64
+ const surface = scheme.surface;
65
+ const titleTokens = tokens_1.title.md;
66
+ const horizontal = isHorizontal(anchor);
67
+ // One border + shadow on the inner edge (the edge facing the content area).
68
+ const edgeBorder = anchor === 'left'
69
+ ? { borderRightWidth: 1 }
70
+ : anchor === 'right'
71
+ ? { borderLeftWidth: 1 }
72
+ : anchor === 'top'
73
+ ? { borderBottomWidth: 1 }
74
+ : { borderTopWidth: 1 };
75
+ const sizing = horizontal
76
+ ? { width: DEFAULT_WIDTH, maxWidth: '100%', height: '100%' }
77
+ : { width: '100%', maxHeight: `${MAX_HEIGHT_RATIO * 100}%` };
78
+ return ((0, jsx_runtime_1.jsx)(react_native_1.View, { accessibilityViewIsModal: true, accessibilityLabel: accessibilityLabel || titleText, style: [
79
+ {
80
+ backgroundColor: surface.overlay.bg,
81
+ borderColor: surface.overlay.border,
82
+ ...edgeBorder,
83
+ padding: tokens.padding,
84
+ ...(react_native_1.Platform.OS === 'web' ? SHADOW_WEB : SHADOW_NATIVE),
85
+ },
86
+ sizing,
87
+ style,
88
+ ], children: (0, jsx_runtime_1.jsxs)(react_native_1.ScrollView, { bounces: false, showsVerticalScrollIndicator: false, contentContainerStyle: { gap: tokens.gap }, style: { flexGrow: 0, flexShrink: 1 }, children: [titleText ? ((0, jsx_runtime_1.jsx)(react_native_1.Text, { accessibilityRole: "header", style: {
89
+ fontFamily: tokens_1.fontFamily.sans,
90
+ fontWeight: tokens_1.fontWeight.medium,
91
+ fontSize: titleTokens.fontSize,
92
+ lineHeight: titleTokens.lineHeight,
93
+ letterSpacing: titleTokens.letterSpacing,
94
+ color: scheme.text.primary,
95
+ }, children: titleText })) : null, children] }) }));
96
+ }
97
+ // ---------------------------------------------------------------------------
98
+ // Drawer — full modal with scrim and slide animation
99
+ // ---------------------------------------------------------------------------
100
+ function Drawer({ open, onClose, closeOnBackdropPress = true, anchor = 'left', ...contentProps }) {
101
+ const { scheme } = (0, theme_1.useTheme)();
102
+ const scrimOpacity = scheme.overlay.scrimOpacity;
103
+ const screen = react_native_1.Dimensions.get('window');
104
+ const horizontal = isHorizontal(anchor);
105
+ const distance = horizontal ? screen.width : screen.height;
106
+ const sign = anchor === 'left' || anchor === 'top' ? -1 : 1;
107
+ const offset = (0, react_1.useRef)(new react_native_1.Animated.Value(distance * sign)).current;
108
+ const backdrop = (0, react_1.useRef)(new react_native_1.Animated.Value(0)).current;
109
+ const [mounted, setMounted] = (0, react_1.useState)(open);
110
+ (0, react_1.useEffect)(() => {
111
+ if (open) {
112
+ setMounted(true);
113
+ react_native_1.Animated.parallel([
114
+ react_native_1.Animated.timing(backdrop, {
115
+ toValue: 1,
116
+ duration: DURATION,
117
+ useNativeDriver: USE_NATIVE_DRIVER,
118
+ }),
119
+ react_native_1.Animated.spring(offset, {
120
+ toValue: 0,
121
+ damping: 24,
122
+ stiffness: 240,
123
+ mass: 0.9,
124
+ useNativeDriver: USE_NATIVE_DRIVER,
125
+ }),
126
+ ]).start();
127
+ }
128
+ else if (mounted) {
129
+ react_native_1.Animated.parallel([
130
+ react_native_1.Animated.timing(backdrop, {
131
+ toValue: 0,
132
+ duration: DURATION,
133
+ useNativeDriver: USE_NATIVE_DRIVER,
134
+ }),
135
+ react_native_1.Animated.timing(offset, {
136
+ toValue: distance * sign,
137
+ duration: DURATION,
138
+ useNativeDriver: USE_NATIVE_DRIVER,
139
+ }),
140
+ ]).start(({ finished }) => {
141
+ if (finished)
142
+ setMounted(false);
143
+ });
144
+ }
145
+ // eslint-disable-next-line react-hooks/exhaustive-deps
146
+ }, [open]);
147
+ if (!mounted)
148
+ return null;
149
+ const rootAlign = horizontal
150
+ ? { flexDirection: 'row', justifyContent: anchor === 'left' ? 'flex-start' : 'flex-end' }
151
+ : { flexDirection: 'column', justifyContent: anchor === 'top' ? 'flex-start' : 'flex-end' };
152
+ const transform = horizontal ? [{ translateX: offset }] : [{ translateY: offset }];
153
+ return ((0, jsx_runtime_1.jsx)(react_native_1.Modal, { visible: mounted, transparent: true, animationType: "none", onRequestClose: onClose, children: (0, jsx_runtime_1.jsxs)(react_native_1.View, { style: { flex: 1, ...rootAlign }, children: [(0, jsx_runtime_1.jsx)(react_native_1.Animated.View, { style: {
154
+ position: 'absolute',
155
+ top: 0,
156
+ left: 0,
157
+ right: 0,
158
+ bottom: 0,
159
+ backgroundColor: '#000000',
160
+ opacity: backdrop.interpolate({
161
+ inputRange: [0, 1],
162
+ outputRange: [0, scrimOpacity],
163
+ }),
164
+ }, children: (0, jsx_runtime_1.jsx)(react_native_1.Pressable, { style: { flex: 1 }, disabled: !closeOnBackdropPress, onPress: closeOnBackdropPress ? onClose : undefined, accessibilityRole: "button", accessibilityLabel: "Close drawer" }) }), (0, jsx_runtime_1.jsx)(react_native_1.Animated.View, { style: {
165
+ transform,
166
+ ...(horizontal ? { height: '100%' } : { width: '100%' }),
167
+ }, children: (0, jsx_runtime_1.jsx)(DrawerContent, { anchor: anchor, ...contentProps }) })] }) }));
168
+ }
@@ -0,0 +1 @@
1
+ export { Drawer, DrawerContent, type DrawerProps, type DrawerContentProps, type DrawerAnchor, } from './Drawer';
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DrawerContent = exports.Drawer = void 0;
4
+ var Drawer_1 = require("./Drawer");
5
+ Object.defineProperty(exports, "Drawer", { enumerable: true, get: function () { return Drawer_1.Drawer; } });
6
+ Object.defineProperty(exports, "DrawerContent", { enumerable: true, get: function () { return Drawer_1.DrawerContent; } });