tamagui 1.5.19 → 1.5.21

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.
@@ -7,16 +7,28 @@ import {
7
7
  mergeProps,
8
8
  spacedChildren,
9
9
  styled,
10
- useMediaPropsActive
10
+ useMediaPropsActive,
11
+ withStaticProperties
11
12
  } from "@tamagui/core";
13
+ import { createContextScope } from "@tamagui/create-context";
12
14
  import { ThemeableStack } from "@tamagui/stacks";
13
- import React, { Children, forwardRef, isValidElement } from "react";
15
+ import { useControllableState } from "@tamagui/use-controllable-state";
16
+ import React, { Children, cloneElement, forwardRef, isValidElement } from "react";
14
17
  import { ScrollView } from "react-native";
18
+ import { useIndex, useIndexedChildren } from "reforest";
19
+ const GROUP_NAME = "Group";
20
+ const [createGroupContext, createGroupScope] = createContextScope(GROUP_NAME);
21
+ const [GroupProvider, useGroupContext] = createGroupContext(GROUP_NAME);
15
22
  const GroupFrame = styled(ThemeableStack, {
16
23
  name: "GroupFrame",
17
- backgroundColor: "$background",
18
- y: 0,
19
24
  variants: {
25
+ unstyled: {
26
+ false: {
27
+ y: 0,
28
+ backgroundColor: "$background",
29
+ size: "$true"
30
+ }
31
+ },
20
32
  size: (val, { tokens }) => {
21
33
  const borderRadius = tokens.radius[val] ?? val ?? tokens.radius["$true"];
22
34
  return {
@@ -25,102 +37,167 @@ const GroupFrame = styled(ThemeableStack, {
25
37
  }
26
38
  },
27
39
  defaultVariants: {
28
- size: "$true"
40
+ unstyled: false
29
41
  }
30
42
  });
31
43
  function createGroup(verticalDefault) {
32
- return forwardRef((props, ref) => {
33
- const activeProps = useMediaPropsActive(props);
34
- const {
35
- children: childrenProp,
36
- space,
37
- size = "$true",
38
- spaceDirection,
39
- separator,
40
- scrollable,
41
- vertical = verticalDefault,
42
- disabled: disabledProp,
43
- disablePassBorderRadius: disablePassBorderRadiusProp,
44
- borderRadius,
45
- ...restProps
46
- } = getExpandedShorthands(activeProps);
47
- const radius = borderRadius ?? (size ? getVariableValue(getTokens().radius[size]) - 1 : void 0);
48
- const hasRadius = radius !== void 0;
49
- const disablePassBorderRadius = disablePassBorderRadiusProp ?? !hasRadius;
50
- const childrens = Children.toArray(childrenProp);
51
- const children = childrens.map((child, i) => {
52
- if (!isValidElement(child))
53
- return child;
54
- const disabled = child.props.disabled ?? disabledProp;
55
- const isFirst = i === 0;
56
- const isLast = i === childrens.length - 1;
57
- const radiusStyles = disablePassBorderRadius ? null : {
58
- borderTopLeftRadius: 0,
59
- borderTopRightRadius: 0,
60
- borderBottomLeftRadius: 0,
61
- borderBottomRightRadius: 0,
62
- ...hasRadius && {
63
- ...isFirst && !vertical && {
64
- borderTopLeftRadius: radius,
65
- borderBottomLeftRadius: radius
66
- },
67
- ...isFirst && vertical && {
68
- borderTopLeftRadius: radius,
69
- borderTopRightRadius: radius
70
- },
71
- ...isLast && !vertical && {
72
- borderTopRightRadius: radius,
73
- borderBottomRightRadius: radius
74
- },
75
- ...isLast && vertical && {
76
- borderBottomLeftRadius: radius,
77
- borderBottomRightRadius: radius
78
- }
44
+ return withStaticProperties(
45
+ forwardRef((props, ref) => {
46
+ const activeProps = useMediaPropsActive(props);
47
+ const {
48
+ __scopeGroup,
49
+ children: childrenProp,
50
+ space,
51
+ size = "$true",
52
+ spaceDirection,
53
+ separator,
54
+ scrollable,
55
+ axis = verticalDefault ? "vertical" : "horizontal",
56
+ disabled: disabledProp,
57
+ disablePassBorderRadius: disablePassBorderRadiusProp,
58
+ borderRadius,
59
+ forceUseItem,
60
+ ...restProps
61
+ } = getExpandedShorthands(activeProps);
62
+ const vertical = axis === "vertical";
63
+ const [itemChildrenCount, setItemChildrenCount] = useControllableState({
64
+ defaultProp: forceUseItem ? 1 : 0
65
+ });
66
+ const isUsingItems = itemChildrenCount > 0;
67
+ const radius = borderRadius ?? (size ? getVariableValue(getTokens().radius[size]) - 1 : void 0);
68
+ const hasRadius = radius !== void 0;
69
+ const disablePassBorderRadius = disablePassBorderRadiusProp ?? !hasRadius;
70
+ const childrenArray = Children.toArray(childrenProp);
71
+ const children = isUsingItems ? childrenProp : childrenArray.map((child, i) => {
72
+ if (!isValidElement(child)) {
73
+ return child;
79
74
  }
80
- };
81
- const props2 = {
82
- disabled,
83
- ...isTamaguiElement(child) ? radiusStyles : { style: radiusStyles }
84
- };
85
- return cloneElementWithPropOrder(child, props2);
75
+ const disabled = child.props.disabled ?? disabledProp;
76
+ const isFirst = i === 0;
77
+ const isLast = i === childrenArray.length - 1;
78
+ const radiusStyles = disablePassBorderRadius ? null : getBorderRadius({ isFirst, isLast, radius, vertical });
79
+ const props2 = {
80
+ disabled,
81
+ ...isTamaguiElement(child) ? radiusStyles : { style: radiusStyles }
82
+ };
83
+ return cloneElementWithPropOrder(child, props2);
84
+ });
85
+ const indexedChildren = useIndexedChildren(
86
+ spacedChildren({
87
+ direction: spaceDirection,
88
+ separator,
89
+ space,
90
+ children
91
+ })
92
+ );
93
+ const onItemMount = React.useCallback(
94
+ () => setItemChildrenCount((prev) => prev + 1),
95
+ []
96
+ );
97
+ const onItemUnmount = React.useCallback(
98
+ () => setItemChildrenCount((prev) => prev - 1),
99
+ []
100
+ );
101
+ return <GroupProvider
102
+ disablePassBorderRadius={disablePassBorderRadius}
103
+ vertical={axis === "vertical"}
104
+ radius={radius}
105
+ disabled={disabledProp}
106
+ onItemMount={onItemMount}
107
+ onItemUnmount={onItemUnmount}
108
+ scope={__scopeGroup}
109
+ ><GroupFrame
110
+ ref={ref}
111
+ size={size}
112
+ flexDirection={axis === "horizontal" ? "row" : "column"}
113
+ borderRadius={borderRadius}
114
+ {...restProps}
115
+ >{wrapScroll({ ...activeProps, axis }, indexedChildren)}</GroupFrame></GroupProvider>;
116
+ }),
117
+ {
118
+ Item: GroupItem
119
+ }
120
+ );
121
+ }
122
+ const GroupItem = (props) => {
123
+ const { __scopeGroup, children } = props;
124
+ const treeIndex = useIndex();
125
+ const context = useGroupContext("GroupItem", __scopeGroup);
126
+ React.useEffect(() => {
127
+ context.onItemMount();
128
+ return () => {
129
+ context.onItemUnmount();
130
+ };
131
+ }, []);
132
+ if (!isValidElement(children)) {
133
+ return children;
134
+ }
135
+ const disabled = children.props.disabled ?? context.disabled;
136
+ if (!treeIndex) {
137
+ throw Error("<Group.Item/> should only be used within a <Group/>");
138
+ }
139
+ const isFirst = treeIndex.index === 0;
140
+ const isLast = treeIndex.index === treeIndex.maxIndex;
141
+ let propsToPass = {
142
+ disabled
143
+ };
144
+ if (!context.disablePassBorderRadius) {
145
+ const radiusStyles = getBorderRadius({
146
+ radius: context.radius,
147
+ isFirst,
148
+ isLast,
149
+ vertical: context.vertical
86
150
  });
87
- return <GroupFrame
88
- ref={ref}
89
- size={size}
90
- flexDirection={!vertical ? "row" : "column"}
91
- borderRadius={borderRadius}
92
- {...restProps}
93
- >{wrapScroll(
94
- activeProps,
95
- spacedChildren({
96
- direction: spaceDirection,
97
- separator,
98
- space,
99
- children
100
- })
101
- )}</GroupFrame>;
151
+ if (isTamaguiElement(children)) {
152
+ propsToPass = { ...propsToPass, ...radiusStyles };
153
+ } else {
154
+ propsToPass.style = radiusStyles;
155
+ }
156
+ }
157
+ return cloneElement(children, {
158
+ ...propsToPass,
159
+ // @ts-ignore
160
+ style: {
161
+ ...children.props?.["style"],
162
+ ...propsToPass.style
163
+ }
102
164
  });
103
- }
104
- const YGroup = createGroup(true);
165
+ };
166
+ const Group = createGroup(true);
167
+ const YGroup = Group;
105
168
  const XGroup = createGroup(false);
106
- const wrapScroll = ({ scrollable, vertical, showScrollIndicator = false }, children) => {
169
+ const wrapScroll = ({ scrollable, axis, showScrollIndicator = false }, children) => {
107
170
  if (scrollable)
108
171
  return <ScrollView
109
- {...vertical && {
172
+ {...axis === "vertical" && {
110
173
  showsVerticalScrollIndicator: showScrollIndicator
111
174
  }}
112
- {...!vertical && {
175
+ {...axis === "horizontal" && {
113
176
  horizontal: true,
114
177
  showsHorizontalScrollIndicator: showScrollIndicator
115
178
  }}
116
179
  >{children}</ScrollView>;
117
180
  return children;
118
181
  };
182
+ const getBorderRadius = ({
183
+ isFirst,
184
+ isLast,
185
+ radius,
186
+ vertical
187
+ }) => {
188
+ return {
189
+ borderTopLeftRadius: isFirst ? radius : 0,
190
+ borderTopRightRadius: vertical && isFirst || !vertical && isLast ? radius : 0,
191
+ borderBottomLeftRadius: vertical && isLast || !vertical && isFirst ? radius : 0,
192
+ borderBottomRightRadius: isLast ? radius : 0
193
+ };
194
+ };
119
195
  const cloneElementWithPropOrder = (child, props) => {
120
196
  const next = mergeProps(child.props, props, false, getConfig().shorthands)[0];
121
197
  return React.cloneElement({ ...child, props: null }, next);
122
198
  };
123
199
  export {
200
+ Group,
124
201
  GroupFrame,
125
202
  XGroup,
126
203
  YGroup
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/views/Group.tsx"],
4
- "sourcesContent": ["import {\n GetProps,\n TamaguiElement,\n getConfig,\n getExpandedShorthands,\n getTokens,\n getVariableValue,\n isTamaguiElement,\n mergeProps,\n spacedChildren,\n styled,\n useMediaPropsActive,\n} from '@tamagui/core'\nimport { ThemeableStack } from '@tamagui/stacks'\nimport React, { Children, forwardRef, isValidElement } from 'react'\nimport { ScrollView } from 'react-native'\n\nexport const GroupFrame = styled(ThemeableStack, {\n name: 'GroupFrame',\n backgroundColor: '$background',\n y: 0,\n\n variants: {\n size: (val, { tokens }) => {\n const borderRadius = tokens.radius[val] ?? val ?? tokens.radius['$true']\n return {\n borderRadius,\n }\n },\n } as const,\n\n defaultVariants: {\n size: '$true',\n },\n})\n\nexport type GroupProps = GetProps<typeof GroupFrame> & {\n scrollable?: boolean\n /**\n * @default false\n */\n showScrollIndicator?: boolean\n disabled?: boolean\n vertical?: boolean\n disablePassBorderRadius?: boolean\n}\n\nfunction createGroup(verticalDefault: boolean) {\n return forwardRef<TamaguiElement, GroupProps>((props, ref) => {\n const activeProps = useMediaPropsActive(props)\n\n const {\n children: childrenProp,\n space,\n size = '$true',\n spaceDirection,\n separator,\n scrollable,\n vertical = verticalDefault,\n disabled: disabledProp,\n disablePassBorderRadius: disablePassBorderRadiusProp,\n borderRadius,\n ...restProps\n } = getExpandedShorthands(activeProps)\n\n const radius =\n borderRadius ?? (size ? getVariableValue(getTokens().radius[size]) - 1 : undefined)\n\n const hasRadius = radius !== undefined\n const disablePassBorderRadius = disablePassBorderRadiusProp ?? !hasRadius\n const childrens = Children.toArray(childrenProp)\n const children = childrens.map((child, i) => {\n if (!isValidElement(child)) return child\n const disabled = child.props.disabled ?? disabledProp\n\n const isFirst = i === 0\n const isLast = i === childrens.length - 1\n\n const radiusStyles = disablePassBorderRadius\n ? null\n : {\n borderTopLeftRadius: 0,\n borderTopRightRadius: 0,\n borderBottomLeftRadius: 0,\n borderBottomRightRadius: 0,\n ...(hasRadius && {\n ...(isFirst &&\n !vertical && {\n borderTopLeftRadius: radius,\n borderBottomLeftRadius: radius,\n }),\n ...(isFirst &&\n vertical && {\n borderTopLeftRadius: radius,\n borderTopRightRadius: radius,\n }),\n ...(isLast &&\n !vertical && {\n borderTopRightRadius: radius,\n borderBottomRightRadius: radius,\n }),\n ...(isLast &&\n vertical && {\n borderBottomLeftRadius: radius,\n borderBottomRightRadius: radius,\n }),\n }),\n }\n\n const props = {\n disabled,\n ...(isTamaguiElement(child) ? radiusStyles : { style: radiusStyles }),\n }\n\n return cloneElementWithPropOrder(child, props)\n })\n\n return (\n <GroupFrame\n ref={ref}\n size={size}\n flexDirection={!vertical ? 'row' : 'column'}\n borderRadius={borderRadius}\n {...restProps}\n >\n {wrapScroll(\n activeProps,\n spacedChildren({\n direction: spaceDirection,\n separator,\n space,\n children,\n })\n )}\n </GroupFrame>\n )\n })\n}\n\nexport const YGroup = createGroup(true)\nexport const XGroup = createGroup(false)\n\nconst wrapScroll = (\n { scrollable, vertical, showScrollIndicator = false }: GroupProps,\n children: any\n) => {\n if (scrollable)\n return (\n <ScrollView\n {...(vertical && {\n showsVerticalScrollIndicator: showScrollIndicator,\n })}\n {...(!vertical && {\n horizontal: true,\n showsHorizontalScrollIndicator: showScrollIndicator,\n })}\n >\n {children}\n </ScrollView>\n )\n return children\n}\n\nconst cloneElementWithPropOrder = (child: any, props: Object) => {\n const next = mergeProps(child.props, props, false, getConfig().shorthands)[0]\n return React.cloneElement({ ...child, props: null }, next)\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import {\n GetProps,\n TamaguiElement,\n UnionableString,\n Variable,\n getConfig,\n getExpandedShorthands,\n getTokens,\n getVariableValue,\n isTamaguiElement,\n mergeProps,\n spacedChildren,\n styled,\n useMediaPropsActive,\n withStaticProperties,\n} from '@tamagui/core'\nimport { Scope, createContextScope } from '@tamagui/create-context'\nimport { ThemeableStack } from '@tamagui/stacks'\nimport { useControllableState } from '@tamagui/use-controllable-state'\nimport React, { Children, cloneElement, forwardRef, isValidElement } from 'react'\nimport { ScrollView } from 'react-native'\nimport { useIndex, useIndexedChildren } from 'reforest'\n\ninterface GroupContextValue {\n vertical: boolean\n disablePassBorderRadius: boolean\n onItemMount: () => void\n onItemUnmount: () => void\n radius?: number | UnionableString | Variable<any>\n disabled?: boolean\n}\n\nconst GROUP_NAME = 'Group'\n\ntype ScopedProps<P> = P & { __scopeGroup?: Scope }\nconst [createGroupContext, createGroupScope] = createContextScope(GROUP_NAME)\nconst [GroupProvider, useGroupContext] = createGroupContext<GroupContextValue>(GROUP_NAME)\n\nexport const GroupFrame = styled(ThemeableStack, {\n name: 'GroupFrame',\n\n variants: {\n unstyled: {\n false: {\n y: 0,\n backgroundColor: '$background',\n size: '$true',\n },\n },\n\n size: (val, { tokens }) => {\n const borderRadius = tokens.radius[val] ?? val ?? tokens.radius['$true']\n return {\n borderRadius,\n }\n },\n } as const,\n\n defaultVariants: {\n unstyled: false,\n },\n})\n\nexport type GroupProps = GetProps<typeof GroupFrame> & {\n axis?: 'horizontal' | 'vertical'\n\n scrollable?: boolean\n /**\n * @default false\n */\n showScrollIndicator?: boolean\n disabled?: boolean\n disablePassBorderRadius?: boolean\n /**\n * forces the group to use the Group.Item API\n */\n forceUseItem?: boolean\n}\n\nfunction createGroup(verticalDefault: boolean) {\n return withStaticProperties(\n forwardRef<TamaguiElement, ScopedProps<GroupProps>>((props, ref) => {\n const activeProps = useMediaPropsActive(props)\n\n const {\n __scopeGroup,\n children: childrenProp,\n space,\n size = '$true',\n spaceDirection,\n separator,\n scrollable,\n axis = verticalDefault ? 'vertical' : 'horizontal',\n disabled: disabledProp,\n disablePassBorderRadius: disablePassBorderRadiusProp,\n borderRadius,\n forceUseItem,\n ...restProps\n } = getExpandedShorthands(activeProps)\n\n const vertical = axis === 'vertical'\n const [itemChildrenCount, setItemChildrenCount] = useControllableState({\n defaultProp: forceUseItem ? 1 : 0,\n })\n const isUsingItems = itemChildrenCount > 0\n\n // 1 off given border to adjust for border radius? This should be user controllable\n const radius =\n borderRadius ??\n (size ? getVariableValue(getTokens().radius[size]) - 1 : undefined)\n\n const hasRadius = radius !== undefined\n const disablePassBorderRadius = disablePassBorderRadiusProp ?? !hasRadius\n\n const childrenArray = Children.toArray(childrenProp)\n const children = isUsingItems\n ? childrenProp\n : childrenArray.map((child, i) => {\n if (!isValidElement(child)) {\n return child\n }\n const disabled = child.props.disabled ?? disabledProp\n\n const isFirst = i === 0\n const isLast = i === childrenArray.length - 1\n\n const radiusStyles = disablePassBorderRadius\n ? null\n : getBorderRadius({ isFirst, isLast, radius, vertical })\n const props = {\n disabled,\n ...(isTamaguiElement(child) ? radiusStyles : { style: radiusStyles }),\n }\n\n return cloneElementWithPropOrder(child, props)\n })\n\n const indexedChildren = useIndexedChildren(\n spacedChildren({\n direction: spaceDirection,\n separator,\n space,\n children,\n })\n )\n\n const onItemMount = React.useCallback(\n () => setItemChildrenCount((prev) => prev + 1),\n []\n )\n const onItemUnmount = React.useCallback(\n () => setItemChildrenCount((prev) => prev - 1),\n []\n )\n\n return (\n <GroupProvider\n disablePassBorderRadius={disablePassBorderRadius}\n vertical={axis === 'vertical'}\n radius={radius}\n disabled={disabledProp}\n onItemMount={onItemMount}\n onItemUnmount={onItemUnmount}\n scope={__scopeGroup}\n >\n <GroupFrame\n ref={ref}\n size={size}\n flexDirection={axis === 'horizontal' ? 'row' : 'column'}\n borderRadius={borderRadius}\n {...restProps}\n >\n {wrapScroll({ ...activeProps, axis }, indexedChildren)}\n </GroupFrame>\n </GroupProvider>\n )\n }),\n {\n Item: GroupItem,\n }\n )\n}\n\nconst GroupItem = (props: ScopedProps<{ children: React.ReactNode }>) => {\n const { __scopeGroup, children } = props\n const treeIndex = useIndex()\n const context = useGroupContext('GroupItem', __scopeGroup)\n\n React.useEffect(() => {\n context.onItemMount()\n return () => {\n context.onItemUnmount()\n }\n }, [])\n\n if (!isValidElement(children)) {\n return children as any\n }\n\n const disabled = children.props.disabled ?? context.disabled\n\n if (!treeIndex) {\n throw Error('<Group.Item/> should only be used within a <Group/>')\n }\n\n const isFirst = treeIndex.index === 0\n const isLast = treeIndex.index === treeIndex.maxIndex\n\n let propsToPass: Record<string, any> = {\n disabled,\n }\n\n if (!context.disablePassBorderRadius) {\n const radiusStyles = getBorderRadius({\n radius: context.radius,\n isFirst,\n isLast,\n vertical: context.vertical,\n })\n if (isTamaguiElement(children)) {\n propsToPass = { ...propsToPass, ...radiusStyles }\n } else {\n propsToPass.style = radiusStyles\n }\n }\n\n return cloneElement(children, {\n ...propsToPass,\n // @ts-ignore\n style: {\n ...children.props?.['style'],\n ...propsToPass.style,\n },\n })\n}\n\nexport const Group = createGroup(true)\nexport const YGroup = Group\nexport const XGroup = createGroup(false)\n\nconst wrapScroll = (\n { scrollable, axis, showScrollIndicator = false }: GroupProps,\n children: any\n) => {\n if (scrollable)\n return (\n <ScrollView\n {...(axis === 'vertical' && {\n showsVerticalScrollIndicator: showScrollIndicator,\n })}\n {...(axis === 'horizontal' && {\n horizontal: true,\n showsHorizontalScrollIndicator: showScrollIndicator,\n })}\n >\n {children}\n </ScrollView>\n )\n return children\n}\n\nconst getBorderRadius = ({\n isFirst,\n isLast,\n radius,\n vertical,\n}: {\n radius: any\n vertical: boolean\n isFirst: boolean\n isLast: boolean\n}) => {\n // TODO: RTL support would be nice here\n return {\n borderTopLeftRadius: isFirst ? radius : 0,\n borderTopRightRadius: (vertical && isFirst) || (!vertical && isLast) ? radius : 0,\n borderBottomLeftRadius: (vertical && isLast) || (!vertical && isFirst) ? radius : 0,\n borderBottomRightRadius: isLast ? radius : 0,\n }\n}\n\nconst cloneElementWithPropOrder = (child: any, props: Object) => {\n const next = mergeProps(child.props, props, false, getConfig().shorthands)[0]\n return React.cloneElement({ ...child, props: null }, next)\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["props"]
7
7
  }
@@ -7,16 +7,28 @@ import {
7
7
  mergeProps,
8
8
  spacedChildren,
9
9
  styled,
10
- useMediaPropsActive
10
+ useMediaPropsActive,
11
+ withStaticProperties
11
12
  } from "@tamagui/core";
13
+ import { createContextScope } from "@tamagui/create-context";
12
14
  import { ThemeableStack } from "@tamagui/stacks";
13
- import React, { Children, forwardRef, isValidElement } from "react";
15
+ import { useControllableState } from "@tamagui/use-controllable-state";
16
+ import React, { Children, cloneElement, forwardRef, isValidElement } from "react";
14
17
  import { ScrollView } from "react-native";
18
+ import { useIndex, useIndexedChildren } from "reforest";
19
+ const GROUP_NAME = "Group";
20
+ const [createGroupContext, createGroupScope] = createContextScope(GROUP_NAME);
21
+ const [GroupProvider, useGroupContext] = createGroupContext(GROUP_NAME);
15
22
  const GroupFrame = styled(ThemeableStack, {
16
23
  name: "GroupFrame",
17
- backgroundColor: "$background",
18
- y: 0,
19
24
  variants: {
25
+ unstyled: {
26
+ false: {
27
+ y: 0,
28
+ backgroundColor: "$background",
29
+ size: "$true"
30
+ }
31
+ },
20
32
  size: (val, { tokens }) => {
21
33
  const borderRadius = tokens.radius[val] ?? val ?? tokens.radius["$true"];
22
34
  return {
@@ -25,102 +37,167 @@ const GroupFrame = styled(ThemeableStack, {
25
37
  }
26
38
  },
27
39
  defaultVariants: {
28
- size: "$true"
40
+ unstyled: false
29
41
  }
30
42
  });
31
43
  function createGroup(verticalDefault) {
32
- return forwardRef((props, ref) => {
33
- const activeProps = useMediaPropsActive(props);
34
- const {
35
- children: childrenProp,
36
- space,
37
- size = "$true",
38
- spaceDirection,
39
- separator,
40
- scrollable,
41
- vertical = verticalDefault,
42
- disabled: disabledProp,
43
- disablePassBorderRadius: disablePassBorderRadiusProp,
44
- borderRadius,
45
- ...restProps
46
- } = getExpandedShorthands(activeProps);
47
- const radius = borderRadius ?? (size ? getVariableValue(getTokens().radius[size]) - 1 : void 0);
48
- const hasRadius = radius !== void 0;
49
- const disablePassBorderRadius = disablePassBorderRadiusProp ?? !hasRadius;
50
- const childrens = Children.toArray(childrenProp);
51
- const children = childrens.map((child, i) => {
52
- if (!isValidElement(child))
53
- return child;
54
- const disabled = child.props.disabled ?? disabledProp;
55
- const isFirst = i === 0;
56
- const isLast = i === childrens.length - 1;
57
- const radiusStyles = disablePassBorderRadius ? null : {
58
- borderTopLeftRadius: 0,
59
- borderTopRightRadius: 0,
60
- borderBottomLeftRadius: 0,
61
- borderBottomRightRadius: 0,
62
- ...hasRadius && {
63
- ...isFirst && !vertical && {
64
- borderTopLeftRadius: radius,
65
- borderBottomLeftRadius: radius
66
- },
67
- ...isFirst && vertical && {
68
- borderTopLeftRadius: radius,
69
- borderTopRightRadius: radius
70
- },
71
- ...isLast && !vertical && {
72
- borderTopRightRadius: radius,
73
- borderBottomRightRadius: radius
74
- },
75
- ...isLast && vertical && {
76
- borderBottomLeftRadius: radius,
77
- borderBottomRightRadius: radius
78
- }
44
+ return withStaticProperties(
45
+ forwardRef((props, ref) => {
46
+ const activeProps = useMediaPropsActive(props);
47
+ const {
48
+ __scopeGroup,
49
+ children: childrenProp,
50
+ space,
51
+ size = "$true",
52
+ spaceDirection,
53
+ separator,
54
+ scrollable,
55
+ axis = verticalDefault ? "vertical" : "horizontal",
56
+ disabled: disabledProp,
57
+ disablePassBorderRadius: disablePassBorderRadiusProp,
58
+ borderRadius,
59
+ forceUseItem,
60
+ ...restProps
61
+ } = getExpandedShorthands(activeProps);
62
+ const vertical = axis === "vertical";
63
+ const [itemChildrenCount, setItemChildrenCount] = useControllableState({
64
+ defaultProp: forceUseItem ? 1 : 0
65
+ });
66
+ const isUsingItems = itemChildrenCount > 0;
67
+ const radius = borderRadius ?? (size ? getVariableValue(getTokens().radius[size]) - 1 : void 0);
68
+ const hasRadius = radius !== void 0;
69
+ const disablePassBorderRadius = disablePassBorderRadiusProp ?? !hasRadius;
70
+ const childrenArray = Children.toArray(childrenProp);
71
+ const children = isUsingItems ? childrenProp : childrenArray.map((child, i) => {
72
+ if (!isValidElement(child)) {
73
+ return child;
79
74
  }
80
- };
81
- const props2 = {
82
- disabled,
83
- ...isTamaguiElement(child) ? radiusStyles : { style: radiusStyles }
84
- };
85
- return cloneElementWithPropOrder(child, props2);
75
+ const disabled = child.props.disabled ?? disabledProp;
76
+ const isFirst = i === 0;
77
+ const isLast = i === childrenArray.length - 1;
78
+ const radiusStyles = disablePassBorderRadius ? null : getBorderRadius({ isFirst, isLast, radius, vertical });
79
+ const props2 = {
80
+ disabled,
81
+ ...isTamaguiElement(child) ? radiusStyles : { style: radiusStyles }
82
+ };
83
+ return cloneElementWithPropOrder(child, props2);
84
+ });
85
+ const indexedChildren = useIndexedChildren(
86
+ spacedChildren({
87
+ direction: spaceDirection,
88
+ separator,
89
+ space,
90
+ children
91
+ })
92
+ );
93
+ const onItemMount = React.useCallback(
94
+ () => setItemChildrenCount((prev) => prev + 1),
95
+ []
96
+ );
97
+ const onItemUnmount = React.useCallback(
98
+ () => setItemChildrenCount((prev) => prev - 1),
99
+ []
100
+ );
101
+ return <GroupProvider
102
+ disablePassBorderRadius={disablePassBorderRadius}
103
+ vertical={axis === "vertical"}
104
+ radius={radius}
105
+ disabled={disabledProp}
106
+ onItemMount={onItemMount}
107
+ onItemUnmount={onItemUnmount}
108
+ scope={__scopeGroup}
109
+ ><GroupFrame
110
+ ref={ref}
111
+ size={size}
112
+ flexDirection={axis === "horizontal" ? "row" : "column"}
113
+ borderRadius={borderRadius}
114
+ {...restProps}
115
+ >{wrapScroll({ ...activeProps, axis }, indexedChildren)}</GroupFrame></GroupProvider>;
116
+ }),
117
+ {
118
+ Item: GroupItem
119
+ }
120
+ );
121
+ }
122
+ const GroupItem = (props) => {
123
+ const { __scopeGroup, children } = props;
124
+ const treeIndex = useIndex();
125
+ const context = useGroupContext("GroupItem", __scopeGroup);
126
+ React.useEffect(() => {
127
+ context.onItemMount();
128
+ return () => {
129
+ context.onItemUnmount();
130
+ };
131
+ }, []);
132
+ if (!isValidElement(children)) {
133
+ return children;
134
+ }
135
+ const disabled = children.props.disabled ?? context.disabled;
136
+ if (!treeIndex) {
137
+ throw Error("<Group.Item/> should only be used within a <Group/>");
138
+ }
139
+ const isFirst = treeIndex.index === 0;
140
+ const isLast = treeIndex.index === treeIndex.maxIndex;
141
+ let propsToPass = {
142
+ disabled
143
+ };
144
+ if (!context.disablePassBorderRadius) {
145
+ const radiusStyles = getBorderRadius({
146
+ radius: context.radius,
147
+ isFirst,
148
+ isLast,
149
+ vertical: context.vertical
86
150
  });
87
- return <GroupFrame
88
- ref={ref}
89
- size={size}
90
- flexDirection={!vertical ? "row" : "column"}
91
- borderRadius={borderRadius}
92
- {...restProps}
93
- >{wrapScroll(
94
- activeProps,
95
- spacedChildren({
96
- direction: spaceDirection,
97
- separator,
98
- space,
99
- children
100
- })
101
- )}</GroupFrame>;
151
+ if (isTamaguiElement(children)) {
152
+ propsToPass = { ...propsToPass, ...radiusStyles };
153
+ } else {
154
+ propsToPass.style = radiusStyles;
155
+ }
156
+ }
157
+ return cloneElement(children, {
158
+ ...propsToPass,
159
+ // @ts-ignore
160
+ style: {
161
+ ...children.props?.["style"],
162
+ ...propsToPass.style
163
+ }
102
164
  });
103
- }
104
- const YGroup = createGroup(true);
165
+ };
166
+ const Group = createGroup(true);
167
+ const YGroup = Group;
105
168
  const XGroup = createGroup(false);
106
- const wrapScroll = ({ scrollable, vertical, showScrollIndicator = false }, children) => {
169
+ const wrapScroll = ({ scrollable, axis, showScrollIndicator = false }, children) => {
107
170
  if (scrollable)
108
171
  return <ScrollView
109
- {...vertical && {
172
+ {...axis === "vertical" && {
110
173
  showsVerticalScrollIndicator: showScrollIndicator
111
174
  }}
112
- {...!vertical && {
175
+ {...axis === "horizontal" && {
113
176
  horizontal: true,
114
177
  showsHorizontalScrollIndicator: showScrollIndicator
115
178
  }}
116
179
  >{children}</ScrollView>;
117
180
  return children;
118
181
  };
182
+ const getBorderRadius = ({
183
+ isFirst,
184
+ isLast,
185
+ radius,
186
+ vertical
187
+ }) => {
188
+ return {
189
+ borderTopLeftRadius: isFirst ? radius : 0,
190
+ borderTopRightRadius: vertical && isFirst || !vertical && isLast ? radius : 0,
191
+ borderBottomLeftRadius: vertical && isLast || !vertical && isFirst ? radius : 0,
192
+ borderBottomRightRadius: isLast ? radius : 0
193
+ };
194
+ };
119
195
  const cloneElementWithPropOrder = (child, props) => {
120
196
  const next = mergeProps(child.props, props, false, getConfig().shorthands)[0];
121
197
  return React.cloneElement({ ...child, props: null }, next);
122
198
  };
123
199
  export {
200
+ Group,
124
201
  GroupFrame,
125
202
  XGroup,
126
203
  YGroup