@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,3 @@
1
+ import baseConfig from "@repo/eslint-config/react.mjs"
2
+
3
+ export default [...baseConfig]
package/llms.txt ADDED
@@ -0,0 +1,458 @@
1
+ # Component Development – LLM Instructions (React Native)
2
+
3
+ Full reference: `packages/pawprint-native/COMPONENT_GUIDELINES.md`
4
+
5
+ Always use the equivalent component in `packages/pawprint-web/src/components` as a reference for API design (props, variants, sizes). Convert it to React Native using `@rn-primitives/*`, `@emotion/native`, and standard React Native primitives (`View`, `Pressable`, `Text`, etc.).
6
+
7
+ ---
8
+
9
+ # 🔒 Hard Rules (MUST / MUST NOT)
10
+
11
+ ## Code Integrity
12
+
13
+ - **MUST NOT** modify any existing file unless explicitly required by Step 7 (exports only).
14
+ - **MUST NOT** refactor, improve, or clean up unrelated code.
15
+ - **MUST NOT** recreate components that already exist.
16
+ - **MUST** reuse existing components (Typography, Icon, Spinner, etc.) whenever possible.
17
+ - Existing code includes:
18
+ - Any file not newly created for this component
19
+ - Tokens
20
+ - Theme
21
+ - Other components
22
+ - Shared types
23
+ - Utilities and fonts
24
+
25
+ ---
26
+
27
+ ## Token Usage (Strict Order)
28
+
29
+ You **MUST** follow this exact fallback order:
30
+
31
+ 1. Component tokens
32
+ `theme.tokens.components.[component].*`
33
+
34
+ 2. Semantic tokens
35
+ `theme.tokens.semantics.*`
36
+
37
+ 3. Primitive tokens
38
+ `theme.tokens.primitives.*`
39
+
40
+ 4. If no token exists → hardcode value with comment:
41
+ `// TODO: Add token`
42
+
43
+ Rules:
44
+ - **MUST NOT** hardcode values if a token exists.
45
+ - Layout values (gap, padding, margin, etc.) MUST use tokens if available.
46
+ - If no layout token exists, hardcode with `// TODO: Add token`.
47
+ - Token values are strings — use `parseTokenValue()` to convert:
48
+ ```tsx
49
+ const parseTokenValue = (value: string): number => parseFloat(value)
50
+ ```
51
+
52
+ ---
53
+
54
+ ## Visual Styling Rules
55
+
56
+ - **MUST NOT** add visual styles not defined in:
57
+ - Design tokens
58
+ - Figma design
59
+
60
+ This includes:
61
+ - opacity (unless for disabled states in tokens)
62
+ - letterSpacing
63
+ - shadows
64
+ - extra borders
65
+ - etc.
66
+
67
+ Animations are allowed **ONLY if present in tokens or Figma** — use `Animated` or `react-native-reanimated`.
68
+
69
+ Layout properties (flexDirection, gap, margin, padding, alignItems, justifyContent) are allowed for structure.
70
+
71
+ ---
72
+
73
+ ## Layout Stability
74
+
75
+ - **MUST prevent layout shifts**
76
+ - Use `transparent` borders instead of removing borders.
77
+ - Use fixed `height`/`minWidth` from tokens to maintain consistent sizing.
78
+
79
+ ---
80
+
81
+ ## Scope Restrictions
82
+
83
+ You may only create files inside:
84
+
85
+ `packages/pawprint-native/src/.../<component>`
86
+
87
+ You may only modify:
88
+ - Required export barrel files (Step 7)
89
+
90
+ You **MUST NOT** modify:
91
+ - Tokens
92
+ - Theme
93
+ - Unrelated components
94
+ - Config files
95
+ - Storybook config
96
+
97
+ ---
98
+
99
+ ## i18n
100
+
101
+ - The design system is **i18n-agnostic**. Components MUST NOT handle translation, interpolation, or localisation.
102
+ - MUST NOT import or depend on `i18next`, `react-i18next`, or any translation library.
103
+ - Components accept `children` or typed props — never translation keys.
104
+ - Consuming apps are responsible for resolving translations and passing already-rendered strings or React nodes.
105
+
106
+ ---
107
+
108
+ # 🧭 Workflow
109
+
110
+ ---
111
+
112
+ ## Step 0 – Requirement Gate (MANDATORY)
113
+
114
+ Ask ONE question at a time.
115
+
116
+ If any answer is missing:
117
+ → Ask only the next missing question.
118
+ → STOP.
119
+ → Do NOT proceed.
120
+
121
+ Questions:
122
+
123
+ a. Ask component level using `ask_user_question` tool with options:
124
+ - atoms
125
+ - molecules
126
+ - organisms
127
+
128
+ b. Ask for component name (plain text)
129
+
130
+ c. Ask for Figma URL (plain text)
131
+
132
+ d. Ask for specific requirements or constraints (plain text)
133
+
134
+ Examples:
135
+ - Exclude certain variants
136
+ - Custom prop structure
137
+ - Platform-specific behavior
138
+ - Accessibility constraints
139
+
140
+ ⚠️ DO NOT proceed until ALL answers are received.
141
+
142
+ ---
143
+
144
+ ## Step 1 – Mandatory Analysis (Before Implementation)
145
+
146
+ ### 1. RN Primitives Check
147
+
148
+ - Check if `@rn-primitives` has a matching component:
149
+ ```
150
+ @rn-primitives/checkbox
151
+ @rn-primitives/switch
152
+ @rn-primitives/slider
153
+ @rn-primitives/accordion
154
+ @rn-primitives/dialog
155
+ @rn-primitives/radio-group
156
+ @rn-primitives/select
157
+ @rn-primitives/tabs
158
+ @rn-primitives/toggle
159
+ @rn-primitives/toggle-group
160
+ @rn-primitives/separator
161
+ @rn-primitives/progress
162
+ @rn-primitives/label
163
+ @rn-primitives/collapsible
164
+ @rn-primitives/popover
165
+ @rn-primitives/tooltip
166
+ @rn-primitives/context-menu
167
+ @rn-primitives/dropdown-menu
168
+ @rn-primitives/menubar
169
+ @rn-primitives/navigation-menu
170
+ @rn-primitives/hover-card
171
+ @rn-primitives/alert-dialog
172
+ @rn-primitives/toolbar
173
+ @rn-primitives/toast
174
+ @rn-primitives/aspect-ratio
175
+ @rn-primitives/table
176
+ @rn-primitives/portal
177
+ ```
178
+ - If a matching primitive exists → MUST use it as the foundation.
179
+ - MUST NOT recreate accessible behavior manually when a primitive is available.
180
+
181
+ ---
182
+
183
+ ### 2. Web Component Reference
184
+
185
+ - Use `read_file` on:
186
+ `packages/pawprint-web/src/components/{atoms,molecules}/[ComponentName]/[ComponentName].tsx`
187
+ - Study the web component's:
188
+ - Prop types and variants
189
+ - Token paths used
190
+ - JSDoc documentation
191
+ - API surface
192
+
193
+ You MUST document:
194
+ - Which props and variants the web component has
195
+ - How they will map to the native implementation
196
+ - Any platform-specific differences
197
+
198
+ ---
199
+
200
+ ### 3. Existing Native Component Audit
201
+
202
+ - Use `list_dir` and `read_file` on:
203
+ `packages/pawprint-native/src`
204
+ - Identify reusable native components (Typography, Icon, Spinner, Illustration, etc.).
205
+
206
+ You MUST document:
207
+ - Which existing components will be reused
208
+ - How they map to Figma elements
209
+
210
+ ---
211
+
212
+ ### 4. Token Audit
213
+
214
+ - Use `read_file` or `grep_search` on:
215
+ `packages/pawprint-tokens/build/tokens.d.ts`
216
+
217
+ You MUST document:
218
+ - Exact token paths available
219
+
220
+ Example:
221
+ `theme.tokens.components.buttons.button.colour.background.primary`
222
+
223
+ You MUST list exact token paths before coding.
224
+
225
+ ---
226
+
227
+ ### 5. Figma Analysis
228
+
229
+ - Use `mcp0_get_screenshot`
230
+ - Document:
231
+
232
+ - All variants
233
+ - All states (default, pressed, disabled, error, selected, checked, etc.)
234
+ - Exact layout order
235
+ - Element positioning
236
+ - Spacing
237
+ - Sizing
238
+ - Typography
239
+ - Colors
240
+
241
+ You MUST NOT invent variants or states not visible in Figma.
242
+
243
+ Note: React Native does not have hover states — skip hover unless the component runs on web via Expo.
244
+
245
+ ---
246
+
247
+ ## Step 2 – Decision Points
248
+
249
+ If multiple valid approaches exist:
250
+
251
+ - Use `ask_user_question`
252
+ - Present:
253
+ - What was detected
254
+ - Architectural recommendation
255
+ - Clear options
256
+ - Allow multi-select if needed
257
+
258
+ Do NOT proceed without user confirmation when structural decisions exist.
259
+
260
+ ---
261
+
262
+ ## Step 3 – Implementation Rules
263
+
264
+ - Only implement what is explicitly requested.
265
+ - Use `@rn-primitives` components if available as the accessible foundation.
266
+ - Use standard React Native primitives for layout:
267
+
268
+ - `View` → generic container
269
+ - `Pressable` → interactive elements (NOT `TouchableOpacity`)
270
+ - `ScrollView` → scrollable content
271
+ - `FlatList` → long lists
272
+
273
+ - Compose existing design system components (Typography, Icon, Spinner).
274
+ - Apply tokens using strict fallback strategy.
275
+ - Use `styled` from `@emotion/native` for token-driven styles.
276
+ - Use `useTheme` from `@emotion/react` for dynamic token access in component body.
277
+ - Use `parseTokenValue()` to convert string tokens to numbers.
278
+ - Prefix internal styled props to avoid clashes with native props:
279
+ ```tsx
280
+ // ✅ GOOD: badgeVariant, badgeSize (prefixed)
281
+ // ❌ BAD: variant, size (may clash with native props)
282
+ ```
283
+ - Use proper TypeScript types.
284
+ - Use `React.forwardRef<View, Props>` (or `Pressable`, `TextInput` as appropriate).
285
+ - Always use `Typography` for text — NEVER raw `<Text>`.
286
+ - Add comprehensive JSDoc comments on the component export:
287
+
288
+ ```tsx
289
+ /**
290
+ * Short description of what the component is and does.
291
+ *
292
+ * @param {"variant-a" | "variant-b"} [variant="variant-a"] - Description.
293
+ * @param {"sm" | "md" | "lg"} [size="md"] - Description.
294
+ * @param {boolean} [disabled=false] - Description.
295
+ *
296
+ * @example
297
+ * ```tsx
298
+ * import { Component } from "@butternutbox/pawprint-native"
299
+ *
300
+ * <Component size="md">Content</Component>
301
+ * ```
302
+ */
303
+ export const Component = React.forwardRef<View, ComponentProps>(
304
+ (props, ref) => { ... }
305
+ )
306
+ ```
307
+
308
+ - Do NOT add comments inside TypeScript type definitions.
309
+ - Follow `COMPONENT_GUIDELINES.md`.
310
+
311
+ ---
312
+
313
+ ## Step 4 – Interactive States
314
+
315
+ React Native has no CSS pseudo-classes. Handle states via:
316
+
317
+ - `Pressable` `style` callback for pressed state:
318
+ ```tsx
319
+ <Pressable style={({ pressed }) => [
320
+ styles.base,
321
+ pressed && styles.pressed
322
+ ]} />
323
+ ```
324
+ - Props on styled components for variant/disabled states:
325
+ ```tsx
326
+ const StyledButton = styled(Pressable)<{ isDisabled: boolean }>(
327
+ ({ theme, isDisabled }) => ({
328
+ backgroundColor: isDisabled
329
+ ? tokens.colour.background.disabled
330
+ : tokens.colour.background.default,
331
+ opacity: isDisabled ? 0.5 : 1
332
+ })
333
+ )
334
+ ```
335
+ - `Animated` or `react-native-reanimated` for animated transitions.
336
+
337
+ States to implement:
338
+ - default
339
+ - pressed (via Pressable callback)
340
+ - disabled (via `disabled` prop + visual tokens)
341
+ - error / success (via `state` or `variant` prop)
342
+ - checked / selected (for toggles, checkboxes, radios)
343
+
344
+ Do NOT implement hover states (not available on mobile).
345
+
346
+ ---
347
+
348
+ ## Step 5 – Accessibility
349
+
350
+ - Use `accessible={true}` on interactive elements.
351
+ - Set `accessibilityRole`:
352
+ - `"button"` for buttons
353
+ - `"checkbox"` for checkboxes
354
+ - `"switch"` for switches
355
+ - `"image"` for icons/illustrations with labels
356
+ - `"link"` for links
357
+ - `"adjustable"` for sliders
358
+ - `"radio"` for radio buttons
359
+ - Set `accessibilityLabel` for icon-only or image components.
360
+ - Set `accessibilityState` for stateful components:
361
+ ```tsx
362
+ accessibilityState={{ disabled, checked, selected }}
363
+ ```
364
+ - Set `accessibilityHint` when the action is not obvious from the label.
365
+ - Ensure sufficient color contrast (use semantic tokens).
366
+ - Dev-mode `console.warn` when `aria-label` is missing on meaningful icons.
367
+
368
+ ---
369
+
370
+ ## Step 6 – Storybook Requirements
371
+
372
+ - Co-locate stories in the component folder: `[ComponentName].stories.tsx`
373
+ - Use CSF format with `export default { title, component, argTypes }`.
374
+ - Every argType MUST have a `description` field.
375
+ - Create stories for:
376
+ - ALL variants
377
+ - ALL states
378
+ - Include:
379
+ - `Playground` story with args for every controllable prop
380
+ - `AllVariants` story showcasing all variant/size combinations
381
+ - State-specific stories (disabled, loading, error, etc.)
382
+ - Use `StyleSheet.create` for story layout styles.
383
+ - For interactive controlled components, use `React.useState` in the story render.
384
+
385
+ ---
386
+
387
+ ## Step 7 – Export Requirements
388
+
389
+ You MUST:
390
+
391
+ 1. Create `index.ts` in the component folder:
392
+ ```tsx
393
+ export { [Component] } from "./[Component]"
394
+ export type { [Component]Props } from "./[Component]"
395
+ ```
396
+ 2. Export from:
397
+ - `atoms/index.ts`
398
+ - OR `molecules/index.ts`
399
+ - OR `organisms/index.ts`
400
+ 3. Export from main:
401
+ `components/index.ts`
402
+ 4. Verify the export chain reaches `src/index.ts`.
403
+
404
+ No other files may be modified.
405
+
406
+ ---
407
+
408
+ ## Step 8 – Visual Verification
409
+
410
+ - Compare Storybook rendering with Figma screenshot.
411
+ - Verify:
412
+ - Spacing
413
+ - Sizing
414
+ - Colors
415
+ - Typography
416
+ - Alignment
417
+ - Test all interactive states visually.
418
+ - Test on both iOS and Android (or Expo web) if possible.
419
+
420
+ ---
421
+
422
+ ## Step 9 – Parity Check
423
+
424
+ - Compare the native component API with the web version:
425
+ - Same prop names where possible
426
+ - Same variants and sizes
427
+ - Same token paths
428
+ - Document any platform-specific differences in JSDoc:
429
+ ```tsx
430
+ /**
431
+ * ...
432
+ * Note: Unlike the web version, `top` and `bottom` accept numbers only (not strings).
433
+ */
434
+ ```
435
+
436
+ ---
437
+
438
+ # 📦 Required Output Format
439
+
440
+ Before coding, you MUST provide:
441
+
442
+ 1. Web component reference (props, variants from web version)
443
+ 2. RN Primitives check result (available primitive or "none — building custom")
444
+ 3. Reuse mapping (existing native components → Figma elements)
445
+ 4. Token paths that will be used (exact strings)
446
+ 5. Proposed component API (props + variants)
447
+ 6. Platform differences from web version (if any)
448
+ 7. File plan (new files + modified export files)
449
+
450
+ After coding:
451
+
452
+ - Provide code grouped by file
453
+ - Clearly label each file path
454
+ - List exactly which files were:
455
+ - Created
456
+ - Modified
457
+
458
+ You MUST NOT output anything outside this structure.
package/package.json ADDED
@@ -0,0 +1,57 @@
1
+ {
2
+ "name": "@butternutbox/pawprint-native",
3
+ "version": "0.0.1",
4
+ "type": "module",
5
+ "description": "ButternutBox Pawprint Design System - React Native Components",
6
+ "main": "./dist/index.js",
7
+ "module": "./dist/index.mjs",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.mjs",
13
+ "require": "./dist/index.js"
14
+ }
15
+ },
16
+ "scripts": {
17
+ "build": "tsup",
18
+ "dev": "tsup --watch",
19
+ "clean": "rm -rf .turbo node_modules dist",
20
+ "lint:check": "eslint src --max-warnings 0",
21
+ "type:check": "tsc --noEmit"
22
+ },
23
+ "dependencies": {
24
+ "@butternutbox/pawprint-tokens": "^0.0.1",
25
+ "@emotion/native": "^11.11.0",
26
+ "@emotion/react": "^11.14.0",
27
+ "@rn-primitives/avatar": "^1.4.0",
28
+ "@rn-primitives/checkbox": "^1.4.0",
29
+ "@rn-primitives/portal": "^1.0.5",
30
+ "@rn-primitives/slider": "^1.4.0",
31
+ "@rn-primitives/slot": "^1.0.5",
32
+ "@rn-primitives/switch": "^1.4.0",
33
+ "@rn-primitives/toggle": "^1.4.0",
34
+ "@rn-primitives/types": "^1.0.5",
35
+ "expo": "^55.0.9"
36
+ },
37
+ "peerDependencies": {
38
+ "react": ">=18.0.0",
39
+ "react-native": ">=0.74.0"
40
+ },
41
+ "devDependencies": {
42
+ "@butternutbox/pawprint-icons": "workspace:*",
43
+ "@butternutbox/pawprint-illustrations": "workspace:*",
44
+ "@repo/eslint-config": "workspace:*",
45
+ "@repo/typescript-config": "workspace:*",
46
+ "@types/react": "~19.1.10",
47
+ "@types/react-native": "^0.73.0",
48
+ "eslint": "^8.57.0",
49
+ "react": "19.1.0",
50
+ "react-native": "0.81.5",
51
+ "tsup": "^8.5.0",
52
+ "typescript": "^5.7.3"
53
+ },
54
+ "publishConfig": {
55
+ "access": "public"
56
+ }
57
+ }
@@ -0,0 +1,125 @@
1
+ import React from "react"
2
+ import { View, StyleSheet } from "react-native"
3
+ import { Avatar } from "./Avatar"
4
+ import type { AvatarProps } from "./Avatar"
5
+
6
+ const DOG_PHOTO_URL = "https://placedog.net/200/200"
7
+
8
+ export default {
9
+ title: "Atoms/Avatar",
10
+ component: Avatar,
11
+ argTypes: {
12
+ src: {
13
+ control: { type: "text" },
14
+ description: "Image source URL"
15
+ },
16
+ alt: {
17
+ control: { type: "text" },
18
+ description: "Accessible label (required)"
19
+ },
20
+ size: {
21
+ control: { type: "select" },
22
+ options: ["sm", "md", "lg"],
23
+ description: "Size variant"
24
+ },
25
+ border: {
26
+ control: { type: "select" },
27
+ options: ["none", "sm", "md"],
28
+ description: "Border width variant"
29
+ },
30
+ fallbackType: {
31
+ control: { type: "select" },
32
+ options: ["string", "image"],
33
+ description: "Fallback display type (auto-detected)"
34
+ },
35
+ fallbackString: {
36
+ control: { type: "text" },
37
+ description: "Text to display as fallback (e.g. user initials)"
38
+ }
39
+ }
40
+ }
41
+
42
+ export const Default = (args: AvatarProps) => <Avatar {...args} />
43
+ Default.args = {
44
+ src: DOG_PHOTO_URL,
45
+ alt: "User Photo",
46
+ size: "md",
47
+ border: "none"
48
+ }
49
+
50
+ export const Sizes = () => (
51
+ <View style={styles.row}>
52
+ <Avatar src={DOG_PHOTO_URL} alt="Small avatar" size="sm" />
53
+ <Avatar src={DOG_PHOTO_URL} alt="Medium avatar" size="md" />
54
+ <Avatar src={DOG_PHOTO_URL} alt="Large avatar" size="lg" />
55
+ </View>
56
+ )
57
+
58
+ export const Borders = () => (
59
+ <View style={styles.row}>
60
+ <Avatar src={DOG_PHOTO_URL} alt="No border" border="none" />
61
+ <Avatar src={DOG_PHOTO_URL} alt="Small border" border="sm" />
62
+ <Avatar src={DOG_PHOTO_URL} alt="Medium border" border="md" />
63
+ </View>
64
+ )
65
+
66
+ export const FallbackString = (args: AvatarProps) => <Avatar {...args} />
67
+ FallbackString.args = {
68
+ alt: "User initials",
69
+ fallbackString: "JD",
70
+ size: "md"
71
+ }
72
+
73
+ export const FallbackStringSizes = () => (
74
+ <View style={styles.row}>
75
+ <Avatar alt="Small" fallbackString="AB" size="sm" />
76
+ <Avatar alt="Medium" fallbackString="CD" size="md" />
77
+ <Avatar alt="Large" fallbackString="EF" size="lg" />
78
+ </View>
79
+ )
80
+
81
+ export const FallbackImage = (args: AvatarProps) => <Avatar {...args} />
82
+ FallbackImage.args = {
83
+ alt: "Default avatar icon",
84
+ fallbackType: "image",
85
+ size: "md"
86
+ }
87
+
88
+ export const BrokenImage = () => (
89
+ <View style={styles.row}>
90
+ <Avatar
91
+ src="https://broken-link.com/photo.jpg"
92
+ alt="Broken with string fallback"
93
+ fallbackString="JD"
94
+ fallbackType="string"
95
+ />
96
+ <Avatar
97
+ src="https://broken-link.com/photo.jpg"
98
+ alt="Broken with image fallback"
99
+ fallbackType="image"
100
+ />
101
+ </View>
102
+ )
103
+
104
+ export const BordersWithFallback = () => (
105
+ <View style={styles.row}>
106
+ <Avatar alt="No border" fallbackString="AB" border="none" />
107
+ <Avatar alt="Small border" fallbackString="CD" border="sm" />
108
+ <Avatar alt="Medium border" fallbackString="EF" border="md" />
109
+ </View>
110
+ )
111
+
112
+ export const LongInitials = (args: AvatarProps) => <Avatar {...args} />
113
+ LongInitials.args = {
114
+ alt: "Long initials",
115
+ fallbackString: "ABC",
116
+ size: "lg"
117
+ }
118
+
119
+ const styles = StyleSheet.create({
120
+ row: {
121
+ flexDirection: "row",
122
+ gap: 16,
123
+ alignItems: "center"
124
+ }
125
+ })