@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.
- package/dist/cjs/Button.js +249 -0
- package/dist/cjs/Button.js.map +7 -0
- package/dist/cjs/ListItem.js +203 -0
- package/dist/cjs/ListItem.js.map +7 -0
- package/dist/cjs/index.js +18 -0
- package/dist/cjs/index.js.map +7 -0
- package/dist/cjs/useCurrentColor.js +41 -0
- package/dist/cjs/useCurrentColor.js.map +7 -0
- package/dist/cjs/useGetThemedIcon.js +45 -0
- package/dist/cjs/useGetThemedIcon.js.map +7 -0
- package/dist/cjs/wrapStringChildrenInText.js +111 -0
- package/dist/cjs/wrapStringChildrenInText.js.map +7 -0
- package/dist/esm/Button.js +190 -0
- package/dist/esm/Button.js.map +7 -0
- package/dist/esm/ListItem.js +183 -0
- package/dist/esm/ListItem.js.map +7 -0
- package/dist/esm/index.js +2 -0
- package/dist/esm/index.js.map +7 -0
- package/dist/esm/useCurrentColor.js +19 -0
- package/dist/esm/useCurrentColor.js.map +7 -0
- package/dist/esm/useGetThemedIcon.js +20 -0
- package/dist/esm/useGetThemedIcon.js.map +7 -0
- package/dist/esm/wrapStringChildrenInText.js +53 -0
- package/dist/esm/wrapStringChildrenInText.js.map +7 -0
- package/dist/jsx/Button.js +177 -0
- package/dist/jsx/ListItem.js +139 -0
- package/dist/jsx/ListItem.js.map +7 -0
- package/dist/jsx/index.js +2 -0
- package/dist/jsx/index.js.map +7 -0
- package/dist/jsx/useCurrentColor.js +18 -0
- package/dist/jsx/useGetThemedIcon.js +19 -0
- package/dist/jsx/wrapStringChildrenInText.js +47 -0
- package/package.json +39 -0
- package/src/ListItem.tsx +200 -0
- package/src/index.ts +1 -0
- package/types/Button.d.ts +127 -0
- package/types/Button.d.ts.map +1 -0
- package/types/ListItem.d.ts +278 -0
- package/types/ListItem.d.ts.map +1 -0
- package/types/index.d.ts +2 -0
- package/types/index.d.ts.map +1 -0
- package/types/useCurrentColor.d.ts +5 -0
- package/types/useCurrentColor.d.ts.map +1 -0
- package/types/useGetThemedIcon.d.ts +6 -0
- package/types/useGetThemedIcon.d.ts.map +1 -0
- package/types/wrapStringChildrenInText.d.ts +8 -0
- 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,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
|
+
}
|
package/src/ListItem.tsx
ADDED
|
@@ -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'
|