@ornikar/bumper 3.9.1 → 3.10.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 (87) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/dist/definitions/shared/storybook/StorySection.d.ts.map +1 -1
  3. package/dist/definitions/shared/storybook/StoryTitle.d.ts.map +1 -1
  4. package/dist/definitions/system/actions/Button/Button.d.ts +4 -4
  5. package/dist/definitions/system/actions/Button/Button.d.ts.map +1 -1
  6. package/dist/definitions/system/actions/IconButton/IconButton.d.ts.map +1 -1
  7. package/dist/definitions/system/content/icon/Icon.d.ts.map +1 -1
  8. package/dist/definitions/system/content/typography/Typography.d.ts +15 -10
  9. package/dist/definitions/system/content/typography/Typography.d.ts.map +1 -1
  10. package/dist/definitions/system/content/typography/TypographyLink.d.ts +1 -0
  11. package/dist/definitions/system/content/typography/TypographyLink.d.ts.map +1 -1
  12. package/dist/definitions/system/core/tokens/palettes/deepPurpleColorPalette.d.ts +70 -69
  13. package/dist/definitions/system/core/tokens/palettes/deepPurpleColorPalette.d.ts.map +1 -1
  14. package/dist/definitions/system/loading/loader/Loader.d.ts +2 -2
  15. package/dist/definitions/system/loading/loader/Loader.d.ts.map +1 -1
  16. package/dist/definitions/system/loading/loader/LoaderBackgroundCircle.d.ts +2 -1
  17. package/dist/definitions/system/loading/loader/LoaderBackgroundCircle.d.ts.map +1 -1
  18. package/dist/definitions/system/loading/loader/LoaderCircleWrapper.d.ts +2 -1
  19. package/dist/definitions/system/loading/loader/LoaderCircleWrapper.d.ts.map +1 -1
  20. package/dist/definitions/system/types.d.ts +38 -1
  21. package/dist/definitions/system/types.d.ts.map +1 -1
  22. package/dist/definitions/tamagui.config.d.ts +142 -2
  23. package/dist/definitions/tamagui.config.d.ts.map +1 -1
  24. package/dist/index-metro.es.android.js +86 -84
  25. package/dist/index-metro.es.android.js.map +1 -1
  26. package/dist/index-metro.es.ios.js +86 -84
  27. package/dist/index-metro.es.ios.js.map +1 -1
  28. package/dist/index-node-22.22.cjs.js +86 -84
  29. package/dist/index-node-22.22.cjs.js.map +1 -1
  30. package/dist/index-node-22.22.cjs.web.js +86 -84
  31. package/dist/index-node-22.22.cjs.web.js.map +1 -1
  32. package/dist/index-node-22.22.es.mjs +86 -84
  33. package/dist/index-node-22.22.es.mjs.map +1 -1
  34. package/dist/index-node-22.22.es.web.mjs +86 -84
  35. package/dist/index-node-22.22.es.web.mjs.map +1 -1
  36. package/dist/index.es.js +86 -84
  37. package/dist/index.es.js.map +1 -1
  38. package/dist/index.es.web.js +86 -84
  39. package/dist/index.es.web.js.map +1 -1
  40. package/dist/storybook-metro.es.android.js +81 -80
  41. package/dist/storybook-metro.es.android.js.map +1 -1
  42. package/dist/storybook-metro.es.ios.js +81 -80
  43. package/dist/storybook-metro.es.ios.js.map +1 -1
  44. package/dist/storybook-node-22.22.cjs.js +81 -80
  45. package/dist/storybook-node-22.22.cjs.js.map +1 -1
  46. package/dist/storybook-node-22.22.cjs.web.js +81 -80
  47. package/dist/storybook-node-22.22.cjs.web.js.map +1 -1
  48. package/dist/storybook-node-22.22.es.mjs +81 -80
  49. package/dist/storybook-node-22.22.es.mjs.map +1 -1
  50. package/dist/storybook-node-22.22.es.web.mjs +81 -80
  51. package/dist/storybook-node-22.22.es.web.mjs.map +1 -1
  52. package/dist/storybook.es.js +81 -80
  53. package/dist/storybook.es.js.map +1 -1
  54. package/dist/storybook.es.web.js +81 -80
  55. package/dist/storybook.es.web.js.map +1 -1
  56. package/dist/tsbuildinfo +1 -1
  57. package/docs/migration/Typography.md +123 -35
  58. package/package.json +2 -2
  59. package/src/.eslintrc.json +2 -5
  60. package/src/shared/storybook/StorySection.tsx +8 -1
  61. package/src/shared/storybook/StoryTitle.tsx +8 -2
  62. package/src/system/actions/Button/Button.mdx +1 -1
  63. package/src/system/actions/Button/Button.tsx +5 -3
  64. package/src/system/actions/Button/__snapshots__/Button.features.stories.tsx.snap +10 -10
  65. package/src/system/actions/Button/__snapshots_web__/Button.features.stories.tsx.snap +2 -2
  66. package/src/system/actions/Button/utils/contentColor.ts +1 -1
  67. package/src/system/actions/IconButton/IconButton.tsx +3 -2
  68. package/src/system/actions/IconButton/__snapshots__/IconButton.features.stories.tsx.snap +10 -10
  69. package/src/system/actions/IconButton/__snapshots_web__/IconButton.features.stories.tsx.snap +2 -2
  70. package/src/system/content/icon/Icon.tsx +7 -2
  71. package/src/system/content/typography/Typography.features.stories.tsx +2 -2
  72. package/src/system/content/typography/Typography.stories.tsx +2 -2
  73. package/src/system/content/typography/Typography.tsx +21 -19
  74. package/src/system/content/typography/TypographyLink.features.stories.tsx +2 -2
  75. package/src/system/content/typography/TypographyLink.stories.tsx +2 -2
  76. package/src/system/content/typography/TypographyLink.tsx +4 -2
  77. package/src/system/core/themes/light/__snapshots__/light.stories.tsx.snap +7 -7
  78. package/src/system/core/themes/light/__snapshots_web__/light.stories.tsx.snap +7 -7
  79. package/src/system/core/themes/light/light.ts +73 -73
  80. package/src/system/core/tokens/palettes/__snapshots__/deepPurpleColorPalette.stories.tsx.snap +141 -70
  81. package/src/system/core/tokens/palettes/__snapshots_web__/deepPurpleColorPalette.stories.tsx.snap +91 -70
  82. package/src/system/core/tokens/palettes/deepPurpleColorPalette.ts +9 -8
  83. package/src/system/loading/loader/Loader.tsx +16 -15
  84. package/src/system/loading/loader/LoaderBackgroundCircle.tsx +8 -1
  85. package/src/system/loading/loader/LoaderCircleWrapper.tsx +11 -1
  86. package/src/system/types.ts +51 -2
  87. package/src/tamagui.config.ts +2 -1
@@ -24,23 +24,23 @@ import { Typography } from '@ornikar/bumper';
24
24
 
25
25
  ### Typography.Text / Typography.Header\*
26
26
 
27
- | Source Prop | Target Prop | Transform | Notes |
28
- | --------------------------------------------- | ---------------------------------------------- | ------------------------------------------------------ | ------------------------------------------------------------------------------------ |
29
- | `base="body-m"` | `variant="body-m"` | Rename prop `base` → `variant` | When used as the only size prop (non-responsive) |
30
- | `base` + `medium` + `large` etc. | `variant` + `$md` + `$lg` etc. | See [Responsive Typography](#responsive-typography) | Legacy breakpoint props become Tamagui media props |
31
- | `type={{ base: "body-m", medium: "body-l" }}` | `variant="body-m" $md={{ variant: "body-l" }}` | Destructure `type` object into `variant` + media props | See [Responsive Typography](#responsive-typography) |
32
- | `variant="regular"` | `weight="regular"` | Rename prop `variant` → `weight` | Only applies to body variants |
33
- | `variant="bold"` | `weight="bold"` | Rename prop `variant` → `weight` | Only applies to body variants |
34
- | `variant="semibold"` | Remove | Remove prop | Headings/labels are always semibold by default; body variants don't support semibold |
35
- | `color="black"` | `color="$content.base.hi"` | Map color value | See [Color Mapping](#color-mapping) |
36
- | `accessibilityRole` | Remove | Remove prop | Sub-components handle roles automatically |
37
- | `textAlign` | `textAlign` | Keep as-is | Same API |
38
- | `textTransform` | `textTransform` | Keep as-is | content-caps auto-applies uppercase in both |
39
- | `underline` | `textDecorationLine="underline"` | Convert boolean to style prop | — |
40
- | `strikeThrough` | `textDecorationLine="line-through"` | Convert boolean to style prop | — |
41
- | `_web={{ ... }}` | `$platform-web={{ ... }}` | Rename platform prop | Tamagui media query syntax |
42
- | `_ios={{ ... }}` | `$platform-native={{ ... }}` | Rename platform prop | No iOS-specific prop; use platform-native |
43
- | `_android={{ ... }}` | `$platform-native={{ ... }}` | Rename platform prop | No Android-specific prop; use platform-native |
27
+ | Source Prop | Target Prop | Transform | Notes |
28
+ | --------------------------------------------- | -------------------------------------------------- | ------------------------------------------------------ | ------------------------------------------------------------------------------------ |
29
+ | `base="body-m"` | `variant="body-m"` | Rename prop `base` → `variant` | When used as the only size prop (non-responsive) |
30
+ | `base` + `medium` + `large` etc. | `variant` + `$medium` + `$large` etc. | See [Responsive Typography](#responsive-typography) | Legacy breakpoint props become Tamagui media props |
31
+ | `type={{ base: "body-m", medium: "body-l" }}` | `variant="body-m" $medium={{ variant: "body-l" }}` | Destructure `type` object into `variant` + media props | See [Responsive Typography](#responsive-typography) |
32
+ | `variant="regular"` | `weight="regular"` | Rename prop `variant` → `weight` | Only applies to body variants |
33
+ | `variant="bold"` | `weight="bold"` | Rename prop `variant` → `weight` | Only applies to body variants |
34
+ | `variant="semibold"` | Remove | Remove prop | Headings/labels are always semibold by default; body variants don't support semibold |
35
+ | `color="black"` | `color="$content.base.hi"` | Map color value | See [Color Mapping](#color-mapping) |
36
+ | `accessibilityRole` | Remove | Remove prop | Sub-components handle roles automatically |
37
+ | `textAlign` | `textAlign` | Keep as-is | Same API |
38
+ | `textTransform` | `textTransform` | Keep as-is | content-caps auto-applies uppercase in both |
39
+ | `underline` | `textDecorationLine="underline"` | Convert boolean to style prop | — |
40
+ | `strikeThrough` | `textDecorationLine="line-through"` | Convert boolean to style prop | — |
41
+ | `_web={{ ... }}` | `$platform-web={{ ... }}` | Rename platform prop | Tamagui media query syntax |
42
+ | `_ios={{ ... }}` | `$platform-native={{ ... }}` | Rename platform prop | No iOS-specific prop; use platform-native |
43
+ | `_android={{ ... }}` | `$platform-native={{ ... }}` | Rename platform prop | No Android-specific prop; use platform-native |
44
44
 
45
45
  ### TypographyLink → Typography.Link
46
46
 
@@ -58,11 +58,13 @@ import { Typography } from '@ornikar/bumper';
58
58
 
59
59
  ### TypographyIcon → Typography.Icon
60
60
 
61
- | Source Prop | Target Prop | Transform | Notes |
62
- | ----------- | ----------- | --------------- | ------------------------------------------------------------------------------------- |
63
- | `icon` | `icon` | Keep as-is | Same API |
64
- | `color` | `color` | Map color value | See [Color Mapping](#color-mapping); `"inherit"` value removed — omit prop to inherit |
65
- | `size` | `size` | Map to token | Numeric values → `$icon.s` (16) / `$icon.m` (20) / `$icon.l` (24) |
61
+ | Source Prop | Target Prop | Transform | Notes |
62
+ | ----------- | ----------- | --------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
63
+ | `icon` | `icon` | Keep as-is | Same API |
64
+ | `color` | `color` | Map color value | See [Color Mapping](#color-mapping); `"inherit"` value removed — omit prop to inherit |
65
+ | `size` | `size` | Map to token | `16` → `$icon.s`, `20` `$icon.m`, `24` `$icon.l`. **Any other numeric value (e.g. `40`, `32`) has no bumper token** — see [Unsupported icon sizes](#unsupported-icon-sizes). |
66
+ | `align` | `alignSelf` | Rename prop | `align="center"` → `alignSelf="center"` |
67
+ | `testID` | `testID` | Keep as-is | Same API |
66
68
 
67
69
  ## Value Mappings
68
70
 
@@ -150,10 +152,12 @@ These are the most common colors found in the codebase. They need the `kitt.bump
150
152
 
151
153
  ```
152
154
  16 → "$icon.s"
153
- 20 → "$icon.m"
155
+ 20 → "$icon.m" (kitt-universal default when size is omitted)
154
156
  24 → "$icon.l"
155
157
  ```
156
158
 
159
+ **Unsupported sizes**: bumper's icon tokens only cover `s` / `m` / `l`. Sizes such as `40` and `32` have no equivalent token (`$icon.xl` does not exist — see [`bumperIcon.ts`](../../src/system/core/tokens/bumperIcon.ts)). Leave such call sites on `@ornikar/kitt-universal`'s `Icon` / `TypographyIcon`, or flag with a `// TODO: bumper has no matching icon size` comment — do not auto-migrate.
160
+
157
161
  ## Sub-Component Mapping
158
162
 
159
163
  | Source | Target | Notes |
@@ -179,12 +183,22 @@ Source uses legacy breakpoint props or a `type` object. Target uses Tamagui medi
179
183
 
180
184
  ```
181
185
  base → variant (the base/default value)
182
- small → $sm={{ variant: "..." }}
183
- medium → $md={{ variant: "..." }}
184
- large → $lg={{ variant: "..." }}
185
- wide → $xl={{ variant: "..." }}
186
+ small → $small={{ variant: "..." }}
187
+ medium → $medium={{ variant: "..." }}
188
+ large → $large={{ variant: "..." }}
189
+ wide → $wide={{ variant: "..." }}
190
+ ```
191
+
192
+ ### Platform Props Mapping
193
+
194
+ ```
195
+ _web={{ ... }} → $platform-web={{ ... }}
196
+ _ios={{ ... }} → $platform-native={{ ... }}
197
+ _android={{ ... }} → $platform-native={{ ... }}
186
198
  ```
187
199
 
200
+ **Important**: `_ios` and `_android` are both mapped to `$platform-native`. There is no per-platform native prop in Tamagui — if the source had different iOS and Android overrides, they must be reconciled into a single `$platform-native` value.
201
+
188
202
  ### Examples
189
203
 
190
204
  ```tsx
@@ -194,7 +208,7 @@ wide → $xl={{ variant: "..." }}
194
208
  </Typography.Text>
195
209
 
196
210
  // After
197
- <Typography.Text variant="body-s" $md={{ variant: "body-l" }}>
211
+ <Typography.Text variant="body-s" $medium={{ variant: "body-l" }}>
198
212
  Responsive text
199
213
  </Typography.Text>
200
214
  ```
@@ -206,11 +220,23 @@ wide → $xl={{ variant: "..." }}
206
220
  </Typography.Text>
207
221
 
208
222
  // After
209
- <Typography.Text variant="body-s" $md={{ variant: "body-m" }} $lg={{ variant: "body-l" }}>
223
+ <Typography.Text variant="body-s" $medium={{ variant: "body-m" }} $large={{ variant: "body-l" }}>
210
224
  Responsive text
211
225
  </Typography.Text>
212
226
  ```
213
227
 
228
+ ```tsx
229
+ // Before — platform-specific props
230
+ <Typography.Text base="body-m" _web={{ style: { cursor: 'pointer' } }} _ios={{ style: { paddingTop: 2 } }}>
231
+ Platform text
232
+ </Typography.Text>
233
+
234
+ // After
235
+ <Typography.Text variant="body-m" $platform-web={{ style: { cursor: 'pointer' } }} $platform-native={{ style: { paddingTop: 2 } }}>
236
+ Platform text
237
+ </Typography.Text>
238
+ ```
239
+
214
240
  ## Children & Composition
215
241
 
216
242
  Children patterns are largely identical between source and target. Both accept:
@@ -288,11 +314,13 @@ Key differences:
288
314
  4. **No Typography.Paragraph**: Target has no Paragraph sub-component. Use Typography.Text.
289
315
  5. **No SetDefaultColor**: Target has no context provider for default colors. Colors must be set on each component individually.
290
316
  6. **No TypographyEmoji**: Target has no emoji sub-component.
291
- 7. **Platform props syntax**: `_web`/`_ios`/`_android` → `$platform-web`/`$platform-native`.
292
- 8. **Color inheritance**: Both support color inheritance via context, but the context APIs differ internally. Behavior is equivalent.
293
- 9. **Responsive API**: Source uses breakpoint props (`base`, `medium`, `large`) or `type` object. Target uses Tamagui media props (`$sm`, `$md`, `$lg`).
317
+ 7. **Platform props syntax**: `_web` → `$platform-web`, `_ios`/`_android` → `$platform-native`. Note that both `_ios` and `_android` map to the same `$platform-native` prop — Tamagui has no per-platform native distinction. If the source used different values for iOS and Android, they must be reconciled manually.
318
+ 8. **Color inheritance**: When a `Typography.Text` is nested inside another bumper `Typography.*`, color propagates automatically via Tamagui's styled context — omit the `color` prop on the child and it will inherit the parent's value. However, inheritance **does NOT work** when the ancestor is a kitt-universal component that provides color via its own context (e.g., `Button`, `RadioGroup`, `CustomTooltip`). In those cases, **do not migrate** the `Typography.Text` — leave it on `@ornikar/kitt-universal`. See [Color inheritance from parent context](#color-inheritance-from-parent-context).
319
+ 9. **Responsive API**: Source uses breakpoint props (`base`, `medium`, `large`) or `type` object. Target uses Tamagui media props (`$small`, `$medium`, `$large`).
294
320
  10. **TypographyLink/TypographyIcon**: Source exports as standalone components. Target uses compound component pattern (`Typography.Link`, `Typography.Icon`).
295
321
  11. **Icon color="inherit"**: Source supports `color="inherit"`. Target does not — simply omit the color prop to inherit from parent.
322
+ 12. **Icon `align` prop renamed**: Source uses `align`; target uses `alignSelf`.
323
+ 13. **Icon tokens only cover s/m/l**: Source accepts any numeric `size`; target only has `$icon.s` (16), `$icon.m` (20), `$icon.l` (24). Other values have no equivalent.
296
324
 
297
325
  ## Edge Cases
298
326
 
@@ -436,6 +464,34 @@ const color = getTypographyColor(state); // should return '$content.accent', '$c
436
464
  <Typography.Text color={color}>text</Typography.Text>;
437
465
  ```
438
466
 
467
+ ### Color inheritance from parent context
468
+
469
+ **Inheritance works automatically** when the parent is a bumper `Typography.*`. Tamagui's styled context propagates the color to descendants — omit the `color` prop on the child:
470
+
471
+ ```tsx
472
+ // Parent sets the color; child inherits via Tamagui context
473
+ <Typography.Text color="$content.accent">
474
+ Headline with <Typography.Text weight="bold">bold</Typography.Text> inside
475
+ </Typography.Text>
476
+ ```
477
+
478
+ **Inheritance does NOT work** when the ancestor is a kitt-universal component that provides color via its own (non-Tamagui) context. bumper's `Typography.Text` applies its default `$content.base.hi` and has no reliable way to read those foreign contexts.
479
+
480
+ **Skip the migration entirely** in these cases — leave the `Typography.*` on `@ornikar/kitt-universal`. Known problematic ancestors:
481
+
482
+ - `Button` (any variant that renders on a contrasted surface)
483
+ - `RadioGroup`
484
+ - `CustomTooltip`
485
+
486
+ ```tsx
487
+ // ❌ DO NOT migrate — Button provides color via kitt's context, bumper cannot inherit it
488
+ <Button type="primary">
489
+ <Typography.Text>Action</Typography.Text> {/* keep on @ornikar/kitt-universal */}
490
+ </Button>
491
+ ```
492
+
493
+ If you cannot leave the call site on kitt-universal (e.g. mixed-imports are undesirable), the only safe escape hatch is to pass the correct bumper token explicitly — but prefer skipping the migration over guessing the token.
494
+
439
495
  ### TypographyIcon with color="inherit"
440
496
 
441
497
  ```tsx
@@ -446,6 +502,31 @@ const color = getTypographyColor(state); // should return '$content.accent', '$c
446
502
  <Typography.Icon icon={<CheckIcon />} />
447
503
  ```
448
504
 
505
+ ### TypographyIcon with `align`
506
+
507
+ ```tsx
508
+ // Before — kitt-universal supports align
509
+ <TypographyIcon icon={<LoaderIcon />} align="center" />
510
+
511
+ // After — bumper renames to alignSelf
512
+ <Typography.Icon icon={<LoaderIcon />} alignSelf="center" />
513
+ ```
514
+
515
+ ### Unsupported icon sizes
516
+
517
+ `bumper`'s icon tokens only cover `s` (16) / `m` (20) / `l` (24). Any other numeric size has no equivalent token.
518
+
519
+ ```tsx
520
+ // Before
521
+ <TypographyIcon icon={<AvatarIcon />} size={40} />
522
+
523
+ // After — DO NOT auto-migrate. Either:
524
+ // (a) leave the call site on kitt-universal's TypographyIcon, or
525
+ // (b) flag for manual review:
526
+ // TODO: bumper has no matching icon size for 40
527
+ <TypographyIcon icon={<AvatarIcon />} size={40} />
528
+ ```
529
+
449
530
  ## Migration Rules (machine-readable)
450
531
 
451
532
  1. **Update import**: Replace `import { Typography } from '@ornikar/kitt-universal'` with `import { Typography } from '@ornikar/bumper'`
@@ -464,13 +545,18 @@ const color = getTypographyColor(state); // should return '$content.accent', '$c
464
545
  14. **Rename platform prop**: `_web={{ ... }}` → `$platform-web={{ ... }}`
465
546
  15. **Rename platform prop**: `_ios={{ ... }}` → `$platform-native={{ ... }}`
466
547
  16. **Rename platform prop**: `_android={{ ... }}` → `$platform-native={{ ... }}`
467
- 17. **Convert responsive**: `type={{ base: X, small: Y, medium: Z, large: W, wide: V }}` → `variant={X} $sm={{ variant: Y }} $md={{ variant: Z }} $lg={{ variant: W }} $xl={{ variant: V }}`
468
- 18. **Convert responsive shorthand**: `small="X"` → `$sm={{ variant: "X" }}`; `medium="X"` → `$md={{ variant: "X" }}`; `large="X"` → `$lg={{ variant: "X" }}`; `wide="X"` → `$xl={{ variant: "X" }}`
548
+ 17. **Convert responsive**: `type={{ base: X, small: Y, medium: Z, large: W, wide: V }}` → `variant={X} $small={{ variant: Y }} $medium={{ variant: Z }} $large={{ variant: W }} $wide={{ variant: V }}`
549
+ 18. **Convert responsive shorthand**: `small="X"` → `$small={{ variant: "X" }}`; `medium="X"` → `$medium={{ variant: "X" }}`; `large="X"` → `$large={{ variant: "X" }}`; `wide="X"` → `$wide={{ variant: "X" }}`
469
550
  19. **Map variant values**: Apply value mapping table (e.g. `heading-xxs` → `heading-2xs`, `label-small` → `label-s`)
470
551
  20. **Map color values**: Apply color mapping table (e.g. `"black"` → `"$content.base.hi"`, `"kitt.bumper.X"` → `"$X"`)
471
552
  21. **Remove weight on headings/labels**: If target `variant` is a heading or label type, remove the `weight` prop (it's fixed)
472
553
  22. **Icon color="inherit"**: Remove `color="inherit"` prop (omitting color achieves inheritance)
473
- 23. **Icon size**: Map numeric sizes to tokens (`16` → `"$icon.s"`, `20` → `"$icon.m"`, `24` → `"$icon.l"`)
554
+ 23. **Icon size**: Map numeric sizes to tokens (`16` → `"$icon.s"`, `20` → `"$icon.m"`, `24` → `"$icon.l"`). **Omitted `size`** on the source (kitt-universal defaults to 20) also maps to `"$icon.m"`.
555
+ 24. **Color inheritance — prefer automatic inheritance, skip inside foreign contexts**:
556
+ - When the parent is a bumper `Typography.*` and the child has no `color` prop, inheritance works automatically via Tamagui's styled context — do not add an explicit `color`.
557
+ - When the ancestor is a kitt-universal component that provides color via its own context — specifically `Button`, `RadioGroup`, or `CustomTooltip` — **do not migrate** the nested `Typography.*`. Leave it on `@ornikar/kitt-universal`. Bumper cannot read those foreign contexts, so any migration would either regress the color or require a guessed explicit token.
558
+ 25. **Icon `align` → `alignSelf`**: Rename `align` to `alignSelf`.
559
+ 26. **Unsupported icon sizes**: If the source `size` is a numeric value other than `16` / `20` / `24`, do NOT migrate. Either leave the call site on `@ornikar/kitt-universal`'s `TypographyIcon`, or flag with a `// TODO: bumper has no matching icon size` comment.
474
560
 
475
561
  ## Not Migratable (requires human review)
476
562
 
@@ -482,3 +568,5 @@ const color = getTypographyColor(state); // should return '$content.accent', '$c
482
568
  - **NativeBase styled() extensions** — Must be migrated to Tamagui `styled()` with updated prop names.
483
569
  - **Type imports** — `TypographyTextProps`, `TypographyHeadingProps`, `TypographyColor`, `ExtendedTypographyColor` type imports must be updated to bumper equivalents.
484
570
  - **Platform-specific overrides merging** — Source has separate `_ios` and `_android` props. Target only has `$platform-native`. If different iOS/Android overrides were used, they need reconciliation.
571
+ - **TypographyIcon with unsupported `size`** — Any numeric `size` other than `16` / `20` / `24` has no bumper token. Call sites must either stay on `@ornikar/kitt-universal` or be resized to a supported token manually.
572
+ - **`Typography.*` nested inside `Button`, `RadioGroup`, or `CustomTooltip`** — These components provide text color via kitt's own (non-Tamagui) context; bumper cannot inherit from them. Leave such call sites on `@ornikar/kitt-universal`.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ornikar/bumper",
3
- "version": "3.9.1",
3
+ "version": "3.10.1",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "directory": "@ornikar/bumper",
@@ -30,7 +30,7 @@
30
30
  },
31
31
  "dependencies": {
32
32
  "@babel/runtime": "^7.24.0",
33
- "@ornikar/kitt-icons": "^15.3.0",
33
+ "@ornikar/kitt-icons": "^15.3.1",
34
34
  "@tamagui/core": "1.144.2",
35
35
  "@tamagui/image": "1.144.2",
36
36
  "@tamagui/scroll-view": "1.144.2"
@@ -1,9 +1,6 @@
1
1
  {
2
2
  "root": true,
3
3
  "parser": "@typescript-eslint/parser",
4
- "parserOptions": {
5
- "project": "@ornikar/bumper/tsconfig.eslint.json"
6
- },
7
4
  "extends": [
8
5
  "@ornikar/eslint-config-typescript-react",
9
6
  "@ornikar/eslint-config/rollup",
@@ -12,8 +9,8 @@
12
9
  ],
13
10
  "settings": {
14
11
  "import/resolver": {
15
- "node": {
16
- "moduleDirectory": ["node_modules", "src"]
12
+ "typescript": {
13
+ "project": "@ornikar/bumper/tsconfig.json"
17
14
  }
18
15
  }
19
16
  },
@@ -2,8 +2,14 @@ import { styled } from '@tamagui/core';
2
2
  import type { ReactNode } from 'react';
3
3
  import type { Except } from 'type-fest';
4
4
  import { VStack, type VStackProps } from '../../system/core/primitives/Stack';
5
+ import type { ViewProps } from '../../system/core/primitives/View';
6
+ import type { PropsToTamaguiVariants } from '../../system/types';
5
7
  import { StoryTitle } from './StoryTitle';
6
8
 
9
+ interface InternalStorySectionWithoutMediaProps {
10
+ withBackground?: boolean;
11
+ }
12
+
7
13
  const InternalStorySection = styled(VStack, {
8
14
  paddingVertical: '$space.4',
9
15
  paddingHorizontal: '$space.4',
@@ -12,8 +18,9 @@ const InternalStorySection = styled(VStack, {
12
18
  true: {
13
19
  backgroundColor: '$content.base.hi',
14
20
  },
21
+ false: {},
15
22
  },
16
- } as const,
23
+ } as const satisfies PropsToTamaguiVariants<InternalStorySectionWithoutMediaProps, ViewProps>,
17
24
  });
18
25
 
19
26
  export type StorySectionProps = Except<VStackProps, 'marginBottom'> & {
@@ -1,5 +1,11 @@
1
+ import type { GetProps } from '@tamagui/core';
1
2
  import { styled } from '@tamagui/core';
2
3
  import { InternalTypography } from '../../system/content/typography/Typography';
4
+ import type { PropsToTamaguiVariants } from '../../system/types';
5
+
6
+ interface StoryTitleWithoutMediaProps {
7
+ level?: 1 | 2 | 3;
8
+ }
3
9
 
4
10
  export const StoryTitle = styled(InternalTypography, {
5
11
  variants: {
@@ -8,9 +14,9 @@ export const StoryTitle = styled(InternalTypography, {
8
14
  2: { variant: 'heading-l', marginBottom: '$space.4' },
9
15
  3: { variant: 'heading-m', marginBottom: '$space.4' },
10
16
  },
11
- } as const,
17
+ } as const satisfies PropsToTamaguiVariants<StoryTitleWithoutMediaProps, GetProps<typeof InternalTypography>>,
12
18
 
13
19
  defaultVariants: {
14
20
  level: 1,
15
21
  },
16
- } as const);
22
+ });
@@ -39,7 +39,7 @@ Append `Button.Badge` after `Button.Text` to surface a count or dot indicator. P
39
39
 
40
40
  ## Disabled
41
41
 
42
- Set `disabled` to prevent interaction. Pointer events and focus are removed, and `aria-disabled` is set. The visual treatment differs by type — `primary` uses `$bg.disabled.mid`, while `secondary` and `danger` show a `$border.disabled` outline.
42
+ Set `disabled` to prevent interaction. Pointer events and focus are removed, and `aria-disabled` is set. The visual treatment differs by type — `primary` uses `$bg.disabled.hi` with `$content.disabled.onContrasted` label for contrast, while `secondary` and `danger` show a `$border.disabled` outline.
43
43
 
44
44
  <Canvas of={ButtonFeatures.Disabled} />
45
45
 
@@ -1,14 +1,16 @@
1
1
  import { styled, withStaticProperties } from '@tamagui/core';
2
2
  import { useProps } from '../../core/hooks/useProps';
3
+ import type { HStackProps } from '../../core/primitives/Stack';
3
4
  import { HStack } from '../../core/primitives/Stack';
4
5
  import { View } from '../../core/primitives/View';
5
6
  import { Loader } from '../../loading/loader/Loader';
7
+ import type { PropsToTamaguiVariants } from '../../types';
6
8
  import { ButtonBadge } from './components/ButtonBadge';
7
9
  import { ButtonIcon } from './components/ButtonIcon';
8
10
  import { ButtonText } from './components/ButtonText';
9
11
  import type { ButtonType } from './context';
10
12
  import { context } from './context';
11
- import type { ButtonProps, ButtonTypeStyle } from './types';
13
+ import type { ButtonProps, ButtonTypeStyle, ButtonWithoutMediaProps } from './types';
12
14
 
13
15
  export const InternalButtonFrame = styled(HStack, {
14
16
  name: 'Button',
@@ -44,7 +46,7 @@ export const InternalButtonFrame = styled(HStack, {
44
46
  if (disabled) {
45
47
  return {
46
48
  ...commonTypeStyle,
47
- backgroundColor: '$bg.disabled.mid',
49
+ backgroundColor: '$bg.disabled.hi',
48
50
  };
49
51
  }
50
52
  }
@@ -125,7 +127,7 @@ export const InternalButtonFrame = styled(HStack, {
125
127
  },
126
128
  false: {},
127
129
  },
128
- } as const,
130
+ } as const satisfies PropsToTamaguiVariants<ButtonWithoutMediaProps, HStackProps>,
129
131
  });
130
132
 
131
133
  export const InternalButton = InternalButtonFrame.styleable<ButtonProps, ButtonProps>((props, ref) => {
@@ -38,7 +38,7 @@ exports[`Bumper/Actions/Button/Features Disabled 1`] = `
38
38
  {
39
39
  "alignItems": "center",
40
40
  "alignSelf": "flex-start",
41
- "backgroundColor": "#ECECEC",
41
+ "backgroundColor": "#BABABA",
42
42
  "borderBottomColor": "transparent",
43
43
  "borderBottomLeftRadius": 4,
44
44
  "borderBottomRightRadius": 4,
@@ -73,7 +73,7 @@ exports[`Bumper/Actions/Button/Features Disabled 1`] = `
73
73
  <Text
74
74
  style={
75
75
  {
76
- "color": "#A8A8A8",
76
+ "color": "#ffffff",
77
77
  "fontFamily": "GTStandardSemibold",
78
78
  "fontSize": 16,
79
79
  "letterSpacing": 0,
@@ -103,16 +103,16 @@ exports[`Bumper/Actions/Button/Features Disabled 1`] = `
103
103
  {
104
104
  "alignItems": "center",
105
105
  "alignSelf": "flex-start",
106
- "borderBottomColor": "#CDCED0",
106
+ "borderBottomColor": "#DCDCDC",
107
107
  "borderBottomLeftRadius": 4,
108
108
  "borderBottomRightRadius": 4,
109
109
  "borderBottomWidth": 1,
110
- "borderLeftColor": "#CDCED0",
110
+ "borderLeftColor": "#DCDCDC",
111
111
  "borderLeftWidth": 1,
112
- "borderRightColor": "#CDCED0",
112
+ "borderRightColor": "#DCDCDC",
113
113
  "borderRightWidth": 1,
114
114
  "borderStyle": "solid",
115
- "borderTopColor": "#CDCED0",
115
+ "borderTopColor": "#DCDCDC",
116
116
  "borderTopLeftRadius": 4,
117
117
  "borderTopRightRadius": 4,
118
118
  "borderTopWidth": 1,
@@ -241,16 +241,16 @@ exports[`Bumper/Actions/Button/Features Disabled 1`] = `
241
241
  {
242
242
  "alignItems": "center",
243
243
  "alignSelf": "flex-start",
244
- "borderBottomColor": "#CDCED0",
244
+ "borderBottomColor": "#DCDCDC",
245
245
  "borderBottomLeftRadius": 4,
246
246
  "borderBottomRightRadius": 4,
247
247
  "borderBottomWidth": 1,
248
- "borderLeftColor": "#CDCED0",
248
+ "borderLeftColor": "#DCDCDC",
249
249
  "borderLeftWidth": 1,
250
- "borderRightColor": "#CDCED0",
250
+ "borderRightColor": "#DCDCDC",
251
251
  "borderRightWidth": 1,
252
252
  "borderStyle": "solid",
253
- "borderTopColor": "#CDCED0",
253
+ "borderTopColor": "#DCDCDC",
254
254
  "borderTopLeftRadius": 4,
255
255
  "borderTopRightRadius": 4,
256
256
  "borderTopWidth": 1,
@@ -22,7 +22,7 @@ exports[`Bumper/Actions/Button/Features Disabled 1`] = `
22
22
  >
23
23
  <div
24
24
  aria-disabled="true"
25
- class="is_Button _outlineWidth-0focus-visible-3px _outlineColor-0focus-visible-border--foc3742 _outlineStyle-0focus-visible-solid _backgroundColor-0hover-button--bg-27634925 _backgroundColor-0active-button--bg-27634925 _dsp-flex _fb-auto _bxs-border-box _pos-relative _minHeight-0px _minWidth-0px _flexShrink-0 _fd-row _alignItems-center _justifyContent-center _btlr-t-radius-ra1673638410 _btrr-t-radius-ra1673638410 _bbrr-t-radius-ra1673638410 _bblr-t-radius-ra1673638410 _alignSelf-flex-start _gap-t-space-spa94482166 _cur-pointer _btc-border--tra718859951 _brc-border--tra718859951 _borderBottomColor-border--tra718859951 _borderLeftColor-border--tra718859951 _btw-1px _brw-1px _borderBottomWidth-1px _borderLeftWidth-1px _height-48px _paddingRight-16px _paddingLeft-16px _paddingTop-14px _paddingBottom-14px _pe-none _backgroundColor-bg--disable1389045052 _borderBottomStyle-solid _borderTopStyle-solid _borderLeftStyle-solid _borderRightStyle-solid"
25
+ class="is_Button _outlineWidth-0focus-visible-3px _outlineColor-0focus-visible-border--foc3742 _outlineStyle-0focus-visible-solid _backgroundColor-0hover-button--bg-27634925 _backgroundColor-0active-button--bg-27634925 _dsp-flex _fb-auto _bxs-border-box _pos-relative _minHeight-0px _minWidth-0px _flexShrink-0 _fd-row _alignItems-center _justifyContent-center _btlr-t-radius-ra1673638410 _btrr-t-radius-ra1673638410 _bbrr-t-radius-ra1673638410 _bblr-t-radius-ra1673638410 _alignSelf-flex-start _gap-t-space-spa94482166 _cur-pointer _btc-border--tra718859951 _brc-border--tra718859951 _borderBottomColor-border--tra718859951 _borderLeftColor-border--tra718859951 _btw-1px _brw-1px _borderBottomWidth-1px _borderLeftWidth-1px _height-48px _paddingRight-16px _paddingLeft-16px _paddingTop-14px _paddingBottom-14px _pe-none _backgroundColor-bg--disable93739269 _borderBottomStyle-solid _borderTopStyle-solid _borderLeftStyle-solid _borderRightStyle-solid"
26
26
  data-disable-theme="true"
27
27
  role="button"
28
28
  tabindex="-1"
@@ -31,7 +31,7 @@ exports[`Bumper/Actions/Button/Features Disabled 1`] = `
31
31
  class="is_VStack _dsp-flex _alignItems-stretch _fb-auto _bxs-border-box _pos-relative _minHeight-0px _minWidth-0px _flexShrink-0 _fd-column"
32
32
  >
33
33
  <span
34
- class="font_GTStandard _WebkitFontSmoothing-_platformweb_antialiased _dsp-inline _bxs-border-box _ww-break-word _ws-pre-wrap _marginTop-0px _marginRight-0px _marginBottom-0px _marginLeft-0px _ff-f-family _fs-f-size-labe105291 _lh-f-lineHeigh1842530170 _ls-f-letterSpa379059035 _fw-f-weight-se1074390495 _textAlign-left _col-content--di910006857"
34
+ class="font_GTStandard _WebkitFontSmoothing-_platformweb_antialiased _dsp-inline _bxs-border-box _ww-break-word _ws-pre-wrap _marginTop-0px _marginRight-0px _marginBottom-0px _marginLeft-0px _ff-f-family _fs-f-size-labe105291 _lh-f-lineHeigh1842530170 _ls-f-letterSpa379059035 _fw-f-weight-se1074390495 _textAlign-left _col-content--di396036745"
35
35
  >
36
36
  Primary
37
37
  </span>
@@ -3,7 +3,7 @@ import type { ButtonType } from '../types';
3
3
 
4
4
  export function getButtonContentColor(type: ButtonType, disabled?: boolean, isOnContrasted?: boolean): ColorTokens {
5
5
  if (disabled) {
6
- return '$content.disabled';
6
+ return type === 'primary' ? '$content.disabled.onContrasted' : '$content.disabled';
7
7
  }
8
8
 
9
9
  switch (type) {
@@ -1,7 +1,8 @@
1
1
  import { styled, withStaticProperties } from '@tamagui/core';
2
2
  import type { ReactNode } from 'react';
3
3
  import type { Except } from 'type-fest';
4
- import type { TamaguiMediaProps } from '../../types';
4
+ import type { ViewProps } from '../../core/primitives/View';
5
+ import type { PropsToTamaguiVariants, TamaguiMediaProps } from '../../types';
5
6
  import { InternalButton } from '../Button/Button';
6
7
  import { ButtonBadge } from '../Button/components/ButtonBadge';
7
8
  import { ButtonIcon } from '../Button/components/ButtonIcon';
@@ -31,7 +32,7 @@ export const InternalIconButtonFrame = styled(InternalButton, {
31
32
  height: 48,
32
33
  },
33
34
  },
34
- } as const,
35
+ } as const satisfies PropsToTamaguiVariants<IconButtonWithoutMediaProps, ViewProps>,
35
36
  });
36
37
 
37
38
  function InternalIconButton(props: IconButtonProps): ReactNode {
@@ -38,7 +38,7 @@ exports[`Bumper/Actions/IconButton/Features Disabled 1`] = `
38
38
  {
39
39
  "alignItems": "center",
40
40
  "alignSelf": "flex-start",
41
- "backgroundColor": "#ECECEC",
41
+ "backgroundColor": "#BABABA",
42
42
  "borderBottomColor": "transparent",
43
43
  "borderBottomLeftRadius": 4,
44
44
  "borderBottomRightRadius": 4,
@@ -73,7 +73,7 @@ exports[`Bumper/Actions/IconButton/Features Disabled 1`] = `
73
73
  }
74
74
  >
75
75
  <svg
76
- color="#A8A8A8"
76
+ color="#ffffff"
77
77
  data-file-name="star.inline.svg"
78
78
  />
79
79
  </View>
@@ -94,16 +94,16 @@ exports[`Bumper/Actions/IconButton/Features Disabled 1`] = `
94
94
  {
95
95
  "alignItems": "center",
96
96
  "alignSelf": "flex-start",
97
- "borderBottomColor": "#CDCED0",
97
+ "borderBottomColor": "#DCDCDC",
98
98
  "borderBottomLeftRadius": 4,
99
99
  "borderBottomRightRadius": 4,
100
100
  "borderBottomWidth": 1,
101
- "borderLeftColor": "#CDCED0",
101
+ "borderLeftColor": "#DCDCDC",
102
102
  "borderLeftWidth": 1,
103
- "borderRightColor": "#CDCED0",
103
+ "borderRightColor": "#DCDCDC",
104
104
  "borderRightWidth": 1,
105
105
  "borderStyle": "solid",
106
- "borderTopColor": "#CDCED0",
106
+ "borderTopColor": "#DCDCDC",
107
107
  "borderTopLeftRadius": 4,
108
108
  "borderTopRightRadius": 4,
109
109
  "borderTopWidth": 1,
@@ -205,16 +205,16 @@ exports[`Bumper/Actions/IconButton/Features Disabled 1`] = `
205
205
  {
206
206
  "alignItems": "center",
207
207
  "alignSelf": "flex-start",
208
- "borderBottomColor": "#CDCED0",
208
+ "borderBottomColor": "#DCDCDC",
209
209
  "borderBottomLeftRadius": 4,
210
210
  "borderBottomRightRadius": 4,
211
211
  "borderBottomWidth": 1,
212
- "borderLeftColor": "#CDCED0",
212
+ "borderLeftColor": "#DCDCDC",
213
213
  "borderLeftWidth": 1,
214
- "borderRightColor": "#CDCED0",
214
+ "borderRightColor": "#DCDCDC",
215
215
  "borderRightWidth": 1,
216
216
  "borderStyle": "solid",
217
- "borderTopColor": "#CDCED0",
217
+ "borderTopColor": "#DCDCDC",
218
218
  "borderTopLeftRadius": 4,
219
219
  "borderTopRightRadius": 4,
220
220
  "borderTopWidth": 1,
@@ -22,7 +22,7 @@ exports[`Bumper/Actions/IconButton/Features Disabled 1`] = `
22
22
  >
23
23
  <div
24
24
  aria-disabled="true"
25
- class="is_Button _outlineWidth-0focus-visible-3px _outlineColor-0focus-visible-border--foc3742 _outlineStyle-0focus-visible-solid _backgroundColor-0hover-button--bg-27634925 _backgroundColor-0active-button--bg-27634925 _dsp-flex _fb-auto _bxs-border-box _pos-relative _minHeight-0px _minWidth-0px _flexShrink-0 _fd-row _alignItems-center _justifyContent-center _btlr-t-radius-ra1673638410 _btrr-t-radius-ra1673638410 _bbrr-t-radius-ra1673638410 _bblr-t-radius-ra1673638410 _alignSelf-flex-start _gap-t-space-spa94482166 _cur-pointer _btc-border--tra718859951 _brc-border--tra718859951 _borderBottomColor-border--tra718859951 _borderLeftColor-border--tra718859951 _btw-1px _brw-1px _borderBottomWidth-1px _borderLeftWidth-1px _pe-none _height-48px _paddingRight-14px _paddingLeft-14px _paddingTop-14px _paddingBottom-14px _backgroundColor-bg--disable1389045052 _width-48px _borderBottomStyle-solid _borderTopStyle-solid _borderLeftStyle-solid _borderRightStyle-solid"
25
+ class="is_Button _outlineWidth-0focus-visible-3px _outlineColor-0focus-visible-border--foc3742 _outlineStyle-0focus-visible-solid _backgroundColor-0hover-button--bg-27634925 _backgroundColor-0active-button--bg-27634925 _dsp-flex _fb-auto _bxs-border-box _pos-relative _minHeight-0px _minWidth-0px _flexShrink-0 _fd-row _alignItems-center _justifyContent-center _btlr-t-radius-ra1673638410 _btrr-t-radius-ra1673638410 _bbrr-t-radius-ra1673638410 _bblr-t-radius-ra1673638410 _alignSelf-flex-start _gap-t-space-spa94482166 _cur-pointer _btc-border--tra718859951 _brc-border--tra718859951 _borderBottomColor-border--tra718859951 _borderLeftColor-border--tra718859951 _btw-1px _brw-1px _borderBottomWidth-1px _borderLeftWidth-1px _pe-none _height-48px _paddingRight-14px _paddingLeft-14px _paddingTop-14px _paddingBottom-14px _backgroundColor-bg--disable93739269 _width-48px _borderBottomStyle-solid _borderTopStyle-solid _borderLeftStyle-solid _borderRightStyle-solid"
26
26
  data-disable-theme="true"
27
27
  role="button"
28
28
  tabindex="-1"
@@ -31,7 +31,7 @@ exports[`Bumper/Actions/IconButton/Features Disabled 1`] = `
31
31
  class="is_Icon _dsp-flex _alignItems-stretch _fd-column _fb-auto _bxs-border-box _pos-relative _minHeight-0px _minWidth-0px _flexShrink-0 _width-t-bumperIco1504282965 _height-t-bumperIco1504282965"
32
32
  >
33
33
  <svg
34
- color="var(--content--disabled)"
34
+ color="var(--content--disabled--onContrasted)"
35
35
  data-file-name="star.inline.svg"
36
36
  />
37
37
  </div>
@@ -3,9 +3,14 @@ import { styled, useStyle } from '@tamagui/core';
3
3
  import type { ReactElement, ReactNode } from 'react';
4
4
  import { cloneElement } from 'react';
5
5
  import { useProps } from '../../core/hooks/useProps';
6
+ import type { ViewProps } from '../../core/primitives/View';
6
7
  import { View } from '../../core/primitives/View';
7
8
  import type { BumperIconTokens } from '../../core/tokens/bumperIcon';
8
- import type { TamaguiMediaProps } from '../../types';
9
+ import type { PropsToTamaguiVariants, TamaguiMediaProps } from '../../types';
10
+
11
+ interface IconContainerVariantProps {
12
+ size?: BumperIconTokens;
13
+ }
9
14
 
10
15
  const IconContainer = styled(View, {
11
16
  name: 'Icon',
@@ -16,7 +21,7 @@ const IconContainer = styled(View, {
16
21
  height: tokens.bumperIcon[iconSize],
17
22
  };
18
23
  },
19
- } as const,
24
+ } as const satisfies PropsToTamaguiVariants<IconContainerVariantProps, ViewProps>,
20
25
 
21
26
  defaultVariants: {
22
27
  size: '$icon.m',
@@ -1,9 +1,9 @@
1
1
  import type { Meta, StoryObj } from '@storybook/react';
2
2
  import { VStack } from '../../core/primitives/Stack';
3
- import type { BodyProps, TypographyTextProps } from './Typography';
3
+ import type { TypographyBodyProps, TypographyTextProps } from './Typography';
4
4
  import { Typography } from '.';
5
5
 
6
- const meta: Meta<Extract<TypographyTextProps, BodyProps>> = {
6
+ const meta: Meta<Extract<TypographyTextProps, TypographyBodyProps>> = {
7
7
  title: 'Bumper/Content/Typography/Features',
8
8
  component: Typography.Text,
9
9
  };