@tamagui/button
Version:
220 lines (219 loc) • 6.6 kB
JavaScript
import { getFontSize } from "@tamagui/font-size";
import { getButtonSized } from "@tamagui/get-button-sized";
import { withStaticProperties } from "@tamagui/helpers";
import { useGetThemedIcon } from "@tamagui/helpers-tamagui";
import { ButtonNestingContext, ThemeableStack } from "@tamagui/stacks";
import { SizableText, wrapChildrenInText } from "@tamagui/text";
import {
createStyledContext,
getVariableValue,
spacedChildren,
styled,
useProps
} from "@tamagui/web";
import { useContext } from "react";
import { jsx } from "react/jsx-runtime";
const ButtonContext = createStyledContext({
// keeping these here means they work with styled() passing down color to text
color: void 0,
ellipse: void 0,
fontFamily: void 0,
fontSize: void 0,
fontStyle: void 0,
fontWeight: void 0,
letterSpacing: void 0,
maxFontSizeMultiplier: void 0,
size: void 0,
textAlign: void 0,
variant: void 0
}), BUTTON_NAME = "Button", ButtonFrame = styled(ThemeableStack, {
name: BUTTON_NAME,
tag: "button",
context: ButtonContext,
role: "button",
focusable: !0,
variants: {
unstyled: {
false: {
size: "$true",
justifyContent: "center",
alignItems: "center",
flexWrap: "nowrap",
flexDirection: "row",
cursor: "pointer",
hoverTheme: !0,
pressTheme: !0,
backgrounded: !0,
borderWidth: 1,
borderColor: "transparent",
focusVisibleStyle: {
outlineColor: "$outlineColor",
outlineStyle: "solid",
outlineWidth: 2
}
}
},
variant: {
outlined: {
backgroundColor: "transparent",
borderWidth: 2,
borderColor: "$borderColor",
hoverStyle: {
backgroundColor: "transparent",
borderColor: "$borderColorHover"
},
pressStyle: {
backgroundColor: "transparent",
borderColor: "$borderColorPress"
},
focusVisibleStyle: {
backgroundColor: "transparent",
borderColor: "$borderColorFocus"
}
}
},
size: {
"...size": getButtonSized,
":number": getButtonSized
},
disabled: {
true: {
pointerEvents: "none"
}
}
},
defaultVariants: {
unstyled: process.env.TAMAGUI_HEADLESS === "1"
}
}), ButtonText = styled(SizableText, {
name: "Button",
context: ButtonContext,
variants: {
unstyled: {
false: {
userSelect: "none",
cursor: "pointer",
// flexGrow 1 leads to inconsistent native style where text pushes to start of view
flexGrow: 0,
flexShrink: 1,
ellipse: !0,
color: "$color"
}
}
},
defaultVariants: {
unstyled: process.env.TAMAGUI_HEADLESS === "1"
}
}), ButtonIcon = (props) => {
const { children, scaleIcon = 1 } = props, { size, color } = useContext(ButtonContext), iconSize = (typeof size == "number" ? size * 0.5 : getFontSize(size)) * scaleIcon;
return useGetThemedIcon({ size: iconSize, color })(children);
}, ButtonComponent = ButtonFrame.styleable(
function(props, ref) {
const { props: buttonProps } = useButton(props);
return /* @__PURE__ */ jsx(ButtonFrame, { ...buttonProps, ref });
}
), buttonStaticConfig = {
inlineProps: /* @__PURE__ */ new Set([
// text props go here (can't really optimize them, but we never fully extract button anyway)
// may be able to remove this entirely, as the compiler / runtime have gotten better
"color",
"fontWeight",
"fontSize",
"fontFamily",
"fontStyle",
"letterSpacing",
"textAlign",
"unstyled"
])
}, Button2 = withStaticProperties(ButtonComponent, {
Text: ButtonText,
Icon: ButtonIcon
});
function useButton({ textProps, ...propsIn }, { Text = Button2.Text } = { Text: Button2.Text }) {
const isNested = useContext(ButtonNestingContext), propsActive = useProps(propsIn, {
noNormalize: !0,
noExpand: !0
}), {
icon,
iconAfter,
space,
spaceFlex,
scaleIcon = 1,
scaleSpace = 0.66,
separator,
noTextWrap,
fontFamily,
fontSize,
fontWeight,
fontStyle,
letterSpacing,
tag,
ellipse,
maxFontSizeMultiplier,
...restProps
} = propsActive, size = propsActive.size || (propsActive.unstyled ? void 0 : "$true"), color = propsActive.color, iconSize = (typeof size == "number" ? size * 0.5 : getFontSize(size, {
font: fontFamily?.[0] === "$" ? fontFamily : void 0
})) * scaleIcon, getThemedIcon = useGetThemedIcon({
size: iconSize,
color
}), [themedIcon, themedIconAfter] = [icon, iconAfter].map(getThemedIcon), spaceSize = space ?? getVariableValue(iconSize) * scaleSpace, contents = noTextWrap ? [propsIn.children] : wrapChildrenInText(
Text,
{
children: propsIn.children,
fontFamily,
fontSize,
textProps,
fontWeight,
fontStyle,
letterSpacing,
ellipse,
maxFontSizeMultiplier
},
Text === ButtonText && propsActive.unstyled !== !0 ? {
unstyled: process.env.TAMAGUI_HEADLESS === "1",
size
} : void 0
), inner = spacedChildren({
// a bit arbitrary but scaling to font size is necessary so long as button does
space: spaceSize,
spaceFlex,
separator,
direction: propsActive.flexDirection === "column" || propsActive.flexDirection === "column-reverse" ? "vertical" : "horizontal",
children: [themedIcon, ...contents, themedIconAfter]
}), props = {
size,
...propsIn.disabled && {
// in rnw - false still has keyboard tabIndex, undefined = not actually focusable
focusable: void 0,
// even with tabIndex unset, it will keep focusVisibleStyle on web so disable it here
focusVisibleStyle: {
borderColor: "$background"
}
},
// fixes SSR issue + DOM nesting issue of not allowing button in button
tag: tag ?? (isNested ? "span" : (
// defaults to <a /> when accessibilityRole = link
// see https://github.com/tamagui/tamagui/issues/505
propsActive.accessibilityRole === "link" || propsActive.role === "link" ? "a" : "button"
)),
...restProps,
children: /* @__PURE__ */ jsx(ButtonNestingContext.Provider, { value: !0, children: inner }),
// forces it to be a runtime pressStyle so it passes through context text colors
disableClassName: !0
};
return {
spaceSize,
isNested,
props
};
}
export {
Button2 as Button,
ButtonContext,
ButtonFrame,
ButtonIcon,
ButtonText,
buttonStaticConfig,
useButton
};
//# sourceMappingURL=Button.js.map