@oztix/roadie-components 1.2.0 → 2.0.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 (221) hide show
  1. package/dist/Accordion.d.ts +37 -0
  2. package/dist/Accordion.js +3 -0
  3. package/dist/Accordion.js.map +1 -0
  4. package/dist/Autocomplete.d.ts +131 -0
  5. package/dist/Autocomplete.js +3 -0
  6. package/dist/Autocomplete.js.map +1 -0
  7. package/dist/Badge.d.ts +22 -0
  8. package/dist/Badge.js +2 -0
  9. package/dist/Badge.js.map +1 -0
  10. package/dist/Breadcrumb.d.ts +43 -0
  11. package/dist/Breadcrumb.js +2 -0
  12. package/dist/Breadcrumb.js.map +1 -0
  13. package/dist/Button-DagX1D_q.d.ts +19 -0
  14. package/dist/Button.d.ts +11 -15
  15. package/dist/Button.js +1 -1
  16. package/dist/Card.d.ts +51 -0
  17. package/dist/Card.js +2 -0
  18. package/dist/Card.js.map +1 -0
  19. package/dist/Code.d.ts +14 -24
  20. package/dist/Code.js +1 -1
  21. package/dist/Combobox.d.ts +137 -0
  22. package/dist/Combobox.js +3 -0
  23. package/dist/Combobox.js.map +1 -0
  24. package/dist/Field.d.ts +71 -0
  25. package/dist/Field.js +3 -0
  26. package/dist/Field.js.map +1 -0
  27. package/dist/Fieldset.d.ts +36 -0
  28. package/dist/Fieldset.js +3 -0
  29. package/dist/Fieldset.js.map +1 -0
  30. package/dist/Highlight.d.ts +14 -36
  31. package/dist/Highlight.js +1 -1
  32. package/dist/Indicator.d.ts +17 -0
  33. package/dist/Indicator.js +2 -0
  34. package/dist/Indicator.js.map +1 -0
  35. package/dist/Input.d.ts +18 -0
  36. package/dist/Input.js +3 -0
  37. package/dist/Input.js.map +1 -0
  38. package/dist/Label.d.ts +11 -0
  39. package/dist/Label.js +2 -0
  40. package/dist/Label.js.map +1 -0
  41. package/dist/LinkButton.d.ts +35 -0
  42. package/dist/LinkButton.js +2 -0
  43. package/dist/LinkButton.js.map +1 -0
  44. package/dist/Mark.d.ts +15 -26
  45. package/dist/Mark.js +1 -1
  46. package/dist/Marquee.d.ts +21 -0
  47. package/dist/Marquee.js +3 -0
  48. package/dist/Marquee.js.map +1 -0
  49. package/dist/Prose.d.ts +22 -0
  50. package/dist/Prose.js +2 -0
  51. package/dist/Prose.js.map +1 -0
  52. package/dist/RadioGroup.d.ts +59 -0
  53. package/dist/RadioGroup.js +3 -0
  54. package/dist/RadioGroup.js.map +1 -0
  55. package/dist/Select.d.ts +144 -0
  56. package/dist/Select.js +3 -0
  57. package/dist/Select.js.map +1 -0
  58. package/dist/Separator.d.ts +16 -0
  59. package/dist/Separator.js +2 -0
  60. package/dist/Separator.js.map +1 -0
  61. package/dist/SpotIllustration.d.ts +59 -24
  62. package/dist/SpotIllustration.js +2 -1
  63. package/dist/SpotIllustration.js.map +1 -1
  64. package/dist/Steps.d.ts +105 -0
  65. package/dist/Steps.js +3 -0
  66. package/dist/Steps.js.map +1 -0
  67. package/dist/Textarea.d.ts +19 -0
  68. package/dist/Textarea.js +3 -0
  69. package/dist/Textarea.js.map +1 -0
  70. package/dist/_chunks/chunk-2MBFDJ6K.js +3 -0
  71. package/dist/_chunks/chunk-2MBFDJ6K.js.map +1 -0
  72. package/dist/_chunks/chunk-3HWPLULJ.js +2 -0
  73. package/dist/_chunks/chunk-3HWPLULJ.js.map +1 -0
  74. package/dist/_chunks/chunk-3NU36NBL.js +3 -0
  75. package/dist/_chunks/chunk-3NU36NBL.js.map +1 -0
  76. package/dist/_chunks/chunk-42UB7PQB.js +3 -0
  77. package/dist/_chunks/chunk-42UB7PQB.js.map +1 -0
  78. package/dist/_chunks/chunk-4LGCF3SN.js +3 -0
  79. package/dist/_chunks/chunk-4LGCF3SN.js.map +1 -0
  80. package/dist/_chunks/chunk-A6JSYXKN.js +2 -0
  81. package/dist/_chunks/chunk-A6JSYXKN.js.map +1 -0
  82. package/dist/_chunks/chunk-AFSDN4WI.js +2 -0
  83. package/dist/_chunks/chunk-AFSDN4WI.js.map +1 -0
  84. package/dist/_chunks/chunk-DRVUAPKN.js +2 -0
  85. package/dist/_chunks/chunk-DRVUAPKN.js.map +1 -0
  86. package/dist/_chunks/chunk-EKOEXSAP.js +2 -0
  87. package/dist/_chunks/chunk-EKOEXSAP.js.map +1 -0
  88. package/dist/_chunks/chunk-FQNVMKKV.js +7 -0
  89. package/dist/_chunks/chunk-FQNVMKKV.js.map +1 -0
  90. package/dist/_chunks/chunk-FSO4EAAY.js +3 -0
  91. package/dist/_chunks/chunk-FSO4EAAY.js.map +1 -0
  92. package/dist/_chunks/chunk-IEDKSZAQ.js +3 -0
  93. package/dist/_chunks/chunk-IEDKSZAQ.js.map +1 -0
  94. package/dist/_chunks/chunk-JBHYUOI2.js +3 -0
  95. package/dist/_chunks/chunk-JBHYUOI2.js.map +1 -0
  96. package/dist/_chunks/chunk-JGTZ3GCR.js +2 -0
  97. package/dist/_chunks/chunk-JGTZ3GCR.js.map +1 -0
  98. package/dist/_chunks/chunk-LHNOY24C.js +2 -0
  99. package/dist/_chunks/chunk-LHNOY24C.js.map +1 -0
  100. package/dist/_chunks/chunk-LMV3JECI.js +3 -0
  101. package/dist/_chunks/chunk-LMV3JECI.js.map +1 -0
  102. package/dist/_chunks/chunk-M4FEKBLW.js +2 -0
  103. package/dist/_chunks/chunk-M4FEKBLW.js.map +1 -0
  104. package/dist/_chunks/chunk-MDRAL676.js +3 -0
  105. package/dist/_chunks/chunk-MDRAL676.js.map +1 -0
  106. package/dist/_chunks/chunk-N2HGY7W7.js +3 -0
  107. package/dist/_chunks/chunk-N2HGY7W7.js.map +1 -0
  108. package/dist/_chunks/chunk-OIAETOZT.js +3 -0
  109. package/dist/_chunks/chunk-OIAETOZT.js.map +1 -0
  110. package/dist/_chunks/chunk-RXMWFJ6W.js +3 -0
  111. package/dist/_chunks/chunk-RXMWFJ6W.js.map +1 -0
  112. package/dist/_chunks/chunk-VSKUGXQG.js +3 -0
  113. package/dist/_chunks/chunk-VSKUGXQG.js.map +1 -0
  114. package/dist/_chunks/chunk-WOU2B425.js +3 -0
  115. package/dist/_chunks/chunk-WOU2B425.js.map +1 -0
  116. package/dist/_chunks/chunk-Y6TDYPCZ.js +3 -0
  117. package/dist/_chunks/chunk-Y6TDYPCZ.js.map +1 -0
  118. package/dist/_chunks/chunk-ZXR32FYA.js +2 -0
  119. package/dist/_chunks/chunk-ZXR32FYA.js.map +1 -0
  120. package/dist/index.d.ts +60 -15
  121. package/dist/index.js +34 -1
  122. package/dist/index.js.map +1 -1
  123. package/package.json +18 -22
  124. package/dist/Container.d.ts +0 -34
  125. package/dist/Container.js +0 -2
  126. package/dist/Container.js.map +0 -1
  127. package/dist/Heading.d.ts +0 -45
  128. package/dist/Heading.js +0 -2
  129. package/dist/Heading.js.map +0 -1
  130. package/dist/Text.d.ts +0 -47
  131. package/dist/Text.js +0 -2
  132. package/dist/Text.js.map +0 -1
  133. package/dist/View.d.ts +0 -12
  134. package/dist/View.js +0 -2
  135. package/dist/View.js.map +0 -1
  136. package/dist/_chunks/chunk-AZZHYO2A.js +0 -3
  137. package/dist/_chunks/chunk-AZZHYO2A.js.map +0 -1
  138. package/dist/_chunks/chunk-JOQJCXYF.js +0 -2
  139. package/dist/_chunks/chunk-JOQJCXYF.js.map +0 -1
  140. package/dist/_chunks/chunk-NMGF2AP6.js +0 -2
  141. package/dist/_chunks/chunk-NMGF2AP6.js.map +0 -1
  142. package/dist/_chunks/chunk-OH4JYS35.js +0 -3
  143. package/dist/_chunks/chunk-OH4JYS35.js.map +0 -1
  144. package/dist/_chunks/chunk-P5L5LN6E.js +0 -2
  145. package/dist/_chunks/chunk-P5L5LN6E.js.map +0 -1
  146. package/dist/_chunks/chunk-RJEJUZ3O.js +0 -2
  147. package/dist/_chunks/chunk-RJEJUZ3O.js.map +0 -1
  148. package/dist/_chunks/chunk-SUDUTP6A.js +0 -3
  149. package/dist/_chunks/chunk-SUDUTP6A.js.map +0 -1
  150. package/dist/_chunks/chunk-YNF56IUK.js +0 -2
  151. package/dist/_chunks/chunk-YNF56IUK.js.map +0 -1
  152. package/dist/_chunks/chunk-ZXS7U3VJ.js +0 -2
  153. package/dist/_chunks/chunk-ZXS7U3VJ.js.map +0 -1
  154. package/dist/hooks/index.d.ts +0 -27
  155. package/dist/hooks/index.js +0 -2
  156. package/dist/hooks/index.js.map +0 -1
  157. package/src/components/Button/Button.test.tsx +0 -156
  158. package/src/components/Button/Button.tsx +0 -12
  159. package/src/components/Button/IconButton.test.tsx +0 -234
  160. package/src/components/Button/IconButton.tsx +0 -14
  161. package/src/components/Button/index.tsx +0 -2
  162. package/src/components/Code/Code.test.tsx +0 -85
  163. package/src/components/Code/index.tsx +0 -37
  164. package/src/components/Container/Container.test.tsx +0 -241
  165. package/src/components/Container/index.tsx +0 -34
  166. package/src/components/Heading/Heading.test.tsx +0 -128
  167. package/src/components/Heading/index.tsx +0 -49
  168. package/src/components/Highlight/Highlight.test.tsx +0 -113
  169. package/src/components/Highlight/index.tsx +0 -96
  170. package/src/components/Mark/Mark.test.tsx +0 -82
  171. package/src/components/Mark/index.tsx +0 -33
  172. package/src/components/SpotIllustration/ArrowUpRight.tsx +0 -9
  173. package/src/components/SpotIllustration/CowboyHat.tsx +0 -6
  174. package/src/components/SpotIllustration/Cursor.tsx +0 -6
  175. package/src/components/SpotIllustration/FlowerSpiral.tsx +0 -9
  176. package/src/components/SpotIllustration/Football.tsx +0 -6
  177. package/src/components/SpotIllustration/Hand.tsx +0 -6
  178. package/src/components/SpotIllustration/Heart.tsx +0 -6
  179. package/src/components/SpotIllustration/HighFive.tsx +0 -6
  180. package/src/components/SpotIllustration/MapPin.tsx +0 -6
  181. package/src/components/SpotIllustration/NoteMusic.tsx +0 -6
  182. package/src/components/SpotIllustration/README.md +0 -280
  183. package/src/components/SpotIllustration/SpotIllustration.test.tsx +0 -179
  184. package/src/components/SpotIllustration/SpotIllustration.tsx +0 -96
  185. package/src/components/SpotIllustration/Ticket.tsx +0 -6
  186. package/src/components/SpotIllustration/WineGlass.tsx +0 -6
  187. package/src/components/SpotIllustration/createSpotIllustration.tsx +0 -46
  188. package/src/components/SpotIllustration/index.tsx +0 -42
  189. package/src/components/SpotIllustration/json/arrow-up-right.json +0 -34
  190. package/src/components/SpotIllustration/json/cowboy-hat.json +0 -34
  191. package/src/components/SpotIllustration/json/cursor.json +0 -34
  192. package/src/components/SpotIllustration/json/flower-spiral.json +0 -38
  193. package/src/components/SpotIllustration/json/football.json +0 -46
  194. package/src/components/SpotIllustration/json/hand.json +0 -22
  195. package/src/components/SpotIllustration/json/heart.json +0 -26
  196. package/src/components/SpotIllustration/json/high-five.json +0 -62
  197. package/src/components/SpotIllustration/json/map-pin.json +0 -26
  198. package/src/components/SpotIllustration/json/note-music.json +0 -42
  199. package/src/components/SpotIllustration/json/ticket.json +0 -42
  200. package/src/components/SpotIllustration/json/wine-glass.json +0 -34
  201. package/src/components/SpotIllustration/svgs/arrow-up-right.svg +0 -9
  202. package/src/components/SpotIllustration/svgs/cowboy-hat.svg +0 -9
  203. package/src/components/SpotIllustration/svgs/cursor.svg +0 -9
  204. package/src/components/SpotIllustration/svgs/flower-spiral.svg +0 -10
  205. package/src/components/SpotIllustration/svgs/football.svg +0 -12
  206. package/src/components/SpotIllustration/svgs/hand.svg +0 -6
  207. package/src/components/SpotIllustration/svgs/heart.svg +0 -7
  208. package/src/components/SpotIllustration/svgs/high-five.svg +0 -16
  209. package/src/components/SpotIllustration/svgs/map-pin.svg +0 -7
  210. package/src/components/SpotIllustration/svgs/note-music.svg +0 -11
  211. package/src/components/SpotIllustration/svgs/ticket.svg +0 -11
  212. package/src/components/SpotIllustration/svgs/wine-glass.svg +0 -9
  213. package/src/components/Text/Text.test.tsx +0 -121
  214. package/src/components/Text/index.tsx +0 -51
  215. package/src/components/View/View.test.tsx +0 -161
  216. package/src/components/View/index.tsx +0 -12
  217. package/src/components/index.ts +0 -17
  218. package/src/hooks/index.ts +0 -1
  219. package/src/hooks/useColorMode.ts +0 -37
  220. package/src/index.test.tsx +0 -37
  221. package/src/index.tsx +0 -9
@@ -1,280 +0,0 @@
1
- # SpotIllustration System
2
-
3
- A fully automated system for creating themed SVG illustrations that adapt to the design system's color palette.
4
-
5
- ## Quick Start
6
-
7
- ### Adding a New Illustration
8
-
9
- 1. **Export from Figma**: Save your SVG to `svgs/your-name.svg`
10
- 2. **Run the script**: `pnpm build:spotillustration`
11
- 3. **Done!** Your component is ready to use
12
-
13
- The script automatically generates:
14
-
15
- - Optimized JSON data file
16
- - React TypeScript component
17
- - Updated exports in `index.tsx`
18
-
19
- ### Development Workflow
20
-
21
- During development, the script runs in watch mode:
22
-
23
- ```bash
24
- pnpm dev
25
- ```
26
-
27
- Any SVG files added or modified in the `svgs/` directory will automatically trigger:
28
-
29
- 1. SVG optimization
30
- 2. Component generation
31
- 3. Export updates
32
-
33
- No manual intervention required.
34
-
35
- ## Design Requirements
36
-
37
- ### Frame Size
38
-
39
- Use a **48x48** frame in Figma (or maintain the same aspect ratio).
40
-
41
- ### Color Palette
42
-
43
- Use these exact hex colors in your Figma design. The script categorizes paths by color:
44
-
45
- | Color | Hex | Layer | Purpose |
46
- | ----------- | --------- | ----------- | ---------------------------------------- |
47
- | White | `#ffffff` | `outline` | White stroke outline (hidden by default) |
48
- | Purple tint | `#E1D1FB` | `face` | Main fills, primary shapes |
49
- | Orange tint | `#FFC3A8` | `detail` | Accent details, highlights |
50
- | Blue | `#0091EB` | `shadow` | Shadow layers, depth |
51
- | Light blue | `#C2DFFB` | `highlight` | Light highlights, shine |
52
- | Near black | `#1A1F2B` | `stroke` | Outlines, strokes |
53
-
54
- ### Layer Ordering
55
-
56
- SVG renders paths in order, so arrange layers intentionally:
57
-
58
- 1. Outline (if needed)
59
- 2. Shadows (background)
60
- 3. Face/main shapes
61
- 4. Details
62
- 5. Highlights (foreground)
63
- 6. Strokes (top layer)
64
-
65
- The script preserves your exact path order from Figma.
66
-
67
- ## How the Script Works
68
-
69
- ### Build Script: `svg-to-spot-illustration.cjs`
70
-
71
- Location: `packages/components/scripts/svg-to-spot-illustration.cjs`
72
-
73
- #### Process Flow
74
-
75
- 1. **SVG Optimization** (SVGO)
76
- - Removes unnecessary attributes
77
- - Cleans up paths
78
- - Removes dimensions (preserves viewBox)
79
- - Skip with `--no-optimize` flag if needed
80
-
81
- 2. **Path Categorization**
82
- - Reads semantic illustration tokens from `@oztix/roadie-core`
83
- - Matches each path's fill/stroke color to closest token color
84
- - Assigns semantic layer name (face, detail, shadow, etc.)
85
- - Preserves exact path order from source SVG
86
-
87
- 3. **JSON Generation**
88
- - Creates optimized JSON in `json/` directory
89
- - Structure:
90
- ```json
91
- {
92
- "$comment": "Generated file - do not edit directly",
93
- "viewBox": "0 0 48 48",
94
- "paths": [{ "d": "M26.179...", "layer": "face" }]
95
- }
96
- ```
97
-
98
- 4. **Component Generation**
99
- - Converts `kebab-case.svg` → `PascalCase.tsx`
100
- - Uses `createSpotIllustration` factory
101
- - Adds TypeScript types
102
- - Example output:
103
-
104
- ```tsx
105
- // Generated file - do not edit directly
106
- import { createSpotIllustration } from './createSpotIllustration'
107
- import heartData from './json/heart.json'
108
-
109
- export const Heart = createSpotIllustration('Heart', heartData)
110
- export type HeartProps = React.ComponentPropsWithRef<typeof Heart>
111
- ```
112
-
113
- 5. **Export Updates**
114
- - Scans directory for all component files
115
- - Updates `index.tsx` with alphabetically sorted exports
116
- - Preserves base component exports (SpotIllustration, createSpotIllustration)
117
-
118
- ### Usage Modes
119
-
120
- **Build all SVGs:**
121
-
122
- ```bash
123
- pnpm build:spotillustration
124
- ```
125
-
126
- **Build specific SVG:**
127
-
128
- ```bash
129
- pnpm build:spotillustration src/components/SpotIllustration/svgs/heart.svg
130
- ```
131
-
132
- **Watch mode (auto-rebuild on changes):**
133
-
134
- ```bash
135
- pnpm build:spotillustration --watch
136
- ```
137
-
138
- **Skip optimization:**
139
-
140
- ```bash
141
- pnpm build:spotillustration --no-optimize
142
- ```
143
-
144
- ### Color Matching Algorithm
145
-
146
- The script uses Euclidean distance in RGB color space to match fills/strokes to semantic tokens:
147
-
148
- 1. Normalize colors (expand short hex, lowercase)
149
- 2. Calculate RGB distance to each token color
150
- 3. Assign to closest matching layer
151
- 4. Default to 'face' if distance > 100 (no close match)
152
- 5. Strokes (paths with stroke but no fill) → 'stroke' layer
153
-
154
- ## Component Architecture
155
-
156
- ### Base Component: `SpotIllustration`
157
-
158
- Accepts illustration data and renders themed SVG:
159
-
160
- ```tsx
161
- <SpotIllustration
162
- illustration={illustrationData}
163
- boxSize='600'
164
- outline={false}
165
- />
166
- ```
167
-
168
- ### Factory: `createSpotIllustration`
169
-
170
- Creates pre-configured components from JSON data:
171
-
172
- ```tsx
173
- export const Heart = createSpotIllustration('Heart', heartData)
174
- ```
175
-
176
- This returns a component with:
177
-
178
- - Pre-loaded illustration data
179
- - Forward ref support
180
- - All SpotIllustration props except `illustration`
181
- - TypeScript types
182
-
183
- ### Styling System
184
-
185
- Components use PandaCSS with semantic tokens:
186
-
187
- - `colorPalette` system for theming
188
- - Data attributes for layer targeting: `data-part="face"`, `data-part="shadow"`, etc.
189
- - `outline` variant to show/hide white outline
190
- - All PandaCSS style props supported
191
-
192
- ## File Structure
193
-
194
- ```
195
- SpotIllustration/
196
- ├── README.md # This file
197
- ├── SpotIllustration.tsx # Base component
198
- ├── createSpotIllustration.tsx # Factory function
199
- ├── index.tsx # Exports (auto-updated)
200
- ├── svgs/ # Source SVG files
201
- │ ├── heart.svg
202
- │ ├── high-five.svg
203
- │ └── note-music.svg
204
- ├── json/ # Generated JSON (do not edit)
205
- │ ├── heart.json
206
- │ ├── high-five.json
207
- │ └── note-music.json
208
- ├── Heart.tsx # Generated component (do not edit)
209
- ├── HighFive.tsx # Generated component (do not edit)
210
- └── NoteMusic.tsx # Generated component (do not edit)
211
- ```
212
-
213
- ## Troubleshooting
214
-
215
- ### Colors Not Matching Correctly
216
-
217
- - Verify you're using exact hex colors from the table above
218
- - Check that fills/strokes are applied directly to paths (not groups)
219
- - Try `--no-optimize` if SVGO is changing colors
220
-
221
- ### Wrong Layer Order
222
-
223
- - Check layer order in Figma (bottom to top)
224
- - SVG renders paths sequentially
225
- - Reorder in Figma and re-export
226
-
227
- ### Component Not Exported
228
-
229
- - Check that `index.tsx` was updated (should happen automatically)
230
- - Run `pnpm build:spotillustration` again
231
- - Verify component file was created in SpotIllustration directory
232
-
233
- ### Watch Mode Not Detecting Changes
234
-
235
- - Ensure file is saved in `svgs/` directory with `.svg` extension
236
- - Check terminal for error messages
237
- - Restart watch mode if needed
238
-
239
- ## Advanced Usage
240
-
241
- ### Custom Illustrations at Runtime
242
-
243
- Use the base component with custom JSON data:
244
-
245
- ```tsx
246
- import { SpotIllustration } from '@oztix/roadie-components'
247
-
248
- const customData = {
249
- viewBox: "0 0 48 48",
250
- paths: [
251
- { d: "M10,10 L30,30", layer: "stroke" }
252
- ]
253
- }
254
-
255
- <SpotIllustration illustration={customData} />
256
- ```
257
-
258
- ### Importing from Dedicated Export Path
259
-
260
- ```tsx
261
- import { Heart, NoteMusic } from '@oztix/roadie-components/spot-illustrations'
262
- ```
263
-
264
- This import path only includes SpotIllustration components, useful for tree-shaking.
265
-
266
- ## Contributing
267
-
268
- When adding new illustrations:
269
-
270
- 1. Follow the design requirements above
271
- 2. Use descriptive, kebab-case filenames (e.g., `music-note.svg`, not `icon-1.svg`)
272
- 3. Test in both light and dark themes
273
- 4. Verify outline variant works if applicable
274
- 5. Run the build script and commit all generated files
275
-
276
- ## Related Files
277
-
278
- - Script: `packages/components/scripts/svg-to-spot-illustration.cjs`
279
- - Tokens: `packages/core/src/tokens/semantic-tokens.json`
280
- - Documentation: `docs/src/app/components/spot-illustration/page.mdx`
@@ -1,179 +0,0 @@
1
- import { render } from '@testing-library/react'
2
- import { describe, expect, it } from 'vitest'
3
-
4
- import { Hand } from './Hand'
5
- import { Heart } from './Heart'
6
- import { Ticket } from './Ticket'
7
-
8
- describe('SpotIllustration', () => {
9
- describe('rendering', () => {
10
- it('should render an illustration', () => {
11
- const { container } = render(<Heart />)
12
- const svg = container.querySelector('svg')
13
- expect(svg).toBeInTheDocument()
14
- })
15
-
16
- it('should render with default viewBox', () => {
17
- const { container } = render(<Heart />)
18
- const svg = container.querySelector('svg')
19
- expect(svg).toHaveAttribute('viewBox', '0 0 48 48')
20
- })
21
-
22
- it('should render all path layers', () => {
23
- const { container } = render(<Heart />)
24
- const paths = container.querySelectorAll('path')
25
- expect(paths.length).toBeGreaterThan(0)
26
- })
27
- })
28
-
29
- describe('boxSize prop', () => {
30
- it('should apply default boxSize of 600', () => {
31
- const { container } = render(<Heart />)
32
- const svg = container.querySelector('svg')
33
- // Check for class name base (PandaCSS uses different format)
34
- expect(svg?.classList.length).toBeGreaterThan(0)
35
- })
36
-
37
- it('should apply custom boxSize', () => {
38
- const { container } = render(<Heart boxSize='800' />)
39
- const svg = container.querySelector('svg')
40
- expect(svg?.classList.length).toBeGreaterThan(0)
41
- })
42
-
43
- it('should support numeric boxSize values', () => {
44
- const { container } = render(<Heart boxSize='1200' />)
45
- const svg = container.querySelector('svg')
46
- expect(svg?.classList.length).toBeGreaterThan(0)
47
- })
48
- })
49
-
50
- describe('outline prop', () => {
51
- it('should render outline layer by default (outline=false)', () => {
52
- const { container } = render(<Ticket />)
53
- const paths = container.querySelectorAll('path')
54
- const outlinePaths = Array.from(paths).filter(
55
- (path) => (path as Element).getAttribute('data-part') === 'outline'
56
- )
57
- expect(outlinePaths.length).toBeGreaterThan(0)
58
- })
59
-
60
- it('should hide outline when outline=false (default)', () => {
61
- const { container } = render(<Ticket outline={false} />)
62
- const svg = container.querySelector('svg')
63
- // The outline should have opacity: 0 via CSS
64
- expect(svg).toBeInTheDocument()
65
- })
66
-
67
- it('should show outline when outline=true', () => {
68
- const { container } = render(<Ticket outline={true} />)
69
- const svg = container.querySelector('svg')
70
- // The outline should be visible via CSS
71
- expect(svg).toBeInTheDocument()
72
- })
73
- })
74
-
75
- describe('className prop', () => {
76
- it('should accept custom className', () => {
77
- const { container } = render(<Heart className='custom-class' />)
78
- const svg = container.querySelector('svg')
79
- // PandaCSS merges classes differently - just check element exists
80
- expect(svg).toBeInTheDocument()
81
- expect(svg?.classList.length).toBeGreaterThan(0)
82
- })
83
-
84
- it('should merge custom className with default classes', () => {
85
- const { container } = render(
86
- <Heart className='custom-class' boxSize='400' />
87
- )
88
- const svg = container.querySelector('svg')
89
- expect(svg).toBeInTheDocument()
90
- expect(svg?.classList.length).toBeGreaterThan(0)
91
- })
92
- })
93
-
94
- describe('ref forwarding', () => {
95
- it('should forward ref to svg element', () => {
96
- let svgRef: SVGSVGElement | null = null
97
- render(
98
- <Heart
99
- ref={(el) => {
100
- svgRef = el
101
- }}
102
- />
103
- )
104
- expect(svgRef).toBeInstanceOf(SVGSVGElement)
105
- })
106
-
107
- it('should allow accessing svg properties via ref', () => {
108
- let svgRef: SVGSVGElement | null = null
109
- render(
110
- <Heart
111
- ref={(el) => {
112
- svgRef = el
113
- }}
114
- />
115
- )
116
- expect(svgRef).not.toBeNull()
117
- expect(svgRef!.getAttribute('viewBox')).toBeDefined()
118
- })
119
- })
120
-
121
- describe('different illustrations', () => {
122
- it('should render Heart illustration', () => {
123
- const { container } = render(<Heart />)
124
- const svg = container.querySelector('svg')
125
- expect(svg).toBeInTheDocument()
126
- })
127
-
128
- it('should render Ticket illustration', () => {
129
- const { container } = render(<Ticket />)
130
- const svg = container.querySelector('svg')
131
- expect(svg).toBeInTheDocument()
132
- })
133
-
134
- it('should render Hand illustration', () => {
135
- const { container } = render(<Hand />)
136
- const svg = container.querySelector('svg')
137
- expect(svg).toBeInTheDocument()
138
- })
139
-
140
- it('should render different number of paths for different illustrations', () => {
141
- const { container: heartContainer } = render(<Heart />)
142
- const { container: handContainer } = render(<Hand />)
143
-
144
- const heartPaths = heartContainer.querySelectorAll('path').length
145
- const handPaths = handContainer.querySelectorAll('path').length
146
-
147
- // Heart and Hand have different numbers of paths
148
- expect(heartPaths).not.toBe(handPaths)
149
- })
150
- })
151
-
152
- describe('layer colors', () => {
153
- it('should use semantic token colors via data-part attributes', () => {
154
- const { container } = render(<Heart />)
155
- const paths = container.querySelectorAll('path')
156
-
157
- // Check that paths have data-part attributes for styling
158
- const dataParts = Array.from(paths)
159
- .map((path) => (path as Element).getAttribute('data-part'))
160
- .filter(Boolean)
161
-
162
- expect(dataParts.length).toBeGreaterThan(0)
163
- })
164
- })
165
-
166
- describe('accessibility', () => {
167
- it('should be decorative by default (no role)', () => {
168
- const { container } = render(<Heart />)
169
- const svg = container.querySelector('svg')
170
- expect(svg).not.toHaveAttribute('role')
171
- })
172
-
173
- it('should accept aria attributes', () => {
174
- const { container } = render(<Heart aria-label='Heart icon' />)
175
- const svg = container.querySelector('svg')
176
- expect(svg).toHaveAttribute('aria-label', 'Heart icon')
177
- })
178
- })
179
- })
@@ -1,96 +0,0 @@
1
- import { forwardRef } from 'react'
2
-
3
- import { styled } from '@oztix/roadie-core/jsx'
4
- import type { HTMLStyledProps } from '@oztix/roadie-core/jsx'
5
-
6
- interface PathData {
7
- d: string
8
- layer: 'outline' | 'face' | 'detail' | 'shadow' | 'highlight' | 'stroke'
9
- }
10
-
11
- interface IllustrationData {
12
- viewBox: string
13
- paths: PathData[]
14
- }
15
-
16
- const StyledSvg = styled('svg', {
17
- base: {
18
- boxSize: '600',
19
- fill: 'none',
20
- '& [data-part="outline"]': {
21
- fill: 'illustrations.outline'
22
- },
23
- '& [data-part="face"]': {
24
- fill: 'illustrations.face'
25
- },
26
- '& [data-part="detail"]': {
27
- fill: 'illustrations.detail'
28
- },
29
- '& [data-part="shadow"]': {
30
- fill: 'illustrations.shadow'
31
- },
32
- '& [data-part="highlight"]': {
33
- fill: 'illustrations.highlight'
34
- },
35
- '& [data-part="stroke"]': {
36
- stroke: 'illustrations.stroke',
37
- strokeWidth: '0.5',
38
- strokeLinecap: 'round',
39
- strokeLinejoin: 'round',
40
- fill: 'none'
41
- }
42
- },
43
- variants: {
44
- outline: {
45
- true: {
46
- '& [data-part="outline"]': {
47
- opacity: 1
48
- }
49
- },
50
- false: {
51
- '& [data-part="outline"]': {
52
- opacity: 0
53
- }
54
- }
55
- }
56
- },
57
- defaultVariants: {
58
- outline: false
59
- }
60
- })
61
-
62
- export interface SpotIllustrationProps
63
- extends Omit<HTMLStyledProps<'svg'>, 'outline'> {
64
- /**
65
- * Illustration definition containing viewBox and paths
66
- */
67
- illustration: IllustrationData
68
- /**
69
- * Whether to show the outline layer
70
- * @default false
71
- */
72
- outline?: boolean
73
- }
74
-
75
- export const SpotIllustration = forwardRef<
76
- SVGSVGElement,
77
- SpotIllustrationProps
78
- >(({ illustration, ...props }, ref) => {
79
- // Fallback to default viewBox if not provided
80
- const { viewBox = '0 0 48 48', paths } = illustration
81
-
82
- return (
83
- <StyledSvg
84
- ref={ref}
85
- xmlns='http://www.w3.org/2000/svg'
86
- viewBox={viewBox}
87
- {...props}
88
- >
89
- {paths.map((path: PathData, index: number) => (
90
- <path key={index} d={path.d} data-part={path.layer} />
91
- ))}
92
- </StyledSvg>
93
- )
94
- })
95
-
96
- SpotIllustration.displayName = 'SpotIllustration'
@@ -1,6 +0,0 @@
1
- // Generated file - do not edit directly
2
- import { createSpotIllustration } from './createSpotIllustration'
3
- import ticketData from './json/ticket.json'
4
-
5
- export const Ticket = createSpotIllustration('Ticket', ticketData)
6
- export type TicketProps = React.ComponentPropsWithRef<typeof Ticket>
@@ -1,6 +0,0 @@
1
- // Generated file - do not edit directly
2
- import { createSpotIllustration } from './createSpotIllustration'
3
- import wineglassData from './json/wine-glass.json'
4
-
5
- export const WineGlass = createSpotIllustration('WineGlass', wineglassData)
6
- export type WineGlassProps = React.ComponentPropsWithRef<typeof WineGlass>
@@ -1,46 +0,0 @@
1
- import { forwardRef } from 'react'
2
-
3
- import {
4
- SpotIllustration,
5
- type SpotIllustrationProps
6
- } from './SpotIllustration'
7
-
8
- type IllustrationJson = SpotIllustrationProps['illustration']
9
-
10
- export type SpotIllustrationComponentProps = Omit<
11
- SpotIllustrationProps,
12
- 'illustration'
13
- >
14
-
15
- /**
16
- * Factory function to create a SpotIllustration component from JSON data
17
- *
18
- * @param name - Display name for the component
19
- * @param data - JSON data imported from the json folder
20
- * @returns A React component that renders the spot illustration
21
- *
22
- * @example
23
- * ```tsx
24
- * import { createSpotIllustration } from './createSpotIllustration'
25
- * import noteMusicData from './json/note-music.json'
26
- *
27
- * export const NoteMusic = createSpotIllustration('NoteMusic', noteMusicData)
28
- * ```
29
- */
30
- export function createSpotIllustration(name: string, data: unknown) {
31
- const Component = forwardRef<SVGSVGElement, SpotIllustrationComponentProps>(
32
- (props, ref) => {
33
- return (
34
- <SpotIllustration
35
- ref={ref}
36
- illustration={data as IllustrationJson}
37
- {...props}
38
- />
39
- )
40
- }
41
- )
42
-
43
- Component.displayName = name
44
-
45
- return Component
46
- }
@@ -1,42 +0,0 @@
1
- export { SpotIllustration } from './SpotIllustration'
2
- export type { SpotIllustrationProps } from './SpotIllustration'
3
-
4
- export { createSpotIllustration } from './createSpotIllustration'
5
- export type { SpotIllustrationComponentProps } from './createSpotIllustration'
6
-
7
- // Generated exports - do not edit manually
8
- export { ArrowUpRight } from './ArrowUpRight'
9
- export type { ArrowUpRightProps } from './ArrowUpRight'
10
-
11
- export { CowboyHat } from './CowboyHat'
12
- export type { CowboyHatProps } from './CowboyHat'
13
-
14
- export { Cursor } from './Cursor'
15
- export type { CursorProps } from './Cursor'
16
-
17
- export { FlowerSpiral } from './FlowerSpiral'
18
- export type { FlowerSpiralProps } from './FlowerSpiral'
19
-
20
- export { Football } from './Football'
21
- export type { FootballProps } from './Football'
22
-
23
- export { Hand } from './Hand'
24
- export type { HandProps } from './Hand'
25
-
26
- export { Heart } from './Heart'
27
- export type { HeartProps } from './Heart'
28
-
29
- export { HighFive } from './HighFive'
30
- export type { HighFiveProps } from './HighFive'
31
-
32
- export { MapPin } from './MapPin'
33
- export type { MapPinProps } from './MapPin'
34
-
35
- export { NoteMusic } from './NoteMusic'
36
- export type { NoteMusicProps } from './NoteMusic'
37
-
38
- export { Ticket } from './Ticket'
39
- export type { TicketProps } from './Ticket'
40
-
41
- export { WineGlass } from './WineGlass'
42
- export type { WineGlassProps } from './WineGlass'
@@ -1,34 +0,0 @@
1
- {
2
- "$comment": "Generated file - do not edit directly",
3
- "viewBox": "0 0 48 48",
4
- "paths": [
5
- {
6
- "d": "m40.531.849 6.605 4.69c.574.396.906 1.083.857 1.782L46.694 25.9c-.117 1.677-2.22 2.462-3.409 1.275l-3.032-3.031-8.035 8.033-.413 4.054a2 2 0 0 1-.575 1.211l-8.488 8.485a2.026 2.026 0 0 1-2.695.2l-6.541-4.64a2 2 0 0 1-.703-.897l-2.287-5.8-2.626-1.035a2 2 0 0 1-.424-.23l-6.624-4.7c-.995-.707-1.12-2.183-.257-3.046l8.657-8.646a2 2 0 0 1 1.084-.46l4.051-.413 8.527-8.529-3.267-2.319a2.001 2.001 0 0 1 1.018-3.626l18.578-1.3c.466-.014.913.09 1.298.364",
7
- "layer": "outline"
8
- },
9
- {
10
- "d": "m17.153 23.364-8.53 8.53-6.624-4.702 8.53-8.53 3.312 2.351z",
11
- "layer": "detail"
12
- },
13
- {
14
- "d": "m27.417 8.481 4.446 4.446-9.95 9.949.001.001h-.002l-4.759.487-6.624-4.702 4.76-.486L25.993 7.47z",
15
- "layer": "detail"
16
- },
17
- {
18
- "d": "M45.998 7.183 27.42 8.479 20.795 3.78l18.578-1.3z",
19
- "layer": "detail"
20
- },
21
- {
22
- "d": "M45.998 7.182 27.419 8.48l4.446 4.447-9.95 9.95-4.762.487-8.53 8.53 9.082 3.58 3.58 9.083 8.53-8.53.487-4.762 9.951-9.95 4.446 4.445z",
23
- "layer": "face"
24
- },
25
- {
26
- "d": "m12.058 33.247 5.65 2.227 3.58 9.082-6.625-4.701z",
27
- "layer": "shadow"
28
- },
29
- {
30
- "d": "M45.998 7.182 27.419 8.48m18.579-1.298L44.699 25.76l-4.446-4.445-9.951 9.95-.487 4.762-8.53 8.53-3.58-9.083-9.082-3.58 8.53-8.53M45.998 7.182 39.373 2.48l-18.578 1.3 6.624 4.7m0 0 4.446 4.447-9.95 9.95m0 0-4.762.487m4.762-.487-6.626-4.701-4.76.487 6.624 4.701m-5.095 9.883 5.65 2.227 3.58 9.082-6.625-4.701zm-3.434-1.351 8.53-8.53-6.624-4.702L2 27.194zm23.239-18.969-4.446-4.446-1.424-1.01-10.705 10.706 6.624 4.701 9.951-9.95z",
31
- "layer": "stroke"
32
- }
33
- ]
34
- }