@butternutbox/pawprint-native 0.0.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.
Files changed (105) hide show
  1. package/.turbo/turbo-build.log +30 -0
  2. package/COMPONENT_GUIDELINES.md +610 -0
  3. package/README.md +72 -0
  4. package/dist/ibm-plex-sans-condensed-400-normal-I2XLJNNB.woff2 +0 -0
  5. package/dist/ibm-plex-sans-condensed-500-normal-IEQBNVGX.woff2 +0 -0
  6. package/dist/ibm-plex-sans-condensed-600-normal-UX5ZU5T6.woff2 +0 -0
  7. package/dist/ibm-plex-sans-condensed-700-normal-4PFYFTSO.woff2 +0 -0
  8. package/dist/ida-narrow-500-normal-C6I2PK4T.woff2 +0 -0
  9. package/dist/ida-narrow-700-normal-UPHPRIN6.woff2 +0 -0
  10. package/dist/index.cjs +2686 -0
  11. package/dist/index.cjs.map +1 -0
  12. package/dist/index.d.cts +780 -0
  13. package/dist/index.d.ts +780 -0
  14. package/dist/index.js +2617 -0
  15. package/dist/index.js.map +1 -0
  16. package/eslint.config.js +3 -0
  17. package/llms.txt +458 -0
  18. package/package.json +57 -0
  19. package/src/components/atoms/Avatar/Avatar.stories.tsx +125 -0
  20. package/src/components/atoms/Avatar/Avatar.tsx +159 -0
  21. package/src/components/atoms/Avatar/index.ts +7 -0
  22. package/src/components/atoms/Badge/Badge.stories.tsx +231 -0
  23. package/src/components/atoms/Badge/Badge.tsx +184 -0
  24. package/src/components/atoms/Badge/index.ts +2 -0
  25. package/src/components/atoms/Button/Button.stories.tsx +145 -0
  26. package/src/components/atoms/Button/Button.tsx +261 -0
  27. package/src/components/atoms/Button/index.ts +7 -0
  28. package/src/components/atoms/Hint/Hint.stories.tsx +84 -0
  29. package/src/components/atoms/Hint/Hint.tsx +59 -0
  30. package/src/components/atoms/Hint/index.ts +2 -0
  31. package/src/components/atoms/Icon/Icon.stories.tsx +200 -0
  32. package/src/components/atoms/Icon/Icon.tsx +112 -0
  33. package/src/components/atoms/Icon/index.ts +8 -0
  34. package/src/components/atoms/IconButton/IconButton.stories.tsx +162 -0
  35. package/src/components/atoms/IconButton/IconButton.tsx +227 -0
  36. package/src/components/atoms/IconButton/index.ts +7 -0
  37. package/src/components/atoms/Illustration/Illustration.stories.tsx +167 -0
  38. package/src/components/atoms/Illustration/Illustration.tsx +81 -0
  39. package/src/components/atoms/Illustration/index.ts +6 -0
  40. package/src/components/atoms/Input/Input.stories.tsx +142 -0
  41. package/src/components/atoms/Input/Input.tsx +110 -0
  42. package/src/components/atoms/Input/InputDescription.tsx +49 -0
  43. package/src/components/atoms/Input/InputError.tsx +39 -0
  44. package/src/components/atoms/Input/InputField.tsx +119 -0
  45. package/src/components/atoms/Input/InputLabel.tsx +61 -0
  46. package/src/components/atoms/Input/index.ts +10 -0
  47. package/src/components/atoms/Link/Link.stories.tsx +119 -0
  48. package/src/components/atoms/Link/Link.tsx +118 -0
  49. package/src/components/atoms/Link/index.ts +2 -0
  50. package/src/components/atoms/Logo/Logo.registry.ts +39 -0
  51. package/src/components/atoms/Logo/Logo.tsx +68 -0
  52. package/src/components/atoms/Logo/index.ts +4 -0
  53. package/src/components/atoms/Spinner/Spinner.stories.tsx +98 -0
  54. package/src/components/atoms/Spinner/Spinner.tsx +91 -0
  55. package/src/components/atoms/Spinner/index.ts +2 -0
  56. package/src/components/atoms/Switch/Switch.stories.tsx +120 -0
  57. package/src/components/atoms/Switch/Switch.tsx +196 -0
  58. package/src/components/atoms/Switch/index.ts +2 -0
  59. package/src/components/atoms/Tag/Tag.stories.tsx +89 -0
  60. package/src/components/atoms/Tag/Tag.tsx +122 -0
  61. package/src/components/atoms/Tag/index.ts +2 -0
  62. package/src/components/atoms/Typography/Typography.stories.tsx +315 -0
  63. package/src/components/atoms/Typography/Typography.tsx +284 -0
  64. package/src/components/atoms/Typography/index.ts +2 -0
  65. package/src/components/atoms/index.ts +14 -0
  66. package/src/components/index.ts +2 -0
  67. package/src/components/molecules/ButtonDock/ButtonDock.stories.tsx +95 -0
  68. package/src/components/molecules/ButtonDock/ButtonDock.tsx +148 -0
  69. package/src/components/molecules/ButtonDock/index.ts +2 -0
  70. package/src/components/molecules/ButtonGroup/ButtonGroup.stories.tsx +82 -0
  71. package/src/components/molecules/ButtonGroup/ButtonGroup.tsx +94 -0
  72. package/src/components/molecules/ButtonGroup/index.ts +2 -0
  73. package/src/components/molecules/Checkbox/Checkbox.stories.tsx +148 -0
  74. package/src/components/molecules/Checkbox/Checkbox.tsx +279 -0
  75. package/src/components/molecules/Checkbox/CheckboxGroup.tsx +53 -0
  76. package/src/components/molecules/Checkbox/index.ts +4 -0
  77. package/src/components/molecules/Radio/Radio.stories.tsx +182 -0
  78. package/src/components/molecules/Radio/Radio.tsx +249 -0
  79. package/src/components/molecules/Radio/RadioGroup.tsx +142 -0
  80. package/src/components/molecules/Radio/index.ts +4 -0
  81. package/src/components/molecules/SegmentedControl/SegmentedControl.stories.tsx +151 -0
  82. package/src/components/molecules/SegmentedControl/SegmentedControl.tsx +323 -0
  83. package/src/components/molecules/SegmentedControl/index.ts +5 -0
  84. package/src/components/molecules/Slider/Slider.stories.tsx +144 -0
  85. package/src/components/molecules/Slider/Slider.tsx +303 -0
  86. package/src/components/molecules/Slider/index.ts +2 -0
  87. package/src/components/molecules/index.ts +6 -0
  88. package/src/fonts/ibm-plex-sans-condensed-400-normal.woff2 +0 -0
  89. package/src/fonts/ibm-plex-sans-condensed-500-normal.woff2 +0 -0
  90. package/src/fonts/ibm-plex-sans-condensed-600-normal.woff2 +0 -0
  91. package/src/fonts/ibm-plex-sans-condensed-700-normal.woff2 +0 -0
  92. package/src/fonts/ida-narrow-500-normal.woff2 +0 -0
  93. package/src/fonts/ida-narrow-700-normal.woff2 +0 -0
  94. package/src/fonts/index.ts +49 -0
  95. package/src/index.ts +9 -0
  96. package/src/theme/PawprintProvider.tsx +26 -0
  97. package/src/theme/ThemeProvider.tsx +63 -0
  98. package/src/theme/index.ts +5 -0
  99. package/src/theme/theme.ts +3 -0
  100. package/src/theme/utils.ts +31 -0
  101. package/src/types/fonts.d.ts +4 -0
  102. package/src/types/index.ts +1 -0
  103. package/src/types/theme.ts +24 -0
  104. package/tsconfig.json +5 -0
  105. package/tsup.config.ts +11 -0
@@ -0,0 +1,249 @@
1
+ import React from "react"
2
+ import { Pressable, View, PressableProps } from "react-native"
3
+ import styled from "@emotion/native"
4
+ import { useTheme } from "@emotion/react"
5
+ import { Typography } from "../../atoms/Typography"
6
+ import { Illustration, type IllustrationProps } from "../../atoms/Illustration"
7
+
8
+ export type RadioOwnProps = {
9
+ value: string
10
+ variant?: "standalone" | "tile"
11
+ label?: React.ReactNode
12
+ subText?: React.ReactNode
13
+ asset?: IllustrationProps
14
+ disabled?: boolean
15
+ selected?: boolean
16
+ onSelect?: (value: string) => void
17
+ }
18
+
19
+ export type RadioProps = RadioOwnProps &
20
+ Omit<PressableProps, keyof RadioOwnProps | "children">
21
+
22
+ const parseTokenValue = (value: string): number => parseFloat(value)
23
+
24
+ const StyledRadioRoot = styled(Pressable)<{
25
+ radioGap: number
26
+ radioOpacity: number
27
+ radioPaddingVertical?: number
28
+ radioPaddingHorizontal?: number
29
+ radioMaxWidth?: number
30
+ radioBgColor?: string
31
+ radioBorderWidth?: number
32
+ radioBorderColor?: string
33
+ radioBorderRadius?: number
34
+ }>(
35
+ ({
36
+ radioGap,
37
+ radioOpacity,
38
+ radioPaddingVertical,
39
+ radioPaddingHorizontal,
40
+ radioMaxWidth,
41
+ radioBgColor,
42
+ radioBorderWidth,
43
+ radioBorderColor,
44
+ radioBorderRadius
45
+ }) => ({
46
+ flexDirection: "row",
47
+ alignItems: "flex-start",
48
+ width: "100%",
49
+ gap: radioGap,
50
+ opacity: radioOpacity,
51
+ ...(radioPaddingVertical !== undefined
52
+ ? { paddingVertical: radioPaddingVertical }
53
+ : {}),
54
+ ...(radioPaddingHorizontal !== undefined
55
+ ? { paddingHorizontal: radioPaddingHorizontal }
56
+ : {}),
57
+ ...(radioMaxWidth !== undefined ? { maxWidth: radioMaxWidth } : {}),
58
+ ...(radioBgColor ? { backgroundColor: radioBgColor } : {}),
59
+ ...(radioBorderWidth !== undefined
60
+ ? { borderWidth: radioBorderWidth, borderColor: radioBorderColor }
61
+ : {}),
62
+ ...(radioBorderRadius !== undefined
63
+ ? { borderRadius: radioBorderRadius }
64
+ : {})
65
+ })
66
+ )
67
+
68
+ const StyledRadioControl = styled(View)<{
69
+ controlSize: number
70
+ controlBorderWidth: number
71
+ controlBorderColor: string
72
+ }>(({ controlSize, controlBorderWidth, controlBorderColor }) => ({
73
+ width: controlSize,
74
+ height: controlSize,
75
+ minWidth: controlSize,
76
+ minHeight: controlSize,
77
+ borderWidth: controlBorderWidth,
78
+ borderColor: controlBorderColor,
79
+ borderRadius: controlSize / 2,
80
+ alignItems: "center",
81
+ justifyContent: "center"
82
+ }))
83
+
84
+ const StyledIndicator = styled(View)<{
85
+ indicatorSize: number
86
+ indicatorBgColor: string
87
+ }>(({ indicatorSize, indicatorBgColor }) => ({
88
+ width: indicatorSize,
89
+ height: indicatorSize,
90
+ borderRadius: indicatorSize / 2,
91
+ backgroundColor: indicatorBgColor
92
+ }))
93
+
94
+ const StyledTextContent = styled(View)<{
95
+ textContentGap: number
96
+ }>(({ textContentGap }) => ({
97
+ flexDirection: "column",
98
+ gap: textContentGap,
99
+ marginTop: 2
100
+ }))
101
+
102
+ const StyledAssetWrapper = styled(View)({
103
+ alignSelf: "center"
104
+ })
105
+
106
+ /**
107
+ * Radio button component for single selection within a group.
108
+ *
109
+ * @param {string} value - The value of the radio button (required).
110
+ * @param {"standalone" | "tile"} [variant="standalone"] - Visual style variant.
111
+ * @param {React.ReactNode} [label] - Main label text or content.
112
+ * @param {React.ReactNode} [subText] - Optional descriptive subtext.
113
+ * @param {IllustrationProps} [asset] - Optional illustration asset for tile variant.
114
+ * @param {boolean} [disabled=false] - Whether the radio is disabled.
115
+ * @param {boolean} [selected=false] - Whether the radio is currently selected.
116
+ * @param {(value: string) => void} [onSelect] - Callback when radio is selected.
117
+ *
118
+ * @example
119
+ * <Radio value="chicken" label="Chicken" subText="Tender & tasty" />
120
+ */
121
+ export const Radio = React.forwardRef<View, RadioProps>(
122
+ (
123
+ {
124
+ variant = "standalone",
125
+ label,
126
+ subText,
127
+ asset,
128
+ disabled = false,
129
+ value,
130
+ selected = false,
131
+ onSelect,
132
+ style,
133
+ ...rest
134
+ },
135
+ ref
136
+ ) => {
137
+ const theme = useTheme()
138
+ const { radio } = theme.tokens.components
139
+ const { spacing, typography, colour } = radio
140
+
141
+ const handlePress = () => {
142
+ if (disabled) return
143
+ onSelect?.(value)
144
+ }
145
+
146
+ const controlSize = parseTokenValue(radio.size.control.default)
147
+ const indicatorSize = parseTokenValue(radio.size.indicator.default)
148
+ const borderWidthVal = parseTokenValue(radio.borderWidth.default)
149
+ const isTile = variant === "tile"
150
+
151
+ return (
152
+ <StyledRadioRoot
153
+ ref={ref}
154
+ onPress={handlePress}
155
+ disabled={disabled}
156
+ accessibilityRole="radio"
157
+ accessibilityState={{ selected, disabled }}
158
+ radioGap={parseTokenValue(
159
+ isTile ? radio.radioTile.spacing.gap : spacing.gap
160
+ )}
161
+ radioOpacity={disabled ? parseFloat(radio.opacity.disabled) : 1}
162
+ radioPaddingVertical={
163
+ isTile
164
+ ? parseTokenValue(radio.radioTile.spacing.verticalPadding)
165
+ : undefined
166
+ }
167
+ radioPaddingHorizontal={
168
+ isTile
169
+ ? parseTokenValue(radio.radioTile.spacing.horizontalPadding)
170
+ : undefined
171
+ }
172
+ radioMaxWidth={
173
+ isTile ? parseTokenValue(radio.radioTile.size.maxWidth) : undefined
174
+ }
175
+ radioBgColor={
176
+ isTile
177
+ ? selected
178
+ ? radio.radioTile.colour.background.selected
179
+ : radio.radioTile.colour.background.default
180
+ : undefined
181
+ }
182
+ radioBorderWidth={
183
+ isTile
184
+ ? parseTokenValue(radio.radioTile.borderWidth.default)
185
+ : undefined
186
+ }
187
+ radioBorderColor={
188
+ isTile
189
+ ? selected
190
+ ? radio.radioTile.colour.border.selected
191
+ : radio.radioTile.colour.border.default
192
+ : undefined
193
+ }
194
+ radioBorderRadius={
195
+ isTile
196
+ ? parseTokenValue(radio.radioTile.borderRadius.default)
197
+ : undefined
198
+ }
199
+ style={typeof style === "function" ? undefined : style}
200
+ {...rest}
201
+ >
202
+ <StyledRadioControl
203
+ controlSize={controlSize}
204
+ controlBorderWidth={borderWidthVal}
205
+ controlBorderColor={
206
+ selected
207
+ ? radio.colour.control.border.selected
208
+ : radio.colour.control.border.default
209
+ }
210
+ >
211
+ {selected && (
212
+ <StyledIndicator
213
+ indicatorSize={indicatorSize}
214
+ indicatorBgColor={radio.colour.indicator.background.selected}
215
+ />
216
+ )}
217
+ </StyledRadioControl>
218
+
219
+ {(label || subText) && (
220
+ <StyledTextContent
221
+ textContentGap={parseTokenValue(spacing.content.gap)}
222
+ >
223
+ {label && (
224
+ <Typography token={typography.label} color={colour.text.title}>
225
+ {label}
226
+ </Typography>
227
+ )}
228
+ {subText && (
229
+ <Typography
230
+ token={typography.subText}
231
+ color={colour.text.subtext}
232
+ >
233
+ {subText}
234
+ </Typography>
235
+ )}
236
+ </StyledTextContent>
237
+ )}
238
+
239
+ {isTile && asset && (
240
+ <StyledAssetWrapper>
241
+ <Illustration {...asset} />
242
+ </StyledAssetWrapper>
243
+ )}
244
+ </StyledRadioRoot>
245
+ )
246
+ }
247
+ )
248
+
249
+ Radio.displayName = "Radio"
@@ -0,0 +1,142 @@
1
+ import React from "react"
2
+ import { View, ViewProps } from "react-native"
3
+ import styled from "@emotion/native"
4
+ import { useTheme } from "@emotion/react"
5
+ import { Radio, type RadioOwnProps } from "./Radio"
6
+
7
+ type RadioGroupOwnProps = {
8
+ name: string
9
+ options?: RadioOwnProps[]
10
+ orientation?: "horizontal" | "vertical"
11
+ value?: string
12
+ defaultValue?: string
13
+ disabled?: boolean
14
+ onValueChange?: (value: string) => void
15
+ }
16
+
17
+ export type RadioGroupProps = RadioGroupOwnProps &
18
+ Omit<ViewProps, keyof RadioGroupOwnProps>
19
+
20
+ const parseTokenValue = (value: string): number => parseFloat(value)
21
+
22
+ const StyledRadioGroup = styled(View)<{
23
+ groupDirection: "row" | "column"
24
+ groupGap: number
25
+ }>(({ groupDirection, groupGap }) => ({
26
+ flexDirection: groupDirection,
27
+ gap: groupGap
28
+ }))
29
+
30
+ /**
31
+ * RadioGroup component that manages state for a collection of Radio buttons.
32
+ *
33
+ * @param {string} name - Name attribute for the radio group (required).
34
+ * @param {Array} [options] - Options to render as radio buttons.
35
+ * @param {"horizontal" | "vertical"} [orientation="vertical"] - Layout direction.
36
+ * @param {string} [value] - Controlled value of the selected radio.
37
+ * @param {string} [defaultValue] - Default selected value for uncontrolled usage.
38
+ * @param {boolean} [disabled=false] - Whether all radios in the group are disabled.
39
+ * @param {(value: string) => void} [onValueChange] - Callback when selection changes.
40
+ *
41
+ * @example
42
+ * <RadioGroup
43
+ * name="size"
44
+ * options={[
45
+ * { value: "small", label: "Small" },
46
+ * { value: "medium", label: "Medium" }
47
+ * ]}
48
+ * value={size}
49
+ * onValueChange={setSize}
50
+ * />
51
+ *
52
+ * @example
53
+ * <RadioGroup name="size" defaultValue="medium">
54
+ * <RadioGroup.Radio value="small" label="Small" />
55
+ * <RadioGroup.Radio value="medium" label="Medium" />
56
+ * </RadioGroup>
57
+ */
58
+ const RadioGroupRoot = React.forwardRef<View, RadioGroupProps>(
59
+ (
60
+ {
61
+ name: _name,
62
+ options,
63
+ orientation = "vertical",
64
+ value,
65
+ defaultValue,
66
+ onValueChange,
67
+ disabled = false,
68
+ children,
69
+ ...rest
70
+ },
71
+ ref
72
+ ) => {
73
+ const theme = useTheme()
74
+ const { radio } = theme.tokens.components
75
+
76
+ const optionsFirstValue = options?.[0]?.value
77
+ const derivedDefaultValue = defaultValue ?? optionsFirstValue
78
+
79
+ const isControlled = value !== undefined
80
+ const [internalValue, setInternalValue] = React.useState(
81
+ derivedDefaultValue ?? ""
82
+ )
83
+ const currentValue = isControlled ? value : internalValue
84
+
85
+ const handleSelect = React.useCallback(
86
+ (newValue: string) => {
87
+ if (!isControlled) {
88
+ setInternalValue(newValue)
89
+ }
90
+ onValueChange?.(newValue)
91
+ },
92
+ [isControlled, onValueChange]
93
+ )
94
+
95
+ const renderChildren = () => {
96
+ if (options) {
97
+ return options.map((option) => (
98
+ <Radio
99
+ key={option.value}
100
+ {...option}
101
+ selected={currentValue === option.value}
102
+ onSelect={handleSelect}
103
+ disabled={disabled || option.disabled}
104
+ />
105
+ ))
106
+ }
107
+
108
+ return React.Children.map(children, (child) => {
109
+ if (!React.isValidElement(child)) return child
110
+ return React.cloneElement(child as React.ReactElement<RadioOwnProps>, {
111
+ selected: currentValue === (child.props as RadioOwnProps).value,
112
+ onSelect: handleSelect,
113
+ disabled: disabled || (child.props as RadioOwnProps).disabled
114
+ })
115
+ })
116
+ }
117
+
118
+ return (
119
+ <StyledRadioGroup
120
+ ref={ref}
121
+ accessibilityRole="radiogroup"
122
+ groupDirection={orientation === "horizontal" ? "row" : "column"}
123
+ groupGap={parseTokenValue(radio.spacing.gap)}
124
+ {...rest}
125
+ >
126
+ {renderChildren()}
127
+ </StyledRadioGroup>
128
+ )
129
+ }
130
+ )
131
+
132
+ RadioGroupRoot.displayName = "RadioGroup"
133
+
134
+ type RadioGroupComponent = React.ForwardRefExoticComponent<
135
+ RadioGroupProps & React.RefAttributes<View>
136
+ > & {
137
+ Radio: typeof Radio
138
+ }
139
+
140
+ export const RadioGroup = Object.assign(RadioGroupRoot, {
141
+ Radio
142
+ }) as RadioGroupComponent
@@ -0,0 +1,4 @@
1
+ export { Radio } from "./Radio"
2
+ export type { RadioProps, RadioOwnProps } from "./Radio"
3
+ export { RadioGroup } from "./RadioGroup"
4
+ export type { RadioGroupProps } from "./RadioGroup"
@@ -0,0 +1,151 @@
1
+ import React, { useState } from "react"
2
+ import { View, StyleSheet } from "react-native"
3
+ import { SegmentedControl } from "./SegmentedControl"
4
+ import type { SegmentedControlProps } from "./SegmentedControl"
5
+ import { Typography } from "../../atoms/Typography"
6
+
7
+ export default {
8
+ title: "Molecules/SegmentedControl",
9
+ component: SegmentedControl,
10
+ argTypes: {
11
+ layout: {
12
+ control: { type: "select" },
13
+ options: ["fixed", "intrinsic"],
14
+ description: "Layout mode (fixed = equal width, intrinsic = fit content)"
15
+ },
16
+ disabled: {
17
+ control: { type: "boolean" },
18
+ description: "Disables entire control"
19
+ }
20
+ }
21
+ }
22
+
23
+ const fourOptions = [
24
+ { value: "daily", label: "Daily" },
25
+ { value: "weekly", label: "Weekly" },
26
+ { value: "monthly", label: "Monthly" },
27
+ { value: "yearly", label: "Yearly" }
28
+ ]
29
+
30
+ const sevenOptions = [
31
+ { value: "mon", label: "Mon" },
32
+ { value: "tue", label: "Tue" },
33
+ { value: "wed", label: "Wed" },
34
+ { value: "thu", label: "Thu" },
35
+ { value: "fri", label: "Fri" },
36
+ { value: "sat", label: "Sat" },
37
+ { value: "sun", label: "Sun" }
38
+ ]
39
+
40
+ export const FixedWidth = () => (
41
+ <View style={styles.column}>
42
+ <Typography size="sm" weight="semiBold" color="tertiary">
43
+ Fixed layout (420px container)
44
+ </Typography>
45
+ <View style={styles.fixedContainer}>
46
+ <SegmentedControl
47
+ layout="fixed"
48
+ options={fourOptions}
49
+ defaultValue="daily"
50
+ />
51
+ </View>
52
+ </View>
53
+ )
54
+
55
+ export const IntrinsicWidth = () => (
56
+ <View style={styles.column}>
57
+ <Typography size="sm" weight="semiBold" color="tertiary">
58
+ Intrinsic layout (scrollable)
59
+ </Typography>
60
+ <SegmentedControl
61
+ layout="intrinsic"
62
+ options={sevenOptions}
63
+ defaultValue="mon"
64
+ />
65
+ </View>
66
+ )
67
+
68
+ export const States = () => (
69
+ <View style={styles.column}>
70
+ <View style={styles.section}>
71
+ <Typography size="sm" weight="semiBold" color="tertiary">
72
+ Enabled
73
+ </Typography>
74
+ <SegmentedControl
75
+ layout="fixed"
76
+ options={fourOptions}
77
+ defaultValue="daily"
78
+ />
79
+ </View>
80
+
81
+ <View style={styles.section}>
82
+ <Typography size="sm" weight="semiBold" color="tertiary">
83
+ Disabled (all)
84
+ </Typography>
85
+ <SegmentedControl
86
+ layout="fixed"
87
+ options={fourOptions}
88
+ defaultValue="daily"
89
+ disabled
90
+ />
91
+ </View>
92
+
93
+ <View style={styles.section}>
94
+ <Typography size="sm" weight="semiBold" color="tertiary">
95
+ Disabled (single item)
96
+ </Typography>
97
+ <SegmentedControl
98
+ layout="fixed"
99
+ options={[
100
+ { value: "daily", label: "Daily" },
101
+ { value: "weekly", label: "Weekly", disabled: true },
102
+ { value: "monthly", label: "Monthly" },
103
+ { value: "yearly", label: "Yearly" }
104
+ ]}
105
+ defaultValue="daily"
106
+ />
107
+ </View>
108
+ </View>
109
+ )
110
+
111
+ export const Controlled = () => {
112
+ const [value, setValue] = useState("daily")
113
+
114
+ return (
115
+ <View style={styles.column}>
116
+ <Typography size="sm" weight="semiBold" color="tertiary">
117
+ Selected: {value}
118
+ </Typography>
119
+ <SegmentedControl
120
+ layout="fixed"
121
+ options={fourOptions}
122
+ value={value}
123
+ onValueChange={setValue}
124
+ />
125
+ </View>
126
+ )
127
+ }
128
+
129
+ export const Playground = {
130
+ args: {
131
+ layout: "fixed",
132
+ disabled: false
133
+ },
134
+ render: (args: SegmentedControlProps) => (
135
+ <SegmentedControl {...args} options={fourOptions} defaultValue="daily" />
136
+ )
137
+ }
138
+
139
+ const styles = StyleSheet.create({
140
+ column: {
141
+ flexDirection: "column",
142
+ gap: 32
143
+ },
144
+ section: {
145
+ flexDirection: "column",
146
+ gap: 12
147
+ },
148
+ fixedContainer: {
149
+ width: 420
150
+ }
151
+ })