@tamagui/list-item 1.0.1-beta.100

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 (47) hide show
  1. package/dist/cjs/Button.js +249 -0
  2. package/dist/cjs/Button.js.map +7 -0
  3. package/dist/cjs/ListItem.js +203 -0
  4. package/dist/cjs/ListItem.js.map +7 -0
  5. package/dist/cjs/index.js +18 -0
  6. package/dist/cjs/index.js.map +7 -0
  7. package/dist/cjs/useCurrentColor.js +41 -0
  8. package/dist/cjs/useCurrentColor.js.map +7 -0
  9. package/dist/cjs/useGetThemedIcon.js +45 -0
  10. package/dist/cjs/useGetThemedIcon.js.map +7 -0
  11. package/dist/cjs/wrapStringChildrenInText.js +111 -0
  12. package/dist/cjs/wrapStringChildrenInText.js.map +7 -0
  13. package/dist/esm/Button.js +190 -0
  14. package/dist/esm/Button.js.map +7 -0
  15. package/dist/esm/ListItem.js +183 -0
  16. package/dist/esm/ListItem.js.map +7 -0
  17. package/dist/esm/index.js +2 -0
  18. package/dist/esm/index.js.map +7 -0
  19. package/dist/esm/useCurrentColor.js +19 -0
  20. package/dist/esm/useCurrentColor.js.map +7 -0
  21. package/dist/esm/useGetThemedIcon.js +20 -0
  22. package/dist/esm/useGetThemedIcon.js.map +7 -0
  23. package/dist/esm/wrapStringChildrenInText.js +53 -0
  24. package/dist/esm/wrapStringChildrenInText.js.map +7 -0
  25. package/dist/jsx/Button.js +177 -0
  26. package/dist/jsx/ListItem.js +139 -0
  27. package/dist/jsx/ListItem.js.map +7 -0
  28. package/dist/jsx/index.js +2 -0
  29. package/dist/jsx/index.js.map +7 -0
  30. package/dist/jsx/useCurrentColor.js +18 -0
  31. package/dist/jsx/useGetThemedIcon.js +19 -0
  32. package/dist/jsx/wrapStringChildrenInText.js +47 -0
  33. package/package.json +39 -0
  34. package/src/ListItem.tsx +200 -0
  35. package/src/index.ts +1 -0
  36. package/types/Button.d.ts +127 -0
  37. package/types/Button.d.ts.map +1 -0
  38. package/types/ListItem.d.ts +278 -0
  39. package/types/ListItem.d.ts.map +1 -0
  40. package/types/index.d.ts +2 -0
  41. package/types/index.d.ts.map +1 -0
  42. package/types/useCurrentColor.d.ts +5 -0
  43. package/types/useCurrentColor.d.ts.map +1 -0
  44. package/types/useGetThemedIcon.d.ts +6 -0
  45. package/types/useGetThemedIcon.d.ts.map +1 -0
  46. package/types/wrapStringChildrenInText.d.ts +8 -0
  47. package/types/wrapStringChildrenInText.d.ts.map +1 -0
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/wrapStringChildrenInText.tsx"],
4
+ "sourcesContent": ["import { SizeTokens } from '@tamagui/core'\nimport React from 'react'\n\nimport { ListItemText, TextOnlyStyles } from './ListItem'\n\nexport function wrapStringChildrenInText({\n children,\n textProps,\n size,\n noTextWrap,\n ...directTextProps\n}: TextOnlyStyles & { children?: React.ReactNode; size?: SizeTokens }) {\n if (noTextWrap || !children) {\n return children\n }\n\n // in the case of using variables, like so:\n // <ListItem>Hello, {name}</ListItem>\n // it gives us props.children as ['Hello, ', 'name']\n // but we don't want to wrap multiple SizableText around each part\n // so we group them\n let allChildren = React.Children.toArray(children)\n let nextChildren: any[] = []\n let lastIsString = false\n\n function concatStringChildren() {\n if (!lastIsString) return\n const index = nextChildren.length - 1\n const childrenStrings = nextChildren[index]\n nextChildren[index] = (\n <ListItemText key={index} {...directTextProps} size={size} {...textProps}>\n {childrenStrings}\n </ListItemText>\n )\n }\n\n for (const child of allChildren) {\n const last = nextChildren[nextChildren.length - 1]\n const isString = typeof child === 'string'\n if (isString) {\n if (lastIsString) {\n last.push(child)\n } else {\n nextChildren.push([child])\n }\n } else {\n concatStringChildren()\n nextChildren.push(child)\n }\n lastIsString = isString\n }\n concatStringChildren()\n\n return nextChildren\n}\n"],
5
+ "mappings": ";;AACA;AAEA;AAEO,kCAAkC;AAAA,EACvC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,KACG;AAAA,GACkE;AACrE,MAAI,cAAc,CAAC,UAAU;AAC3B,WAAO;AAAA,EACT;AAOA,MAAI,cAAc,MAAM,SAAS,QAAQ,QAAQ;AACjD,MAAI,eAAsB,CAAC;AAC3B,MAAI,eAAe;AAEnB,kCAAgC;AAC9B,QAAI,CAAC;AAAc;AACnB,UAAM,QAAQ,aAAa,SAAS;AACpC,UAAM,kBAAkB,aAAa;AACrC,iBAAa,SACX,oCAAC;AAAA,MAAa,KAAK;AAAA,SAAW;AAAA,MAAiB;AAAA,SAAgB;AAAA,OAC5D,eACH;AAAA,EAEJ;AATS;AAWT,aAAW,SAAS,aAAa;AAC/B,UAAM,OAAO,aAAa,aAAa,SAAS;AAChD,UAAM,WAAW,OAAO,UAAU;AAClC,QAAI,UAAU;AACZ,UAAI,cAAc;AAChB,aAAK,KAAK,KAAK;AAAA,MACjB,OAAO;AACL,qBAAa,KAAK,CAAC,KAAK,CAAC;AAAA,MAC3B;AAAA,IACF,OAAO;AACL,2BAAqB;AACrB,mBAAa,KAAK,KAAK;AAAA,IACzB;AACA,mBAAe;AAAA,EACjB;AACA,uBAAqB;AAErB,SAAO;AACT;AAjDgB;",
6
+ "names": []
7
+ }
@@ -0,0 +1,177 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
3
+ import {
4
+ ButtonInsideButtonContext,
5
+ getButtonSize,
6
+ getVariableValue,
7
+ spacedChildren,
8
+ styled,
9
+ themeable,
10
+ useTheme
11
+ } from "@tamagui/core";
12
+ import { getFontSize } from "@tamagui/font-size";
13
+ import { ThemeableStack } from "@tamagui/stacks";
14
+ import { SizableText } from "@tamagui/text";
15
+ import React, { forwardRef, isValidElement, useContext } from "react";
16
+ React["createElement"];
17
+ const ButtonFrame = styled(ThemeableStack, {
18
+ name: "Button",
19
+ tag: "button",
20
+ hoverable: true,
21
+ pressable: true,
22
+ backgrounded: true,
23
+ borderWidth: 1,
24
+ borderColor: "transparent",
25
+ justifyContent: "center",
26
+ alignItems: "center",
27
+ flexWrap: "nowrap",
28
+ flexDirection: "row",
29
+ cursor: "pointer",
30
+ pressStyle: {
31
+ borderColor: "transparent"
32
+ },
33
+ hoverStyle: {
34
+ borderColor: "transparent"
35
+ },
36
+ focusStyle: {
37
+ borderColor: "$borderColorFocus"
38
+ },
39
+ variants: {
40
+ size: {
41
+ "...size": getButtonSize
42
+ },
43
+ active: {
44
+ true: {
45
+ hoverStyle: {
46
+ backgroundColor: "$background"
47
+ }
48
+ }
49
+ },
50
+ disabled: {
51
+ true: {
52
+ opacity: 0.5,
53
+ pointerEvents: "none"
54
+ }
55
+ }
56
+ },
57
+ defaultVariants: {
58
+ size: "$4"
59
+ }
60
+ });
61
+ const ButtonText = styled(SizableText, {
62
+ color: "$color",
63
+ selectable: false,
64
+ flexGrow: 1,
65
+ flexShrink: 1,
66
+ ellipse: true
67
+ });
68
+ const ButtonComponent = forwardRef((props, ref) => {
69
+ const {
70
+ children,
71
+ icon,
72
+ iconAfter,
73
+ noTextWrap,
74
+ theme: themeName,
75
+ space,
76
+ spaceFlex,
77
+ scaleIcon = 1,
78
+ scaleSpace = 0.5,
79
+ color: colorProp,
80
+ fontWeight,
81
+ letterSpacing,
82
+ fontSize,
83
+ fontFamily,
84
+ textAlign,
85
+ textProps,
86
+ ...rest
87
+ } = props;
88
+ const isInsideButton = useContext(ButtonInsideButtonContext);
89
+ const theme = useTheme();
90
+ const size = props.size || "$4";
91
+ let color;
92
+ if (theme && colorProp && colorProp in theme) {
93
+ color = theme[colorProp];
94
+ } else if (colorProp) {
95
+ color = colorProp;
96
+ } else {
97
+ color = theme == null ? void 0 : theme.color;
98
+ }
99
+ color = color == null ? void 0 : color.toString();
100
+ const iconSize = getFontSize(size) * scaleIcon;
101
+ const addTheme = /* @__PURE__ */ __name((el) => {
102
+ if (isValidElement(el)) {
103
+ return el;
104
+ }
105
+ if (el) {
106
+ return React.createElement(el, {
107
+ color,
108
+ size: iconSize
109
+ });
110
+ }
111
+ return el;
112
+ }, "addTheme");
113
+ const themedIcon = icon ? addTheme(icon) : null;
114
+ const themedIconAfter = iconAfter ? addTheme(iconAfter) : null;
115
+ let contents = children;
116
+ if (!noTextWrap && children) {
117
+ let concatStringChildren = function() {
118
+ if (!lastIsString)
119
+ return;
120
+ const index = nextChildren.length - 1;
121
+ const childrenStrings = nextChildren[index];
122
+ nextChildren[index] = <ButtonText key={index} {...{
123
+ fontWeight,
124
+ letterSpacing,
125
+ fontSize,
126
+ fontFamily,
127
+ textAlign,
128
+ size
129
+ }} {...colorProp && {
130
+ color: colorProp
131
+ }} {...textProps}>{childrenStrings}</ButtonText>;
132
+ };
133
+ __name(concatStringChildren, "concatStringChildren");
134
+ let allChildren = React.Children.toArray(children);
135
+ let nextChildren = [];
136
+ let lastIsString = false;
137
+ for (const child of allChildren) {
138
+ const last = nextChildren[nextChildren.length - 1];
139
+ const isString = typeof child === "string";
140
+ if (isString) {
141
+ if (lastIsString) {
142
+ last.push(child);
143
+ } else {
144
+ nextChildren.push([child]);
145
+ }
146
+ } else {
147
+ concatStringChildren();
148
+ nextChildren.push(child);
149
+ }
150
+ lastIsString = isString;
151
+ }
152
+ concatStringChildren();
153
+ contents = nextChildren;
154
+ }
155
+ return <ButtonInsideButtonContext.Provider value={true}><ButtonFrame fontFamily={fontFamily} {...isInsideButton && {
156
+ tag: "span"
157
+ }} ref={ref} {...rest}>{themedIcon || themedIconAfter ? spacedChildren({
158
+ space: getVariableValue(iconSize) * scaleSpace,
159
+ spaceFlex,
160
+ direction: props.flexDirection || "row",
161
+ children: [themedIcon, contents, themedIconAfter]
162
+ }) : contents}</ButtonFrame></ButtonInsideButtonContext.Provider>;
163
+ });
164
+ const Button = ButtonFrame.extractable(themeable(ButtonComponent), {
165
+ inlineProps: /* @__PURE__ */ new Set([
166
+ "color",
167
+ "fontWeight",
168
+ "fontSize",
169
+ "fontFamily",
170
+ "letterSpacing",
171
+ "textAlign"
172
+ ])
173
+ });
174
+ export {
175
+ Button,
176
+ ButtonText
177
+ };
@@ -0,0 +1,139 @@
1
+ import {
2
+ Spacer,
3
+ getSize,
4
+ getVariableValue,
5
+ styled,
6
+ themeable,
7
+ withStaticProperties
8
+ } from "@tamagui/core";
9
+ import { getFontSize } from "@tamagui/font-size";
10
+ import { useGetThemedIcon } from "@tamagui/helpers-tamagui";
11
+ import { ThemeableStack, YStack } from "@tamagui/stacks";
12
+ import { SizableText, wrapChildrenInText } from "@tamagui/text";
13
+ import React, { forwardRef } from "react";
14
+ React["createElement"];
15
+ const ListItemFrame = styled(ThemeableStack, {
16
+ name: "ListItem",
17
+ tag: "li",
18
+ alignItems: "center",
19
+ flexWrap: "nowrap",
20
+ width: "100%",
21
+ borderColor: "$borderColor",
22
+ maxWidth: "100%",
23
+ overflow: "hidden",
24
+ flexDirection: "row",
25
+ variants: {
26
+ size: {
27
+ "...size": (val, { tokens }) => {
28
+ return {
29
+ minHeight: tokens.size[val],
30
+ paddingHorizontal: tokens.space[val]
31
+ };
32
+ }
33
+ },
34
+ active: {
35
+ true: {
36
+ hoverStyle: {
37
+ backgroundColor: "$background"
38
+ }
39
+ }
40
+ },
41
+ disabled: {
42
+ true: {
43
+ opacity: 0.5,
44
+ pointerEvents: "none"
45
+ }
46
+ }
47
+ },
48
+ defaultVariants: {
49
+ size: "$4"
50
+ }
51
+ });
52
+ const ListItemText = styled(SizableText, {
53
+ name: "ListItemText",
54
+ color: "$color",
55
+ selectable: false,
56
+ flexGrow: 1,
57
+ flexShrink: 1,
58
+ ellipse: true
59
+ });
60
+ const ListItemSubtitle = styled(ListItemText, {
61
+ name: "ListItemSubtitle",
62
+ color: "$colorPress",
63
+ marginTop: "$-2",
64
+ opacity: 0.65,
65
+ ellipse: true,
66
+ maxWidth: "100%",
67
+ size: "$3"
68
+ });
69
+ const ListItemTitle = styled(ListItemText, {
70
+ name: "ListItemTitle",
71
+ ellipse: true
72
+ });
73
+ const ListItemComponent = forwardRef((props, ref) => {
74
+ const {
75
+ children,
76
+ icon,
77
+ iconAfter,
78
+ noTextWrap,
79
+ theme: themeName,
80
+ space,
81
+ spaceFlex,
82
+ scaleIcon = 1,
83
+ scaleSpace = 1,
84
+ subTitle,
85
+ color,
86
+ fontWeight,
87
+ letterSpacing,
88
+ fontSize,
89
+ fontFamily,
90
+ textAlign,
91
+ textProps,
92
+ title,
93
+ ...rest
94
+ } = props;
95
+ const size = props.size || "$4";
96
+ const subtitleSizeToken = getSize(size, -3);
97
+ const subtitleSize = `$${subtitleSizeToken.key}`;
98
+ const iconSize = getFontSize(size) * scaleIcon;
99
+ const getThemedIcon = useGetThemedIcon({ size: iconSize, color });
100
+ const [themedIcon, themedIconAfter] = [icon, iconAfter].map(getThemedIcon);
101
+ const spaceSize = getVariableValue(iconSize) * scaleSpace;
102
+ const contents = wrapChildrenInText(ListItemText, props);
103
+ return <ListItemFrame fontFamily={fontFamily} ref={ref} {...rest}>
104
+ {themedIcon ? <>
105
+ {themedIcon}
106
+ <Spacer size={spaceSize} />
107
+ </> : null}
108
+ {Boolean(title || subTitle) ? <YStack flex={1}>
109
+ <ListItemTitle>{title}</ListItemTitle>
110
+ {subTitle ? typeof subTitle === "string" ? <ListItemSubtitle size={subtitleSize}>{subTitle}</ListItemSubtitle> : subTitle : null}
111
+ {contents}
112
+ </YStack> : contents}
113
+ {themedIconAfter ? <>
114
+ <Spacer flex size={spaceSize} />
115
+ {themedIconAfter}
116
+ </> : null}
117
+ </ListItemFrame>;
118
+ });
119
+ const ListItemInner = ListItemFrame.extractable(themeable(ListItemComponent), {
120
+ inlineProps: /* @__PURE__ */ new Set([
121
+ "color",
122
+ "fontWeight",
123
+ "fontSize",
124
+ "fontFamily",
125
+ "letterSpacing",
126
+ "textAlign"
127
+ ])
128
+ });
129
+ const ListItem = withStaticProperties(ListItemInner, {
130
+ Text: ListItemText,
131
+ Subtitle: ListItemSubtitle
132
+ });
133
+ export {
134
+ ListItem,
135
+ ListItemFrame,
136
+ ListItemSubtitle,
137
+ ListItemText
138
+ };
139
+ //# sourceMappingURL=ListItem.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/ListItem.tsx"],
4
+ "sourcesContent": ["import {\n FontSizeTokens,\n GetProps,\n Spacer,\n TamaguiComponent,\n ThemeableProps,\n getSize,\n getVariableValue,\n styled,\n themeable,\n withStaticProperties,\n} from '@tamagui/core'\nimport { getFontSize } from '@tamagui/font-size'\nimport { TextParentStyles, useGetThemedIcon } from '@tamagui/helpers-tamagui'\nimport { ThemeableStack, YStack } from '@tamagui/stacks'\nimport { SizableText, wrapChildrenInText } from '@tamagui/text'\nimport React, { FunctionComponent, forwardRef } from 'react'\nimport { View } from 'react-native'\n\n// bugfix esbuild strips react jsx: 'preserve'\nReact['createElement']\n\ntype ListItemIconProps = { color?: string; size?: number }\ntype IconProp = JSX.Element | FunctionComponent<ListItemIconProps> | null\n\nexport type ListItemProps = Omit<TextParentStyles, 'TextComponent'> &\n GetProps<typeof ListItemFrame> &\n ThemeableProps & {\n // add icon before, passes color and size automatically if Component\n icon?: IconProp\n // add icon after, passes color and size automatically if Component\n iconAfter?: IconProp\n // adjust icon relative to size\n // default: -1\n scaleIcon?: number\n // make the spacing elements flex\n spaceFlex?: number | boolean\n // adjust internal space relative to icon size\n scaleSpace?: number\n // title\n title?: React.ReactNode\n // subtitle\n subTitle?: React.ReactNode\n }\n\nexport const ListItemFrame = styled(ThemeableStack, {\n name: 'ListItem',\n tag: 'li',\n alignItems: 'center',\n flexWrap: 'nowrap',\n width: '100%',\n borderColor: '$borderColor',\n maxWidth: '100%',\n overflow: 'hidden',\n flexDirection: 'row',\n\n variants: {\n size: {\n '...size': (val, { tokens }) => {\n return {\n minHeight: tokens.size[val],\n paddingHorizontal: tokens.space[val],\n }\n },\n },\n\n active: {\n true: {\n hoverStyle: {\n backgroundColor: '$background',\n },\n },\n },\n\n disabled: {\n true: {\n opacity: 0.5,\n // TODO breaking types\n pointerEvents: 'none' as any,\n },\n },\n },\n\n defaultVariants: {\n size: '$4',\n },\n})\n\nexport const ListItemText = styled(SizableText, {\n name: 'ListItemText',\n color: '$color',\n selectable: false,\n flexGrow: 1,\n flexShrink: 1,\n ellipse: true,\n})\n\nexport const ListItemSubtitle = styled(ListItemText, {\n name: 'ListItemSubtitle',\n color: '$colorPress',\n marginTop: '$-2',\n opacity: 0.65,\n ellipse: true,\n maxWidth: '100%',\n size: '$3',\n})\n\nconst ListItemTitle = styled(ListItemText, {\n name: 'ListItemTitle',\n ellipse: true,\n})\n\nconst ListItemComponent = forwardRef((props: ListItemProps, ref) => {\n // careful not to desctructure and re-order props, order is important\n const {\n children,\n icon,\n iconAfter,\n noTextWrap,\n theme: themeName,\n space,\n spaceFlex,\n scaleIcon = 1,\n scaleSpace = 1,\n subTitle,\n\n // text props\n color,\n fontWeight,\n letterSpacing,\n fontSize,\n fontFamily,\n textAlign,\n textProps,\n title,\n ...rest\n } = props as ListItemProps\n\n const size = props.size || '$4'\n const subtitleSizeToken = getSize(size, -3)\n const subtitleSize = `$${subtitleSizeToken.key}` as FontSizeTokens\n const iconSize = getFontSize(size) * scaleIcon\n const getThemedIcon = useGetThemedIcon({ size: iconSize, color })\n const [themedIcon, themedIconAfter] = [icon, iconAfter].map(getThemedIcon)\n const spaceSize = getVariableValue(iconSize) * scaleSpace\n const contents = wrapChildrenInText(ListItemText, props)\n\n return (\n <ListItemFrame fontFamily={fontFamily} ref={ref as any} {...rest}>\n {themedIcon ? (\n <>\n {themedIcon}\n <Spacer size={spaceSize} />\n </>\n ) : null}\n {/* helper for common title/subtitle pttern */}\n {Boolean(title || subTitle) ? (\n <YStack flex={1}>\n <ListItemTitle>{title}</ListItemTitle>\n {subTitle ? (\n typeof subTitle === 'string' ? (\n // TODO can use theme but we need to standardize to alt themes\n // or standardize on subtle colors in themes\n <ListItemSubtitle size={subtitleSize}>{subTitle}</ListItemSubtitle>\n ) : (\n subTitle\n )\n ) : null}\n {contents}\n </YStack>\n ) : (\n contents\n )}\n {themedIconAfter ? (\n <>\n <Spacer flex size={spaceSize} />\n {themedIconAfter}\n </>\n ) : null}\n </ListItemFrame>\n )\n})\n\nconst ListItemInner: TamaguiComponent<ListItemProps, HTMLLIElement | View> =\n ListItemFrame.extractable(themeable(ListItemComponent as any) as any, {\n inlineProps: new Set([\n // text props go here (can't really optimize them, but we never fully extract listItem anyway)\n 'color',\n 'fontWeight',\n 'fontSize',\n 'fontFamily',\n 'letterSpacing',\n 'textAlign',\n ]),\n })\n\nexport const ListItem = withStaticProperties(ListItemInner, {\n Text: ListItemText,\n Subtitle: ListItemSubtitle,\n})\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,2 @@
1
+ export * from "./ListItem";
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/index.ts"],
4
+ "sourcesContent": ["export * from './ListItem'\n"],
5
+ "mappings": "AAAA;",
6
+ "names": []
7
+ }
@@ -0,0 +1,18 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
3
+ import { useTheme } from "@tamagui/core";
4
+ const useCurrentColor = /* @__PURE__ */ __name((colorProp) => {
5
+ const theme = useTheme();
6
+ let color;
7
+ if (theme && colorProp && colorProp in theme) {
8
+ color = theme[colorProp];
9
+ } else if (colorProp) {
10
+ color = colorProp;
11
+ } else {
12
+ color = theme == null ? void 0 : theme.color;
13
+ }
14
+ return (color == null ? void 0 : color.toString()) || "";
15
+ }, "useCurrentColor");
16
+ export {
17
+ useCurrentColor
18
+ };
@@ -0,0 +1,19 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
3
+ import React, { isValidElement } from "react";
4
+ import { useCurrentColor } from "./useCurrentColor";
5
+ const useGetThemedIcon = /* @__PURE__ */ __name((props) => {
6
+ const color = useCurrentColor(props.color);
7
+ return (el) => {
8
+ if (isValidElement(el)) {
9
+ return el;
10
+ }
11
+ if (el) {
12
+ return React.createElement(el, props);
13
+ }
14
+ return el;
15
+ };
16
+ }, "useGetThemedIcon");
17
+ export {
18
+ useGetThemedIcon
19
+ };
@@ -0,0 +1,47 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
3
+ import React from "react";
4
+ import { ListItemText } from "./ListItem";
5
+ function wrapStringChildrenInText({
6
+ children,
7
+ textProps,
8
+ size,
9
+ noTextWrap,
10
+ ...directTextProps
11
+ }) {
12
+ if (noTextWrap || !children) {
13
+ return children;
14
+ }
15
+ let allChildren = React.Children.toArray(children);
16
+ let nextChildren = [];
17
+ let lastIsString = false;
18
+ function concatStringChildren() {
19
+ if (!lastIsString)
20
+ return;
21
+ const index = nextChildren.length - 1;
22
+ const childrenStrings = nextChildren[index];
23
+ nextChildren[index] = <ListItemText key={index} {...directTextProps} size={size} {...textProps}>{childrenStrings}</ListItemText>;
24
+ }
25
+ __name(concatStringChildren, "concatStringChildren");
26
+ for (const child of allChildren) {
27
+ const last = nextChildren[nextChildren.length - 1];
28
+ const isString = typeof child === "string";
29
+ if (isString) {
30
+ if (lastIsString) {
31
+ last.push(child);
32
+ } else {
33
+ nextChildren.push([child]);
34
+ }
35
+ } else {
36
+ concatStringChildren();
37
+ nextChildren.push(child);
38
+ }
39
+ lastIsString = isString;
40
+ }
41
+ concatStringChildren();
42
+ return nextChildren;
43
+ }
44
+ __name(wrapStringChildrenInText, "wrapStringChildrenInText");
45
+ export {
46
+ wrapStringChildrenInText
47
+ };
package/package.json ADDED
@@ -0,0 +1,39 @@
1
+ {
2
+ "name": "@tamagui/list-item",
3
+ "version": "1.0.1-beta.100",
4
+ "sideEffects": [
5
+ "*.css"
6
+ ],
7
+ "source": "src/index.ts",
8
+ "types": "./types/index.d.ts",
9
+ "main": "dist/cjs",
10
+ "module": "dist/esm",
11
+ "module:jsx": "dist/jsx",
12
+ "files": [
13
+ "src",
14
+ "types",
15
+ "dist"
16
+ ],
17
+ "scripts": {
18
+ "build": "tamagui-build",
19
+ "watch": "tamagui-build --watch"
20
+ },
21
+ "dependencies": {
22
+ "@tamagui/core": "^1.0.1-beta.100",
23
+ "@tamagui/font-size": "^1.0.1-beta.100",
24
+ "@tamagui/helpers-tamagui": "^1.0.1-beta.100"
25
+ },
26
+ "peerDependencies": {
27
+ "react": "*",
28
+ "react-dom": "*"
29
+ },
30
+ "devDependencies": {
31
+ "@tamagui/build": "^1.0.1-beta.100",
32
+ "react": "*",
33
+ "react-dom": "*"
34
+ },
35
+ "publishConfig": {
36
+ "access": "public"
37
+ },
38
+ "gitHead": "a49cc7ea6b93ba384e77a4880ae48ac4a5635c14"
39
+ }
@@ -0,0 +1,200 @@
1
+ import {
2
+ FontSizeTokens,
3
+ GetProps,
4
+ Spacer,
5
+ TamaguiComponent,
6
+ ThemeableProps,
7
+ getSize,
8
+ getVariableValue,
9
+ styled,
10
+ themeable,
11
+ withStaticProperties,
12
+ } from '@tamagui/core'
13
+ import { getFontSize } from '@tamagui/font-size'
14
+ import { TextParentStyles, useGetThemedIcon } from '@tamagui/helpers-tamagui'
15
+ import { ThemeableStack, YStack } from '@tamagui/stacks'
16
+ import { SizableText, wrapChildrenInText } from '@tamagui/text'
17
+ import React, { FunctionComponent, forwardRef } from 'react'
18
+ import { View } from 'react-native'
19
+
20
+ // bugfix esbuild strips react jsx: 'preserve'
21
+ React['createElement']
22
+
23
+ type ListItemIconProps = { color?: string; size?: number }
24
+ type IconProp = JSX.Element | FunctionComponent<ListItemIconProps> | null
25
+
26
+ export type ListItemProps = Omit<TextParentStyles, 'TextComponent'> &
27
+ GetProps<typeof ListItemFrame> &
28
+ ThemeableProps & {
29
+ // add icon before, passes color and size automatically if Component
30
+ icon?: IconProp
31
+ // add icon after, passes color and size automatically if Component
32
+ iconAfter?: IconProp
33
+ // adjust icon relative to size
34
+ // default: -1
35
+ scaleIcon?: number
36
+ // make the spacing elements flex
37
+ spaceFlex?: number | boolean
38
+ // adjust internal space relative to icon size
39
+ scaleSpace?: number
40
+ // title
41
+ title?: React.ReactNode
42
+ // subtitle
43
+ subTitle?: React.ReactNode
44
+ }
45
+
46
+ export const ListItemFrame = styled(ThemeableStack, {
47
+ name: 'ListItem',
48
+ tag: 'li',
49
+ alignItems: 'center',
50
+ flexWrap: 'nowrap',
51
+ width: '100%',
52
+ borderColor: '$borderColor',
53
+ maxWidth: '100%',
54
+ overflow: 'hidden',
55
+ flexDirection: 'row',
56
+
57
+ variants: {
58
+ size: {
59
+ '...size': (val, { tokens }) => {
60
+ return {
61
+ minHeight: tokens.size[val],
62
+ paddingHorizontal: tokens.space[val],
63
+ }
64
+ },
65
+ },
66
+
67
+ active: {
68
+ true: {
69
+ hoverStyle: {
70
+ backgroundColor: '$background',
71
+ },
72
+ },
73
+ },
74
+
75
+ disabled: {
76
+ true: {
77
+ opacity: 0.5,
78
+ // TODO breaking types
79
+ pointerEvents: 'none' as any,
80
+ },
81
+ },
82
+ },
83
+
84
+ defaultVariants: {
85
+ size: '$4',
86
+ },
87
+ })
88
+
89
+ export const ListItemText = styled(SizableText, {
90
+ name: 'ListItemText',
91
+ color: '$color',
92
+ selectable: false,
93
+ flexGrow: 1,
94
+ flexShrink: 1,
95
+ ellipse: true,
96
+ })
97
+
98
+ export const ListItemSubtitle = styled(ListItemText, {
99
+ name: 'ListItemSubtitle',
100
+ color: '$colorPress',
101
+ marginTop: '$-2',
102
+ opacity: 0.65,
103
+ ellipse: true,
104
+ maxWidth: '100%',
105
+ size: '$3',
106
+ })
107
+
108
+ const ListItemTitle = styled(ListItemText, {
109
+ name: 'ListItemTitle',
110
+ ellipse: true,
111
+ })
112
+
113
+ const ListItemComponent = forwardRef((props: ListItemProps, ref) => {
114
+ // careful not to desctructure and re-order props, order is important
115
+ const {
116
+ children,
117
+ icon,
118
+ iconAfter,
119
+ noTextWrap,
120
+ theme: themeName,
121
+ space,
122
+ spaceFlex,
123
+ scaleIcon = 1,
124
+ scaleSpace = 1,
125
+ subTitle,
126
+
127
+ // text props
128
+ color,
129
+ fontWeight,
130
+ letterSpacing,
131
+ fontSize,
132
+ fontFamily,
133
+ textAlign,
134
+ textProps,
135
+ title,
136
+ ...rest
137
+ } = props as ListItemProps
138
+
139
+ const size = props.size || '$4'
140
+ const subtitleSizeToken = getSize(size, -3)
141
+ const subtitleSize = `$${subtitleSizeToken.key}` as FontSizeTokens
142
+ const iconSize = getFontSize(size) * scaleIcon
143
+ const getThemedIcon = useGetThemedIcon({ size: iconSize, color })
144
+ const [themedIcon, themedIconAfter] = [icon, iconAfter].map(getThemedIcon)
145
+ const spaceSize = getVariableValue(iconSize) * scaleSpace
146
+ const contents = wrapChildrenInText(ListItemText, props)
147
+
148
+ return (
149
+ <ListItemFrame fontFamily={fontFamily} ref={ref as any} {...rest}>
150
+ {themedIcon ? (
151
+ <>
152
+ {themedIcon}
153
+ <Spacer size={spaceSize} />
154
+ </>
155
+ ) : null}
156
+ {/* helper for common title/subtitle pttern */}
157
+ {Boolean(title || subTitle) ? (
158
+ <YStack flex={1}>
159
+ <ListItemTitle>{title}</ListItemTitle>
160
+ {subTitle ? (
161
+ typeof subTitle === 'string' ? (
162
+ // TODO can use theme but we need to standardize to alt themes
163
+ // or standardize on subtle colors in themes
164
+ <ListItemSubtitle size={subtitleSize}>{subTitle}</ListItemSubtitle>
165
+ ) : (
166
+ subTitle
167
+ )
168
+ ) : null}
169
+ {contents}
170
+ </YStack>
171
+ ) : (
172
+ contents
173
+ )}
174
+ {themedIconAfter ? (
175
+ <>
176
+ <Spacer flex size={spaceSize} />
177
+ {themedIconAfter}
178
+ </>
179
+ ) : null}
180
+ </ListItemFrame>
181
+ )
182
+ })
183
+
184
+ const ListItemInner: TamaguiComponent<ListItemProps, HTMLLIElement | View> =
185
+ ListItemFrame.extractable(themeable(ListItemComponent as any) as any, {
186
+ inlineProps: new Set([
187
+ // text props go here (can't really optimize them, but we never fully extract listItem anyway)
188
+ 'color',
189
+ 'fontWeight',
190
+ 'fontSize',
191
+ 'fontFamily',
192
+ 'letterSpacing',
193
+ 'textAlign',
194
+ ]),
195
+ })
196
+
197
+ export const ListItem = withStaticProperties(ListItemInner, {
198
+ Text: ListItemText,
199
+ Subtitle: ListItemSubtitle,
200
+ })
package/src/index.ts ADDED
@@ -0,0 +1 @@
1
+ export * from './ListItem'