@olympusoss/canvas 4.0.0 → 5.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 (297) hide show
  1. package/README.md +108 -0
  2. package/package.json +14 -3
  3. package/src/atoms/avatar/avatar.md +185 -0
  4. package/src/atoms/avatar/avatar.styles.ts +48 -0
  5. package/src/atoms/avatar/avatar.tsx +99 -0
  6. package/src/atoms/badge/badge.md +237 -0
  7. package/src/atoms/badge/badge.styles.ts +79 -0
  8. package/src/atoms/badge/badge.tsx +86 -0
  9. package/src/atoms/breadcrumb/breadcrumb.md +233 -0
  10. package/src/atoms/breadcrumb/breadcrumb.styles.ts +40 -0
  11. package/src/atoms/breadcrumb/breadcrumb.tsx +130 -0
  12. package/src/atoms/button/button.android.tsx +6 -0
  13. package/src/atoms/button/button.ios.tsx +6 -0
  14. package/src/atoms/button/button.md +184 -0
  15. package/src/atoms/button/button.shared.tsx +79 -0
  16. package/src/atoms/button/button.styles.ts +152 -0
  17. package/src/atoms/button/button.tsx +6 -0
  18. package/src/atoms/button-group/button-group.android.tsx +6 -0
  19. package/src/atoms/button-group/button-group.ios.tsx +6 -0
  20. package/src/atoms/button-group/button-group.md +120 -0
  21. package/src/atoms/button-group/button-group.shared.tsx +398 -0
  22. package/src/atoms/button-group/button-group.styles.ts +483 -0
  23. package/src/atoms/button-group/button-group.tsx +6 -0
  24. package/src/atoms/checkbox/checkbox.android.tsx +6 -0
  25. package/src/atoms/checkbox/checkbox.ios.tsx +6 -0
  26. package/src/atoms/checkbox/checkbox.md +150 -0
  27. package/src/atoms/checkbox/checkbox.shared.tsx +103 -0
  28. package/src/atoms/checkbox/checkbox.styles.ts +106 -0
  29. package/src/atoms/checkbox/checkbox.tsx +6 -0
  30. package/src/atoms/combobox/combobox.android.tsx +6 -0
  31. package/src/atoms/combobox/combobox.ios.tsx +6 -0
  32. package/src/atoms/combobox/combobox.md +213 -0
  33. package/src/atoms/combobox/combobox.shared.tsx +160 -0
  34. package/src/atoms/combobox/combobox.styles.ts +270 -0
  35. package/src/atoms/combobox/combobox.tsx +6 -0
  36. package/src/atoms/divider/divider.md +140 -0
  37. package/src/atoms/divider/divider.styles.ts +35 -0
  38. package/src/atoms/divider/divider.tsx +67 -0
  39. package/src/atoms/dropdown/dropdown.android.tsx +6 -0
  40. package/src/atoms/dropdown/dropdown.ios.tsx +6 -0
  41. package/src/atoms/dropdown/dropdown.md +221 -0
  42. package/src/atoms/dropdown/dropdown.shared.tsx +190 -0
  43. package/src/atoms/dropdown/dropdown.styles.ts +233 -0
  44. package/src/atoms/dropdown/dropdown.tsx +6 -0
  45. package/src/atoms/icon/icon.md +131 -0
  46. package/src/atoms/icon/icon.styles.ts +30 -0
  47. package/src/atoms/icon/icon.tsx +328 -0
  48. package/src/atoms/index.ts +24 -0
  49. package/src/atoms/input/input.android.tsx +6 -0
  50. package/src/atoms/input/input.ios.tsx +6 -0
  51. package/src/atoms/input/input.md +118 -0
  52. package/src/atoms/input/input.shared.tsx +203 -0
  53. package/src/atoms/input/input.styles.ts +286 -0
  54. package/src/atoms/input/input.tsx +6 -0
  55. package/src/atoms/kbd/kbd.md +91 -0
  56. package/src/atoms/kbd/kbd.styles.ts +33 -0
  57. package/src/atoms/kbd/kbd.tsx +27 -0
  58. package/src/atoms/listbox/listbox.md +177 -0
  59. package/src/atoms/listbox/listbox.styles.ts +60 -0
  60. package/src/atoms/listbox/listbox.tsx +113 -0
  61. package/src/atoms/pagination/pagination.android.tsx +6 -0
  62. package/src/atoms/pagination/pagination.ios.tsx +6 -0
  63. package/src/atoms/pagination/pagination.md +133 -0
  64. package/src/atoms/pagination/pagination.shared.tsx +289 -0
  65. package/src/atoms/pagination/pagination.styles.ts +245 -0
  66. package/src/atoms/pagination/pagination.tsx +6 -0
  67. package/src/atoms/popover/popover.android.tsx +8 -0
  68. package/src/atoms/popover/popover.ios.tsx +6 -0
  69. package/src/atoms/popover/popover.md +87 -0
  70. package/src/atoms/popover/popover.shared.tsx +124 -0
  71. package/src/atoms/popover/popover.styles.ts +144 -0
  72. package/src/atoms/popover/popover.tsx +6 -0
  73. package/src/atoms/radio/radio.android.tsx +6 -0
  74. package/src/atoms/radio/radio.ios.tsx +6 -0
  75. package/src/atoms/radio/radio.md +173 -0
  76. package/src/atoms/radio/radio.shared.tsx +98 -0
  77. package/src/atoms/radio/radio.styles.ts +109 -0
  78. package/src/atoms/radio/radio.tsx +6 -0
  79. package/src/atoms/select/select.android.tsx +6 -0
  80. package/src/atoms/select/select.ios.tsx +6 -0
  81. package/src/atoms/select/select.md +156 -0
  82. package/src/atoms/select/select.shared.tsx +143 -0
  83. package/src/atoms/select/select.styles.ts +310 -0
  84. package/src/atoms/select/select.tsx +6 -0
  85. package/src/atoms/skeleton/skeleton.md +135 -0
  86. package/src/atoms/skeleton/skeleton.styles.ts +117 -0
  87. package/src/atoms/skeleton/skeleton.tsx +145 -0
  88. package/src/atoms/spinner/spinner.android.tsx +7 -0
  89. package/src/atoms/spinner/spinner.ios.tsx +7 -0
  90. package/src/atoms/spinner/spinner.md +94 -0
  91. package/src/atoms/spinner/spinner.shared.tsx +92 -0
  92. package/src/atoms/spinner/spinner.styles.tsx +115 -0
  93. package/src/atoms/spinner/spinner.tsx +7 -0
  94. package/src/atoms/switch/switch.android.tsx +6 -0
  95. package/src/atoms/switch/switch.ios.tsx +6 -0
  96. package/src/atoms/switch/switch.md +91 -0
  97. package/src/atoms/switch/switch.shared.tsx +97 -0
  98. package/src/atoms/switch/switch.styles.ts +79 -0
  99. package/src/atoms/switch/switch.tsx +6 -0
  100. package/src/atoms/textarea/textarea.android.tsx +6 -0
  101. package/src/atoms/textarea/textarea.ios.tsx +6 -0
  102. package/src/atoms/textarea/textarea.md +140 -0
  103. package/src/atoms/textarea/textarea.shared.tsx +74 -0
  104. package/src/atoms/textarea/textarea.styles.ts +116 -0
  105. package/src/atoms/textarea/textarea.tsx +6 -0
  106. package/src/atoms/tooltip/tooltip.android.tsx +6 -0
  107. package/src/atoms/tooltip/tooltip.ios.tsx +7 -0
  108. package/src/atoms/tooltip/tooltip.md +122 -0
  109. package/src/atoms/tooltip/tooltip.shared.tsx +113 -0
  110. package/src/atoms/tooltip/tooltip.styles.ts +113 -0
  111. package/src/atoms/tooltip/tooltip.tsx +6 -0
  112. package/src/atoms/typography/typography.md +330 -0
  113. package/src/atoms/typography/typography.styles.ts +95 -0
  114. package/src/atoms/typography/typography.tsx +76 -0
  115. package/src/index.ts +12 -2
  116. package/src/molecules/action-panels/action-panels.md +133 -0
  117. package/src/molecules/action-panels/action-panels.styles.ts +39 -0
  118. package/src/molecules/action-panels/action-panels.tsx +113 -0
  119. package/src/molecules/alert/alert.md +119 -0
  120. package/src/molecules/alert/alert.styles.ts +88 -0
  121. package/src/molecules/alert/alert.tsx +74 -0
  122. package/src/molecules/alert-dialog/alert-dialog.android.tsx +6 -0
  123. package/src/molecules/alert-dialog/alert-dialog.ios.tsx +6 -0
  124. package/src/molecules/alert-dialog/alert-dialog.md +177 -0
  125. package/src/molecules/alert-dialog/alert-dialog.shared.tsx +187 -0
  126. package/src/molecules/alert-dialog/alert-dialog.styles.ts +248 -0
  127. package/src/molecules/alert-dialog/alert-dialog.tsx +6 -0
  128. package/src/molecules/card/card.md +190 -0
  129. package/src/molecules/card/card.styles.ts +67 -0
  130. package/src/molecules/card/card.tsx +176 -0
  131. package/src/molecules/code-block/code-block.md +159 -0
  132. package/src/molecules/code-block/code-block.styles.ts +167 -0
  133. package/src/molecules/code-block/code-block.tsx +176 -0
  134. package/src/molecules/description-lists/description-lists.md +129 -0
  135. package/src/molecules/description-lists/description-lists.styles.ts +102 -0
  136. package/src/molecules/description-lists/description-lists.tsx +133 -0
  137. package/src/molecules/empty-state/empty-state.md +218 -0
  138. package/src/molecules/empty-state/empty-state.styles.ts +63 -0
  139. package/src/molecules/empty-state/empty-state.tsx +77 -0
  140. package/src/molecules/feeds/feeds.md +102 -0
  141. package/src/molecules/feeds/feeds.styles.ts +120 -0
  142. package/src/molecules/feeds/feeds.tsx +167 -0
  143. package/src/molecules/field/field.md +117 -0
  144. package/src/molecules/field/field.styles.ts +85 -0
  145. package/src/molecules/field/field.tsx +175 -0
  146. package/src/molecules/fieldset/fieldset.md +141 -0
  147. package/src/molecules/fieldset/fieldset.styles.ts +79 -0
  148. package/src/molecules/fieldset/fieldset.tsx +182 -0
  149. package/src/molecules/form/form.md +137 -0
  150. package/src/molecules/form/form.styles.ts +39 -0
  151. package/src/molecules/form/form.tsx +246 -0
  152. package/src/molecules/grid-lists/grid-lists.md +114 -0
  153. package/src/molecules/grid-lists/grid-lists.styles.ts +79 -0
  154. package/src/molecules/grid-lists/grid-lists.tsx +157 -0
  155. package/src/molecules/index.ts +16 -0
  156. package/src/molecules/media-objects/media-objects.md +87 -0
  157. package/src/molecules/media-objects/media-objects.styles.ts +94 -0
  158. package/src/molecules/media-objects/media-objects.tsx +128 -0
  159. package/src/molecules/stacked-lists/stacked-lists.md +116 -0
  160. package/src/molecules/stacked-lists/stacked-lists.styles.ts +111 -0
  161. package/src/molecules/stacked-lists/stacked-lists.tsx +195 -0
  162. package/src/molecules/stats/stats.md +166 -0
  163. package/src/molecules/stats/stats.styles.ts +91 -0
  164. package/src/molecules/stats/stats.tsx +88 -0
  165. package/src/organisms/calendar/calendar.android.tsx +6 -0
  166. package/src/organisms/calendar/calendar.ios.tsx +6 -0
  167. package/src/organisms/calendar/calendar.md +114 -0
  168. package/src/organisms/calendar/calendar.shared.tsx +146 -0
  169. package/src/organisms/calendar/calendar.styles.ts +315 -0
  170. package/src/organisms/calendar/calendar.tsx +6 -0
  171. package/src/organisms/charts/charts.md +326 -0
  172. package/src/organisms/charts/charts.styles.ts +135 -0
  173. package/src/organisms/charts/charts.tsx +124 -0
  174. package/src/organisms/command/command.md +117 -0
  175. package/src/organisms/command/command.styles.ts +179 -0
  176. package/src/organisms/command/command.tsx +164 -0
  177. package/src/organisms/data-table/data-table.md +182 -0
  178. package/src/organisms/data-table/data-table.styles.ts +103 -0
  179. package/src/organisms/data-table/data-table.tsx +105 -0
  180. package/src/organisms/dialog/dialog.android.tsx +6 -0
  181. package/src/organisms/dialog/dialog.ios.tsx +6 -0
  182. package/src/organisms/dialog/dialog.md +271 -0
  183. package/src/organisms/dialog/dialog.shared.tsx +230 -0
  184. package/src/organisms/dialog/dialog.styles.ts +272 -0
  185. package/src/organisms/dialog/dialog.tsx +6 -0
  186. package/src/organisms/filter-panel/filter-panel.md +116 -0
  187. package/src/organisms/filter-panel/filter-panel.styles.ts +83 -0
  188. package/src/organisms/filter-panel/filter-panel.tsx +91 -0
  189. package/src/organisms/index.ts +13 -0
  190. package/src/organisms/navbars/navbars.android.tsx +6 -0
  191. package/src/organisms/navbars/navbars.ios.tsx +6 -0
  192. package/src/organisms/navbars/navbars.md +144 -0
  193. package/src/organisms/navbars/navbars.shared.tsx +137 -0
  194. package/src/organisms/navbars/navbars.styles.ts +251 -0
  195. package/src/organisms/navbars/navbars.tsx +6 -0
  196. package/src/organisms/overlays/overlays.android.tsx +6 -0
  197. package/src/organisms/overlays/overlays.ios.tsx +6 -0
  198. package/src/organisms/overlays/overlays.md +123 -0
  199. package/src/organisms/overlays/overlays.shared.tsx +175 -0
  200. package/src/organisms/overlays/overlays.styles.ts +309 -0
  201. package/src/organisms/overlays/overlays.tsx +6 -0
  202. package/src/organisms/row-menu/row-menu.android.tsx +6 -0
  203. package/src/organisms/row-menu/row-menu.ios.tsx +6 -0
  204. package/src/organisms/row-menu/row-menu.md +102 -0
  205. package/src/organisms/row-menu/row-menu.shared.tsx +105 -0
  206. package/src/organisms/row-menu/row-menu.styles.ts +262 -0
  207. package/src/organisms/row-menu/row-menu.tsx +6 -0
  208. package/src/organisms/sidebar/sidebar.android.tsx +6 -0
  209. package/src/organisms/sidebar/sidebar.ios.tsx +6 -0
  210. package/src/organisms/sidebar/sidebar.md +188 -0
  211. package/src/organisms/sidebar/sidebar.shared.tsx +167 -0
  212. package/src/organisms/sidebar/sidebar.styles.ts +262 -0
  213. package/src/organisms/sidebar/sidebar.tsx +6 -0
  214. package/src/organisms/stepper/stepper.android.tsx +6 -0
  215. package/src/organisms/stepper/stepper.ios.tsx +6 -0
  216. package/src/organisms/stepper/stepper.md +150 -0
  217. package/src/organisms/stepper/stepper.shared.tsx +158 -0
  218. package/src/organisms/stepper/stepper.styles.ts +280 -0
  219. package/src/organisms/stepper/stepper.tsx +6 -0
  220. package/src/organisms/tabs/tabs.android.tsx +6 -0
  221. package/src/organisms/tabs/tabs.ios.tsx +6 -0
  222. package/src/organisms/tabs/tabs.md +127 -0
  223. package/src/organisms/tabs/tabs.shared.tsx +281 -0
  224. package/src/organisms/tabs/tabs.styles.ts +398 -0
  225. package/src/organisms/tabs/tabs.tsx +6 -0
  226. package/src/style/color.ts +17 -0
  227. package/src/style/index.ts +14 -0
  228. package/src/style/primitives.ts +26 -0
  229. package/src/style/responsive.ts +45 -0
  230. package/src/style/shadow.ts +21 -0
  231. package/src/style/theme.tsx +56 -0
  232. package/src/style/tokens.ts +487 -0
  233. package/src/theme.ts +21 -0
  234. package/styles/canvas.css +128 -67
  235. package/tsconfig.json +4 -2
  236. package/src/cn.ts +0 -3
  237. package/styles/base.css +0 -17
  238. package/styles/components/alert.css +0 -66
  239. package/styles/components/app-shell.css +0 -46
  240. package/styles/components/avatar.css +0 -15
  241. package/styles/components/badge.css +0 -83
  242. package/styles/components/breadcrumb.css +0 -35
  243. package/styles/components/button-group.css +0 -23
  244. package/styles/components/button.css +0 -107
  245. package/styles/components/calendar.css +0 -73
  246. package/styles/components/card.css +0 -58
  247. package/styles/components/checkbox.css +0 -55
  248. package/styles/components/code-block.css +0 -18
  249. package/styles/components/combobox.css +0 -75
  250. package/styles/components/command.css +0 -94
  251. package/styles/components/data-table.css +0 -142
  252. package/styles/components/dialog.css +0 -72
  253. package/styles/components/dropdown.css +0 -54
  254. package/styles/components/empty-state.css +0 -17
  255. package/styles/components/field.css +0 -27
  256. package/styles/components/filter-panel.css +0 -58
  257. package/styles/components/form.css +0 -27
  258. package/styles/components/icon.css +0 -8
  259. package/styles/components/input-group.css +0 -45
  260. package/styles/components/input.css +0 -56
  261. package/styles/components/kbd.css +0 -15
  262. package/styles/components/page-header.css +0 -52
  263. package/styles/components/pagination.css +0 -48
  264. package/styles/components/popover.css +0 -14
  265. package/styles/components/radio.css +0 -28
  266. package/styles/components/row-menu.css +0 -69
  267. package/styles/components/section-card.css +0 -49
  268. package/styles/components/select.css +0 -57
  269. package/styles/components/separator.css +0 -32
  270. package/styles/components/sheet.css +0 -70
  271. package/styles/components/sidebar.css +0 -146
  272. package/styles/components/skeleton.css +0 -32
  273. package/styles/components/spinner.css +0 -26
  274. package/styles/components/stat-card.css +0 -71
  275. package/styles/components/stepper.css +0 -63
  276. package/styles/components/switch.css +0 -45
  277. package/styles/components/tabs.css +0 -40
  278. package/styles/components/textarea.css +0 -31
  279. package/styles/components/toast.css +0 -95
  280. package/styles/components/tooltip.css +0 -53
  281. package/styles/components/topbar.css +0 -24
  282. package/styles/components/typography.css +0 -105
  283. package/styles/patterns/backdrops.css +0 -35
  284. package/styles/patterns/density.css +0 -66
  285. package/styles/patterns/focus.css +0 -38
  286. package/styles/patterns/glass.css +0 -85
  287. package/styles/patterns/high-contrast.css +0 -70
  288. package/styles/patterns/reduced-motion.css +0 -12
  289. package/styles/patterns/scrollbar.css +0 -10
  290. package/styles/reset.css +0 -89
  291. package/styles/tokens/colors.css +0 -106
  292. package/styles/tokens/motion.css +0 -33
  293. package/styles/tokens/radius.css +0 -10
  294. package/styles/tokens/shadows.css +0 -35
  295. package/styles/tokens/spacing.css +0 -19
  296. package/styles/tokens/typography.css +0 -6
  297. package/styles/tokens/z-index.css +0 -12
@@ -0,0 +1,237 @@
1
+ # Badges
2
+
3
+ Two families on one Badge component, picked by boolean props. The metadata badge is a rectangular pill for labels like schema, role, or tag (tones: default, secondary, outline, destructive; add `mono` for token names). The status badge (`status`) is a rounded pill with a leading dot for live state like active, pending, or failed (tones: success, warning, error, info, neutral).
4
+
5
+ ## Usage
6
+
7
+ ```tsx
8
+ <Badge secondary>admin</Badge>
9
+ ```
10
+
11
+ ## Variants
12
+
13
+ ### Type - status
14
+
15
+ ```tsx
16
+ <Badge status success>admin</Badge>
17
+ ```
18
+
19
+ ### Type - identity
20
+
21
+ ```tsx
22
+ <View style={{ flexDirection: "row", flexWrap: "wrap", alignItems: "center", gap: 8 }}>
23
+ <Text style={{ fontSize: 15, fontWeight: "600", color: tokens.foreground }}>Rachel Chen</Text>
24
+ <Badge status success>active</Badge>
25
+ <Badge status info>Verified</Badge>
26
+ <Badge secondary>employee</Badge>
27
+ </View>
28
+ ```
29
+
30
+ ### Type - grants
31
+
32
+ ```tsx
33
+ <View style={{ flexDirection: "row", flexWrap: "wrap", gap: 4 }}>
34
+ <Badge secondary mono>authorization_code</Badge>
35
+ <Badge secondary mono>refresh_token</Badge>
36
+ <Badge secondary mono>client_credentials</Badge>
37
+ </View>
38
+ ```
39
+
40
+ ### Badge variant - default
41
+
42
+ ```tsx
43
+ <Badge default>admin</Badge>
44
+ ```
45
+
46
+ ### Badge variant - outline
47
+
48
+ ```tsx
49
+ <Badge outline>admin</Badge>
50
+ ```
51
+
52
+ ### Badge variant - destructive
53
+
54
+ ```tsx
55
+ <Badge destructive>admin</Badge>
56
+ ```
57
+
58
+ ### Mono (token / event names)
59
+
60
+ ```tsx
61
+ <Badge secondary mono>admin</Badge>
62
+ ```
63
+
64
+ ## Do & Don't
65
+
66
+ ### Metadata badge
67
+
68
+ **Do** — Neutral tags for metadata; reserve color and the status-badge dot for live state.
69
+
70
+ ```tsx
71
+ <View style={{ flexDirection: "row", flexWrap: "wrap", alignItems: "center", gap: 6 }}>
72
+ <Badge secondary>employee</Badge>
73
+ <Badge secondary>engineering</Badge>
74
+ <Badge secondary>remote</Badge>
75
+ <Badge status success>active</Badge>
76
+ </View>
77
+ ```
78
+
79
+ **Don't** — Borrowing status colors for plain metadata reads as severity that isn't there; a red tag looks like an error.
80
+
81
+ ```tsx
82
+ <View style={{ flexDirection: "row", flexWrap: "wrap", alignItems: "center", gap: 6 }}>
83
+ <Badge default>employee</Badge>
84
+ <Badge destructive>engineering</Badge>
85
+ <Badge default>remote</Badge>
86
+ <Badge destructive>active</Badge>
87
+ </View>
88
+ ```
89
+
90
+ ### Status badge
91
+
92
+ **Do** — Always pair the dot with a word: active, pending, failed.
93
+
94
+ ```tsx
95
+ <Badge status error>Failed</Badge>
96
+ ```
97
+
98
+ **Don't** — A bare colored dot isn't a label and fails for color-blind users.
99
+
100
+ ```tsx
101
+ <Badge status error />
102
+ ```
103
+
104
+ ### Identity row
105
+
106
+ **Do** — Show only the one or two badges relevant to this view.
107
+
108
+ ```tsx
109
+ <View style={{ flexDirection: "row", flexWrap: "wrap", alignItems: "center", gap: 8 }}>
110
+ <Text style={{ fontSize: 15, fontWeight: "600", color: tokens.foreground }}>Rachel Chen</Text>
111
+ <Badge status success>active</Badge>
112
+ <Badge secondary>employee</Badge>
113
+ </View>
114
+ ```
115
+
116
+ **Don't** — A wall of badges after a name buries the one that matters.
117
+
118
+ ```tsx
119
+ <View style={{ flexDirection: "row", flexWrap: "wrap", alignItems: "center", gap: 8 }}>
120
+ <Text style={{ fontSize: 15, fontWeight: "600", color: tokens.foreground }}>Rachel Chen</Text>
121
+ <Badge status success>active</Badge>
122
+ <Badge status info>Verified</Badge>
123
+ <Badge secondary>employee</Badge>
124
+ <Badge secondary>engineering</Badge>
125
+ <Badge secondary>remote</Badge>
126
+ <Badge secondary>admin</Badge>
127
+ </View>
128
+ ```
129
+
130
+ ### Token / code badge
131
+
132
+ **Do** — Use the mono variant for tokens, scopes, and event names.
133
+
134
+ ```tsx
135
+ <View style={{ flexDirection: "row", flexWrap: "wrap", gap: 4 }}>
136
+ <Badge secondary mono>authorization_code</Badge>
137
+ <Badge secondary mono>refresh_token</Badge>
138
+ <Badge secondary mono>client_credentials</Badge>
139
+ </View>
140
+ ```
141
+
142
+ **Don't** — Proportional type makes identifiers hard to scan and compare.
143
+
144
+ ```tsx
145
+ <View style={{ flexDirection: "row", flexWrap: "wrap", gap: 4 }}>
146
+ <Badge secondary>authorization_code</Badge>
147
+ <Badge secondary>refresh_token</Badge>
148
+ <Badge secondary>client_credentials</Badge>
149
+ </View>
150
+ ```
151
+
152
+ ### Default variant
153
+
154
+ **Do** — Reserve the default fill for the single tag you want noticed first; keep the rest secondary.
155
+
156
+ ```tsx
157
+ <View style={{ flexDirection: "row", flexWrap: "wrap", alignItems: "center", gap: 6 }}>
158
+ <Badge default>admin</Badge>
159
+ <Badge secondary>engineering</Badge>
160
+ <Badge secondary>remote</Badge>
161
+ </View>
162
+ ```
163
+
164
+ **Don't** — The solid primary fill is the loudest badge; using it for every tag makes the whole row shout and nothing leads.
165
+
166
+ ```tsx
167
+ <View style={{ flexDirection: "row", flexWrap: "wrap", alignItems: "center", gap: 6 }}>
168
+ <Badge default>employee</Badge>
169
+ <Badge default>engineering</Badge>
170
+ <Badge default>remote</Badge>
171
+ <Badge default>admin</Badge>
172
+ </View>
173
+ ```
174
+
175
+ ### Secondary variant
176
+
177
+ **Do** — Keep secondary for static metadata (role, team) and switch to the status-badge for anything live.
178
+
179
+ ```tsx
180
+ <View style={{ flexDirection: "row", flexWrap: "wrap", alignItems: "center", gap: 6 }}>
181
+ <Badge secondary>employee</Badge>
182
+ <Badge secondary>engineering</Badge>
183
+ <Badge status success>active</Badge>
184
+ </View>
185
+ ```
186
+
187
+ **Don't** — A muted gray pill reads as static metadata, so live state shown as a secondary badge looks inert and goes unnoticed.
188
+
189
+ ```tsx
190
+ <View style={{ flexDirection: "row", flexWrap: "wrap", alignItems: "center", gap: 6 }}>
191
+ <Badge secondary>active</Badge>
192
+ <Badge secondary>pending</Badge>
193
+ <Badge secondary>failed</Badge>
194
+ </View>
195
+ ```
196
+
197
+ ### Outline variant
198
+
199
+ **Do** — Use outline on a plain surface where the quiet border has contrast, for low-priority secondary tags.
200
+
201
+ ```tsx
202
+ <View style={{ flexDirection: "row", flexWrap: "wrap", alignItems: "center", gap: 6, borderRadius: 6, borderWidth: 1, borderColor: tokens.border, backgroundColor: tokens.card, padding: 12 }}>
203
+ <Badge outline>draft</Badge>
204
+ <Badge outline>internal</Badge>
205
+ </View>
206
+ ```
207
+
208
+ **Don't** — The thin border is the whole badge; on a colored or busy surface it disappears and the label floats unboxed.
209
+
210
+ ```tsx
211
+ <View style={{ flexDirection: "row", flexWrap: "wrap", alignItems: "center", gap: 6, borderRadius: 6, backgroundColor: tokens.primary, padding: 12 }}>
212
+ <Badge outline>draft</Badge>
213
+ <Badge outline>internal</Badge>
214
+ </View>
215
+ ```
216
+
217
+ ### Destructive variant
218
+
219
+ **Do** — Reserve destructive for genuinely destructive or error semantics like revoked or banned.
220
+
221
+ ```tsx
222
+ <View style={{ flexDirection: "row", flexWrap: "wrap", alignItems: "center", gap: 6 }}>
223
+ <Badge destructive>Revoked</Badge>
224
+ <Badge destructive>Banned</Badge>
225
+ <Badge secondary>marketing</Badge>
226
+ </View>
227
+ ```
228
+
229
+ **Don't** — Solid red signals error or danger, so using it to color-code neutral categories raises a false alarm.
230
+
231
+ ```tsx
232
+ <View style={{ flexDirection: "row", flexWrap: "wrap", alignItems: "center", gap: 6 }}>
233
+ <Badge destructive>marketing</Badge>
234
+ <Badge destructive>finance</Badge>
235
+ <Badge destructive>legal</Badge>
236
+ </View>
237
+ ```
@@ -0,0 +1,79 @@
1
+ import { type ViewStyle, type TextStyle } from "react-native";
2
+ import { type ColorTokens, palette } from "../../style/index.js";
3
+
4
+ // Co-located Badge styles. The metadata badge uses semantic tokens; the status
5
+ // badge uses the Tailwind palette (a soft 50/200/700 surface in light, a
6
+ // 950/800/400 surface in dark) with a saturated 500 dot, and neutral stays on
7
+ // the semantic muted token.
8
+
9
+ export type Tone = "default" | "secondary" | "outline" | "destructive";
10
+ export type Status = "success" | "warning" | "error" | "info" | "neutral";
11
+
12
+ export const metaBase: ViewStyle = {
13
+ flexDirection: "row",
14
+ alignItems: "center",
15
+ alignSelf: "flex-start",
16
+ borderRadius: 6,
17
+ borderWidth: 1,
18
+ paddingHorizontal: 8,
19
+ paddingVertical: 2,
20
+ };
21
+
22
+ export const statusBase: ViewStyle = {
23
+ flexDirection: "row",
24
+ alignItems: "center",
25
+ alignSelf: "flex-start",
26
+ gap: 6,
27
+ borderRadius: 9999,
28
+ borderWidth: 1,
29
+ paddingHorizontal: 8,
30
+ paddingVertical: 2,
31
+ };
32
+
33
+ export const labelType: TextStyle = { fontSize: 12, lineHeight: 16, fontWeight: "500" };
34
+
35
+ export function metaContainer(tokens: ColorTokens, tone: Tone): ViewStyle {
36
+ switch (tone) {
37
+ case "default": return { borderColor: "transparent", backgroundColor: tokens.primary };
38
+ case "secondary": return { borderColor: "transparent", backgroundColor: tokens.secondary };
39
+ case "outline": return { borderColor: tokens.border, backgroundColor: "transparent" };
40
+ case "destructive": return { borderColor: "transparent", backgroundColor: tokens.destructive };
41
+ }
42
+ }
43
+
44
+ export function metaLabel(tokens: ColorTokens, tone: Tone): TextStyle {
45
+ switch (tone) {
46
+ case "default": return { color: tokens["primary-foreground"] };
47
+ case "secondary": return { color: tokens["secondary-foreground"] };
48
+ case "outline": return { color: tokens.foreground };
49
+ case "destructive": return { color: tokens["destructive-foreground"] };
50
+ }
51
+ }
52
+
53
+ // The palette hue per status tone (neutral is handled on the semantic tokens).
54
+ const STATUS_HUE: Record<Exclude<Status, "neutral">, string> = {
55
+ success: "green",
56
+ warning: "amber",
57
+ error: "red",
58
+ info: "blue",
59
+ };
60
+
61
+ export function statusContainer(tokens: ColorTokens, dark: boolean, status: Status): ViewStyle {
62
+ if (status === "neutral") return { borderColor: tokens.border, backgroundColor: tokens.muted };
63
+ const hue = STATUS_HUE[status];
64
+ return dark
65
+ ? { borderColor: palette[`${hue}-800`], backgroundColor: palette[`${hue}-950`] }
66
+ : { borderColor: palette[`${hue}-200`], backgroundColor: palette[`${hue}-50`] };
67
+ }
68
+
69
+ export function statusLabel(tokens: ColorTokens, dark: boolean, status: Status): TextStyle {
70
+ if (status === "neutral") return { color: tokens["muted-foreground"] };
71
+ const hue = STATUS_HUE[status];
72
+ return { color: dark ? palette[`${hue}-400`] : palette[`${hue}-700`] };
73
+ }
74
+
75
+ export function statusDot(tokens: ColorTokens, status: Status): ViewStyle {
76
+ const base: ViewStyle = { height: 6, width: 6, borderRadius: 9999 };
77
+ if (status === "neutral") return { ...base, backgroundColor: tokens["muted-foreground"] };
78
+ return { ...base, backgroundColor: palette[`${STATUS_HUE[status]}-500`] };
79
+ }
@@ -0,0 +1,86 @@
1
+ import { type ReactNode } from "react";
2
+ import { View, Text, useTheme, type StyleProp, type ViewStyle } from "../../style/index.js";
3
+ import * as s from "./badge.styles.js";
4
+ import { type Tone, type Status } from "./badge.styles.js";
5
+
6
+ // Two families of badge.
7
+ //
8
+ // 1. The metadata badge: a rectangular pill (rounded-md) for static labels like
9
+ // schema, role, or tag. Configured by a tone axis (default / secondary /
10
+ // outline / destructive) plus a `mono` modifier for token / event names.
11
+ // 2. The status badge (`status`): a fully rounded pill carrying a leading dot,
12
+ // for live state like active / pending / failed. Configured by a status-tone
13
+ // axis (success / warning / error / info / neutral).
14
+ //
15
+ // Boolean-prop API: one boolean per option, grouped by axis, first-match
16
+ // precedence within an axis (mirrors Button's intentOf). The `status` boolean
17
+ // switches families; the status-tone booleans only apply in that family.
18
+
19
+ export interface BadgeProps {
20
+ children?: ReactNode;
21
+ // Family: metadata badge (default) vs. status badge (with a dot).
22
+ status?: boolean;
23
+ // Metadata tone (pick one; default is the solid primary fill).
24
+ default?: boolean;
25
+ secondary?: boolean;
26
+ outline?: boolean;
27
+ destructive?: boolean;
28
+ // Metadata modifier: monospace face for tokens, scopes, event names.
29
+ mono?: boolean;
30
+ // Status tone (pick one; only applies when `status`).
31
+ success?: boolean;
32
+ warning?: boolean;
33
+ error?: boolean;
34
+ info?: boolean;
35
+ neutral?: boolean;
36
+ /** Escape hatch for layout/positioning composition. */
37
+ style?: StyleProp<ViewStyle>;
38
+ }
39
+
40
+ // Tone precedence when more than one is passed: first match wins.
41
+ function toneOf(p: BadgeProps): Tone {
42
+ if (p.default) return "default";
43
+ if (p.destructive) return "destructive";
44
+ if (p.secondary) return "secondary";
45
+ if (p.outline) return "outline";
46
+ return "secondary";
47
+ }
48
+
49
+ function statusOf(p: BadgeProps): Status {
50
+ if (p.success) return "success";
51
+ if (p.error) return "error";
52
+ if (p.warning) return "warning";
53
+ if (p.info) return "info";
54
+ if (p.neutral) return "neutral";
55
+ return "neutral";
56
+ }
57
+
58
+ export function Badge(props: BadgeProps) {
59
+ const { children, mono, style } = props;
60
+ const { tokens, dark } = useTheme();
61
+
62
+ if (props.status) {
63
+ const tone = statusOf(props);
64
+ return (
65
+ <View style={[s.statusBase, s.statusContainer(tokens, dark, tone), style]}>
66
+ <View style={s.statusDot(tokens, tone)} />
67
+ {children != null ? (
68
+ <Text style={[s.labelType, s.statusLabel(tokens, dark, tone)]}>{children}</Text>
69
+ ) : null}
70
+ </View>
71
+ );
72
+ }
73
+
74
+ const tone = toneOf(props);
75
+ // The mono modifier asks for a monospace face; RN has no font-family utility,
76
+ // so request the cross-platform monospace alias via inline style.
77
+ const monoStyle = mono ? { fontFamily: "monospace" as const } : null;
78
+
79
+ return (
80
+ <View style={[s.metaBase, s.metaContainer(tokens, tone), style]}>
81
+ {children != null ? (
82
+ <Text style={[s.labelType, s.metaLabel(tokens, tone), monoStyle]}>{children}</Text>
83
+ ) : null}
84
+ </View>
85
+ );
86
+ }
@@ -0,0 +1,233 @@
1
+ # Breadcrumbs
2
+
3
+ Hierarchical navigation showing where you are.
4
+
5
+ ## Usage
6
+
7
+ ```tsx
8
+ <Breadcrumb
9
+ items={["Projects", "Identity Platform", "Settings", "Profile"]}
10
+ chevron
11
+ />
12
+ ```
13
+
14
+ ## Variants
15
+
16
+ ### Separator - slash
17
+
18
+ ```tsx
19
+ <Breadcrumb
20
+ items={["Projects", "Identity Platform", "Settings", "Profile"]}
21
+ slash
22
+ />
23
+ ```
24
+
25
+ ### Separator - dot
26
+
27
+ ```tsx
28
+ <Breadcrumb items={["Projects", "Identity Platform", "Settings", "Profile"]} dot />
29
+ ```
30
+
31
+ ### Leading home icon
32
+
33
+ ```tsx
34
+ <Breadcrumb
35
+ items={["Projects", "Identity Platform", "Settings", "Profile"]}
36
+ chevron
37
+ homeIcon
38
+ />
39
+ ```
40
+
41
+ ### In a page header
42
+
43
+ ```tsx
44
+ <View style={{ flexDirection: "row", flexWrap: "wrap", alignItems: "flex-start", justifyContent: "space-between", gap: 16 }}>
45
+ <View>
46
+ <View style={{ marginBottom: 8 }}>
47
+ <Breadcrumb items={["Users", "Rachel Chen"]} />
48
+ </View>
49
+ <Text style={{ fontSize: 24, lineHeight: 32, fontWeight: "600", letterSpacing: -0.4, color: tokens.foreground }}>Rachel Chen</Text>
50
+ </View>
51
+ <View style={{ flexDirection: "row", alignItems: "center", gap: 8 }}>
52
+ <Button outline small>Edit</Button>
53
+ <Button primary small>Save</Button>
54
+ </View>
55
+ </View>
56
+ ```
57
+
58
+ ## Do & Don't
59
+
60
+ ### Current page
61
+
62
+ **Do** — Ancestors are links; the page you're on is plain text at the end of the trail.
63
+
64
+ ```tsx
65
+ <Breadcrumb items={["Projects", "Identity Platform", "Settings"]} />
66
+ ```
67
+
68
+ **Don't** — Linking the current page implies there's somewhere to go; it's a dead link to itself.
69
+
70
+ ```tsx
71
+ <View style={{ flexDirection: "row", flexWrap: "wrap", alignItems: "center", gap: 6 }}>
72
+ <Pressable accessibilityRole="link" style={({ pressed }) => (pressed ? { opacity: 0.7 } : null)}>
73
+ <Text style={{ fontSize: 14, lineHeight: 20, color: tokens["muted-foreground"] }}>Projects</Text>
74
+ </Pressable>
75
+ <Text style={{ fontSize: 14, lineHeight: 20, color: alpha(tokens["muted-foreground"], 0.6) }}>/</Text>
76
+ <Pressable accessibilityRole="link" style={({ pressed }) => (pressed ? { opacity: 0.7 } : null)}>
77
+ <Text style={{ fontSize: 14, lineHeight: 20, color: tokens["muted-foreground"] }}>Identity Platform</Text>
78
+ </Pressable>
79
+ <Text style={{ fontSize: 14, lineHeight: 20, color: alpha(tokens["muted-foreground"], 0.6) }}>/</Text>
80
+ <Pressable accessibilityRole="link" style={({ pressed }) => (pressed ? { opacity: 0.7 } : null)}>
81
+ <Text style={{ fontSize: 14, lineHeight: 20, color: tokens["muted-foreground"] }}>Settings</Text>
82
+ </Pressable>
83
+ </View>
84
+ ```
85
+
86
+ ### Deep paths
87
+
88
+ **Do** — Collapse the middle to an ellipsis; keep the root and the last couple of levels.
89
+
90
+ ```tsx
91
+ <View style={{ flexDirection: "row", flexWrap: "wrap", alignItems: "center", gap: 6 }}>
92
+ <Pressable accessibilityRole="link" style={({ pressed }) => (pressed ? { opacity: 0.7 } : null)}>
93
+ <Text style={{ fontSize: 14, lineHeight: 20, color: tokens["muted-foreground"] }}>Projects</Text>
94
+ </Pressable>
95
+ <Text style={{ fontSize: 14, lineHeight: 20, color: alpha(tokens["muted-foreground"], 0.6) }}>›</Text>
96
+ <Text style={{ fontSize: 14, lineHeight: 20, color: tokens["muted-foreground"], paddingHorizontal: 4 }}>…</Text>
97
+ <Text style={{ fontSize: 14, lineHeight: 20, color: alpha(tokens["muted-foreground"], 0.6) }}>›</Text>
98
+ <Pressable accessibilityRole="link" style={({ pressed }) => (pressed ? { opacity: 0.7 } : null)}>
99
+ <Text style={{ fontSize: 14, lineHeight: 20, color: tokens["muted-foreground"] }}>Avatar</Text>
100
+ </Pressable>
101
+ <Text style={{ fontSize: 14, lineHeight: 20, color: alpha(tokens["muted-foreground"], 0.6) }}>›</Text>
102
+ <Text style={{ fontSize: 14, lineHeight: 20, fontWeight: "500", color: tokens.foreground }}>Edit</Text>
103
+ </View>
104
+ ```
105
+
106
+ **Don't** — A fully expanded deep path wraps and competes with the page.
107
+
108
+ ```tsx
109
+ <Breadcrumb items={[
110
+ "Projects",
111
+ "Identity Platform",
112
+ "Settings",
113
+ "Profile",
114
+ "Avatar",
115
+ "Edit"
116
+ ]} />
117
+ ```
118
+
119
+ ### Separator
120
+
121
+ **Do** — Pick one separator and use it the whole way.
122
+
123
+ ```tsx
124
+ <Breadcrumb items={["Projects", "Identity Platform", "Settings"]} />
125
+ ```
126
+
127
+ **Don't** — Mixing separators in one trail looks broken.
128
+
129
+ ```tsx
130
+ <View style={{ flexDirection: "row", flexWrap: "wrap", alignItems: "center", gap: 6 }}>
131
+ <Pressable accessibilityRole="link" style={({ pressed }) => (pressed ? { opacity: 0.7 } : null)}>
132
+ <Text style={{ fontSize: 14, lineHeight: 20, color: tokens["muted-foreground"] }}>Projects</Text>
133
+ </Pressable>
134
+ <Text style={{ fontSize: 14, lineHeight: 20, color: alpha(tokens["muted-foreground"], 0.6) }}>/</Text>
135
+ <Pressable accessibilityRole="link" style={({ pressed }) => (pressed ? { opacity: 0.7 } : null)}>
136
+ <Text style={{ fontSize: 14, lineHeight: 20, color: tokens["muted-foreground"] }}>Identity Platform</Text>
137
+ </Pressable>
138
+ <Text style={{ fontSize: 14, lineHeight: 20, color: alpha(tokens["muted-foreground"], 0.6) }}>›</Text>
139
+ <Text style={{ fontSize: 14, lineHeight: 20, fontWeight: "500", color: tokens.foreground }}>Settings</Text>
140
+ </View>
141
+ ```
142
+
143
+ ### Home root
144
+
145
+ **Do** — Give the home icon an aria-label so the root is announced.
146
+
147
+ ```tsx
148
+ <Breadcrumb homeIcon items={["Settings"]} />
149
+ ```
150
+
151
+ **Don't** — An icon-only root with no label is unclear to screen readers.
152
+
153
+ ```tsx
154
+ <View style={{ flexDirection: "row", flexWrap: "wrap", alignItems: "center", gap: 6 }}>
155
+ <Pressable accessibilityRole="link" style={({ pressed }) => (pressed ? { opacity: 0.7 } : null)}>
156
+ <Icon home muted size={14} />
157
+ </Pressable>
158
+ <Text style={{ fontSize: 14, lineHeight: 20, color: alpha(tokens["muted-foreground"], 0.6) }}>/</Text>
159
+ <Text style={{ fontSize: 14, lineHeight: 20, fontWeight: "500", color: tokens.foreground }}>Settings</Text>
160
+ </View>
161
+ ```
162
+
163
+ ### Chevron
164
+
165
+ **Do** — Point the chevron in the reading direction (right in LTR) so each one means 'drill into the next level'.
166
+
167
+ ```tsx
168
+ <Breadcrumb chevron items={["Projects", "Identity Platform", "Settings"]} />
169
+ ```
170
+
171
+ **Don't** — A down (or back) chevron reads as a dropdown or a back affordance, not progression down the hierarchy.
172
+
173
+ ```tsx
174
+ <View style={{ flexDirection: "row", flexWrap: "wrap", alignItems: "center", gap: 6 }}>
175
+ <Pressable accessibilityRole="link" style={({ pressed }) => (pressed ? { opacity: 0.7 } : null)}>
176
+ <Text style={{ fontSize: 14, lineHeight: 20, color: tokens["muted-foreground"] }}>Projects</Text>
177
+ </Pressable>
178
+ <Text style={{ fontSize: 14, lineHeight: 20, color: alpha(tokens["muted-foreground"], 0.6) }}>⌄</Text>
179
+ <Pressable accessibilityRole="link" style={({ pressed }) => (pressed ? { opacity: 0.7 } : null)}>
180
+ <Text style={{ fontSize: 14, lineHeight: 20, color: tokens["muted-foreground"] }}>Identity Platform</Text>
181
+ </Pressable>
182
+ <Text style={{ fontSize: 14, lineHeight: 20, color: alpha(tokens["muted-foreground"], 0.6) }}>⌄</Text>
183
+ <Text style={{ fontSize: 14, lineHeight: 20, fontWeight: "500", color: tokens.foreground }}>Settings</Text>
184
+ </View>
185
+ ```
186
+
187
+ ### Slash
188
+
189
+ **Do** — Keep the slash muted and lighter than the text so it reads as a quiet path divider.
190
+
191
+ ```tsx
192
+ <Breadcrumb slash items={["Projects", "Identity Platform", "Settings"]} />
193
+ ```
194
+
195
+ **Don't** — A full-weight, foreground slash competes with the labels and can read as part of a link.
196
+
197
+ ```tsx
198
+ <View style={{ flexDirection: "row", flexWrap: "wrap", alignItems: "center", gap: 6 }}>
199
+ <Pressable accessibilityRole="link" style={({ pressed }) => (pressed ? { opacity: 0.7 } : null)}>
200
+ <Text style={{ fontSize: 14, lineHeight: 20, color: tokens["muted-foreground"] }}>Projects</Text>
201
+ </Pressable>
202
+ <Text style={{ fontSize: 14, lineHeight: 20, fontWeight: "500", color: tokens.foreground, paddingHorizontal: 4 }}>/</Text>
203
+ <Pressable accessibilityRole="link" style={({ pressed }) => (pressed ? { opacity: 0.7 } : null)}>
204
+ <Text style={{ fontSize: 14, lineHeight: 20, color: tokens["muted-foreground"] }}>Identity Platform</Text>
205
+ </Pressable>
206
+ <Text style={{ fontSize: 14, lineHeight: 20, fontWeight: "500", color: tokens.foreground, paddingHorizontal: 4 }}>/</Text>
207
+ <Text style={{ fontSize: 14, lineHeight: 20, fontWeight: "500", color: tokens.foreground }}>Settings</Text>
208
+ </View>
209
+ ```
210
+
211
+ ### Dot
212
+
213
+ **Do** — Use a centered middot (·) so the dot sits between the crumbs and clearly divides them.
214
+
215
+ ```tsx
216
+ <Breadcrumb dot items={["Projects", "Identity Platform", "Settings"]} />
217
+ ```
218
+
219
+ **Don't** — A baseline period looks like a typo or end-of-sentence, not a separator between crumbs.
220
+
221
+ ```tsx
222
+ <View style={{ flexDirection: "row", flexWrap: "wrap", alignItems: "center", gap: 6 }}>
223
+ <Pressable accessibilityRole="link" style={({ pressed }) => (pressed ? { opacity: 0.7 } : null)}>
224
+ <Text style={{ fontSize: 14, lineHeight: 20, color: tokens["muted-foreground"] }}>Projects</Text>
225
+ </Pressable>
226
+ <Text style={{ fontSize: 14, lineHeight: 20, color: alpha(tokens["muted-foreground"], 0.6) }}>.</Text>
227
+ <Pressable accessibilityRole="link" style={({ pressed }) => (pressed ? { opacity: 0.7 } : null)}>
228
+ <Text style={{ fontSize: 14, lineHeight: 20, color: tokens["muted-foreground"] }}>Identity Platform</Text>
229
+ </Pressable>
230
+ <Text style={{ fontSize: 14, lineHeight: 20, color: alpha(tokens["muted-foreground"], 0.6) }}>.</Text>
231
+ <Text style={{ fontSize: 14, lineHeight: 20, fontWeight: "500", color: tokens.foreground }}>Settings</Text>
232
+ </View>
233
+ ```
@@ -0,0 +1,40 @@
1
+ import { type ViewStyle, type TextStyle } from "react-native";
2
+ import { type ColorTokens, alpha } from "../../style/index.js";
3
+
4
+ // Co-located Breadcrumb styles. Layout-only fragments are static objects; the
5
+ // label/divider colors read the active tokens (so the trail follows light/dark
6
+ // and the glass surface). The press-dim for links is applied by the component's
7
+ // Pressable, matching the old `active:opacity-70`.
8
+
9
+ // The nav row: wrapping horizontal trail, centered, with a tight gap (gap-1.5).
10
+ export const nav: ViewStyle = {
11
+ flexDirection: "row",
12
+ flexWrap: "wrap",
13
+ alignItems: "center",
14
+ gap: 6,
15
+ };
16
+
17
+ // A crumb cell (and the homeIcon cell): the icon/label sits next to its divider.
18
+ export const crumb: ViewStyle = {
19
+ flexDirection: "row",
20
+ alignItems: "center",
21
+ gap: 6,
22
+ };
23
+
24
+ // A muted ancestor link (text-sm text-muted-foreground). Press feedback (the old
25
+ // `active:opacity-70`) is applied by the component's Pressable.
26
+ export function link(tokens: ColorTokens): TextStyle {
27
+ return { fontSize: 14, lineHeight: 20, color: tokens["muted-foreground"] };
28
+ }
29
+
30
+ // The current page: emphasized foreground text, not a link
31
+ // (text-sm font-medium text-foreground).
32
+ export function current(tokens: ColorTokens): TextStyle {
33
+ return { fontSize: 14, lineHeight: 20, fontWeight: "500", color: tokens.foreground };
34
+ }
35
+
36
+ // The divider glyph: quieter than the labels so it reads as a path divider
37
+ // (text-sm text-muted-foreground/60).
38
+ export function separator(tokens: ColorTokens): TextStyle {
39
+ return { fontSize: 14, lineHeight: 20, color: alpha(tokens["muted-foreground"], 0.6) };
40
+ }