@ornikar/bumper 3.11.0 → 3.12.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 (49) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/dist/definitions/index.d.ts +2 -0
  3. package/dist/definitions/index.d.ts.map +1 -1
  4. package/dist/definitions/system/dataDisplays/Sticker/Sticker.d.ts +18 -0
  5. package/dist/definitions/system/dataDisplays/Sticker/Sticker.d.ts.map +1 -0
  6. package/dist/definitions/system/dataDisplays/Sticker/components/StickerLabel.d.ts +7 -0
  7. package/dist/definitions/system/dataDisplays/Sticker/components/StickerLabel.d.ts.map +1 -0
  8. package/dist/definitions/system/dataDisplays/Sticker/context.d.ts +3 -0
  9. package/dist/definitions/system/dataDisplays/Sticker/context.d.ts.map +1 -0
  10. package/dist/definitions/system/dataDisplays/Sticker/types.d.ts +24 -0
  11. package/dist/definitions/system/dataDisplays/Sticker/types.d.ts.map +1 -0
  12. package/dist/definitions/system/layout/divider/Divider.d.ts.map +1 -1
  13. package/dist/definitions/system/types.d.ts +10 -9
  14. package/dist/definitions/system/types.d.ts.map +1 -1
  15. package/dist/index-metro.es.android.js +146 -9
  16. package/dist/index-metro.es.android.js.map +1 -1
  17. package/dist/index-metro.es.ios.js +146 -9
  18. package/dist/index-metro.es.ios.js.map +1 -1
  19. package/dist/index-node-22.22.cjs.js +145 -6
  20. package/dist/index-node-22.22.cjs.js.map +1 -1
  21. package/dist/index-node-22.22.cjs.web.js +145 -6
  22. package/dist/index-node-22.22.cjs.web.js.map +1 -1
  23. package/dist/index-node-22.22.es.mjs +145 -7
  24. package/dist/index-node-22.22.es.mjs.map +1 -1
  25. package/dist/index-node-22.22.es.web.mjs +145 -7
  26. package/dist/index-node-22.22.es.web.mjs.map +1 -1
  27. package/dist/index.es.js +141 -9
  28. package/dist/index.es.js.map +1 -1
  29. package/dist/index.es.web.js +141 -9
  30. package/dist/index.es.web.js.map +1 -1
  31. package/dist/tsbuildinfo +1 -1
  32. package/docs/migration/Sticker.md +222 -0
  33. package/package.json +1 -1
  34. package/src/index.ts +2 -0
  35. package/src/system/dataDisplays/Sticker/Sticker.features.stories.tsx +50 -0
  36. package/src/system/dataDisplays/Sticker/Sticker.mdx +38 -0
  37. package/src/system/dataDisplays/Sticker/Sticker.stories.tsx +49 -0
  38. package/src/system/dataDisplays/Sticker/Sticker.tsx +52 -0
  39. package/src/system/dataDisplays/Sticker/__snapshots__/Sticker.features.stories.tsx.snap +747 -0
  40. package/src/system/dataDisplays/Sticker/__snapshots__/Sticker.stories.tsx.snap +52 -0
  41. package/src/system/dataDisplays/Sticker/__snapshots_web__/Sticker.features.stories.tsx.snap +294 -0
  42. package/src/system/dataDisplays/Sticker/__snapshots_web__/Sticker.stories.tsx.snap +35 -0
  43. package/src/system/dataDisplays/Sticker/components/StickerLabel.tsx +33 -0
  44. package/src/system/dataDisplays/Sticker/context.ts +10 -0
  45. package/src/system/dataDisplays/Sticker/types.ts +61 -0
  46. package/src/system/layout/divider/Divider.tsx +7 -2
  47. package/src/system/layout/divider/__snapshots_web__/Divider.features.stories.tsx.snap +7 -0
  48. package/src/system/layout/divider/__snapshots_web__/Divider.stories.tsx.snap +1 -0
  49. package/src/system/types.ts +26 -14
@@ -0,0 +1,222 @@
1
+ # Sticker → Sticker Migration Guide
2
+
3
+ > Source: `@ornikar/kitt-universal/Sticker`
4
+ > Target: `@ornikar/bumper/Sticker`
5
+ > Generated: 2026-04-21 · Updated: 2026-04-29 (target prop reverted from `stickerColor` back to `color`)
6
+
7
+ ## Import Change
8
+
9
+ ```tsx
10
+ // Before
11
+ import { Sticker } from '@ornikar/kitt-universal';
12
+ // Type imports (rare — kitt-universal only re-exports the value, not the types)
13
+ import type { StickerProps, StickerColor, StickerSize } from '@ornikar/kitt-universal/Sticker/Sticker';
14
+
15
+ // After
16
+ import { Sticker } from '@ornikar/bumper';
17
+ import type { StickerProps, StickerColor, StickerSize } from '@ornikar/bumper';
18
+ ```
19
+
20
+ ## Props Mapping
21
+
22
+ | Source Prop | Target Prop | Transform | Notes |
23
+ | ------------------- | ----------- | --------------------------- | --------------------------------------------------------------------------------------------- |
24
+ | `label` | `label` | Keep as-is | Same API (`ReactNode`, required) |
25
+ | `color` | `color` | Remap values | See [Color Value Mapping](#color-value-mapping). Default changed: `linen` → `green` |
26
+ | `color="disabled"` | `disabled` | Replace prop + drop value | `disabled` is now a boolean state, not a color. See [Disabled Migration](#disabled-migration) |
27
+ | `size` | `size` | Keep prop, values unchanged | Default changed: `medium` → `small` |
28
+ | `stretch` (boolean) | — | **Not migratable** | Removed from bumper. See [Stretch Removal](#stretch-removal) |
29
+
30
+ ## Value Mappings
31
+
32
+ ### Color Value Mapping
33
+
34
+ ```
35
+ green → green (unchanged)
36
+ darkGreen → greenDark (camelCase order flipped)
37
+ blue → blue (unchanged)
38
+ darkBlue → blueDark (camelCase order flipped)
39
+ red → red (unchanged)
40
+ orange → orange (unchanged)
41
+ pink → pink (unchanged)
42
+ gold → gold (unchanged)
43
+ cream → cream (unchanged)
44
+ linen → linen (unchanged)
45
+ promo → lightning (renamed)
46
+ darkPromo → lightningDark (renamed + order flipped)
47
+ disabled → (remove color) + add `disabled` prop — see below
48
+ ```
49
+
50
+ ### Size Value Mapping
51
+
52
+ Unchanged:
53
+
54
+ ```
55
+ small → small
56
+ medium → medium
57
+ large → large
58
+ ```
59
+
60
+ ## Children & Composition
61
+
62
+ No change — both components accept a single `label` prop (`ReactNode`). No compound components, no children slot.
63
+
64
+ ## Behavioral Differences
65
+
66
+ ### Default value changes
67
+
68
+ | Prop (bumper) | kitt-universal default | bumper default | Action for migrating code |
69
+ | ------------- | ---------------------- | -------------- | ------------------------------------------------------------------------------------------------------------------- |
70
+ | `color` | `'linen'` | `'green'` | If source code relied on the default (`<Sticker label="x" />`), add explicit `color="linen"` to preserve appearance |
71
+ | `size` | `'medium'` | `'small'` | If source code relied on the default, add explicit `size="medium"` to preserve appearance |
72
+
73
+ ### Typography size per `size` variant
74
+
75
+ Typography mapping is **identical** between source and target (both use the same content-caps scale):
76
+
77
+ - `size="small"` → `content-caps-xs` (12px)
78
+ - `size="medium"` → `content-caps-m` (16px)
79
+ - `size="large"` → `content-caps-l` (18px)
80
+
81
+ ### Disabled visual
82
+
83
+ In kitt-universal, `color="disabled"` paints a beige background (`beige.6`) with beige text (`beige.2`). In bumper, `disabled` prop paints the semantic disabled tokens (`$bg.disabled.hi` = grey `#bababa`, `$content.disabled.onContrasted` = white @ 90%). The visual is close but not pixel-identical. Flag for design QA.
84
+
85
+ ### Responsive props
86
+
87
+ bumper `Sticker` accepts Tamagui media props (`$small`, `$medium`, `$large`, `$wide`) — kitt-universal does not. No migration action needed; this is a net gain, not a break.
88
+
89
+ ## Edge Cases
90
+
91
+ ### Disabled migration
92
+
93
+ kitt-universal exposes `disabled` as a **color value**. bumper exposes it as a **boolean prop** — `disabled` is no longer part of the `StickerColor` union.
94
+
95
+ ```tsx
96
+ // Before — static
97
+ <Sticker label="Offline" color="disabled" />
98
+
99
+ // After
100
+ <Sticker label="Offline" disabled />
101
+ ```
102
+
103
+ ```tsx
104
+ // Before — conditional disabled state based on a boolean
105
+ <Sticker label="Item" color={isInactive ? 'disabled' : 'green'} />
106
+
107
+ // After — split the condition into `disabled` + static `color`
108
+ <Sticker label="Item" color="green" disabled={isInactive} />
109
+ ```
110
+
111
+ ```tsx
112
+ // Before — multi-branch conditional color including 'disabled'
113
+ <Sticker label="Item" color={state === 'off' ? 'disabled' : state === 'hot' ? 'red' : 'green'} />
114
+
115
+ // After — extract the disabled branch into the `disabled` prop
116
+ <Sticker
117
+ label="Item"
118
+ color={state === 'hot' ? 'red' : 'green'}
119
+ disabled={state === 'off'}
120
+ />
121
+ ```
122
+
123
+ ### Renamed color values in dynamic expressions
124
+
125
+ When `color` is computed dynamically, remap the values inside the expression (the prop name is unchanged):
126
+
127
+ ```tsx
128
+ // Before
129
+ <Sticker label={x.label} color={x.theme === 'dark' ? 'darkGreen' : 'green'} />
130
+
131
+ // After
132
+ <Sticker label={x.label} color={x.theme === 'dark' ? 'greenDark' : 'green'} />
133
+ ```
134
+
135
+ ```tsx
136
+ // Before — lookup table
137
+ const colorMap = { success: 'green', warning: 'gold', error: 'red', paused: 'darkBlue', pro: 'promo' } as const;
138
+ <Sticker label={status} color={colorMap[kind]} />;
139
+
140
+ // After — rename values in the table
141
+ const colorMap = { success: 'green', warning: 'gold', error: 'red', paused: 'blueDark', pro: 'lightning' } as const;
142
+ <Sticker label={status} color={colorMap[kind]} />;
143
+ ```
144
+
145
+ ### Spread props
146
+
147
+ ```tsx
148
+ // Before
149
+ <Sticker {...stickerProps} />;
150
+
151
+ // After — if stickerProps may contain `stretch`, filter it out (see Stretch Removal)
152
+ const { stretch, ...rest } = stickerProps;
153
+ <Sticker {...rest} />;
154
+ ```
155
+
156
+ If `stickerProps.color` may be `'disabled'` at runtime, the spread will no longer type-check. Transform dynamically:
157
+
158
+ ```tsx
159
+ // After — handle legacy 'disabled' color at call site, remap value
160
+ const { color, stretch, ...rest } = stickerProps;
161
+ <Sticker {...rest} {...(color === 'disabled' ? { disabled: true } : { color: remapColor(color) })} />;
162
+ ```
163
+
164
+ ### Stretch removal
165
+
166
+ `stretch` has no bumper equivalent. The source component used it to make the sticker `width: 100%` and center-align the label. Options:
167
+
168
+ 1. **Default** — remove the prop. The sticker becomes `alignSelf: 'flex-start'` (shrink-to-content). Acceptable if the parent didn't rely on the stretch behavior.
169
+ 2. **Preserve full-width behavior manually**:
170
+
171
+ ```tsx
172
+ // Before
173
+ <Sticker label="x" stretch />
174
+
175
+ // After — manual wrapper
176
+ <View width="100%" alignItems="center">
177
+ <Sticker label="x" />
178
+ </View>
179
+ ```
180
+
181
+ 3. **If `stretch` was responsive** (e.g. `stretch={{ base: false, medium: true }}`), **not migratable mechanically** — flag for human review.
182
+
183
+ Any call site using `stretch` must be reviewed: the sticker's layout will change otherwise.
184
+
185
+ ### Wrapper / re-export migration
186
+
187
+ If a project wraps `Sticker` in a local component, update the wrapper's imports and forward-props first (same mapping as above), then the usages resolve automatically.
188
+
189
+ If the wrapper forwards `stretch`, either drop it from the wrapper's own public API (breaking change for the wrapper) or implement the manual full-width pattern inside the wrapper.
190
+
191
+ ### Styled / extended components
192
+
193
+ kitt-universal's `Sticker` uses native-base `HStack` internally and does not support being extended via `styled()`. bumper's `Sticker` is built with Tamagui but only the public `Sticker` function component is exported — **not** the underlying styled frame. If a consumer relied on `styled(Sticker)` patterns (rare), that is not migratable; use `View` + `Typography.Text` primitives to rebuild.
194
+
195
+ ## Migration Rules (machine-readable)
196
+
197
+ 1. Update import path: `@ornikar/kitt-universal` → `@ornikar/bumper`.
198
+ 2. Update type imports (if any): `@ornikar/kitt-universal/Sticker/Sticker` → `@ornikar/bumper`.
199
+ 3. Keep the component name as-is: `Sticker` → `Sticker`.
200
+ 4. For each prop on every `<Sticker />` usage:
201
+ 1. `label` — keep unchanged.
202
+ 2. `color="disabled"` — **remove the `color` prop** and **add `disabled`** (boolean, `true`).
203
+ 3. `color="darkGreen"` — remap value to `color="greenDark"`.
204
+ 4. `color="darkBlue"` — remap value to `color="blueDark"`.
205
+ 5. `color="promo"` — remap value to `color="lightning"`.
206
+ 6. `color="darkPromo"` — remap value to `color="lightningDark"`.
207
+ 7. `color` with any other static value from the union (`green`, `blue`, `red`, `orange`, `pink`, `gold`, `cream`, `linen`) — keep as-is (values unchanged).
208
+ 8. `color` with a **dynamic expression** (ternary, lookup, variable) — keep the prop name, then recursively apply rules 4.2–4.6 to every literal value inside that expression. If the expression can evaluate to `'disabled'`, split it: extract that branch into a `disabled={…}` prop and remove `'disabled'` from the `color` expression.
209
+ 9. `size` — keep unchanged (values are identical).
210
+ 10. `stretch={false}` — remove the prop.
211
+ 11. `stretch` (bare, or `={true}`, or dynamic) — **flag for manual review**. Leave the prop in place with a `// TODO: bumper Sticker has no stretch prop` comment. Do not guess.
212
+ 5. If the call site relied on the default `color` (no `color` prop) and the visual must be preserved, add `color="linen"` explicitly.
213
+ 6. If the call site relied on the default `size` (no `size` prop) and the visual must be preserved, add `size="medium"` explicitly.
214
+ 7. For spread usages `<Sticker {...props} />`, do **not** rewrite the call site blindly — inspect the source type of `props` and transform the object creation site instead (or introduce a local destructure that filters `stretch` and remaps `'disabled'` to a `disabled={true}` prop, as shown in [Spread props](#spread-props)).
215
+ 8. Do not migrate `styled(Sticker)` wrappers; flag them for manual rewrite.
216
+
217
+ ## Not Migratable (requires human review)
218
+
219
+ - **`stretch` prop** — no bumper equivalent. Manual decision needed per call site: drop the prop (accept layout change), or wrap in `<View width="100%" alignItems="center">`. Responsive `stretch` values (e.g. `stretch={{ base: false, medium: true }}`) always require manual review.
220
+ - **`styled(Sticker)` / extended Sticker wrappers** — underlying styled component is not exported from bumper. Rebuild with primitives if needed.
221
+ - **Default-value regressions** — when `color` or `size` default is relied upon, the visual will change (cream pill in `medium` becomes green pill in `small`). If the migration tool cannot determine whether the default is intentional, flag the call site for design review.
222
+ - **Runtime-only `'disabled'` color values** — when `color` is passed as an untyped string from an external source (e.g. a CMS field), rule 4.8 cannot rewrite it statically. Add a defensive remap at the call site.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ornikar/bumper",
3
- "version": "3.11.0",
3
+ "version": "3.12.0",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "directory": "@ornikar/bumper",
package/src/index.ts CHANGED
@@ -29,6 +29,8 @@ export type { TypographyLinkProps } from './system/content/typography/Typography
29
29
  // Data Displays
30
30
  export type { BadgeProps } from './system/dataDisplays/Badge/Badge';
31
31
  export { Badge } from './system/dataDisplays/Badge/Badge';
32
+ export { Sticker } from './system/dataDisplays/Sticker/Sticker';
33
+ export type { StickerProps } from './system/dataDisplays/Sticker/types';
32
34
 
33
35
  // Breakpoints
34
36
  export { useBreakpointValue } from './system/core/breakpoints/hooks/useBreakpointValue';
@@ -0,0 +1,50 @@
1
+ import type { Meta, StoryObj } from '@storybook/react';
2
+ import { HStack, VStack } from '../../core/primitives/Stack';
3
+ import { View } from '../../core/primitives/View';
4
+ import { Sticker } from './Sticker';
5
+ import { STICKER_COLORS_LIST } from './types';
6
+
7
+ const meta: Meta<typeof Sticker> = {
8
+ title: 'Bumper/Data Displays/Sticker/Features',
9
+ component: Sticker,
10
+ };
11
+
12
+ export default meta;
13
+ type Story = StoryObj<typeof meta>;
14
+
15
+ export const Sizes: Story = {
16
+ render: () => (
17
+ <HStack gap="$space.16" alignItems="center">
18
+ <Sticker label="Small" size="small" />
19
+ <Sticker label="Medium" size="medium" />
20
+ <Sticker label="Large" size="large" />
21
+ </HStack>
22
+ ),
23
+ };
24
+
25
+ export const Colors: Story = {
26
+ render: () => (
27
+ <VStack gap="$space.8" alignItems="flex-start">
28
+ {STICKER_COLORS_LIST.map((color) => (
29
+ <Sticker key={color} label={color} color={color} />
30
+ ))}
31
+ </VStack>
32
+ ),
33
+ };
34
+
35
+ export const Disabled: Story = {
36
+ render: () => (
37
+ <HStack gap="$space.16" alignItems="center">
38
+ <Sticker label="Enabled" color="lightning" />
39
+ <Sticker disabled label="Disabled" color="lightning" />
40
+ </HStack>
41
+ ),
42
+ };
43
+
44
+ export const LongLabel: Story = {
45
+ render: () => (
46
+ <View width={200}>
47
+ <Sticker label="A very long label that should be truncated with an ellipsis" color="linen" />
48
+ </View>
49
+ ),
50
+ };
@@ -0,0 +1,38 @@
1
+ import { Meta, Title, Subtitle, Primary, Controls, Canvas } from '@storybook/blocks';
2
+ import * as StickerStories from './Sticker.stories';
3
+ import * as StickerFeatures from './Sticker.features.stories';
4
+
5
+ <Meta of={StickerStories} />
6
+ <Title />
7
+ <Subtitle />
8
+
9
+ <Primary />
10
+ <Controls />
11
+
12
+ ## Overview
13
+
14
+ `Sticker` is a pill-shaped label used to flag status, category, or highlight content. It renders a short `label` inside a rounded container with a paired background and text color. Twelve colors are available plus three sizes (`small`, `medium`, `large`). Pass `disabled` to force the disabled color variant.
15
+
16
+ ## Sizes
17
+
18
+ Three sizes cover the most common usages. Typography scales along with the container: `small` uses `content-caps-xs`, `medium` uses `content-caps-m`, `large` uses `content-caps-l`.
19
+
20
+ <Canvas of={StickerFeatures.Sizes} />
21
+
22
+ ## Colors
23
+
24
+ Each color pairs a background tone with a matching text tone for legibility. Pick the color that best aligns with the surrounding context (e.g. `lightning` for promotional content, `red` for error states).
25
+
26
+ <Canvas of={StickerFeatures.Colors} />
27
+
28
+ ## Disabled
29
+
30
+ `disabled` forces the internal disabled color variant, overriding any `color` prop. Use it to visually signal that the sticker's content is inactive.
31
+
32
+ <Canvas of={StickerFeatures.Disabled} />
33
+
34
+ ## Truncation
35
+
36
+ Labels are truncated with an ellipsis when the sticker can't fit the full text. The sticker itself never grows beyond its parent.
37
+
38
+ <Canvas of={StickerFeatures.LongLabel} />
@@ -0,0 +1,49 @@
1
+ import type { Meta, StoryObj } from '@storybook/react';
2
+ import { Sticker } from './Sticker';
3
+ import { STICKER_COLORS_LIST, STICKER_SIZES_LIST } from './types';
4
+
5
+ const meta: Meta<typeof Sticker> = {
6
+ title: 'Bumper/Data Displays/Sticker',
7
+ component: Sticker,
8
+ argTypes: {
9
+ label: {
10
+ control: 'text',
11
+ description: 'Text content rendered inside the sticker.',
12
+ },
13
+ color: {
14
+ control: 'select',
15
+ options: STICKER_COLORS_LIST,
16
+ description: 'Color variant.',
17
+ table: {
18
+ defaultValue: { summary: 'green' },
19
+ },
20
+ },
21
+ size: {
22
+ control: 'select',
23
+ options: STICKER_SIZES_LIST,
24
+ description: 'Sticker size.',
25
+ table: {
26
+ defaultValue: { summary: 'small' },
27
+ },
28
+ },
29
+ disabled: {
30
+ control: 'boolean',
31
+ description: 'Forces the disabled color variant.',
32
+ table: {
33
+ defaultValue: { summary: 'false' },
34
+ },
35
+ },
36
+ },
37
+ };
38
+
39
+ export default meta;
40
+ type Story = StoryObj<typeof meta>;
41
+
42
+ export const Default: Story = {
43
+ args: {
44
+ label: 'Label',
45
+ color: 'green',
46
+ size: 'small',
47
+ disabled: false,
48
+ },
49
+ };
@@ -0,0 +1,52 @@
1
+ import { styled } from '@tamagui/core';
2
+ import type { ReactNode } from 'react';
3
+ import { useProps } from '../../core/hooks/useProps';
4
+ import type { ViewProps } from '../../core/primitives/View';
5
+ import { View } from '../../core/primitives/View';
6
+ import type { PropsToTamaguiVariants } from '../../types';
7
+ import { InternalStickerLabel } from './components/StickerLabel';
8
+ import { context } from './context';
9
+ import type { InternalStickerWithoutMediaProps, StickerColor, StickerProps } from './types';
10
+ import { STICKER_COLORS } from './types';
11
+
12
+ export const InternalStickerFrame = styled(View, {
13
+ name: 'Sticker',
14
+ context,
15
+ alignSelf: 'flex-start',
16
+ maxWidth: '100%',
17
+ padding: '$space.4',
18
+ variants: {
19
+ label: {},
20
+ size: {
21
+ small: { borderRadius: '$radius.s' },
22
+ medium: { borderRadius: '$radius.m' },
23
+ large: { borderRadius: '$radius.m' },
24
+ },
25
+ color: (color: StickerColor): ViewProps => {
26
+ const { disabled } = context.useStyledContext();
27
+
28
+ return {
29
+ backgroundColor: STICKER_COLORS[disabled ? 'disabled' : color].background,
30
+ };
31
+ },
32
+ } as const satisfies PropsToTamaguiVariants<InternalStickerWithoutMediaProps, ViewProps>,
33
+
34
+ defaultVariants: {
35
+ size: 'small',
36
+ color: 'green',
37
+ },
38
+ });
39
+
40
+ export const InternalSticker = InternalStickerFrame.styleable<StickerProps>((props) => {
41
+ const { label, ...frameProps } = useProps(props);
42
+
43
+ return (
44
+ <InternalStickerFrame {...frameProps}>
45
+ <InternalStickerLabel>{label}</InternalStickerLabel>
46
+ </InternalStickerFrame>
47
+ );
48
+ });
49
+
50
+ export function Sticker(props: StickerProps): ReactNode {
51
+ return <InternalSticker {...props} />;
52
+ }