@ornikar/bumper 3.10.0 → 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.
- package/CHANGELOG.md +9 -0
- package/dist/definitions/shared/storybook/StorySection.d.ts.map +1 -1
- package/dist/definitions/shared/storybook/StoryTitle.d.ts.map +1 -1
- package/dist/definitions/system/actions/Button/Button.d.ts +4 -4
- package/dist/definitions/system/actions/Button/Button.d.ts.map +1 -1
- package/dist/definitions/system/actions/IconButton/IconButton.d.ts.map +1 -1
- package/dist/definitions/system/content/icon/Icon.d.ts.map +1 -1
- package/dist/definitions/system/content/typography/Typography.d.ts +15 -10
- package/dist/definitions/system/content/typography/Typography.d.ts.map +1 -1
- package/dist/definitions/system/content/typography/TypographyLink.d.ts +1 -0
- package/dist/definitions/system/content/typography/TypographyLink.d.ts.map +1 -1
- package/dist/definitions/system/loading/loader/Loader.d.ts +2 -2
- package/dist/definitions/system/loading/loader/Loader.d.ts.map +1 -1
- package/dist/definitions/system/loading/loader/LoaderBackgroundCircle.d.ts +2 -1
- package/dist/definitions/system/loading/loader/LoaderBackgroundCircle.d.ts.map +1 -1
- package/dist/definitions/system/loading/loader/LoaderCircleWrapper.d.ts +2 -1
- package/dist/definitions/system/loading/loader/LoaderCircleWrapper.d.ts.map +1 -1
- package/dist/definitions/system/types.d.ts +38 -1
- package/dist/definitions/system/types.d.ts.map +1 -1
- package/dist/index-metro.es.android.js +3 -2
- package/dist/index-metro.es.android.js.map +1 -1
- package/dist/index-metro.es.ios.js +3 -2
- package/dist/index-metro.es.ios.js.map +1 -1
- package/dist/index-node-22.22.cjs.js +3 -2
- package/dist/index-node-22.22.cjs.js.map +1 -1
- package/dist/index-node-22.22.cjs.web.js +3 -2
- package/dist/index-node-22.22.cjs.web.js.map +1 -1
- package/dist/index-node-22.22.es.mjs +3 -2
- package/dist/index-node-22.22.es.mjs.map +1 -1
- package/dist/index-node-22.22.es.web.mjs +3 -2
- package/dist/index-node-22.22.es.web.mjs.map +1 -1
- package/dist/index.es.js +3 -2
- package/dist/index.es.js.map +1 -1
- package/dist/index.es.web.js +3 -2
- package/dist/index.es.web.js.map +1 -1
- package/dist/tsbuildinfo +1 -1
- package/docs/migration/Typography.md +74 -8
- package/package.json +2 -2
- package/src/.eslintrc.json +2 -5
- package/src/shared/storybook/StorySection.tsx +8 -1
- package/src/shared/storybook/StoryTitle.tsx +8 -2
- package/src/system/actions/Button/Button.tsx +4 -2
- package/src/system/actions/IconButton/IconButton.tsx +3 -2
- package/src/system/content/icon/Icon.tsx +7 -2
- package/src/system/content/typography/Typography.features.stories.tsx +2 -2
- package/src/system/content/typography/Typography.stories.tsx +2 -2
- package/src/system/content/typography/Typography.tsx +21 -19
- package/src/system/content/typography/TypographyLink.features.stories.tsx +2 -2
- package/src/system/content/typography/TypographyLink.stories.tsx +2 -2
- package/src/system/content/typography/TypographyLink.tsx +4 -2
- package/src/system/loading/loader/Loader.tsx +16 -15
- package/src/system/loading/loader/LoaderBackgroundCircle.tsx +8 -1
- package/src/system/loading/loader/LoaderCircleWrapper.tsx +11 -1
- package/src/system/types.ts +51 -2
|
@@ -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 |
|
|
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 |
|
|
@@ -311,10 +315,12 @@ Key differences:
|
|
|
311
315
|
5. **No SetDefaultColor**: Target has no context provider for default colors. Colors must be set on each component individually.
|
|
312
316
|
6. **No TypographyEmoji**: Target has no emoji sub-component.
|
|
313
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.
|
|
314
|
-
8. **Color inheritance**:
|
|
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).
|
|
315
319
|
9. **Responsive API**: Source uses breakpoint props (`base`, `medium`, `large`) or `type` object. Target uses Tamagui media props (`$small`, `$medium`, `$large`).
|
|
316
320
|
10. **TypographyLink/TypographyIcon**: Source exports as standalone components. Target uses compound component pattern (`Typography.Link`, `Typography.Icon`).
|
|
317
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.
|
|
318
324
|
|
|
319
325
|
## Edge Cases
|
|
320
326
|
|
|
@@ -458,6 +464,34 @@ const color = getTypographyColor(state); // should return '$content.accent', '$c
|
|
|
458
464
|
<Typography.Text color={color}>text</Typography.Text>;
|
|
459
465
|
```
|
|
460
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
|
+
|
|
461
495
|
### TypographyIcon with color="inherit"
|
|
462
496
|
|
|
463
497
|
```tsx
|
|
@@ -468,6 +502,31 @@ const color = getTypographyColor(state); // should return '$content.accent', '$c
|
|
|
468
502
|
<Typography.Icon icon={<CheckIcon />} />
|
|
469
503
|
```
|
|
470
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
|
+
|
|
471
530
|
## Migration Rules (machine-readable)
|
|
472
531
|
|
|
473
532
|
1. **Update import**: Replace `import { Typography } from '@ornikar/kitt-universal'` with `import { Typography } from '@ornikar/bumper'`
|
|
@@ -492,7 +551,12 @@ const color = getTypographyColor(state); // should return '$content.accent', '$c
|
|
|
492
551
|
20. **Map color values**: Apply color mapping table (e.g. `"black"` → `"$content.base.hi"`, `"kitt.bumper.X"` → `"$X"`)
|
|
493
552
|
21. **Remove weight on headings/labels**: If target `variant` is a heading or label type, remove the `weight` prop (it's fixed)
|
|
494
553
|
22. **Icon color="inherit"**: Remove `color="inherit"` prop (omitting color achieves inheritance)
|
|
495
|
-
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.
|
|
496
560
|
|
|
497
561
|
## Not Migratable (requires human review)
|
|
498
562
|
|
|
@@ -504,3 +568,5 @@ const color = getTypographyColor(state); // should return '$content.accent', '$c
|
|
|
504
568
|
- **NativeBase styled() extensions** — Must be migrated to Tamagui `styled()` with updated prop names.
|
|
505
569
|
- **Type imports** — `TypographyTextProps`, `TypographyHeadingProps`, `TypographyColor`, `ExtendedTypographyColor` type imports must be updated to bumper equivalents.
|
|
506
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.10.
|
|
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.
|
|
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"
|
package/src/.eslintrc.json
CHANGED
|
@@ -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
|
-
"
|
|
16
|
-
"
|
|
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
|
-
}
|
|
22
|
+
});
|
|
@@ -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',
|
|
@@ -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) => {
|
|
@@ -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 {
|
|
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 {
|
|
@@ -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 {
|
|
3
|
+
import type { TypographyBodyProps, TypographyTextProps } from './Typography';
|
|
4
4
|
import { Typography } from '.';
|
|
5
5
|
|
|
6
|
-
const meta: Meta<Extract<TypographyTextProps,
|
|
6
|
+
const meta: Meta<Extract<TypographyTextProps, TypographyBodyProps>> = {
|
|
7
7
|
title: 'Bumper/Content/Typography/Features',
|
|
8
8
|
component: Typography.Text,
|
|
9
9
|
};
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
2
|
import { contentColorArgType } from '../../../shared/storybook/helpers/argsHelpers';
|
|
3
|
-
import type {
|
|
3
|
+
import type { TypographyBodyProps, TypographyTextProps } from './Typography';
|
|
4
4
|
import { Typography } from '.';
|
|
5
5
|
|
|
6
|
-
const meta: Meta<Extract<TypographyTextProps,
|
|
6
|
+
const meta: Meta<Extract<TypographyTextProps, TypographyBodyProps>> = {
|
|
7
7
|
title: 'Bumper/Content/Typography',
|
|
8
8
|
component: Typography.Text,
|
|
9
9
|
argTypes: {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ColorTokens,
|
|
1
|
+
import type { ColorTokens, TextProps } from '@tamagui/core';
|
|
2
2
|
import { Text, styled } from '@tamagui/core';
|
|
3
3
|
import type { ReactNode } from 'react';
|
|
4
4
|
import { type Except } from 'type-fest';
|
|
@@ -13,13 +13,11 @@ import {
|
|
|
13
13
|
} from '../../core/tokens/GTStandardFont';
|
|
14
14
|
import { CONTENT_CAPS_VARIANTS, type ContentCapsVariants } from '../../core/tokens/GTStandardNarrowFont';
|
|
15
15
|
import type { FontVariants } from '../../core/tokens/fonts';
|
|
16
|
-
import type { TamaguiMediaProps } from '../../types';
|
|
16
|
+
import type { PropsToTamaguiVariants, TamaguiMediaProps } from '../../types';
|
|
17
17
|
import { typographyStyleContext } from './utils/typographyContext';
|
|
18
18
|
|
|
19
|
-
interface TypographyWithoutMediaProps extends TypographyPropsWithoutFontStyleProps {}
|
|
20
|
-
|
|
21
19
|
// Remove font-related style props from InternalTypography Props
|
|
22
|
-
type
|
|
20
|
+
type InternalTypographyExcludedFontStyleProps =
|
|
23
21
|
| 'fontFamily'
|
|
24
22
|
| 'fontSize'
|
|
25
23
|
| 'lineHeight'
|
|
@@ -28,27 +26,30 @@ type TypographyExcludedFontStyleProps =
|
|
|
28
26
|
| 'fontWeight'
|
|
29
27
|
| 'color';
|
|
30
28
|
|
|
31
|
-
type
|
|
29
|
+
type InternalTypographyPropsWithoutFontStyleProps = Except<TextProps, InternalTypographyExcludedFontStyleProps> & {
|
|
32
30
|
color?: ColorTokens;
|
|
33
31
|
};
|
|
34
32
|
|
|
35
|
-
|
|
33
|
+
interface InternalTypographyWithoutMediaProps extends InternalTypographyPropsWithoutFontStyleProps {}
|
|
34
|
+
|
|
35
|
+
interface TypographyBodyWithoutMediaProps extends InternalTypographyWithoutMediaProps {
|
|
36
36
|
variant?: BodyFontVariants;
|
|
37
37
|
weight?: 'regular' | 'bold';
|
|
38
38
|
}
|
|
39
|
-
|
|
39
|
+
interface TypographyHeadingLabelWithoutMediaProps extends InternalTypographyWithoutMediaProps {
|
|
40
40
|
variant: HeadingFontVariants | LabelFontVariants;
|
|
41
41
|
weight?: 'semibold';
|
|
42
42
|
}
|
|
43
|
-
|
|
43
|
+
interface TypographyContentCapsWithoutMediaProps extends InternalTypographyWithoutMediaProps {
|
|
44
44
|
variant: ContentCapsVariants;
|
|
45
45
|
weight?: 'bold';
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
-
export
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
48
|
+
export interface TypographyBodyProps extends TamaguiMediaProps<TypographyBodyWithoutMediaProps> {}
|
|
49
|
+
export interface TypographyHeadingLabelProps extends TamaguiMediaProps<TypographyHeadingLabelWithoutMediaProps> {}
|
|
50
|
+
export interface TypographyContentCapsProps extends TamaguiMediaProps<TypographyContentCapsWithoutMediaProps> {}
|
|
51
|
+
|
|
52
|
+
export type TypographyTextProps = TypographyBodyProps | TypographyHeadingLabelProps | TypographyContentCapsProps;
|
|
52
53
|
|
|
53
54
|
export const InternalTypography = styled(Text, {
|
|
54
55
|
context: typographyStyleContext,
|
|
@@ -63,9 +64,9 @@ export const InternalTypography = styled(Text, {
|
|
|
63
64
|
WebkitFontSmoothing: 'antialiased',
|
|
64
65
|
},
|
|
65
66
|
variants: {
|
|
66
|
-
variant: (variant: FontVariants) => {
|
|
67
|
+
variant: (variant: FontVariants): TextProps => {
|
|
67
68
|
const commonVariantStyles = {
|
|
68
|
-
fontSize: `$${variant}
|
|
69
|
+
fontSize: `$${variant}` as const,
|
|
69
70
|
lineHeight: `$${variant}`,
|
|
70
71
|
letterSpacing: `$${variant}`,
|
|
71
72
|
};
|
|
@@ -100,7 +101,7 @@ export const InternalTypography = styled(Text, {
|
|
|
100
101
|
};
|
|
101
102
|
}
|
|
102
103
|
|
|
103
|
-
return
|
|
104
|
+
return {};
|
|
104
105
|
},
|
|
105
106
|
weight: {
|
|
106
107
|
regular: {
|
|
@@ -113,14 +114,15 @@ export const InternalTypography = styled(Text, {
|
|
|
113
114
|
fontWeight: '$bold',
|
|
114
115
|
},
|
|
115
116
|
},
|
|
116
|
-
} as const
|
|
117
|
+
} as const satisfies PropsToTamaguiVariants<
|
|
118
|
+
TypographyBodyWithoutMediaProps | TypographyHeadingLabelWithoutMediaProps | TypographyContentCapsWithoutMediaProps,
|
|
119
|
+
TextProps
|
|
120
|
+
>,
|
|
117
121
|
defaultVariants: {
|
|
118
122
|
weight: 'regular',
|
|
119
123
|
},
|
|
120
124
|
});
|
|
121
125
|
|
|
122
|
-
export type InternalTypographyProps = GetProps<typeof InternalTypography>;
|
|
123
|
-
|
|
124
126
|
export function TypographyBase(props: TypographyTextProps): ReactNode {
|
|
125
127
|
const flattenProps = useProps(props);
|
|
126
128
|
return <InternalTypography {...flattenProps} />;
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { action } from '@storybook/addon-actions';
|
|
2
2
|
import type { Meta, StoryObj } from '@storybook/react';
|
|
3
3
|
import { VStack } from '../../core/primitives/Stack';
|
|
4
|
-
import type {
|
|
4
|
+
import type { TypographyBodyProps } from './Typography';
|
|
5
5
|
import type { TypographyLinkProps } from './TypographyLink';
|
|
6
6
|
import { InternalTypographyLink, TypographyLink } from './TypographyLink';
|
|
7
7
|
import { Typography } from '.';
|
|
8
8
|
|
|
9
|
-
const meta: Meta<Extract<TypographyLinkProps,
|
|
9
|
+
const meta: Meta<Extract<TypographyLinkProps, TypographyBodyProps>> = {
|
|
10
10
|
title: 'Bumper/Content/TypographyLink/Features',
|
|
11
11
|
component: TypographyLink,
|
|
12
12
|
};
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { action } from '@storybook/addon-actions';
|
|
2
2
|
import type { Meta, StoryObj } from '@storybook/react';
|
|
3
3
|
import { contentColorArgType } from '../../../shared/storybook/helpers/argsHelpers';
|
|
4
|
-
import type {
|
|
4
|
+
import type { TypographyBodyProps } from './Typography';
|
|
5
5
|
import type { TypographyLinkProps } from './TypographyLink';
|
|
6
6
|
import { TypographyLink } from './TypographyLink';
|
|
7
7
|
|
|
8
|
-
const meta: Meta<Extract<TypographyLinkProps,
|
|
8
|
+
const meta: Meta<Extract<TypographyLinkProps, TypographyBodyProps>> = {
|
|
9
9
|
title: 'Bumper/Content/TypographyLink',
|
|
10
10
|
component: TypographyLink,
|
|
11
11
|
argTypes: {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import type { TextProps } from '@tamagui/core';
|
|
1
2
|
import { styled } from '@tamagui/core';
|
|
2
3
|
import type { ReactNode } from 'react';
|
|
3
|
-
import type { TamaguiMediaProps } from '../../types';
|
|
4
|
+
import type { PropsToTamaguiVariants, TamaguiMediaProps } from '../../types';
|
|
4
5
|
import type { TypographyTextProps } from './Typography';
|
|
5
6
|
import { InternalTypography } from './Typography';
|
|
6
7
|
import { typographyStyleContext } from './utils/typographyContext';
|
|
@@ -9,6 +10,7 @@ export interface TypographyLinkWithoutMediaProps {
|
|
|
9
10
|
disabled?: boolean;
|
|
10
11
|
noUnderline?: boolean;
|
|
11
12
|
onPress?: () => void;
|
|
13
|
+
href?: string;
|
|
12
14
|
}
|
|
13
15
|
|
|
14
16
|
export type TypographyLinkProps = TypographyTextProps & TamaguiMediaProps<TypographyLinkWithoutMediaProps>;
|
|
@@ -41,7 +43,7 @@ export const InternalTypographyLink = styled(InternalTypography, {
|
|
|
41
43
|
textDecorationLine: 'underline',
|
|
42
44
|
},
|
|
43
45
|
},
|
|
44
|
-
} as const,
|
|
46
|
+
} as const satisfies PropsToTamaguiVariants<TypographyLinkWithoutMediaProps, TextProps>,
|
|
45
47
|
defaultVariants: {
|
|
46
48
|
disabled: false,
|
|
47
49
|
noUnderline: false,
|
|
@@ -2,8 +2,9 @@ import { styled, useStyle } from '@tamagui/core';
|
|
|
2
2
|
import type { ReactNode } from 'react';
|
|
3
3
|
import { useEffect } from 'react';
|
|
4
4
|
import { useSharedValue, withRepeat, withTiming } from 'react-native-reanimated';
|
|
5
|
+
import type { ViewProps } from '../../core/primitives/View';
|
|
5
6
|
import { View } from '../../core/primitives/View';
|
|
6
|
-
import type { TamaguiMediaProps } from '../../types';
|
|
7
|
+
import type { PropsToTamaguiVariants, TamaguiMediaProps } from '../../types';
|
|
7
8
|
import { LoaderBackgroundCircle } from './LoaderBackgroundCircle';
|
|
8
9
|
import { LoaderCircleWrapper } from './LoaderCircleWrapper';
|
|
9
10
|
import { LoaderForegroundCircle } from './LoaderForegroundCircle';
|
|
@@ -12,19 +13,7 @@ import { LOADER_ANIMATION, LOADER_SIZE_CONFIG } from './loaderConfig';
|
|
|
12
13
|
|
|
13
14
|
const { icon, page } = LOADER_SIZE_CONFIG;
|
|
14
15
|
|
|
15
|
-
|
|
16
|
-
name: 'Loader',
|
|
17
|
-
position: 'relative',
|
|
18
|
-
rotate: '-90deg',
|
|
19
|
-
variants: {
|
|
20
|
-
size: {
|
|
21
|
-
icon: { width: icon.size, height: icon.size },
|
|
22
|
-
page: { width: page.size, height: page.size },
|
|
23
|
-
},
|
|
24
|
-
} as const,
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
interface InternalLoaderProps {
|
|
16
|
+
interface InternalLoaderWithoutMediaProps {
|
|
28
17
|
/** The size of the loader. `'icon'` renders a small 20px loader, `'page'` renders a larger 48px loader.
|
|
29
18
|
* @default 'page'
|
|
30
19
|
* */
|
|
@@ -37,7 +26,19 @@ interface InternalLoaderProps {
|
|
|
37
26
|
testID?: string;
|
|
38
27
|
}
|
|
39
28
|
|
|
40
|
-
|
|
29
|
+
const LoaderContainer = styled(View, {
|
|
30
|
+
name: 'Loader',
|
|
31
|
+
position: 'relative',
|
|
32
|
+
rotate: '-90deg',
|
|
33
|
+
variants: {
|
|
34
|
+
size: {
|
|
35
|
+
icon: { width: icon.size, height: icon.size },
|
|
36
|
+
page: { width: page.size, height: page.size },
|
|
37
|
+
},
|
|
38
|
+
} as const satisfies PropsToTamaguiVariants<InternalLoaderWithoutMediaProps, ViewProps>,
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
export type LoaderProps = TamaguiMediaProps<InternalLoaderWithoutMediaProps>;
|
|
41
42
|
|
|
42
43
|
export function Loader({ size = 'page', isOnContrasted = false, testID }: LoaderProps): ReactNode {
|
|
43
44
|
const backgroundStyle = useStyle({ color: '$border.base.mid' });
|
|
@@ -1,9 +1,16 @@
|
|
|
1
1
|
import { styled } from '@tamagui/core';
|
|
2
|
+
import type { CircleProps } from 'react-native-svg';
|
|
2
3
|
import { Circle } from 'react-native-svg';
|
|
4
|
+
import type { PropsToTamaguiVariants } from '../../types';
|
|
5
|
+
import type { LoaderSize } from './loaderConfig';
|
|
3
6
|
import { LOADER_SIZE_CONFIG } from './loaderConfig';
|
|
4
7
|
|
|
5
8
|
const { icon, page } = LOADER_SIZE_CONFIG;
|
|
6
9
|
|
|
10
|
+
interface LoaderBackgroundCircleVariantProps {
|
|
11
|
+
size?: LoaderSize;
|
|
12
|
+
}
|
|
13
|
+
|
|
7
14
|
export const LoaderBackgroundCircle = styled(Circle, {
|
|
8
15
|
fill: 'none',
|
|
9
16
|
variants: {
|
|
@@ -11,5 +18,5 @@ export const LoaderBackgroundCircle = styled(Circle, {
|
|
|
11
18
|
icon: { strokeWidth: icon.strokeWidth, cx: icon.center, cy: icon.center, r: icon.radius },
|
|
12
19
|
page: { strokeWidth: page.strokeWidth, cx: page.center, cy: page.center, r: page.radius },
|
|
13
20
|
},
|
|
14
|
-
} as const,
|
|
21
|
+
} as const satisfies PropsToTamaguiVariants<LoaderBackgroundCircleVariantProps, CircleProps>,
|
|
15
22
|
});
|
|
@@ -1,9 +1,18 @@
|
|
|
1
1
|
import { styled } from '@tamagui/core';
|
|
2
|
+
import type { SvgProps } from 'react-native-svg';
|
|
2
3
|
import Svg from 'react-native-svg';
|
|
4
|
+
import type { ViewProps } from '../../core/primitives/View';
|
|
5
|
+
import type { PropsToTamaguiVariants } from '../../types';
|
|
6
|
+
import type { LoaderSize } from './loaderConfig';
|
|
3
7
|
import { LOADER_SIZE_CONFIG } from './loaderConfig';
|
|
4
8
|
|
|
5
9
|
const { icon, page } = LOADER_SIZE_CONFIG;
|
|
6
10
|
|
|
11
|
+
interface LoaderCircleWrapperVariantProps {
|
|
12
|
+
size?: LoaderSize;
|
|
13
|
+
isForeground?: boolean;
|
|
14
|
+
}
|
|
15
|
+
|
|
7
16
|
export const LoaderCircleWrapper = styled(Svg, {
|
|
8
17
|
variants: {
|
|
9
18
|
size: {
|
|
@@ -14,6 +23,7 @@ export const LoaderCircleWrapper = styled(Svg, {
|
|
|
14
23
|
true: {
|
|
15
24
|
position: 'absolute',
|
|
16
25
|
},
|
|
26
|
+
false: {},
|
|
17
27
|
},
|
|
18
|
-
} as const,
|
|
28
|
+
} as const satisfies PropsToTamaguiVariants<LoaderCircleWrapperVariantProps, SvgProps & ViewProps>,
|
|
19
29
|
});
|
package/src/system/types.ts
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import type {
|
|
2
|
+
// eslint-disable-next-line no-restricted-imports
|
|
3
|
+
PropsWithoutMediaStyles as InternalPropsWithoutMediaStyles,
|
|
4
|
+
TokensParsed,
|
|
5
|
+
WithMediaProps,
|
|
6
|
+
} from '@tamagui/core';
|
|
3
7
|
|
|
4
8
|
/**
|
|
5
9
|
* Rewrite of Tamagui PropsWithoutMediaStyles to make all responsive props optionnal.
|
|
@@ -17,3 +21,48 @@ export type PropsWithoutMediaStyles<A> = {
|
|
|
17
21
|
* pass breakpoint-specific prop objects alongside regular props.
|
|
18
22
|
*/
|
|
19
23
|
export type TamaguiMediaProps<A> = PropsWithoutMediaStyles<A> & WithMediaProps<InternalPropsWithoutMediaStyles<A>>;
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* A list of keys to ignore as variants.
|
|
27
|
+
* If you do not want to ignore keys globally, you should instead use the third param of the {@link PropsToTamaguiVariants}.
|
|
28
|
+
*/
|
|
29
|
+
export type DefaultIgnoredKeys = 'children';
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Maps a component's variant-prop interface `T` to a Tamagui `variants` config whose entries produce
|
|
33
|
+
* style objects of type `V`.
|
|
34
|
+
*
|
|
35
|
+
* For each key `K` of `T`, the entry must be either:
|
|
36
|
+
* - a record keyed by the prop's literal values (with `boolean` props normalised to `'true' | 'false'`),
|
|
37
|
+
* where each value is a style `V` or a function returning `V`, or
|
|
38
|
+
* - a function that receives the raw prop value and a {@link VariantGoodiesParams} context and returns
|
|
39
|
+
* a style `V` (or `undefined`).
|
|
40
|
+
*
|
|
41
|
+
* Pass a union of keys as `IgnoredKeys` to skip props that should never be variants (e.g.
|
|
42
|
+
* event handlers). Ignored keys are stripped only from both the top-level map, not from `params.props`.
|
|
43
|
+
*
|
|
44
|
+
* Intended to be used with `satisfies` on the `variants` field of a `styled(...)` call so that the
|
|
45
|
+
* config is inferred `as const` while still being checked against the component's prop types, e.g.
|
|
46
|
+
* `{ ... } as const satisfies PropsToTamaguiVariants<MyVariantProps, ViewProps, 'size'>`.
|
|
47
|
+
*/
|
|
48
|
+
export type PropsToTamaguiVariants<T, V, IgnoredKeys extends keyof T = never> = {
|
|
49
|
+
[K in keyof T as K extends IgnoredKeys | Extract<keyof T, DefaultIgnoredKeys> ? never : K]: NonNullable<
|
|
50
|
+
T[K]
|
|
51
|
+
> extends boolean
|
|
52
|
+
? Record<'true' | 'false', V | ((value: boolean | string | number, params: VariantGoodiesParams<T>) => V)>
|
|
53
|
+
: NonNullable<T[K]> extends PropertyKey
|
|
54
|
+
? Record<NonNullable<T[K]>, V> | ((value: NonNullable<T[K]>, params: VariantGoodiesParams<T>) => V | undefined)
|
|
55
|
+
: never;
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Second argument passed to function-form variants declared via {@link PropsToTamaguiVariants}.
|
|
60
|
+
*
|
|
61
|
+
* - `props`: the flattened props of the instance being styled, so a variant can branch on sibling
|
|
62
|
+
* props (e.g. read `disabled` or `isOnContrasted` while resolving `type`).
|
|
63
|
+
* - `tokens`: Tamagui's parsed token map, for resolving design tokens from inside the variant.
|
|
64
|
+
*/
|
|
65
|
+
interface VariantGoodiesParams<T> {
|
|
66
|
+
props: T;
|
|
67
|
+
tokens: TokensParsed;
|
|
68
|
+
}
|