@idealyst/components 1.2.56 → 1.2.58

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@idealyst/components",
3
- "version": "1.2.56",
3
+ "version": "1.2.58",
4
4
  "description": "Shared component library for React and React Native",
5
5
  "documentation": "https://github.com/IdealystIO/idealyst-framework/tree/main/packages/components#readme",
6
6
  "readme": "README.md",
@@ -56,7 +56,7 @@
56
56
  "publish:npm": "npm publish"
57
57
  },
58
58
  "peerDependencies": {
59
- "@idealyst/theme": "^1.2.56",
59
+ "@idealyst/theme": "^1.2.58",
60
60
  "@mdi/js": ">=7.0.0",
61
61
  "@mdi/react": ">=1.0.0",
62
62
  "@react-native-vector-icons/common": ">=12.0.0",
@@ -107,7 +107,7 @@
107
107
  },
108
108
  "devDependencies": {
109
109
  "@idealyst/blur": "^1.2.40",
110
- "@idealyst/theme": "^1.2.56",
110
+ "@idealyst/theme": "^1.2.58",
111
111
  "@idealyst/tooling": "^1.2.30",
112
112
  "@mdi/react": "^1.6.1",
113
113
  "@types/react": "^19.1.0",
@@ -6,6 +6,7 @@ import { IconSvg } from '../Icon/IconSvg/IconSvg.web';
6
6
  import { isIconName } from '../Icon/icon-resolver';
7
7
  import useMergeRefs from '../hooks/useMergeRefs';
8
8
  import type { IdealystElement } from '../utils/refTypes';
9
+ import { flattenStyle } from '../utils/flattenStyle';
9
10
 
10
11
  // Default icons for each intent
11
12
  const defaultIcons: Record<string, React.ComponentType<any>> = {
@@ -42,7 +43,7 @@ const Alert = forwardRef<IdealystElement, AlertProps>(({
42
43
 
43
44
  // Compute dynamic styles with intent, type, and size
44
45
  const dynamicProps = { intent, type, size };
45
- const containerProps = getWebProps([(alertStyles.container as any)(dynamicProps), style as any]);
46
+ const containerProps = getWebProps([(alertStyles.container as any)(dynamicProps), flattenStyle(style)]);
46
47
  const iconContainerProps = getWebProps([(alertStyles.iconContainer as any)(dynamicProps)]);
47
48
  const contentProps = getWebProps([(alertStyles.content as any)(dynamicProps)]);
48
49
  const titleProps = getWebProps([(alertStyles.title as any)(dynamicProps)]);
@@ -5,6 +5,7 @@ import { avatarStyles } from './Avatar.styles';
5
5
  import useMergeRefs from '../hooks/useMergeRefs';
6
6
  import { getWebAriaProps } from '../utils/accessibility';
7
7
  import type { IdealystElement } from '../utils/refTypes';
8
+ import { flattenStyle } from '../utils/flattenStyle';
8
9
 
9
10
  /**
10
11
  * User or entity representation with image support and fallback initials.
@@ -44,7 +45,7 @@ const Avatar = forwardRef<IdealystElement, AvatarProps>(({
44
45
  shape,
45
46
  });
46
47
 
47
- const avatarStyleArray = [(avatarStyles.avatar as any)({ color }), style];
48
+ const avatarStyleArray = [(avatarStyles.avatar as any)({ color }), flattenStyle(style)];
48
49
  const avatarProps = getWebProps(avatarStyleArray);
49
50
 
50
51
  // Generate fallback text styles with proper theming and size
@@ -5,6 +5,7 @@ import { badgeStyles } from './Badge.styles';
5
5
  import { IconSvg } from '../Icon/IconSvg/IconSvg.web';
6
6
  import useMergeRefs from '../hooks/useMergeRefs';
7
7
  import type { IdealystElement } from '../utils/refTypes';
8
+ import { flattenStyle } from '../utils/flattenStyle';
8
9
 
9
10
  /**
10
11
  * Small status indicator for counts, labels, or notifications.
@@ -67,11 +68,14 @@ const Badge = forwardRef<IdealystElement, BadgeProps>((props, ref) => {
67
68
 
68
69
  const mergedRef = useMergeRefs(ref, badgeProps.ref);
69
70
 
71
+ // Flatten style array for web compatibility
72
+ const flatStyle = flattenStyle(style);
73
+
70
74
  if (type === 'dot') {
71
75
  return (
72
76
  <span
73
77
  {...badgeProps}
74
- style={style as React.CSSProperties}
78
+ style={flatStyle}
75
79
  ref={mergedRef}
76
80
  id={id}
77
81
  data-testid={testID}
@@ -86,7 +90,7 @@ const Badge = forwardRef<IdealystElement, BadgeProps>((props, ref) => {
86
90
  return (
87
91
  <span
88
92
  {...badgeProps}
89
- style={style as React.CSSProperties}
93
+ style={flatStyle}
90
94
  ref={mergedRef}
91
95
  id={id}
92
96
  data-testid={testID}
@@ -6,6 +6,7 @@ import { IconSvg } from '../Icon/IconSvg/IconSvg.web';
6
6
  import useMergeRefs from '../hooks/useMergeRefs';
7
7
  import { getWebInteractiveAriaProps, generateAccessibilityId } from '../utils/accessibility';
8
8
  import type { IdealystElement } from '../utils/refTypes';
9
+ import { flattenStyle } from '../utils/flattenStyle';
9
10
 
10
11
  /**
11
12
  * Interactive button component with multiple visual variants, sizes, and icon support.
@@ -117,7 +118,7 @@ const Button = forwardRef<IdealystElement, ButtonProps>((props, ref) => {
117
118
  const buttonStyleArray = [
118
119
  (buttonStyles.button as any)(dynamicProps),
119
120
  (buttonStyles.text as any)(dynamicProps),
120
- style as any,
121
+ flattenStyle(style),
121
122
  ];
122
123
 
123
124
  // Use getWebProps to generate className and ref for web
@@ -6,6 +6,7 @@ import useMergeRefs from '../hooks/useMergeRefs';
6
6
  import { useWebLayout } from '../hooks/useWebLayout';
7
7
  import { getWebInteractiveAriaProps } from '../utils/accessibility';
8
8
  import type { IdealystElement } from '../utils/refTypes';
9
+ import { flattenStyle } from '../utils/flattenStyle';
9
10
 
10
11
  // Track if we've logged the onClick deprecation warning (log once per session)
11
12
  let hasLoggedOnClickWarning = false;
@@ -108,7 +109,7 @@ const Card = forwardRef<IdealystElement, CardProps>(({
108
109
  const cardStyle = (cardStyles.card as any)({});
109
110
 
110
111
  // Generate web props
111
- const webProps = getWebProps([cardStyle, style as any]);
112
+ const webProps = getWebProps([cardStyle, flattenStyle(style)]);
112
113
 
113
114
  const mergedRef = useMergeRefs(ref, webProps.ref, layoutRef);
114
115
 
@@ -6,6 +6,7 @@ import { IconSvg } from '../Icon/IconSvg/IconSvg.web';
6
6
  import useMergeRefs from '../hooks/useMergeRefs';
7
7
  import { getWebSelectionAriaProps, generateAccessibilityId, combineIds } from '../utils/accessibility';
8
8
  import type { IdealystElement } from '../utils/refTypes';
9
+ import { flattenStyle } from '../utils/flattenStyle';
9
10
 
10
11
  /**
11
12
  * Checkbox input for boolean selection with support for indeterminate state.
@@ -132,7 +133,7 @@ const Checkbox = forwardRef<IdealystElement, CheckboxProps>(({
132
133
  });
133
134
 
134
135
  // Create style arrays - call as functions with required props for theme reactivity
135
- const wrapperStyleArray = [(checkboxStyles.wrapper as any)({}), style as any];
136
+ const wrapperStyleArray = [(checkboxStyles.wrapper as any)({}), flattenStyle(style)];
136
137
  const containerStyleArray = [(checkboxStyles.container as any)({})];
137
138
  const checkboxStyleArray = [(checkboxStyles.checkbox as any)({ intent, checked: internalChecked, disabled, type: variant })];
138
139
  const labelStyleArray = [(checkboxStyles.label as any)({ disabled })];
@@ -6,6 +6,7 @@ import { IconSvg } from '../Icon/IconSvg/IconSvg.web';
6
6
  import { isIconName } from '../Icon/icon-resolver';
7
7
  import useMergeRefs from '../hooks/useMergeRefs';
8
8
  import type { IdealystElement } from '../utils/refTypes';
9
+ import { flattenStyle } from '../utils/flattenStyle';
9
10
 
10
11
  // Track if we've logged the onClick deprecation warning (log once per session)
11
12
  let hasLoggedOnClickWarning = false;
@@ -55,7 +56,7 @@ const Chip = forwardRef<IdealystElement, ChipProps>(({
55
56
  const isSelected = selectable ? selected : false;
56
57
 
57
58
  // Compute dynamic styles
58
- const containerProps = getWebProps([(chipStyles.container as any)({ size, intent, type, selected: isSelected, disabled }), style as any]);
59
+ const containerProps = getWebProps([(chipStyles.container as any)({ size, intent, type, selected: isSelected, disabled }), flattenStyle(style)]);
59
60
  const labelProps = getWebProps([(chipStyles.label as any)({ size, intent, type, selected: isSelected })]);
60
61
  const iconProps = getWebProps([(chipStyles.icon as any)({ size, intent, type, selected: isSelected })]);
61
62
  const deleteButtonProps = getWebProps([(chipStyles.deleteButton as any)({ size })]);
@@ -6,6 +6,7 @@ import { dialogStyles } from './Dialog.styles';
6
6
  import Icon from '../Icon';
7
7
  import useMergeRefs from '../hooks/useMergeRefs';
8
8
  import { getWebInteractiveAriaProps, generateAccessibilityId } from '../utils/accessibility';
9
+ import { flattenStyle } from '../utils/flattenStyle';
9
10
 
10
11
  /**
11
12
  * Modal overlay dialog for focused user interactions and confirmations.
@@ -145,7 +146,7 @@ const Dialog = forwardRef<HTMLDivElement, DialogProps>(({
145
146
  ]);
146
147
  const containerProps = getWebProps([
147
148
  (dialogStyles.container as any)({}),
148
- style as any,
149
+ flattenStyle(style),
149
150
  height !== undefined ? { height, display: 'flex', flexDirection: 'column' } : null,
150
151
  isVisible
151
152
  ? { opacity: 1, transform: 'scale(1) translateY(0px)' }
@@ -8,6 +8,7 @@ import useMergeRefs from '../hooks/useMergeRefs';
8
8
  import { getColorFromString, Intent, Color, Text } from '@idealyst/theme';
9
9
  import { IconRegistry } from './IconRegistry';
10
10
  import type { IdealystElement } from '../utils/refTypes';
11
+ import { flattenStyle } from '../utils/flattenStyle';
11
12
 
12
13
  /**
13
14
  * Vector icon display from the Material Design Icons library.
@@ -61,7 +62,7 @@ const Icon = forwardRef<IdealystElement, IconProps>((props, ref) => {
61
62
 
62
63
  // Use getWebProps for className generation but override with computed values
63
64
  const iconStyle = (iconStyles.icon as any)({ intent, color, textColor, size });
64
- const iconProps = getWebProps([iconStyle, style]);
65
+ const iconProps = getWebProps([iconStyle, flattenStyle(style)]);
65
66
 
66
67
  const mergedRef = useMergeRefs(ref, iconProps.ref);
67
68
 
@@ -4,6 +4,7 @@ import { PressableProps } from './types';
4
4
  import { pressableStyles } from './Pressable.styles';
5
5
  import useMergeRefs from '../hooks/useMergeRefs';
6
6
  import type { IdealystElement } from '../utils/refTypes';
7
+ import { flattenStyle } from '../utils/flattenStyle';
7
8
 
8
9
  const Pressable = forwardRef<IdealystElement, PressableProps>(({
9
10
  children,
@@ -62,7 +63,7 @@ const Pressable = forwardRef<IdealystElement, PressableProps>(({
62
63
  paddingHorizontal,
63
64
  });
64
65
 
65
- const webProps = getWebProps([(pressableStyles.pressable as any)({}), style as any]);
66
+ const webProps = getWebProps([(pressableStyles.pressable as any)({}), flattenStyle(style)]);
66
67
 
67
68
  const baseStyle: React.CSSProperties = {
68
69
  cursor: disabled ? 'default' : 'pointer',
@@ -5,6 +5,7 @@ import { screenStyles } from './Screen.styles';
5
5
  import useMergeRefs from '../hooks/useMergeRefs';
6
6
  import { useWebLayout } from '../hooks/useWebLayout';
7
7
  import type { IdealystElement } from '../utils/refTypes';
8
+ import { flattenStyle } from '../utils/flattenStyle';
8
9
 
9
10
  /**
10
11
  * Full-screen container for page layouts with background color and safe area support.
@@ -46,7 +47,7 @@ const Screen = forwardRef<IdealystElement, ScreenProps>(({
46
47
  });
47
48
 
48
49
  // Call style as function to get theme-reactive styles
49
- const webProps = getWebProps([(screenStyles.screen as any)({}), style as any]);
50
+ const webProps = getWebProps([(screenStyles.screen as any)({}), flattenStyle(style)]);
50
51
 
51
52
  const mergedRef = useMergeRefs(ref, webProps.ref, layoutRef);
52
53
 
@@ -7,6 +7,7 @@ import { isIconName } from '../Icon/icon-resolver';
7
7
  import useMergeRefs from '../hooks/useMergeRefs';
8
8
  import { getWebSelectionAriaProps, generateAccessibilityId } from '../utils/accessibility';
9
9
  import type { IdealystElement } from '../utils/refTypes';
10
+ import { flattenStyle } from '../utils/flattenStyle';
10
11
 
11
12
  /**
12
13
  * Toggle switch for binary on/off states with optional label and icons.
@@ -134,7 +135,7 @@ const Switch = forwardRef<IdealystElement, SwitchProps>(({
134
135
  <button
135
136
  {...computedButtonProps}
136
137
  {...ariaProps}
137
- style={style as any}
138
+ style={flattenStyle(style)}
138
139
  ref={mergedButtonRef}
139
140
  onClick={handleClick}
140
141
  disabled={disabled}
@@ -4,6 +4,7 @@ import { TextProps } from './types';
4
4
  import { textStyles } from './Text.styles';
5
5
  import useMergeRefs from '../hooks/useMergeRefs';
6
6
  import type { IdealystElement } from '../utils/refTypes';
7
+ import { flattenStyle } from '../utils/flattenStyle';
7
8
 
8
9
  /**
9
10
  * Typography component for displaying text with predefined styles and semantic variants.
@@ -38,7 +39,7 @@ const Text = forwardRef<IdealystElement, TextProps>(({
38
39
  // Create the style array - pass all style-affecting props to dynamic style function
39
40
  const textStyleArray = [
40
41
  (textStyles.text as any)({ color, typography, weight, align }),
41
- style,
42
+ flattenStyle(style),
42
43
  ];
43
44
 
44
45
  // Use getWebProps to generate className and ref for web
@@ -8,6 +8,7 @@ import { textInputStyles } from './TextInput.styles';
8
8
  import { TextInputProps } from './types';
9
9
  import { getWebFormAriaProps } from '../utils/accessibility';
10
10
  import type { IdealystElement } from '../utils/refTypes';
11
+ import { flattenStyle } from '../utils/flattenStyle';
11
12
 
12
13
  /**
13
14
  * Single-line text input field with support for icons, password visibility toggle, and validation states.
@@ -137,7 +138,7 @@ const TextInput = React.forwardRef<IdealystElement, TextInputProps>(({
137
138
 
138
139
  // Get web props for all styled elements (all styles are dynamic functions)
139
140
  const dynamicContainerStyle = (textInputStyles.container as any)({ type, focused: isFocused, hasError, disabled });
140
- const {ref: containerStyleRef, ...containerProps} = getWebProps([dynamicContainerStyle, style]);
141
+ const {ref: containerStyleRef, ...containerProps} = getWebProps([dynamicContainerStyle, flattenStyle(style)]);
141
142
  const leftIconContainerProps = getWebProps([(textInputStyles.leftIconContainer as any)({})]);
142
143
  const rightIconContainerProps = getWebProps([(textInputStyles.rightIconContainer as any)({})]);
143
144
  const passwordToggleProps = getWebProps([(textInputStyles.passwordToggle as any)({})]);
@@ -5,6 +5,7 @@ import { viewStyles } from './View.styles';
5
5
  import useMergeRefs from '../hooks/useMergeRefs';
6
6
  import { useWebLayout } from '../hooks/useWebLayout';
7
7
  import type { IdealystElement } from '../utils/refTypes';
8
+ import { flattenStyle } from '../utils/flattenStyle';
8
9
 
9
10
  /**
10
11
  * Fundamental layout container with background, border, and spacing options.
@@ -61,12 +62,15 @@ const View = forwardRef<IdealystElement, ViewProps>(({
61
62
 
62
63
  const mergedRef = useMergeRefs(ref, webProps.ref, layoutRef);
63
64
 
65
+ // Flatten style array into a single object (style can be an array on RN)
66
+ const flatStyle = flattenStyle(style);
67
+
64
68
  // When scrollable, render a wrapper + content structure
65
69
  // Wrapper: sizing and margin (positioning in parent layout)
66
70
  // Content: absolutely positioned with overflow:auto, visual styles (padding, background, border)
67
71
  if (scrollable) {
68
72
  // Split user styles: layout/sizing to wrapper, visual styles to content
69
- const styleObj = (style as React.CSSProperties) || {};
73
+ const styleObj = flatStyle;
70
74
  const {
71
75
  // Sizing - goes to wrapper
72
76
  width,
@@ -154,7 +158,7 @@ const View = forwardRef<IdealystElement, ViewProps>(({
154
158
  return (
155
159
  <div
156
160
  {...webProps}
157
- style={style as any}
161
+ style={flatStyle}
158
162
  ref={mergedRef}
159
163
  id={id}
160
164
  data-testid={testID}
@@ -0,0 +1,26 @@
1
+ import type { StyleProp } from 'react-native';
2
+
3
+ /**
4
+ * Flattens a style prop (which can be a single style, an array of styles,
5
+ * or nested arrays) into a single style object.
6
+ *
7
+ * This is needed on web because React Native's StyleProp allows arrays,
8
+ * but web components need a flat object for destructuring and spreading.
9
+ */
10
+ export function flattenStyle<T extends object>(
11
+ style: StyleProp<T> | React.CSSProperties | undefined
12
+ ): React.CSSProperties {
13
+ if (!style) {
14
+ return {};
15
+ }
16
+
17
+ if (Array.isArray(style)) {
18
+ // Recursively flatten and merge all styles in the array
19
+ return style.reduce<React.CSSProperties>((acc, s) => {
20
+ return { ...acc, ...flattenStyle(s as StyleProp<T>) };
21
+ }, {});
22
+ }
23
+
24
+ // Single style object
25
+ return style as React.CSSProperties;
26
+ }