Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(button): adds text container props to enable styling Text/string #42

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions constants/Layout.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@ const pixelRatio = PixelRatio.get();
export const baselineHeight = 680;
export const baselineWidth = 350;

export const defaultFontSize = 8 * pixelRatio
export const defaultFontSize = 4 * pixelRatio;

export default {
window: {
width,
height,
},
pixelRatio,
defaultFontSize,
isSmallDevice: width < 375,
};
71 changes: 56 additions & 15 deletions src/components/Button/Button.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React from 'react';
import React, { ReactNode } from 'react';
import { LayoutChangeEvent, PressableAndroidRippleConfig, Rect } from 'react-native';
// import UnstyledIcon from '@mdi/react';
// import { mdiLoading } from '@mdi/js';
Expand All @@ -13,13 +13,9 @@ import { FoundryContextType, useTheme } from '../../context';
import variants from '../../enums/variants';
// import Progress from '../Progress/Progress';
import { View, Button as ButtonElement, Text } from '../../baseElements';
import {
getFontColorFromVariant,
getBackgroundColorFromVariant,
disabledStyles,
} from '../../utils/color';
import { getFontColorFromVariant, getBackgroundColorFromVariant } from '../../utils/color';
import { SubcomponentPropsType } from '../commonTypes';
import { getShadowStyle } from '../../utils/styles';
import { getShadowStyle, getTextChildren } from '../../utils/styles';
// import InteractionFeedback from '../InteractionFeedback';
// import { InteractionFeedbackProps } from '../InteractionFeedback/InteractionFeedback';
import FeedbackTypes from '../../enums/feedbackTypes';
Expand All @@ -36,6 +32,13 @@ export type ButtonContainerProps = {
feedbackType: FeedbackTypes;
};

export type TextContainerProps = {
theme: FoundryContextType;
color: string;
variant: variants;
disabled: boolean;
};

export enum ButtonTypes {
button = 'button',
reset = 'reset',
Expand All @@ -44,14 +47,16 @@ export enum ButtonTypes {

export type ButtonProps = {
StyledContainer?: string & StyledComponentBase<any, {}, ButtonContainerProps>;
StyledTextContainer?: string & StyledComponentBase<any, {}, TextContainerProps>;
StyledLeftIconContainer?: StyledComponentBase<any, {}>;
StyledRightIconContainer?: StyledComponentBase<any, {}>;
containerProps?: SubcomponentPropsType;
textContainerProps?: SubcomponentPropsType;
iconPrefix?: string | JSX.Element;
iconSuffix?: string | JSX.Element;
isLoading?: boolean;
isProcessing?: boolean;
children?: string;
children?: ReactNode[];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this needs to be an array of ReactNodes - but I could be wrong.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or is this the only way we can do the textcontainer stuff?

elevation?: number;
variant?: variants;
type?: ButtonTypes;
Expand All @@ -66,6 +71,7 @@ export type ButtonProps = {
LoadingBar?: string & StyledComponentBase<any, {}>;
id?: string;
containerRef?: React.RefObject<HTMLButtonElement>;
textContainerRef?: React.RefObject<HTMLDivElement>;
leftIconContainerRef?: React.RefObject<HTMLDivElement>;
rightIconContainerRef?: React.RefObject<HTMLDivElement>;
loadingBarRef?: React.RefObject<HTMLDivElement>;
Expand Down Expand Up @@ -103,10 +109,21 @@ export const ButtonContainer: string & StyledComponentBase<any, {}, ButtonContai
border-width: 0px;
color: ${fontColor};
background-color: ${backgroundColor} !important;
&:hover {
background-color: darkred;
}
`;
`;
}}
`;

export const TextContainer: string & StyledComponentBase<any, {}, TextContainerProps> = styled(
Text,
)`
${({ theme, color, variant }: TextContainerProps) => {
const { colors, scale } = theme;
const fontColor = getFontColorFromVariant(variant, color, colors.background, colors.grayDark);
return `
font-size: ${remToPx(1, scale)}px;
padding: 0px;
color: ${fontColor};
`;
}}
`;

Expand Down Expand Up @@ -135,14 +152,16 @@ const RightIconContainer = styled(IconContainer)`

const Button = ({
StyledContainer = ButtonContainer,
StyledTextContainer = TextContainer,
StyledLeftIconContainer = LeftIconContainer,
StyledRightIconContainer = RightIconContainer,
containerProps = {},
textContainerProps = {},
iconPrefix,
iconSuffix,
isLoading,
isProcessing,
children,
children = [],
elevation = 0,
hitSlop = 6,
android_ripple,
Expand All @@ -156,6 +175,7 @@ const Button = ({
// LoadingBar = StyledProgress,
id,
containerRef,
textContainerRef,
leftIconContainerRef,
rightIconContainerRef,
loadingBarRef,
Expand Down Expand Up @@ -184,6 +204,11 @@ const Button = ({
...android_ripple,
};

const textChildren = getTextChildren(children);
// const nonTextChildren = React.Children.toArray(children).filter(child =>
// !textChildren.includes(child),
// );

// get everything we expose + anything consumer wants to send to container
const mergedContainerProps = {
'data-test-id': 'hsui-button',
Expand All @@ -205,6 +230,16 @@ const Button = ({

const { colors, scale } = theme;

const mergedTextContainerProps = {
'data-test-id': 'hsui-button-text',
color: containerColor,
variant,
type,
disabled,
theme,
...textContainerProps,
};

const buttonContent = isLoading ? (
// <LoadingBar ref={loadingBarRef} />
<View />
Expand All @@ -224,8 +259,13 @@ const Button = ({
<UnstyledIcon path={mdiLoading} size={`${remToPx(1, scale)}px`} spin={1} />
</StyledLeftIconContainer>
)}
{/* // TODO: make Text an exported subcomponent */}
<Text style={{ color: fontColor }}>{children}</Text>
{textChildren && (
<StyledTextContainer ref={textContainerRef} {...mergedTextContainerProps}>
{textChildren}
</StyledTextContainer>
)}
{/* TODO: decide how/if we want to support them passing in a mixture text/nonText children */}
{/* {nonTextChildren && <View>{nonTextChildren}</View>} */}
{iconSuffix &&
(typeof iconSuffix === 'string' ? (
<StyledRightIconContainer hasContent={hasContent} ref={rightIconContainerRef}>
Expand All @@ -247,6 +287,7 @@ const Button = ({
};

Button.Container = ButtonContainer;
Button.TextContainer = TextContainer;
Button.ButtonTypes = ButtonTypes;
// Button.LoadingBar = StyledProgress;
Button.LeftIconContainer = LeftIconContainer;
Expand Down
18 changes: 13 additions & 5 deletions src/utils/styles.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Platform } from 'react-native';
import React, { ReactNode } from 'react';
import { Platform, Text } from 'react-native';
import { parseToRgb } from 'polished';
import variants from '../enums/variants';
import { getFontColorFromVariant } from './color';
Expand All @@ -21,11 +22,18 @@ export type ElevationValues = {
* @param {number} [factor = 1] - The factor to scale by
* @returns {number} The scaled px value
*/
export const remToPx = (size: number, factor = 1) => {
if (!size) return 0;
export const remToPx = (size: number, factor = 1) =>
defaultFontSize * (size + factor * ((Layout.window.width / baselineWidth) * size - size));

return defaultFontSize * (size + factor * ((Layout.window.width / baselineWidth) * size - size));
};
/**
* Gets all text container stylable children
* @param {ReactNode []} children - The children object
* @returns {ReactNode []} The children that are capable of being directly nested in a Text container
*/
export const getTextChildren = (children: ReactNode[]): ReactNode[] =>
React.Children.toArray(children).filter(
child => typeof child === 'string' || (child && child.type && child.type === Text),
);

/**
* Calculates the values for shadows based on the provided elevation
Expand Down
4 changes: 1 addition & 3 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -13768,7 +13768,7 @@ react-sizeme@^2.6.7:
shallowequal "^1.1.0"
throttle-debounce "^2.1.0"

react-spring@^9.2.4:
react-spring@^9.2.3:
version "9.2.4"
resolved "https://registry.yarnpkg.com/react-spring/-/react-spring-9.2.4.tgz#9d89b0321664d594f957dca9459b13d94b3dfa39"
integrity sha512-bMjbyTW0ZGd+/h9cjtohLqCwOGqX2OuaTvalOVfLCGmhzEg/u3GgopI3LAm4UD2Br3MNdVdGgNVoESg4MGqKFQ==
Expand Down Expand Up @@ -16191,10 +16191,8 @@ watchpack@^1.7.4:
resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.7.5.tgz#1267e6c55e0b9b5be44c2023aed5437a2c26c453"
integrity sha512-9P3MWk6SrKjHsGkLT2KHXdQ/9SNkyoJbabxnKOoJepsvJjJG8uYTR3yTPxPQvNDI3w4Nz1xnE0TLHK4RIVe/MQ==
dependencies:
chokidar "^3.4.1"
graceful-fs "^4.1.2"
neo-async "^2.5.0"
watchpack-chokidar2 "^2.0.1"
optionalDependencies:
chokidar "^3.4.1"
watchpack-chokidar2 "^2.0.1"
Expand Down