@impulse-ui-native/primitives 16.0.0 → 17.1.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.
package/README.md CHANGED
@@ -20,7 +20,7 @@ pnpm add react-native-safe-area-context react-native-svg
20
20
 
21
21
  - `View` adds theme spacing, dimensions, flex, borders, colors, and shadow props to React Native's view.
22
22
  - `SafeAreaView` maps safe-area edges to the theme spacing scale.
23
- - `Typography` exposes named text presets such as `DisplayLarge`, `Title1`, `Body`, `Caption`, and `Code`.
23
+ - `Typography` exposes named text presets such as `DisplayLarge`, `Title1`, `Body`, `Caption`, and `Code`. All presets accept the same direct margin and padding props as `View`, including side, horizontal, and vertical props. Explicit `style` values take precedence.
24
24
  - `Button`, `IconButton`, and `Pressable` provide themed interaction primitives.
25
25
  - `Tag` labels categories, filters, and metadata, with optional press and close behavior.
26
26
  - `Badge` provides compact semantic labels with visual variants and Input-style prefix and suffix addons.
@@ -31,6 +31,14 @@ pnpm add react-native-safe-area-context react-native-svg
31
31
  - `createPreset` creates reusable themed typography presets.
32
32
  - Public prop types describe every primitive and control part.
33
33
 
34
+ All Typography presets support direct spacing props:
35
+
36
+ ```tsx
37
+ <Typography.Body marginBottom={8} paddingHorizontal={16}>
38
+ Spaced text
39
+ </Typography.Body>
40
+ ```
41
+
34
42
  Typography presets update their colors with the active theme:
35
43
 
36
44
  - `Subtitle1`, `Subtitle2`, `BodySmall`, `Caption`, `Helper`, `Overline`, and
@@ -146,6 +154,8 @@ appearance, but does not inject label content.
146
154
 
147
155
  Use `Badge` for compact states and metadata. It supports `filled`, `outlined`, and `soft` display variants and semantic tones. Its addons follow Input: use `PrefixIcon` or `Prefix`, `SuffixIcon` or `Suffix`, and optionally `onPressPrefix` or `onPressSuffix`. A custom component takes precedence over its corresponding icon. Use `Tag` when the whole label needs built-in press or close behavior.
148
156
 
157
+ Badge text and Tag labels stay on one line and truncate with a trailing ellipsis when constrained by available width. Their containers shrink within rows while icons and close actions retain their space. Use `style.width` or `style.maxWidth` for a specific limit; custom Badge children own their text overflow behavior.
158
+
149
159
  Badges follow their parent's `alignItems` for cross-axis alignment. For example,
150
160
  use `alignItems="center"` on a column to center badges horizontally. Use
151
161
  `alignSelf` on a badge when it needs a different alignment from its siblings.
@@ -1,19 +1,14 @@
1
1
  import * as react from 'react';
2
- import { ComponentType } from 'react';
3
- import { IconProps } from '@impulse-ui-native/icon/types';
4
- import { PressableCoreProps } from '../../../types/button.types.mjs';
2
+ import { BadgeAddonProps } from '../../../types/badge-addon.types.mjs';
3
+ import '../../../types/badge.types.mjs';
5
4
  import 'react-native';
6
5
  import '@impulse-ui-native/theme';
6
+ import '../../../types/control-components.types.mjs';
7
+ import '@impulse-ui-native/icon/types';
8
+ import '../../../types/button.types.mjs';
7
9
  import '../../../types/view.types.mjs';
10
+ import '../../../types/spinner.types.mjs';
8
11
 
9
- interface BadgeAddonProps {
10
- color: string | undefined;
11
- Content: ComponentType | undefined;
12
- hitSlop: number;
13
- iconSize: number;
14
- IconComponent: IconProps["icon"] | undefined;
15
- onPress: PressableCoreProps["onPress"] | undefined;
16
- }
17
12
  declare const BadgeAddon: react.MemoExoticComponent<({ color, Content, hitSlop, iconSize, IconComponent, onPress, }: BadgeAddonProps) => react.JSX.Element | null>;
18
13
 
19
14
  export { BadgeAddon };
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/components/atoms/badge/addon.tsx"],"sourcesContent":["import type { ComponentType } from \"react\";\nimport { memo, useMemo } from \"react\";\n\nimport type { IconProps } from \"@impulse-ui-native/icon/types\";\nimport { Icon } from \"@impulse-ui-native/icon\";\n\nimport type { PressableCoreProps } from \"../../../types\";\nimport { Pressable } from \"../pressable\";\nimport { View } from \"../view\";\n\ninterface BadgeAddonProps {\n color: string | undefined;\n Content: ComponentType | undefined;\n hitSlop: number;\n iconSize: number;\n IconComponent: IconProps[\"icon\"] | undefined;\n onPress: PressableCoreProps[\"onPress\"] | undefined;\n}\n\nexport const BadgeAddon = memo(function BadgeAddon({\n color,\n Content,\n hitSlop,\n iconSize,\n IconComponent,\n onPress,\n}: BadgeAddonProps) {\n const Container = onPress ? Pressable : View;\n const content = useMemo(() => {\n if (Content) {\n return <Content />;\n }\n\n if (IconComponent) {\n return <Icon color={color} icon={IconComponent} size={iconSize} />;\n }\n\n return null;\n }, [color, Content, iconSize, IconComponent]);\n\n if (!content) {\n return null;\n }\n\n return (\n <Container hitSlop={hitSlop} onPress={onPress}>\n {content}\n </Container>\n );\n});\n"],"mappings":"AA8Ba;AA7Bb,SAAS,MAAM,eAAe;AAG9B,SAAS,YAAY;AAGrB,SAAS,iBAAiB;AAC1B,SAAS,YAAY;AAWd,MAAM,aAAa,KAAK,SAASA,YAAW;AAAA,EACjD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAoB;AAClB,QAAM,YAAY,UAAU,YAAY;AACxC,QAAM,UAAU,QAAQ,MAAM;AAC5B,QAAI,SAAS;AACX,aAAO,oBAAC,WAAQ;AAAA,IAClB;AAEA,QAAI,eAAe;AACjB,aAAO,oBAAC,QAAK,OAAc,MAAM,eAAe,MAAM,UAAU;AAAA,IAClE;AAEA,WAAO;AAAA,EACT,GAAG,CAAC,OAAO,SAAS,UAAU,aAAa,CAAC;AAE5C,MAAI,CAAC,SAAS;AACZ,WAAO;AAAA,EACT;AAEA,SACE,oBAAC,aAAU,SAAkB,SAC1B,mBACH;AAEJ,CAAC;","names":["BadgeAddon"]}
1
+ {"version":3,"sources":["../../../../src/components/atoms/badge/addon.tsx"],"sourcesContent":["import { memo, useMemo } from \"react\";\r\n\r\nimport { Icon } from \"@impulse-ui-native/icon\";\r\n\r\nimport type { BadgeAddonProps } from \"../../../types/badge-addon.types\";\r\nimport { Pressable } from \"../pressable\";\r\nimport { View } from \"../view\";\r\n\r\nexport const BadgeAddon = memo(function BadgeAddon({\r\n color,\r\n Content,\r\n hitSlop,\r\n iconSize,\r\n IconComponent,\r\n onPress,\r\n}: BadgeAddonProps) {\r\n const Container = onPress ? Pressable : View;\r\n const content = useMemo(() => {\r\n if (Content) {\r\n return <Content />;\r\n }\r\n\r\n if (IconComponent) {\r\n return <Icon color={color} icon={IconComponent} size={iconSize} />;\r\n }\r\n\r\n return null;\r\n }, [color, Content, iconSize, IconComponent]);\r\n\r\n if (!content) {\r\n return null;\r\n }\r\n\r\n return (\r\n <Container hitSlop={hitSlop} onPress={onPress}>\r\n {content}\r\n </Container>\r\n );\r\n});\r\n"],"mappings":"AAmBa;AAnBb,SAAS,MAAM,eAAe;AAE9B,SAAS,YAAY;AAGrB,SAAS,iBAAiB;AAC1B,SAAS,YAAY;AAEd,MAAM,aAAa,KAAK,SAASA,YAAW;AAAA,EACjD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAoB;AAClB,QAAM,YAAY,UAAU,YAAY;AACxC,QAAM,UAAU,QAAQ,MAAM;AAC5B,QAAI,SAAS;AACX,aAAO,oBAAC,WAAQ;AAAA,IAClB;AAEA,QAAI,eAAe;AACjB,aAAO,oBAAC,QAAK,OAAc,MAAM,eAAe,MAAM,UAAU;AAAA,IAClE;AAEA,WAAO;AAAA,EACT,GAAG,CAAC,OAAO,SAAS,UAAU,aAAa,CAAC;AAE5C,MAAI,CAAC,SAAS;AACZ,WAAO;AAAA,EACT;AAEA,SACE,oBAAC,aAAU,SAAkB,SAC1B,mBACH;AAEJ,CAAC;","names":["BadgeAddon"]}
@@ -51,7 +51,7 @@ const BadgeRoot = memo(function BadgeRoot2({
51
51
  onPress: onPressPrefix
52
52
  }
53
53
  ),
54
- isTextChild ? /* @__PURE__ */ jsx(Text, { numberOfLines: 1, style: styles.label, children }) : children,
54
+ isTextChild ? /* @__PURE__ */ jsx(Text, { numberOfLines: 1, ellipsizeMode: "tail", style: styles.label, children }) : children,
55
55
  /* @__PURE__ */ jsx(
56
56
  BadgeAddon,
57
57
  {
@@ -74,7 +74,8 @@ function themedStyles(theme, props) {
74
74
  container: {
75
75
  alignItems: "center",
76
76
  flexDirection: "row",
77
- flexShrink: 0,
77
+ flexShrink: 1,
78
+ maxWidth: "100%",
78
79
  justifyContent: "center",
79
80
  borderRadius: badgeTokens.borderRadius,
80
81
  borderWidth: badgeTokens.borderWidth,
@@ -86,6 +87,8 @@ function themedStyles(theme, props) {
86
87
  borderColor: variantTokens.borderColor
87
88
  },
88
89
  label: {
90
+ flexShrink: 1,
91
+ minWidth: 0,
89
92
  textAlign: "center",
90
93
  fontFamily: badgeTokens.fontFamily,
91
94
  fontSize: sizeTokens.fontSize,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/components/atoms/badge/root.tsx"],"sourcesContent":["import { memo, useMemo } from \"react\";\r\nimport { StyleSheet, Text } from \"react-native\";\r\n\r\nimport type { AppTheme } from \"@impulse-ui-native/theme\";\r\nimport {\r\n useComponentsTokens,\r\n useStyleProps,\r\n useThemedStyles,\r\n} from \"@impulse-ui-native/theme\";\r\n\r\nimport type { BadgeProps, BadgeThemeProps } from \"../../../types\";\r\nimport { View } from \"../view\";\r\nimport { BadgeAddon } from \"./addon\";\r\n\r\nexport const BadgeRoot = memo(function BadgeRoot({\r\n backgroundColor,\r\n children,\r\n color,\r\n Prefix,\r\n PrefixIcon,\r\n onPressPrefix,\r\n onPressSuffix,\r\n size = \"medium\",\r\n style,\r\n Suffix,\r\n SuffixIcon,\r\n tone = \"primary\",\r\n variant = \"filled\",\r\n ...props\r\n}: BadgeProps) {\r\n const tokens = useComponentsTokens();\r\n\r\n const badgeTokens = tokens.badge;\r\n const sizeTokens = badgeTokens.sizes[size];\r\n\r\n const extractedStyleProps = useStyleProps(props);\r\n const styles = useThemedStyles(\r\n themedStyles,\r\n { backgroundColor, color, size, tone, variant },\r\n [backgroundColor, color, size, tone, variant],\r\n );\r\n\r\n const containerStyle = useMemo(\r\n () => [styles.container, extractedStyleProps, style],\r\n [extractedStyleProps, style, styles.container],\r\n );\r\n\r\n const affixColor =\r\n typeof styles.label.color === \"string\" ? styles.label.color : undefined;\r\n\r\n const isTextChild =\r\n typeof children === \"string\" || typeof children === \"number\";\r\n\r\n return (\r\n <View {...props} style={containerStyle}>\r\n <BadgeAddon\r\n Content={Prefix}\r\n IconComponent={PrefixIcon}\r\n color={affixColor}\r\n hitSlop={badgeTokens.addonHitSlop}\r\n iconSize={sizeTokens.iconSize}\r\n onPress={onPressPrefix}\r\n />\r\n\r\n {isTextChild ? (\r\n <Text numberOfLines={1} style={styles.label}>\r\n {children}\r\n </Text>\r\n ) : (\r\n children\r\n )}\r\n\r\n <BadgeAddon\r\n Content={Suffix}\r\n IconComponent={SuffixIcon}\r\n color={affixColor}\r\n hitSlop={badgeTokens.addonHitSlop}\r\n iconSize={sizeTokens.iconSize}\r\n onPress={onPressSuffix}\r\n />\r\n </View>\r\n );\r\n});\r\n\r\nfunction themedStyles(theme: AppTheme, props: BadgeThemeProps) {\r\n const { backgroundColor, color, size, tone, variant } = props;\r\n\r\n const badgeTokens = theme.components.badge;\r\n const sizeTokens = badgeTokens.sizes[size];\r\n const variantTokens = badgeTokens.colors[tone][variant];\r\n\r\n return StyleSheet.create({\r\n container: {\r\n alignItems: \"center\",\r\n flexDirection: \"row\",\r\n flexShrink: 0,\r\n justifyContent: \"center\",\r\n\r\n borderRadius: badgeTokens.borderRadius,\r\n borderWidth: badgeTokens.borderWidth,\r\n gap: badgeTokens.gap,\r\n height: sizeTokens.height,\r\n minWidth: sizeTokens.minWidth,\r\n paddingHorizontal: sizeTokens.paddingHorizontal,\r\n\r\n backgroundColor: backgroundColor ?? variantTokens.backgroundColor,\r\n borderColor: variantTokens.borderColor,\r\n },\r\n\r\n label: {\r\n textAlign: \"center\",\r\n\r\n fontFamily: badgeTokens.fontFamily,\r\n fontSize: sizeTokens.fontSize,\r\n lineHeight: sizeTokens.lineHeight,\r\n\r\n color: color ?? variantTokens.color,\r\n },\r\n });\r\n}\r\n"],"mappings":"AAsDI,SACE,KADF;AAtDJ,SAAS,MAAM,eAAe;AAC9B,SAAS,YAAY,YAAY;AAGjC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAGP,SAAS,YAAY;AACrB,SAAS,kBAAkB;AAEpB,MAAM,YAAY,KAAK,SAASA,WAAU;AAAA,EAC/C;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,OAAO;AAAA,EACP;AAAA,EACA;AAAA,EACA;AAAA,EACA,OAAO;AAAA,EACP,UAAU;AAAA,EACV,GAAG;AACL,GAAe;AACb,QAAM,SAAS,oBAAoB;AAEnC,QAAM,cAAc,OAAO;AAC3B,QAAM,aAAa,YAAY,MAAM,IAAI;AAEzC,QAAM,sBAAsB,cAAc,KAAK;AAC/C,QAAM,SAAS;AAAA,IACb;AAAA,IACA,EAAE,iBAAiB,OAAO,MAAM,MAAM,QAAQ;AAAA,IAC9C,CAAC,iBAAiB,OAAO,MAAM,MAAM,OAAO;AAAA,EAC9C;AAEA,QAAM,iBAAiB;AAAA,IACrB,MAAM,CAAC,OAAO,WAAW,qBAAqB,KAAK;AAAA,IACnD,CAAC,qBAAqB,OAAO,OAAO,SAAS;AAAA,EAC/C;AAEA,QAAM,aACJ,OAAO,OAAO,MAAM,UAAU,WAAW,OAAO,MAAM,QAAQ;AAEhE,QAAM,cACJ,OAAO,aAAa,YAAY,OAAO,aAAa;AAEtD,SACE,qBAAC,QAAM,GAAG,OAAO,OAAO,gBACtB;AAAA;AAAA,MAAC;AAAA;AAAA,QACC,SAAS;AAAA,QACT,eAAe;AAAA,QACf,OAAO;AAAA,QACP,SAAS,YAAY;AAAA,QACrB,UAAU,WAAW;AAAA,QACrB,SAAS;AAAA;AAAA,IACX;AAAA,IAEC,cACC,oBAAC,QAAK,eAAe,GAAG,OAAO,OAAO,OACnC,UACH,IAEA;AAAA,IAGF;AAAA,MAAC;AAAA;AAAA,QACC,SAAS;AAAA,QACT,eAAe;AAAA,QACf,OAAO;AAAA,QACP,SAAS,YAAY;AAAA,QACrB,UAAU,WAAW;AAAA,QACrB,SAAS;AAAA;AAAA,IACX;AAAA,KACF;AAEJ,CAAC;AAED,SAAS,aAAa,OAAiB,OAAwB;AAC7D,QAAM,EAAE,iBAAiB,OAAO,MAAM,MAAM,QAAQ,IAAI;AAExD,QAAM,cAAc,MAAM,WAAW;AACrC,QAAM,aAAa,YAAY,MAAM,IAAI;AACzC,QAAM,gBAAgB,YAAY,OAAO,IAAI,EAAE,OAAO;AAEtD,SAAO,WAAW,OAAO;AAAA,IACvB,WAAW;AAAA,MACT,YAAY;AAAA,MACZ,eAAe;AAAA,MACf,YAAY;AAAA,MACZ,gBAAgB;AAAA,MAEhB,cAAc,YAAY;AAAA,MAC1B,aAAa,YAAY;AAAA,MACzB,KAAK,YAAY;AAAA,MACjB,QAAQ,WAAW;AAAA,MACnB,UAAU,WAAW;AAAA,MACrB,mBAAmB,WAAW;AAAA,MAE9B,iBAAiB,mBAAmB,cAAc;AAAA,MAClD,aAAa,cAAc;AAAA,IAC7B;AAAA,IAEA,OAAO;AAAA,MACL,WAAW;AAAA,MAEX,YAAY,YAAY;AAAA,MACxB,UAAU,WAAW;AAAA,MACrB,YAAY,WAAW;AAAA,MAEvB,OAAO,SAAS,cAAc;AAAA,IAChC;AAAA,EACF,CAAC;AACH;","names":["BadgeRoot"]}
1
+ {"version":3,"sources":["../../../../src/components/atoms/badge/root.tsx"],"sourcesContent":["import { memo, useMemo } from \"react\";\r\nimport { StyleSheet, Text } from \"react-native\";\r\n\r\nimport type { AppTheme } from \"@impulse-ui-native/theme\";\r\nimport {\r\n useComponentsTokens,\r\n useStyleProps,\r\n useThemedStyles,\r\n} from \"@impulse-ui-native/theme\";\r\n\r\nimport type { BadgeProps, BadgeThemeProps } from \"../../../types\";\r\nimport { View } from \"../view\";\r\nimport { BadgeAddon } from \"./addon\";\r\n\r\nexport const BadgeRoot = memo(function BadgeRoot({\r\n backgroundColor,\r\n children,\r\n color,\r\n Prefix,\r\n PrefixIcon,\r\n onPressPrefix,\r\n onPressSuffix,\r\n size = \"medium\",\r\n style,\r\n Suffix,\r\n SuffixIcon,\r\n tone = \"primary\",\r\n variant = \"filled\",\r\n ...props\r\n}: BadgeProps) {\r\n const tokens = useComponentsTokens();\r\n\r\n const badgeTokens = tokens.badge;\r\n const sizeTokens = badgeTokens.sizes[size];\r\n\r\n const extractedStyleProps = useStyleProps(props);\r\n const styles = useThemedStyles(\r\n themedStyles,\r\n { backgroundColor, color, size, tone, variant },\r\n [backgroundColor, color, size, tone, variant],\r\n );\r\n\r\n const containerStyle = useMemo(\r\n () => [styles.container, extractedStyleProps, style],\r\n [extractedStyleProps, style, styles.container],\r\n );\r\n\r\n const affixColor =\r\n typeof styles.label.color === \"string\" ? styles.label.color : undefined;\r\n\r\n const isTextChild =\r\n typeof children === \"string\" || typeof children === \"number\";\r\n\r\n return (\r\n <View {...props} style={containerStyle}>\r\n <BadgeAddon\r\n Content={Prefix}\r\n IconComponent={PrefixIcon}\r\n color={affixColor}\r\n hitSlop={badgeTokens.addonHitSlop}\r\n iconSize={sizeTokens.iconSize}\r\n onPress={onPressPrefix}\r\n />\r\n\r\n {isTextChild ? (\r\n <Text numberOfLines={1} ellipsizeMode=\"tail\" style={styles.label}>\r\n {children}\r\n </Text>\r\n ) : (\r\n children\r\n )}\r\n\r\n <BadgeAddon\r\n Content={Suffix}\r\n IconComponent={SuffixIcon}\r\n color={affixColor}\r\n hitSlop={badgeTokens.addonHitSlop}\r\n iconSize={sizeTokens.iconSize}\r\n onPress={onPressSuffix}\r\n />\r\n </View>\r\n );\r\n});\r\n\r\nfunction themedStyles(theme: AppTheme, props: BadgeThemeProps) {\r\n const { backgroundColor, color, size, tone, variant } = props;\r\n\r\n const badgeTokens = theme.components.badge;\r\n const sizeTokens = badgeTokens.sizes[size];\r\n const variantTokens = badgeTokens.colors[tone][variant];\r\n\r\n return StyleSheet.create({\r\n container: {\r\n alignItems: \"center\",\r\n flexDirection: \"row\",\r\n flexShrink: 1,\r\n maxWidth: \"100%\",\r\n justifyContent: \"center\",\r\n\r\n borderRadius: badgeTokens.borderRadius,\r\n borderWidth: badgeTokens.borderWidth,\r\n gap: badgeTokens.gap,\r\n height: sizeTokens.height,\r\n minWidth: sizeTokens.minWidth,\r\n paddingHorizontal: sizeTokens.paddingHorizontal,\r\n\r\n backgroundColor: backgroundColor ?? variantTokens.backgroundColor,\r\n borderColor: variantTokens.borderColor,\r\n },\r\n\r\n label: {\r\n flexShrink: 1,\r\n minWidth: 0,\r\n textAlign: \"center\",\r\n\r\n fontFamily: badgeTokens.fontFamily,\r\n fontSize: sizeTokens.fontSize,\r\n lineHeight: sizeTokens.lineHeight,\r\n\r\n color: color ?? variantTokens.color,\r\n },\r\n });\r\n}\r\n"],"mappings":"AAsDI,SACE,KADF;AAtDJ,SAAS,MAAM,eAAe;AAC9B,SAAS,YAAY,YAAY;AAGjC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAGP,SAAS,YAAY;AACrB,SAAS,kBAAkB;AAEpB,MAAM,YAAY,KAAK,SAASA,WAAU;AAAA,EAC/C;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,OAAO;AAAA,EACP;AAAA,EACA;AAAA,EACA;AAAA,EACA,OAAO;AAAA,EACP,UAAU;AAAA,EACV,GAAG;AACL,GAAe;AACb,QAAM,SAAS,oBAAoB;AAEnC,QAAM,cAAc,OAAO;AAC3B,QAAM,aAAa,YAAY,MAAM,IAAI;AAEzC,QAAM,sBAAsB,cAAc,KAAK;AAC/C,QAAM,SAAS;AAAA,IACb;AAAA,IACA,EAAE,iBAAiB,OAAO,MAAM,MAAM,QAAQ;AAAA,IAC9C,CAAC,iBAAiB,OAAO,MAAM,MAAM,OAAO;AAAA,EAC9C;AAEA,QAAM,iBAAiB;AAAA,IACrB,MAAM,CAAC,OAAO,WAAW,qBAAqB,KAAK;AAAA,IACnD,CAAC,qBAAqB,OAAO,OAAO,SAAS;AAAA,EAC/C;AAEA,QAAM,aACJ,OAAO,OAAO,MAAM,UAAU,WAAW,OAAO,MAAM,QAAQ;AAEhE,QAAM,cACJ,OAAO,aAAa,YAAY,OAAO,aAAa;AAEtD,SACE,qBAAC,QAAM,GAAG,OAAO,OAAO,gBACtB;AAAA;AAAA,MAAC;AAAA;AAAA,QACC,SAAS;AAAA,QACT,eAAe;AAAA,QACf,OAAO;AAAA,QACP,SAAS,YAAY;AAAA,QACrB,UAAU,WAAW;AAAA,QACrB,SAAS;AAAA;AAAA,IACX;AAAA,IAEC,cACC,oBAAC,QAAK,eAAe,GAAG,eAAc,QAAO,OAAO,OAAO,OACxD,UACH,IAEA;AAAA,IAGF;AAAA,MAAC;AAAA;AAAA,QACC,SAAS;AAAA,QACT,eAAe;AAAA,QACf,OAAO;AAAA,QACP,SAAS,YAAY;AAAA,QACrB,UAAU,WAAW;AAAA,QACrB,SAAS;AAAA;AAAA,IACX;AAAA,KACF;AAEJ,CAAC;AAED,SAAS,aAAa,OAAiB,OAAwB;AAC7D,QAAM,EAAE,iBAAiB,OAAO,MAAM,MAAM,QAAQ,IAAI;AAExD,QAAM,cAAc,MAAM,WAAW;AACrC,QAAM,aAAa,YAAY,MAAM,IAAI;AACzC,QAAM,gBAAgB,YAAY,OAAO,IAAI,EAAE,OAAO;AAEtD,SAAO,WAAW,OAAO;AAAA,IACvB,WAAW;AAAA,MACT,YAAY;AAAA,MACZ,eAAe;AAAA,MACf,YAAY;AAAA,MACZ,UAAU;AAAA,MACV,gBAAgB;AAAA,MAEhB,cAAc,YAAY;AAAA,MAC1B,aAAa,YAAY;AAAA,MACzB,KAAK,YAAY;AAAA,MACjB,QAAQ,WAAW;AAAA,MACnB,UAAU,WAAW;AAAA,MACrB,mBAAmB,WAAW;AAAA,MAE9B,iBAAiB,mBAAmB,cAAc;AAAA,MAClD,aAAa,cAAc;AAAA,IAC7B;AAAA,IAEA,OAAO;AAAA,MACL,YAAY;AAAA,MACZ,UAAU;AAAA,MACV,WAAW;AAAA,MAEX,YAAY,YAAY;AAAA,MACxB,UAAU,WAAW;AAAA,MACrB,YAAY,WAAW;AAAA,MAEvB,OAAO,SAAS,cAAc;AAAA,IAChC;AAAA,EACF,CAAC;AACH;","names":["BadgeRoot"]}
@@ -3,6 +3,6 @@ import { TagProps } from '../../types/tag.types.mjs';
3
3
  import 'react-native';
4
4
  import '@impulse-ui-native/theme';
5
5
 
6
- declare const Tag: react.MemoExoticComponent<({ label, size, variant, tone, closable, disabled, onClose, onPress, }: TagProps) => react.JSX.Element>;
6
+ declare const Tag: react.MemoExoticComponent<({ label, style, size, variant, tone, closable, disabled, onClose, onPress, }: TagProps) => react.JSX.Element>;
7
7
 
8
8
  export { Tag };
@@ -1,5 +1,5 @@
1
1
  import { jsx, jsxs } from "react/jsx-runtime";
2
- import { memo } from "react";
2
+ import { memo, useMemo } from "react";
3
3
  import { StyleSheet, View } from "react-native";
4
4
  import { Icon } from "@impulse-ui-native/icon";
5
5
  import { XCircleIcon } from "@impulse-ui-native/icon/icons/x-circle";
@@ -12,6 +12,7 @@ import { Pressable } from "./pressable";
12
12
  import { Typography } from "./typography";
13
13
  const Tag = memo(function Tag2({
14
14
  label,
15
+ style,
15
16
  size = "medium",
16
17
  variant = "filled",
17
18
  tone = "primary",
@@ -32,10 +33,22 @@ const Tag = memo(function Tag2({
32
33
  },
33
34
  [size, variant, disabled, tone]
34
35
  );
36
+ const containerStyle = useMemo(
37
+ () => [styles.container, style],
38
+ [styles.container, style]
39
+ );
35
40
  const Container = onPress ? Pressable : View;
36
41
  const showClose = closable && !disabled && onClose;
37
- return /* @__PURE__ */ jsxs(Container, { onPress, disabled, style: styles.container, children: [
38
- /* @__PURE__ */ jsx(Typography.Caption, { style: styles.label, children: label }),
42
+ return /* @__PURE__ */ jsxs(Container, { onPress, disabled, style: containerStyle, children: [
43
+ /* @__PURE__ */ jsx(
44
+ Typography.Caption,
45
+ {
46
+ numberOfLines: 1,
47
+ ellipsizeMode: "tail",
48
+ style: styles.label,
49
+ children: label
50
+ }
51
+ ),
39
52
  showClose ? /* @__PURE__ */ jsx(Pressable, { onPress: onClose, hitSlop: tagTokens.closeHitSlop, children: /* @__PURE__ */ jsx(
40
53
  Icon,
41
54
  {
@@ -61,6 +74,8 @@ function themedStyles(theme, props) {
61
74
  alignItems: "center",
62
75
  justifyContent: "center",
63
76
  alignSelf: "flex-start",
77
+ flexShrink: 1,
78
+ maxWidth: "100%",
64
79
  height: sizeTokens.height,
65
80
  paddingHorizontal: sizeTokens.paddingHorizontal,
66
81
  minWidth: sizeTokens.minWidth,
@@ -71,6 +86,8 @@ function themedStyles(theme, props) {
71
86
  backgroundColor: appearanceTokens.backgroundColor
72
87
  },
73
88
  label: {
89
+ flexShrink: 1,
90
+ minWidth: 0,
74
91
  fontSize: sizeTokens.fontSize,
75
92
  color: appearanceTokens.color
76
93
  },
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/atoms/tag.tsx"],"sourcesContent":["import { memo } from \"react\";\r\nimport { StyleSheet, View } from \"react-native\";\r\n\r\nimport { Icon } from \"@impulse-ui-native/icon\";\r\nimport { XCircleIcon } from \"@impulse-ui-native/icon/icons/x-circle\";\r\nimport {\r\n AppTheme,\r\n getAvailabilityStateTokens,\r\n useComponentsTokens,\r\n useThemedStyles,\r\n} from \"@impulse-ui-native/theme\";\r\n\r\nimport { TagProps, TagThemeProps } from \"../../types\";\r\nimport { Pressable } from \"./pressable\";\r\nimport { Typography } from \"./typography\";\r\n\r\nexport const Tag = memo(function Tag({\r\n label,\r\n size = \"medium\",\r\n variant = \"filled\",\r\n tone = \"primary\",\r\n closable,\r\n disabled,\r\n onClose,\r\n onPress,\r\n}: TagProps) {\r\n const tokens = useComponentsTokens();\r\n\r\n const tagTokens = tokens.tag;\r\n\r\n const styles = useThemedStyles(\r\n themedStyles,\r\n {\r\n size,\r\n variant,\r\n disabled,\r\n tone,\r\n },\r\n [size, variant, disabled, tone],\r\n );\r\n\r\n const Container = onPress ? Pressable : View;\r\n\r\n const showClose = closable && !disabled && onClose;\r\n\r\n return (\r\n <Container onPress={onPress} disabled={disabled} style={styles.container}>\r\n <Typography.Caption style={styles.label}>{label}</Typography.Caption>\r\n\r\n {showClose ? (\r\n <Pressable onPress={onClose} hitSlop={tagTokens.closeHitSlop}>\r\n <Icon\r\n icon={XCircleIcon}\r\n size=\"small\"\r\n color={styles.icon.color}\r\n style={styles.icon}\r\n />\r\n </Pressable>\r\n ) : null}\r\n </Container>\r\n );\r\n});\r\n\r\nfunction themedStyles(theme: AppTheme, props: TagThemeProps) {\r\n const { size, variant, tone, disabled } = props;\r\n\r\n const tagTokens = theme.components.tag;\r\n const sizeTokens = tagTokens.sizes[size];\r\n const appearanceTokens = getAvailabilityStateTokens(\r\n tagTokens.colors[tone][variant],\r\n { disabled },\r\n );\r\n\r\n return StyleSheet.create({\r\n container: {\r\n flexDirection: \"row\",\r\n alignItems: \"center\",\r\n justifyContent: \"center\",\r\n alignSelf: \"flex-start\",\r\n\r\n height: sizeTokens.height,\r\n paddingHorizontal: sizeTokens.paddingHorizontal,\r\n minWidth: sizeTokens.minWidth,\r\n\r\n borderRadius: tagTokens.borderRadius,\r\n gap: tagTokens.gap,\r\n borderWidth: tagTokens.borderWidth,\r\n\r\n borderColor: appearanceTokens.borderColor,\r\n backgroundColor: appearanceTokens.backgroundColor,\r\n },\r\n\r\n label: {\r\n fontSize: sizeTokens.fontSize,\r\n color: appearanceTokens.color,\r\n },\r\n\r\n icon: {\r\n marginLeft: tagTokens.iconMarginLeft,\r\n color: appearanceTokens.color,\r\n },\r\n });\r\n}\r\n"],"mappings":"AA8CI,SACE,KADF;AA9CJ,SAAS,YAAY;AACrB,SAAS,YAAY,YAAY;AAEjC,SAAS,YAAY;AACrB,SAAS,mBAAmB;AAC5B;AAAA,EAEE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAGP,SAAS,iBAAiB;AAC1B,SAAS,kBAAkB;AAEpB,MAAM,MAAM,KAAK,SAASA,KAAI;AAAA,EACnC;AAAA,EACA,OAAO;AAAA,EACP,UAAU;AAAA,EACV,OAAO;AAAA,EACP;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAa;AACX,QAAM,SAAS,oBAAoB;AAEnC,QAAM,YAAY,OAAO;AAEzB,QAAM,SAAS;AAAA,IACb;AAAA,IACA;AAAA,MACE;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA,CAAC,MAAM,SAAS,UAAU,IAAI;AAAA,EAChC;AAEA,QAAM,YAAY,UAAU,YAAY;AAExC,QAAM,YAAY,YAAY,CAAC,YAAY;AAE3C,SACE,qBAAC,aAAU,SAAkB,UAAoB,OAAO,OAAO,WAC7D;AAAA,wBAAC,WAAW,SAAX,EAAmB,OAAO,OAAO,OAAQ,iBAAM;AAAA,IAE/C,YACC,oBAAC,aAAU,SAAS,SAAS,SAAS,UAAU,cAC9C;AAAA,MAAC;AAAA;AAAA,QACC,MAAM;AAAA,QACN,MAAK;AAAA,QACL,OAAO,OAAO,KAAK;AAAA,QACnB,OAAO,OAAO;AAAA;AAAA,IAChB,GACF,IACE;AAAA,KACN;AAEJ,CAAC;AAED,SAAS,aAAa,OAAiB,OAAsB;AAC3D,QAAM,EAAE,MAAM,SAAS,MAAM,SAAS,IAAI;AAE1C,QAAM,YAAY,MAAM,WAAW;AACnC,QAAM,aAAa,UAAU,MAAM,IAAI;AACvC,QAAM,mBAAmB;AAAA,IACvB,UAAU,OAAO,IAAI,EAAE,OAAO;AAAA,IAC9B,EAAE,SAAS;AAAA,EACb;AAEA,SAAO,WAAW,OAAO;AAAA,IACvB,WAAW;AAAA,MACT,eAAe;AAAA,MACf,YAAY;AAAA,MACZ,gBAAgB;AAAA,MAChB,WAAW;AAAA,MAEX,QAAQ,WAAW;AAAA,MACnB,mBAAmB,WAAW;AAAA,MAC9B,UAAU,WAAW;AAAA,MAErB,cAAc,UAAU;AAAA,MACxB,KAAK,UAAU;AAAA,MACf,aAAa,UAAU;AAAA,MAEvB,aAAa,iBAAiB;AAAA,MAC9B,iBAAiB,iBAAiB;AAAA,IACpC;AAAA,IAEA,OAAO;AAAA,MACL,UAAU,WAAW;AAAA,MACrB,OAAO,iBAAiB;AAAA,IAC1B;AAAA,IAEA,MAAM;AAAA,MACJ,YAAY,UAAU;AAAA,MACtB,OAAO,iBAAiB;AAAA,IAC1B;AAAA,EACF,CAAC;AACH;","names":["Tag"]}
1
+ {"version":3,"sources":["../../../src/components/atoms/tag.tsx"],"sourcesContent":["import { memo, useMemo } from \"react\";\r\nimport { StyleSheet, View } from \"react-native\";\r\n\r\nimport type { AppTheme } from \"@impulse-ui-native/theme\";\r\nimport { Icon } from \"@impulse-ui-native/icon\";\r\nimport { XCircleIcon } from \"@impulse-ui-native/icon/icons/x-circle\";\r\nimport {\r\n getAvailabilityStateTokens,\r\n useComponentsTokens,\r\n useThemedStyles,\r\n} from \"@impulse-ui-native/theme\";\r\n\r\nimport type { TagProps, TagThemeProps } from \"../../types\";\r\nimport { Pressable } from \"./pressable\";\r\nimport { Typography } from \"./typography\";\r\n\r\nexport const Tag = memo(function Tag({\r\n label,\r\n style,\r\n size = \"medium\",\r\n variant = \"filled\",\r\n tone = \"primary\",\r\n closable,\r\n disabled,\r\n onClose,\r\n onPress,\r\n}: TagProps) {\r\n const tokens = useComponentsTokens();\r\n\r\n const tagTokens = tokens.tag;\r\n\r\n const styles = useThemedStyles(\r\n themedStyles,\r\n {\r\n size,\r\n variant,\r\n disabled,\r\n tone,\r\n },\r\n [size, variant, disabled, tone],\r\n );\r\n\r\n const containerStyle = useMemo(\r\n () => [styles.container, style],\r\n [styles.container, style],\r\n );\r\n const Container = onPress ? Pressable : View;\r\n\r\n const showClose = closable && !disabled && onClose;\r\n\r\n return (\r\n <Container onPress={onPress} disabled={disabled} style={containerStyle}>\r\n <Typography.Caption\r\n numberOfLines={1}\r\n ellipsizeMode=\"tail\"\r\n style={styles.label}\r\n >\r\n {label}\r\n </Typography.Caption>\r\n\r\n {showClose ? (\r\n <Pressable onPress={onClose} hitSlop={tagTokens.closeHitSlop}>\r\n <Icon\r\n icon={XCircleIcon}\r\n size=\"small\"\r\n color={styles.icon.color}\r\n style={styles.icon}\r\n />\r\n </Pressable>\r\n ) : null}\r\n </Container>\r\n );\r\n});\r\n\r\nfunction themedStyles(theme: AppTheme, props: TagThemeProps) {\r\n const { size, variant, tone, disabled } = props;\r\n\r\n const tagTokens = theme.components.tag;\r\n const sizeTokens = tagTokens.sizes[size];\r\n const appearanceTokens = getAvailabilityStateTokens(\r\n tagTokens.colors[tone][variant],\r\n { disabled },\r\n );\r\n\r\n return StyleSheet.create({\r\n container: {\r\n flexDirection: \"row\",\r\n alignItems: \"center\",\r\n justifyContent: \"center\",\r\n alignSelf: \"flex-start\",\r\n flexShrink: 1,\r\n maxWidth: \"100%\",\r\n\r\n height: sizeTokens.height,\r\n paddingHorizontal: sizeTokens.paddingHorizontal,\r\n minWidth: sizeTokens.minWidth,\r\n\r\n borderRadius: tagTokens.borderRadius,\r\n gap: tagTokens.gap,\r\n borderWidth: tagTokens.borderWidth,\r\n\r\n borderColor: appearanceTokens.borderColor,\r\n backgroundColor: appearanceTokens.backgroundColor,\r\n },\r\n\r\n label: {\r\n flexShrink: 1,\r\n minWidth: 0,\r\n fontSize: sizeTokens.fontSize,\r\n color: appearanceTokens.color,\r\n },\r\n\r\n icon: {\r\n marginLeft: tagTokens.iconMarginLeft,\r\n color: appearanceTokens.color,\r\n },\r\n });\r\n}\r\n"],"mappings":"AAmDI,SACE,KADF;AAnDJ,SAAS,MAAM,eAAe;AAC9B,SAAS,YAAY,YAAY;AAGjC,SAAS,YAAY;AACrB,SAAS,mBAAmB;AAC5B;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAGP,SAAS,iBAAiB;AAC1B,SAAS,kBAAkB;AAEpB,MAAM,MAAM,KAAK,SAASA,KAAI;AAAA,EACnC;AAAA,EACA;AAAA,EACA,OAAO;AAAA,EACP,UAAU;AAAA,EACV,OAAO;AAAA,EACP;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAa;AACX,QAAM,SAAS,oBAAoB;AAEnC,QAAM,YAAY,OAAO;AAEzB,QAAM,SAAS;AAAA,IACb;AAAA,IACA;AAAA,MACE;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA,CAAC,MAAM,SAAS,UAAU,IAAI;AAAA,EAChC;AAEA,QAAM,iBAAiB;AAAA,IACrB,MAAM,CAAC,OAAO,WAAW,KAAK;AAAA,IAC9B,CAAC,OAAO,WAAW,KAAK;AAAA,EAC1B;AACA,QAAM,YAAY,UAAU,YAAY;AAExC,QAAM,YAAY,YAAY,CAAC,YAAY;AAE3C,SACE,qBAAC,aAAU,SAAkB,UAAoB,OAAO,gBACtD;AAAA;AAAA,MAAC,WAAW;AAAA,MAAX;AAAA,QACC,eAAe;AAAA,QACf,eAAc;AAAA,QACd,OAAO,OAAO;AAAA,QAEb;AAAA;AAAA,IACH;AAAA,IAEC,YACC,oBAAC,aAAU,SAAS,SAAS,SAAS,UAAU,cAC9C;AAAA,MAAC;AAAA;AAAA,QACC,MAAM;AAAA,QACN,MAAK;AAAA,QACL,OAAO,OAAO,KAAK;AAAA,QACnB,OAAO,OAAO;AAAA;AAAA,IAChB,GACF,IACE;AAAA,KACN;AAEJ,CAAC;AAED,SAAS,aAAa,OAAiB,OAAsB;AAC3D,QAAM,EAAE,MAAM,SAAS,MAAM,SAAS,IAAI;AAE1C,QAAM,YAAY,MAAM,WAAW;AACnC,QAAM,aAAa,UAAU,MAAM,IAAI;AACvC,QAAM,mBAAmB;AAAA,IACvB,UAAU,OAAO,IAAI,EAAE,OAAO;AAAA,IAC9B,EAAE,SAAS;AAAA,EACb;AAEA,SAAO,WAAW,OAAO;AAAA,IACvB,WAAW;AAAA,MACT,eAAe;AAAA,MACf,YAAY;AAAA,MACZ,gBAAgB;AAAA,MAChB,WAAW;AAAA,MACX,YAAY;AAAA,MACZ,UAAU;AAAA,MAEV,QAAQ,WAAW;AAAA,MACnB,mBAAmB,WAAW;AAAA,MAC9B,UAAU,WAAW;AAAA,MAErB,cAAc,UAAU;AAAA,MACxB,KAAK,UAAU;AAAA,MACf,aAAa,UAAU;AAAA,MAEvB,aAAa,iBAAiB;AAAA,MAC9B,iBAAiB,iBAAiB;AAAA,IACpC;AAAA,IAEA,OAAO;AAAA,MACL,YAAY;AAAA,MACZ,UAAU;AAAA,MACV,UAAU,WAAW;AAAA,MACrB,OAAO,iBAAiB;AAAA,IAC1B;AAAA,IAEA,MAAM;AAAA,MACJ,YAAY,UAAU;AAAA,MACtB,OAAO,iBAAiB;AAAA,IAC1B;AAAA,EACF,CAAC;AACH;","names":["Tag"]}
@@ -0,0 +1,20 @@
1
+ import { BadgeProps } from './badge.types.mjs';
2
+ import 'react';
3
+ import 'react-native';
4
+ import '@impulse-ui-native/theme';
5
+ import './control-components.types.mjs';
6
+ import '@impulse-ui-native/icon/types';
7
+ import './button.types.mjs';
8
+ import './view.types.mjs';
9
+ import './spinner.types.mjs';
10
+
11
+ interface BadgeAddonProps {
12
+ color: string | undefined;
13
+ Content: BadgeProps["Prefix"];
14
+ hitSlop: number;
15
+ iconSize: number;
16
+ IconComponent: BadgeProps["PrefixIcon"];
17
+ onPress: BadgeProps["onPressPrefix"];
18
+ }
19
+
20
+ export type { BadgeAddonProps };
@@ -0,0 +1 @@
1
+ //# sourceMappingURL=badge-addon.types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -1,7 +1,7 @@
1
1
  import { TextProps as TextProps$1 } from 'react-native';
2
- import { TypographyProps, FlexProps, ColorProps } from '@impulse-ui-native/theme';
2
+ import { TypographyProps, FlexProps, ColorProps, SpacingProps } from '@impulse-ui-native/theme';
3
3
 
4
- interface TextProps extends TextProps$1, TypographyProps, FlexProps, ColorProps {
4
+ interface TextProps extends TextProps$1, TypographyProps, FlexProps, ColorProps, SpacingProps {
5
5
  numeric?: boolean;
6
6
  }
7
7
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@impulse-ui-native/primitives",
3
- "version": "16.0.0",
3
+ "version": "17.1.0",
4
4
  "description": "Foundational UI primitives for building ImpulseUI Native components.",
5
5
  "keywords": [
6
6
  "react-native",
@@ -28,9 +28,9 @@
28
28
  ],
29
29
  "sideEffects": false,
30
30
  "dependencies": {
31
- "@impulse-ui-native/theme": "16.0.0",
32
- "@impulse-ui-native/icon": "16.0.0",
33
- "@impulse-ui-native/core": "16.0.0"
31
+ "@impulse-ui-native/theme": "17.1.0",
32
+ "@impulse-ui-native/icon": "17.1.0",
33
+ "@impulse-ui-native/core": "17.1.0"
34
34
  },
35
35
  "devDependencies": {
36
36
  "@impulse-ui-native/eslint-config": "1.0.0",