@titan-design/react-ui 0.0.2 → 0.1.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/dist/{chunk-NA3EES23.mjs → chunk-MGW37MPO.mjs} +26 -4
- package/dist/chunk-MGW37MPO.mjs.map +1 -0
- package/dist/index.d.mts +115 -2
- package/dist/index.d.ts +115 -2
- package/dist/index.js +262 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +225 -3
- package/dist/index.mjs.map +1 -1
- package/dist/theme/index.d.mts +124 -109
- package/dist/theme/index.d.ts +124 -109
- package/dist/theme/index.js +24 -1
- package/dist/theme/index.js.map +1 -1
- package/dist/theme/index.mjs +1 -1
- package/package.json +12 -5
- package/src/components/custom/DateTime/DateTime.stories.tsx +180 -0
- package/src/components/custom/DateTime/DateTime.test.tsx +152 -0
- package/src/components/custom/DateTime/DateTime.tsx +235 -0
- package/src/components/custom/DateTime/index.ts +2 -0
- package/src/components/custom/EmptyState/EmptyState.stories.tsx +99 -0
- package/src/components/custom/EmptyState/EmptyState.test.tsx +106 -0
- package/src/components/custom/EmptyState/EmptyState.tsx +68 -0
- package/src/components/custom/EmptyState/index.ts +2 -0
- package/src/components/custom/Metric/Metric.stories.tsx +133 -0
- package/src/components/custom/Metric/Metric.test.tsx +120 -0
- package/src/components/custom/Metric/Metric.tsx +92 -0
- package/src/components/custom/Metric/index.ts +2 -0
- package/src/components/custom/Sidebar/Sidebar.stories.tsx +227 -0
- package/src/components/custom/Sidebar/Sidebar.test.tsx +185 -0
- package/src/components/custom/Sidebar/Sidebar.tsx +257 -0
- package/src/components/custom/Sidebar/index.ts +18 -0
- package/src/components/custom/Table/Table.stories.tsx +481 -0
- package/src/components/custom/Table/Table.test.tsx +531 -0
- package/src/components/custom/Table/Table.tsx +696 -0
- package/src/components/custom/Table/index.ts +22 -0
- package/src/components/custom/Typography/Typography.stories.tsx +153 -0
- package/src/components/custom/Typography/Typography.test.tsx +107 -0
- package/src/components/custom/Typography/Typography.tsx +218 -0
- package/src/components/custom/Typography/index.ts +19 -0
- package/src/components/custom/index.ts +8 -0
- package/src/components/custom/stepper/Stepper.stories.tsx +245 -0
- package/src/components/custom/stepper/Stepper.test.tsx +230 -0
- package/src/components/custom/stepper/Stepper.tsx +250 -0
- package/src/components/custom/stepper/index.ts +10 -0
- package/src/components/index.ts +5 -0
- package/src/components/ui/alert/Alert.stories.tsx +154 -0
- package/src/components/ui/alert/Alert.test.tsx +202 -0
- package/src/components/ui/alert/Alert.tsx +170 -0
- package/src/components/ui/alert/index.ts +8 -0
- package/src/components/ui/autocomplete/Autocomplete.stories.tsx +299 -0
- package/src/components/ui/autocomplete/Autocomplete.test.tsx +247 -0
- package/src/components/ui/autocomplete/Autocomplete.tsx +332 -0
- package/src/components/ui/autocomplete/index.ts +2 -0
- package/src/components/ui/avatar/Avatar.stories.tsx +105 -0
- package/src/components/ui/avatar/Avatar.test.tsx +135 -0
- package/src/components/ui/avatar/Avatar.tsx +168 -0
- package/src/components/ui/avatar/index.ts +2 -0
- package/src/components/ui/badge/Badge.stories.tsx +100 -0
- package/src/components/ui/badge/Badge.test.tsx +86 -0
- package/src/components/ui/badge/Badge.tsx +105 -0
- package/src/components/ui/badge/index.ts +2 -0
- package/src/components/ui/breadcrumbs/Breadcrumbs.stories.tsx +70 -0
- package/src/components/ui/breadcrumbs/Breadcrumbs.test.tsx +156 -0
- package/src/components/ui/breadcrumbs/Breadcrumbs.tsx +127 -0
- package/src/components/ui/breadcrumbs/index.ts +2 -0
- package/src/components/ui/button/Button.stories.tsx +216 -0
- package/src/components/ui/button/Button.test.tsx +132 -0
- package/src/components/ui/button/Button.tsx +242 -0
- package/src/components/ui/button/index.ts +10 -0
- package/src/components/ui/card/Card.stories.tsx +443 -0
- package/src/components/ui/card/Card.test.tsx +265 -0
- package/src/components/ui/card/Card.tsx +380 -0
- package/src/components/ui/card/index.ts +20 -0
- package/src/components/ui/checkbox/Checkbox.stories.tsx +126 -0
- package/src/components/ui/checkbox/Checkbox.test.tsx +152 -0
- package/src/components/ui/checkbox/Checkbox.tsx +163 -0
- package/src/components/ui/checkbox/index.ts +2 -0
- package/src/components/ui/chip/Chip.stories.tsx +112 -0
- package/src/components/ui/chip/Chip.test.tsx +119 -0
- package/src/components/ui/chip/Chip.tsx +151 -0
- package/src/components/ui/chip/index.ts +2 -0
- package/src/components/ui/collapse/Collapse.stories.tsx +313 -0
- package/src/components/ui/collapse/Collapse.test.tsx +298 -0
- package/src/components/ui/collapse/Collapse.tsx +275 -0
- package/src/components/ui/collapse/index.ts +18 -0
- package/src/components/ui/data-row/DataRow.stories.tsx +78 -0
- package/src/components/ui/data-row/DataRow.test.tsx +78 -0
- package/src/components/ui/data-row/DataRow.tsx +29 -0
- package/src/components/ui/data-row/index.ts +2 -0
- package/src/components/ui/divider/Divider.stories.tsx +71 -0
- package/src/components/ui/divider/Divider.test.tsx +55 -0
- package/src/components/ui/divider/Divider.tsx +37 -0
- package/src/components/ui/divider/index.ts +2 -0
- package/src/components/ui/drawer/Drawer.stories.tsx +228 -0
- package/src/components/ui/drawer/Drawer.test.tsx +142 -0
- package/src/components/ui/drawer/Drawer.tsx +228 -0
- package/src/components/ui/drawer/index.ts +9 -0
- package/src/components/ui/form-field/FormField.stories.tsx +260 -0
- package/src/components/ui/form-field/FormField.test.tsx +280 -0
- package/src/components/ui/form-field/FormField.tsx +308 -0
- package/src/components/ui/form-field/index.ts +2 -0
- package/src/components/ui/help-tip/HelpTip.stories.tsx +250 -0
- package/src/components/ui/help-tip/HelpTip.test.tsx +198 -0
- package/src/components/ui/help-tip/HelpTip.tsx +229 -0
- package/src/components/ui/help-tip/index.ts +2 -0
- package/src/components/ui/icon-box/IconBox.stories.tsx +139 -0
- package/src/components/ui/icon-box/IconBox.test.tsx +120 -0
- package/src/components/ui/icon-box/IconBox.tsx +57 -0
- package/src/components/ui/icon-box/index.ts +1 -0
- package/src/components/ui/index.ts +36 -0
- package/src/components/ui/input/Input.stories.tsx +192 -0
- package/src/components/ui/input/Input.test.tsx +86 -0
- package/src/components/ui/input/Input.tsx +273 -0
- package/src/components/ui/input/index.ts +2 -0
- package/src/components/ui/link/Link.stories.tsx +78 -0
- package/src/components/ui/link/Link.test.tsx +94 -0
- package/src/components/ui/link/Link.tsx +86 -0
- package/src/components/ui/link/index.ts +2 -0
- package/src/components/ui/list-item/ListItem.stories.tsx +146 -0
- package/src/components/ui/list-item/ListItem.test.tsx +128 -0
- package/src/components/ui/list-item/ListItem.tsx +89 -0
- package/src/components/ui/list-item/index.ts +14 -0
- package/src/components/ui/menu/Menu.stories.tsx +180 -0
- package/src/components/ui/menu/Menu.test.tsx +353 -0
- package/src/components/ui/menu/Menu.tsx +222 -0
- package/src/components/ui/menu/index.ts +2 -0
- package/src/components/ui/modal/Modal.stories.tsx +350 -0
- package/src/components/ui/modal/Modal.test.tsx +159 -0
- package/src/components/ui/modal/Modal.tsx +254 -0
- package/src/components/ui/modal/index.ts +19 -0
- package/src/components/ui/popover/Popover.stories.tsx +190 -0
- package/src/components/ui/popover/Popover.test.tsx +277 -0
- package/src/components/ui/popover/Popover.tsx +162 -0
- package/src/components/ui/popover/index.ts +2 -0
- package/src/components/ui/progress/Progress.stories.tsx +190 -0
- package/src/components/ui/progress/Progress.test.tsx +181 -0
- package/src/components/ui/progress/Progress.tsx +320 -0
- package/src/components/ui/progress/index.ts +9 -0
- package/src/components/ui/radio/Radio.stories.tsx +199 -0
- package/src/components/ui/radio/Radio.test.tsx +166 -0
- package/src/components/ui/radio/Radio.tsx +200 -0
- package/src/components/ui/radio/index.ts +2 -0
- package/src/components/ui/section/Section.stories.tsx +111 -0
- package/src/components/ui/section/Section.test.tsx +121 -0
- package/src/components/ui/section/Section.tsx +52 -0
- package/src/components/ui/section/index.ts +6 -0
- package/src/components/ui/select/Select.stories.tsx +286 -0
- package/src/components/ui/select/Select.test.tsx +180 -0
- package/src/components/ui/select/Select.tsx +236 -0
- package/src/components/ui/select/index.ts +2 -0
- package/src/components/ui/skeleton/Skeleton.stories.tsx +153 -0
- package/src/components/ui/skeleton/Skeleton.test.tsx +162 -0
- package/src/components/ui/skeleton/Skeleton.tsx +229 -0
- package/src/components/ui/skeleton/index.ts +16 -0
- package/src/components/ui/spinner/Spinner.stories.tsx +67 -0
- package/src/components/ui/spinner/Spinner.test.tsx +67 -0
- package/src/components/ui/spinner/Spinner.tsx +72 -0
- package/src/components/ui/spinner/index.ts +2 -0
- package/src/components/ui/stack/Stack.stories.tsx +127 -0
- package/src/components/ui/stack/Stack.test.tsx +184 -0
- package/src/components/ui/stack/Stack.tsx +76 -0
- package/src/components/ui/stack/index.ts +2 -0
- package/src/components/ui/surface/Surface.stories.tsx +91 -0
- package/src/components/ui/surface/Surface.test.tsx +63 -0
- package/src/components/ui/surface/Surface.tsx +51 -0
- package/src/components/ui/surface/index.ts +1 -0
- package/src/components/ui/switch/Switch.stories.tsx +111 -0
- package/src/components/ui/switch/Switch.test.tsx +112 -0
- package/src/components/ui/switch/Switch.tsx +103 -0
- package/src/components/ui/switch/index.ts +2 -0
- package/src/components/ui/tabs/Tabs.stories.tsx +213 -0
- package/src/components/ui/tabs/Tabs.test.tsx +192 -0
- package/src/components/ui/tabs/Tabs.tsx +253 -0
- package/src/components/ui/tabs/index.ts +16 -0
- package/src/components/ui/toast/Toast.stories.tsx +255 -0
- package/src/components/ui/toast/Toast.test.tsx +207 -0
- package/src/components/ui/toast/Toast.tsx +327 -0
- package/src/components/ui/toast/index.ts +8 -0
- package/src/components/ui/toolbar-button/ToolbarButton.stories.tsx +415 -0
- package/src/components/ui/toolbar-button/ToolbarButton.test.tsx +224 -0
- package/src/components/ui/toolbar-button/ToolbarButton.tsx +307 -0
- package/src/components/ui/toolbar-button/index.ts +7 -0
- package/src/components/ui/tooltip/Tooltip.stories.tsx +126 -0
- package/src/components/ui/tooltip/Tooltip.test.tsx +179 -0
- package/src/components/ui/tooltip/Tooltip.tsx +143 -0
- package/src/components/ui/tooltip/index.ts +2 -0
- package/src/index.ts +10 -0
- package/src/test/setup.ts +19 -0
- package/src/theme/Colors.stories.tsx +258 -0
- package/src/theme/config.ts +193 -0
- package/src/theme/elevation.stories.tsx +346 -0
- package/src/theme/elevation.test.ts +27 -0
- package/src/theme/elevation.ts +567 -0
- package/src/theme/index.ts +39 -0
- package/src/theme/shadows.stories.tsx +523 -0
- package/src/theme/shadows.ts +439 -0
- package/src/theme/tokens/index.ts +2 -0
- package/src/theme/tokens/primitives.ts +354 -0
- package/src/theme/tokens/semantic.ts +381 -0
- package/src/types/jest-axe.d.ts +16 -0
- package/src/types/nativewind.d.ts +54 -0
- package/src/utils/cn.ts +14 -0
- package/src/utils/colors.ts +140 -0
- package/src/utils/form.ts +188 -0
- package/src/utils/index.ts +29 -0
- package/src/utils/useTheme.ts +72 -0
- package/dist/chunk-NA3EES23.mjs.map +0 -1
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import { View, Text, Pressable, type ViewProps } from 'react-native'
|
|
3
|
+
import { cn } from '../../../utils/cn'
|
|
4
|
+
|
|
5
|
+
export type ChipVariant = 'solid' | 'subtle' | 'outline'
|
|
6
|
+
export type ChipColor = 'default' | 'primary' | 'secondary' | 'success' | 'error' | 'warning' | 'info'
|
|
7
|
+
export type ChipSize = 'sm' | 'md' | 'lg'
|
|
8
|
+
|
|
9
|
+
export interface ChipProps extends ViewProps {
|
|
10
|
+
/** Visual variant */
|
|
11
|
+
variant?: ChipVariant
|
|
12
|
+
/** Color scheme */
|
|
13
|
+
color?: ChipColor
|
|
14
|
+
/** Size */
|
|
15
|
+
size?: ChipSize
|
|
16
|
+
/** Left element (icon, avatar) */
|
|
17
|
+
leftElement?: React.ReactNode
|
|
18
|
+
/** Whether the chip is dismissible */
|
|
19
|
+
onDelete?: () => void
|
|
20
|
+
/** Whether the chip is clickable */
|
|
21
|
+
onPress?: () => void
|
|
22
|
+
/** Whether the chip is disabled */
|
|
23
|
+
isDisabled?: boolean
|
|
24
|
+
/** Additional className */
|
|
25
|
+
className?: string
|
|
26
|
+
children?: React.ReactNode
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const colorStyles: Record<ChipColor, Record<ChipVariant, string>> = {
|
|
30
|
+
default: {
|
|
31
|
+
solid: 'bg-neutral-600 text-white',
|
|
32
|
+
subtle: 'bg-neutral-100 text-neutral-700 dark:bg-neutral-800 dark:text-neutral-200',
|
|
33
|
+
outline: 'border border-neutral-300 dark:border-neutral-600 text-neutral-700 dark:text-neutral-200',
|
|
34
|
+
},
|
|
35
|
+
primary: {
|
|
36
|
+
solid: 'bg-brand-primary text-white',
|
|
37
|
+
subtle: 'bg-brand-primary-subtle text-brand-primary',
|
|
38
|
+
outline: 'border border-brand-primary text-brand-primary',
|
|
39
|
+
},
|
|
40
|
+
secondary: {
|
|
41
|
+
solid: 'bg-brand-secondary text-white',
|
|
42
|
+
subtle: 'bg-brand-secondary-subtle text-brand-secondary',
|
|
43
|
+
outline: 'border border-brand-secondary text-brand-secondary',
|
|
44
|
+
},
|
|
45
|
+
success: {
|
|
46
|
+
solid: 'bg-status-success text-white',
|
|
47
|
+
subtle: 'bg-status-success-subtle text-status-success',
|
|
48
|
+
outline: 'border border-status-success text-status-success',
|
|
49
|
+
},
|
|
50
|
+
error: {
|
|
51
|
+
solid: 'bg-status-error text-white',
|
|
52
|
+
subtle: 'bg-status-error-subtle text-status-error',
|
|
53
|
+
outline: 'border border-status-error text-status-error',
|
|
54
|
+
},
|
|
55
|
+
warning: {
|
|
56
|
+
solid: 'bg-status-warning text-white',
|
|
57
|
+
subtle: 'bg-status-warning-subtle text-status-warning',
|
|
58
|
+
outline: 'border border-status-warning text-status-warning',
|
|
59
|
+
},
|
|
60
|
+
info: {
|
|
61
|
+
solid: 'bg-status-info text-white',
|
|
62
|
+
subtle: 'bg-status-info-subtle text-status-info',
|
|
63
|
+
outline: 'border border-status-info text-status-info',
|
|
64
|
+
},
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const sizeStyles: Record<ChipSize, { container: string; text: string; deleteButton: string }> = {
|
|
68
|
+
sm: { container: 'px-2 py-0.5 rounded', text: 'text-xs', deleteButton: 'ml-1 -mr-0.5' },
|
|
69
|
+
md: { container: 'px-3 py-1 rounded-md', text: 'text-sm', deleteButton: 'ml-1.5 -mr-1' },
|
|
70
|
+
lg: { container: 'px-4 py-1.5 rounded-md', text: 'text-base', deleteButton: 'ml-2 -mr-1' },
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Chip component for tags, labels, and filters.
|
|
75
|
+
*
|
|
76
|
+
* @example
|
|
77
|
+
* <Chip>Default</Chip>
|
|
78
|
+
* <Chip color="primary" variant="subtle">Primary Subtle</Chip>
|
|
79
|
+
* <Chip onDelete={() => {}}>Dismissible</Chip>
|
|
80
|
+
* <Chip onPress={() => {}}>Clickable</Chip>
|
|
81
|
+
*/
|
|
82
|
+
export function Chip({
|
|
83
|
+
variant = 'subtle',
|
|
84
|
+
color = 'default',
|
|
85
|
+
size = 'md',
|
|
86
|
+
leftElement,
|
|
87
|
+
onDelete,
|
|
88
|
+
onPress,
|
|
89
|
+
isDisabled = false,
|
|
90
|
+
className,
|
|
91
|
+
children,
|
|
92
|
+
...props
|
|
93
|
+
}: ChipProps) {
|
|
94
|
+
const sizes = sizeStyles[size]
|
|
95
|
+
const isClickable = !!onPress
|
|
96
|
+
|
|
97
|
+
const content = (
|
|
98
|
+
<>
|
|
99
|
+
{leftElement && <View className="mr-1.5">{leftElement}</View>}
|
|
100
|
+
<Text className={cn('font-medium', sizes.text)}>
|
|
101
|
+
{children}
|
|
102
|
+
</Text>
|
|
103
|
+
{onDelete && (
|
|
104
|
+
<Pressable
|
|
105
|
+
onPress={(e) => {
|
|
106
|
+
e.stopPropagation?.()
|
|
107
|
+
onDelete()
|
|
108
|
+
}}
|
|
109
|
+
accessibilityRole="button"
|
|
110
|
+
accessibilityLabel="Remove"
|
|
111
|
+
disabled={isDisabled}
|
|
112
|
+
className={cn(
|
|
113
|
+
sizes.deleteButton,
|
|
114
|
+
'rounded-full p-0.5 web:hover:bg-black/10 active:bg-black/20'
|
|
115
|
+
)}
|
|
116
|
+
>
|
|
117
|
+
<Text className="text-xs leading-none">×</Text>
|
|
118
|
+
</Pressable>
|
|
119
|
+
)}
|
|
120
|
+
</>
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
const baseClassName = cn(
|
|
124
|
+
'flex-row items-center',
|
|
125
|
+
sizes.container,
|
|
126
|
+
colorStyles[color][variant],
|
|
127
|
+
isClickable && 'web:cursor-pointer web:hover:opacity-80 active:opacity-70',
|
|
128
|
+
isDisabled && 'opacity-50 cursor-not-allowed',
|
|
129
|
+
className
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
if (isClickable) {
|
|
133
|
+
return (
|
|
134
|
+
<Pressable
|
|
135
|
+
onPress={onPress}
|
|
136
|
+
disabled={isDisabled}
|
|
137
|
+
accessibilityRole="button"
|
|
138
|
+
className={baseClassName}
|
|
139
|
+
{...props}
|
|
140
|
+
>
|
|
141
|
+
{content}
|
|
142
|
+
</Pressable>
|
|
143
|
+
)
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
return (
|
|
147
|
+
<View className={baseClassName} {...props}>
|
|
148
|
+
{content}
|
|
149
|
+
</View>
|
|
150
|
+
)
|
|
151
|
+
}
|
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
import React, { useState } from 'react'
|
|
2
|
+
import type { Meta, StoryObj } from '@storybook/react-vite'
|
|
3
|
+
import { View, Text } from 'react-native'
|
|
4
|
+
import {
|
|
5
|
+
Collapse,
|
|
6
|
+
CollapseButton,
|
|
7
|
+
CollapseContent,
|
|
8
|
+
Accordion,
|
|
9
|
+
AccordionItem,
|
|
10
|
+
AccordionButton,
|
|
11
|
+
AccordionPanel,
|
|
12
|
+
} from './Collapse'
|
|
13
|
+
|
|
14
|
+
const meta: Meta<typeof Accordion> = {
|
|
15
|
+
title: 'Components/Accordion',
|
|
16
|
+
component: Accordion,
|
|
17
|
+
tags: ['autodocs'],
|
|
18
|
+
argTypes: {
|
|
19
|
+
allowMultiple: {
|
|
20
|
+
control: 'boolean',
|
|
21
|
+
description: 'Allow multiple items to be open simultaneously',
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export default meta
|
|
27
|
+
type Story = StoryObj<typeof Accordion>
|
|
28
|
+
|
|
29
|
+
export const Default: Story = {
|
|
30
|
+
render: () => (
|
|
31
|
+
<View style={{ width: 400 }}>
|
|
32
|
+
<Accordion>
|
|
33
|
+
<AccordionItem>
|
|
34
|
+
<AccordionButton>What is Titan Design?</AccordionButton>
|
|
35
|
+
<AccordionPanel>
|
|
36
|
+
<Text className="text-text-secondary text-sm">
|
|
37
|
+
Titan Design is a cross-platform React and React Native design system built on
|
|
38
|
+
Gluestack UI, NativeWind v4, and Tailwind CSS.
|
|
39
|
+
</Text>
|
|
40
|
+
</AccordionPanel>
|
|
41
|
+
</AccordionItem>
|
|
42
|
+
<AccordionItem>
|
|
43
|
+
<AccordionButton>How do I install it?</AccordionButton>
|
|
44
|
+
<AccordionPanel>
|
|
45
|
+
<Text className="text-text-secondary text-sm">
|
|
46
|
+
Install via pnpm: pnpm add @titan-design/react-ui. Then import the global CSS and
|
|
47
|
+
components as needed.
|
|
48
|
+
</Text>
|
|
49
|
+
</AccordionPanel>
|
|
50
|
+
</AccordionItem>
|
|
51
|
+
<AccordionItem>
|
|
52
|
+
<AccordionButton>Is it accessible?</AccordionButton>
|
|
53
|
+
<AccordionPanel>
|
|
54
|
+
<Text className="text-text-secondary text-sm">
|
|
55
|
+
Yes, all components are built with WCAG 2.1 AA compliance in mind and tested with
|
|
56
|
+
jest-axe for accessibility violations.
|
|
57
|
+
</Text>
|
|
58
|
+
</AccordionPanel>
|
|
59
|
+
</AccordionItem>
|
|
60
|
+
</Accordion>
|
|
61
|
+
</View>
|
|
62
|
+
),
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export const AllowMultiple: Story = {
|
|
66
|
+
render: () => (
|
|
67
|
+
<View style={{ width: 400 }}>
|
|
68
|
+
<Accordion allowMultiple>
|
|
69
|
+
<AccordionItem>
|
|
70
|
+
<AccordionButton>Section One</AccordionButton>
|
|
71
|
+
<AccordionPanel>
|
|
72
|
+
<Text className="text-text-secondary text-sm">
|
|
73
|
+
With allowMultiple enabled, you can open multiple accordion items at the same time.
|
|
74
|
+
Try opening this and another section.
|
|
75
|
+
</Text>
|
|
76
|
+
</AccordionPanel>
|
|
77
|
+
</AccordionItem>
|
|
78
|
+
<AccordionItem>
|
|
79
|
+
<AccordionButton>Section Two</AccordionButton>
|
|
80
|
+
<AccordionPanel>
|
|
81
|
+
<Text className="text-text-secondary text-sm">
|
|
82
|
+
This section can be open alongside Section One. In single mode, opening a new
|
|
83
|
+
section would close any previously open one.
|
|
84
|
+
</Text>
|
|
85
|
+
</AccordionPanel>
|
|
86
|
+
</AccordionItem>
|
|
87
|
+
<AccordionItem>
|
|
88
|
+
<AccordionButton>Section Three</AccordionButton>
|
|
89
|
+
<AccordionPanel>
|
|
90
|
+
<Text className="text-text-secondary text-sm">
|
|
91
|
+
All three sections can be expanded simultaneously when allowMultiple is true.
|
|
92
|
+
</Text>
|
|
93
|
+
</AccordionPanel>
|
|
94
|
+
</AccordionItem>
|
|
95
|
+
</Accordion>
|
|
96
|
+
</View>
|
|
97
|
+
),
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export const DefaultOpen: Story = {
|
|
101
|
+
render: () => (
|
|
102
|
+
<View style={{ width: 400 }}>
|
|
103
|
+
<Accordion defaultIndex={[0]}>
|
|
104
|
+
<AccordionItem>
|
|
105
|
+
<AccordionButton>Initially Open</AccordionButton>
|
|
106
|
+
<AccordionPanel>
|
|
107
|
+
<Text className="text-text-secondary text-sm">
|
|
108
|
+
This section is open by default using defaultIndex=[0]. The user can close it by
|
|
109
|
+
clicking the header.
|
|
110
|
+
</Text>
|
|
111
|
+
</AccordionPanel>
|
|
112
|
+
</AccordionItem>
|
|
113
|
+
<AccordionItem>
|
|
114
|
+
<AccordionButton>Initially Closed</AccordionButton>
|
|
115
|
+
<AccordionPanel>
|
|
116
|
+
<Text className="text-text-secondary text-sm">
|
|
117
|
+
This section starts closed and opens when the user clicks on it.
|
|
118
|
+
</Text>
|
|
119
|
+
</AccordionPanel>
|
|
120
|
+
</AccordionItem>
|
|
121
|
+
<AccordionItem>
|
|
122
|
+
<AccordionButton>Also Closed</AccordionButton>
|
|
123
|
+
<AccordionPanel>
|
|
124
|
+
<Text className="text-text-secondary text-sm">
|
|
125
|
+
Another closed section.
|
|
126
|
+
</Text>
|
|
127
|
+
</AccordionPanel>
|
|
128
|
+
</AccordionItem>
|
|
129
|
+
</Accordion>
|
|
130
|
+
</View>
|
|
131
|
+
),
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export const MultipleDefaultOpen: Story = {
|
|
135
|
+
render: () => (
|
|
136
|
+
<View style={{ width: 400 }}>
|
|
137
|
+
<Accordion allowMultiple defaultIndex={[0, 2]}>
|
|
138
|
+
<AccordionItem>
|
|
139
|
+
<AccordionButton>First (Open)</AccordionButton>
|
|
140
|
+
<AccordionPanel>
|
|
141
|
+
<Text className="text-text-secondary text-sm">
|
|
142
|
+
This section starts open via defaultIndex.
|
|
143
|
+
</Text>
|
|
144
|
+
</AccordionPanel>
|
|
145
|
+
</AccordionItem>
|
|
146
|
+
<AccordionItem>
|
|
147
|
+
<AccordionButton>Second (Closed)</AccordionButton>
|
|
148
|
+
<AccordionPanel>
|
|
149
|
+
<Text className="text-text-secondary text-sm">
|
|
150
|
+
This section starts closed.
|
|
151
|
+
</Text>
|
|
152
|
+
</AccordionPanel>
|
|
153
|
+
</AccordionItem>
|
|
154
|
+
<AccordionItem>
|
|
155
|
+
<AccordionButton>Third (Open)</AccordionButton>
|
|
156
|
+
<AccordionPanel>
|
|
157
|
+
<Text className="text-text-secondary text-sm">
|
|
158
|
+
This section also starts open via defaultIndex.
|
|
159
|
+
</Text>
|
|
160
|
+
</AccordionPanel>
|
|
161
|
+
</AccordionItem>
|
|
162
|
+
</Accordion>
|
|
163
|
+
</View>
|
|
164
|
+
),
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
export const WithRichContent: Story = {
|
|
168
|
+
render: () => (
|
|
169
|
+
<View style={{ width: 400 }}>
|
|
170
|
+
<Accordion allowMultiple>
|
|
171
|
+
<AccordionItem>
|
|
172
|
+
<AccordionButton>Pricing Details</AccordionButton>
|
|
173
|
+
<AccordionPanel>
|
|
174
|
+
<View style={{ gap: 8 }}>
|
|
175
|
+
<View style={{ flexDirection: 'row', justifyContent: 'space-between' }}>
|
|
176
|
+
<Text className="text-text-primary text-sm">Base plan</Text>
|
|
177
|
+
<Text className="text-text-primary text-sm font-semibold">$29/mo</Text>
|
|
178
|
+
</View>
|
|
179
|
+
<View style={{ flexDirection: 'row', justifyContent: 'space-between' }}>
|
|
180
|
+
<Text className="text-text-primary text-sm">Pro plan</Text>
|
|
181
|
+
<Text className="text-text-primary text-sm font-semibold">$79/mo</Text>
|
|
182
|
+
</View>
|
|
183
|
+
<View style={{ flexDirection: 'row', justifyContent: 'space-between' }}>
|
|
184
|
+
<Text className="text-text-primary text-sm">Enterprise</Text>
|
|
185
|
+
<Text className="text-text-primary text-sm font-semibold">Custom</Text>
|
|
186
|
+
</View>
|
|
187
|
+
</View>
|
|
188
|
+
</AccordionPanel>
|
|
189
|
+
</AccordionItem>
|
|
190
|
+
<AccordionItem>
|
|
191
|
+
<AccordionButton>Features Included</AccordionButton>
|
|
192
|
+
<AccordionPanel>
|
|
193
|
+
<View style={{ gap: 6 }}>
|
|
194
|
+
{['Unlimited projects', 'Custom domains', 'Priority support', 'API access', 'Team collaboration'].map(
|
|
195
|
+
(feature) => (
|
|
196
|
+
<View key={feature} style={{ flexDirection: 'row', alignItems: 'center', gap: 8 }}>
|
|
197
|
+
<Text className="text-status-success text-sm">✓</Text>
|
|
198
|
+
<Text className="text-text-primary text-sm">{feature}</Text>
|
|
199
|
+
</View>
|
|
200
|
+
)
|
|
201
|
+
)}
|
|
202
|
+
</View>
|
|
203
|
+
</AccordionPanel>
|
|
204
|
+
</AccordionItem>
|
|
205
|
+
<AccordionItem>
|
|
206
|
+
<AccordionButton>Frequently Asked Questions</AccordionButton>
|
|
207
|
+
<AccordionPanel>
|
|
208
|
+
<View style={{ gap: 12 }}>
|
|
209
|
+
<View style={{ gap: 2 }}>
|
|
210
|
+
<Text className="text-text-primary text-sm font-medium">Can I cancel anytime?</Text>
|
|
211
|
+
<Text className="text-text-secondary text-sm">
|
|
212
|
+
Yes, you can cancel your subscription at any time with no penalties.
|
|
213
|
+
</Text>
|
|
214
|
+
</View>
|
|
215
|
+
<View style={{ gap: 2 }}>
|
|
216
|
+
<Text className="text-text-primary text-sm font-medium">Is there a free trial?</Text>
|
|
217
|
+
<Text className="text-text-secondary text-sm">
|
|
218
|
+
We offer a 14-day free trial for all plans.
|
|
219
|
+
</Text>
|
|
220
|
+
</View>
|
|
221
|
+
</View>
|
|
222
|
+
</AccordionPanel>
|
|
223
|
+
</AccordionItem>
|
|
224
|
+
</Accordion>
|
|
225
|
+
</View>
|
|
226
|
+
),
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
export const ManyItems: Story = {
|
|
230
|
+
render: () => (
|
|
231
|
+
<View style={{ width: 400 }}>
|
|
232
|
+
<Accordion>
|
|
233
|
+
{Array.from({ length: 10 }).map((_, i) => (
|
|
234
|
+
<AccordionItem key={i}>
|
|
235
|
+
<AccordionButton>Item {i + 1}</AccordionButton>
|
|
236
|
+
<AccordionPanel>
|
|
237
|
+
<Text className="text-text-secondary text-sm">
|
|
238
|
+
Content for accordion item {i + 1}. Only one item can be expanded at a time in
|
|
239
|
+
single mode.
|
|
240
|
+
</Text>
|
|
241
|
+
</AccordionPanel>
|
|
242
|
+
</AccordionItem>
|
|
243
|
+
))}
|
|
244
|
+
</Accordion>
|
|
245
|
+
</View>
|
|
246
|
+
),
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
export const SingleCollapse: Story = {
|
|
250
|
+
render: () => (
|
|
251
|
+
<View style={{ width: 400 }}>
|
|
252
|
+
<Collapse>
|
|
253
|
+
<CollapseButton>
|
|
254
|
+
<Text className="text-text-primary font-medium">Click to expand</Text>
|
|
255
|
+
</CollapseButton>
|
|
256
|
+
<CollapseContent>
|
|
257
|
+
<View className="px-4 pb-3">
|
|
258
|
+
<Text className="text-text-secondary text-sm">
|
|
259
|
+
This is a standalone Collapse component, useful when you only need a single
|
|
260
|
+
collapsible section rather than an accordion group.
|
|
261
|
+
</Text>
|
|
262
|
+
</View>
|
|
263
|
+
</CollapseContent>
|
|
264
|
+
</Collapse>
|
|
265
|
+
</View>
|
|
266
|
+
),
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
export const CollapseDefaultOpen: Story = {
|
|
270
|
+
render: () => (
|
|
271
|
+
<View style={{ width: 400 }}>
|
|
272
|
+
<Collapse defaultIsOpen>
|
|
273
|
+
<CollapseButton>
|
|
274
|
+
<Text className="text-text-primary font-medium">Details (starts open)</Text>
|
|
275
|
+
</CollapseButton>
|
|
276
|
+
<CollapseContent>
|
|
277
|
+
<View className="px-4 pb-3">
|
|
278
|
+
<Text className="text-text-secondary text-sm">
|
|
279
|
+
This collapse starts in the open state via defaultIsOpen. The user can toggle it
|
|
280
|
+
closed by clicking the header.
|
|
281
|
+
</Text>
|
|
282
|
+
</View>
|
|
283
|
+
</CollapseContent>
|
|
284
|
+
</Collapse>
|
|
285
|
+
</View>
|
|
286
|
+
),
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
export const CollapseControlled: Story = {
|
|
290
|
+
render: function Render() {
|
|
291
|
+
const [isOpen, setIsOpen] = useState(false)
|
|
292
|
+
return (
|
|
293
|
+
<View style={{ width: 400, gap: 8 }}>
|
|
294
|
+
<Text className="text-sm text-text-secondary">
|
|
295
|
+
State: {isOpen ? 'Open' : 'Closed'}
|
|
296
|
+
</Text>
|
|
297
|
+
<Collapse isOpen={isOpen} onToggle={setIsOpen}>
|
|
298
|
+
<CollapseButton>
|
|
299
|
+
<Text className="text-text-primary font-medium">Controlled Collapse</Text>
|
|
300
|
+
</CollapseButton>
|
|
301
|
+
<CollapseContent>
|
|
302
|
+
<View className="px-4 pb-3">
|
|
303
|
+
<Text className="text-text-secondary text-sm">
|
|
304
|
+
This collapse is controlled externally. The isOpen prop and onToggle callback
|
|
305
|
+
manage state outside the component.
|
|
306
|
+
</Text>
|
|
307
|
+
</View>
|
|
308
|
+
</CollapseContent>
|
|
309
|
+
</Collapse>
|
|
310
|
+
</View>
|
|
311
|
+
)
|
|
312
|
+
},
|
|
313
|
+
}
|