diff --git a/.changeset/afraid-monkeys-eat.md b/.changeset/afraid-monkeys-eat.md new file mode 100644 index 00000000..ec5ef376 --- /dev/null +++ b/.changeset/afraid-monkeys-eat.md @@ -0,0 +1,5 @@ +--- +"@cube-dev/ui-kit": minor +--- + +[CUK-72](https://cubedevinc.atlassian.net/jira/software/projects/CUK/boards/3?selectedIssue=CUK-72) Move all style engine logic into a single folder `tasty` and export new `tasty()` helper as `styled` replacement but with simplified and optimized API. diff --git a/src/App.tsx b/src/App.tsx index fe0b9a05..efd26143 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,24 +1,15 @@ import { useState } from 'react'; -import { - Base, - Grid, - TopBar, - Title, - Space, - LoadingAnimation, - Block, -} from './index'; +import { Base, Block, Grid, LoadingAnimation, Space, Title } from './index'; import { Button } from './components/actions'; // import ResponsiveProvider from './providers/Responsive'; -import { color } from './utils/colors'; +// import { Modal } from './components/organisms/Modal/Modal'; +// import { notification } from './services/notification'; +import { color, StyleProvider } from './tasty'; import { Card } from './components/content/Card/Card'; import { Flex } from './components/layout/Flex'; import { Base64Upload } from './components/other/Base64Upload/Base64Upload'; import { Link } from './components/navigation/Link/Link'; -// import { Modal } from './components/organisms/Modal/Modal'; -// import { notification } from './services/notification'; -import { StyleProvider } from './providers/StylesProvider'; -import { Form, useForm, Field } from './components/forms/Form'; +import { Field, Form, useForm } from './components/forms/Form'; import { TextInput } from './components/forms/TextInput/TextInput'; import { Provider } from './provider'; import { GridProvider } from './components/GridProvider'; @@ -145,7 +136,6 @@ function App() { Cube.dev - {}} /> css); /** - * @deprecated consider using styled() instead + * @deprecated consider using tasty() instead */ const Base = function Base( allProps: AllBaseProps, @@ -85,7 +87,7 @@ const Base = function Base( }; /** - * @deprecated consider using styled() instead + * @deprecated consider using tasty() instead */ const _Base = forwardRef(Base); export { _Base as Base }; diff --git a/src/components/Block.tsx b/src/components/Block.tsx index a4ad9b43..5d6c2c47 100644 --- a/src/components/Block.tsx +++ b/src/components/Block.tsx @@ -1,23 +1,28 @@ import { forwardRef } from 'react'; -import { CONTAINER_STYLES } from '../styles/list'; -import { extractStyles } from '../utils/styles'; -import { filterBaseProps } from '../utils/filterBaseProps'; -import { AllBaseProps, ContainerStyleProps } from './types'; -import { Base } from './Base'; +import { + AllBaseProps, + CONTAINER_STYLES, + ContainerStyleProps, + extractStyles, + filterBaseProps, + tasty, +} from '../tasty'; -export const CUBE_BLOCK_STYLES = { - display: 'block', -}; +const RawBlock = tasty({ + styled: { + display: 'block', + }, +}); export interface CubeBlockProps extends Omit, ContainerStyleProps {} export const Block = forwardRef((props: CubeBlockProps, ref) => { - const styles = extractStyles(props, CONTAINER_STYLES, CUBE_BLOCK_STYLES); + const styles = extractStyles(props, CONTAINER_STYLES); return ( - ); }, diff --git a/src/components/actions/Button/Button.tsx b/src/components/actions/Button/Button.tsx index c6038d12..4b47c99b 100644 --- a/src/components/actions/Button/Button.tsx +++ b/src/components/actions/Button/Button.tsx @@ -1,9 +1,8 @@ import { forwardRef, ReactNode } from 'react'; import { Action, CubeActionProps } from '../Action'; import { LoadingOutlined } from '@ant-design/icons'; -import { useContextStyles } from '../../../providers/StylesProvider'; +import { Styles, useContextStyles } from '../../../tasty'; import { FocusableRef } from '@react-types/shared'; -import { Styles } from '../../../styles/types'; import { accessibilityWarning } from '../../../utils/warnings'; export interface CubeButtonProps extends CubeActionProps { @@ -278,18 +277,8 @@ const DEFAULT_STYLES = { export const Button = forwardRef( (allProps: CubeButtonProps, ref: FocusableRef) => { - let { - type, - size, - label, - styles, - children, - theme, - css, - icon, - mods, - ...props - } = allProps; + let { type, size, label, styles, children, theme, icon, mods, ...props } = + allProps; const isDisabled = props.isDisabled; const isLoading = props.isLoading; @@ -339,7 +328,6 @@ export const Button = forwardRef( return ( { let { styles, ...otherProps } = useSlotProps(props, 'buttonGroup'); diff --git a/src/components/content/ActiveZone/ActiveZone.tsx b/src/components/content/ActiveZone/ActiveZone.tsx index 7d1b3df0..947b3fdb 100644 --- a/src/components/content/ActiveZone/ActiveZone.tsx +++ b/src/components/content/ActiveZone/ActiveZone.tsx @@ -1,21 +1,22 @@ import { forwardRef, MouseEventHandler } from 'react'; import { useHover } from '@react-aria/interactions'; import { mergeProps } from '../../../utils/react'; -import { CONTAINER_STYLES, TEXT_STYLES } from '../../../styles/list'; -import { Base } from '../../Base'; -import { extractStyles } from '../../../utils/styles'; -import { filterBaseProps } from '../../../utils/filterBaseProps'; import { BaseProps, BaseStyleProps, + CONTAINER_STYLES, ContainerStyleProps, + extractStyles, + filterBaseProps, + Styles, TagNameProps, + TEXT_STYLES, TextStyleProps, -} from '../../types'; -import { Styles } from '../../../styles/types'; +} from '../../../tasty'; +import { Base } from '../../Base'; import { useFocusableRef } from '@react-spectrum/utils'; import { FocusableOptions, useFocusable } from '@react-aria/focus'; -import { useFocus } from '../../../utils/interactions'; +import { useFocus } from '../../../utils/react/interactions'; export interface CubeActiveZoneProps extends BaseProps, diff --git a/src/components/content/Alert/types.ts b/src/components/content/Alert/types.ts index 2b5f30b4..ce6e2b76 100644 --- a/src/components/content/Alert/types.ts +++ b/src/components/content/Alert/types.ts @@ -1,4 +1,4 @@ -import { BaseProps, ContainerStyleProps, TextStyleProps } from '../../types'; +import { BaseProps, ContainerStyleProps, TextStyleProps } from '../../../tasty'; import THEMES from '../../../data/themes'; export interface CubeAlertProps diff --git a/src/components/content/Alert/use-alert.ts b/src/components/content/Alert/use-alert.ts index 4822ab29..e5b7ba61 100644 --- a/src/components/content/Alert/use-alert.ts +++ b/src/components/content/Alert/use-alert.ts @@ -1,8 +1,11 @@ -import { extractStyles } from '../../../utils/styles'; +import { + CONTAINER_STYLES, + extractStyles, + filterBaseProps, + TEXT_STYLES, +} from '../../../tasty'; import { useDeprecationWarning } from '../../../_internal'; import { CubeAlertProps } from './types'; -import { CONTAINER_STYLES, TEXT_STYLES } from '../../../styles/list'; -import { filterBaseProps } from '../../../utils/filterBaseProps'; const STYLE_LIST = [...CONTAINER_STYLES, ...TEXT_STYLES] as const; diff --git a/src/components/content/Avatar/Avatar.tsx b/src/components/content/Avatar/Avatar.tsx index 09a869d3..6c6ec825 100644 --- a/src/components/content/Avatar/Avatar.tsx +++ b/src/components/content/Avatar/Avatar.tsx @@ -1,10 +1,13 @@ import { forwardRef, ReactNode } from 'react'; import { Base } from '../../Base'; -import { CONTAINER_STYLES } from '../../../styles/list'; -import { extractStyles } from '../../../utils/styles'; -import { filterBaseProps } from '../../../utils/filterBaseProps'; -import { BaseProps, ContainerStyleProps } from '../../types'; -import { Styles } from '../../../styles/types'; +import { + BaseProps, + CONTAINER_STYLES, + ContainerStyleProps, + extractStyles, + filterBaseProps, + Styles, +} from '../../../tasty'; const DEFAULT_STYLES = { display: 'grid', diff --git a/src/components/content/Badge/Badge.tsx b/src/components/content/Badge/Badge.tsx index a6c0c5ac..6779b489 100644 --- a/src/components/content/Badge/Badge.tsx +++ b/src/components/content/Badge/Badge.tsx @@ -1,14 +1,17 @@ import { forwardRef } from 'react'; import THEMES from '../../../data/themes'; -import { CONTAINER_STYLES } from '../../../styles/list'; -import { extractStyles } from '../../../utils/styles'; -import { filterBaseProps } from '../../../utils/filterBaseProps'; -import { BaseProps, ContainerStyleProps } from '../../types'; -import { styled } from '../../../styled'; +import { + BaseProps, + CONTAINER_STYLES, + ContainerStyleProps, + extractStyles, + filterBaseProps, + tasty, +} from '../../../tasty'; -const RawBadge = styled({ - name: 'Badge', - props: { role: 'region' }, +const RawBadge = tasty({ + qa: 'Badge', + role: 'region', styles: { display: 'inline-flex', placeContent: 'center', diff --git a/src/components/content/Card/Card.tsx b/src/components/content/Card/Card.tsx index 95db730b..bfa884ec 100644 --- a/src/components/content/Card/Card.tsx +++ b/src/components/content/Card/Card.tsx @@ -1,9 +1,12 @@ import { forwardRef } from 'react'; import { Base } from '../../Base'; -import { CONTAINER_STYLES } from '../../../styles/list'; -import { extractStyles } from '../../../utils/styles'; -import { filterBaseProps } from '../../../utils/filterBaseProps'; -import { BaseProps, ContainerStyleProps } from '../../types'; +import { + BaseProps, + CONTAINER_STYLES, + ContainerStyleProps, + extractStyles, + filterBaseProps, +} from '../../../tasty'; const DEFAULT_STYLES = { display: 'block', diff --git a/src/components/content/Content.tsx b/src/components/content/Content.tsx index 3935535b..9a9397d0 100644 --- a/src/components/content/Content.tsx +++ b/src/components/content/Content.tsx @@ -1,16 +1,21 @@ import { forwardRef } from 'react'; -import { styled } from '../../styled'; -import { CONTAINER_STYLES, TEXT_STYLES } from '../../styles/list'; -import { extractStyles } from '../../utils/styles'; -import { filterBaseProps } from '../../utils/filterBaseProps'; +import { + BaseProps, + CONTAINER_STYLES, + ContainerStyleProps, + extractStyles, + filterBaseProps, + tasty, + TEXT_STYLES, + TextStyleProps, +} from '../../tasty'; import { useSlotProps } from '../../utils/react'; -import { BaseProps, ContainerStyleProps, TextStyleProps } from '../types'; const STYLE_LIST = [...CONTAINER_STYLES, ...TEXT_STYLES]; -const RawContent = styled({ - name: 'Content', - tag: 'section', +const RawContent = tasty({ + qa: 'Content', + as: 'section', styles: { gridArea: 'content', preset: 'p3', @@ -21,9 +26,6 @@ const RawContent = styled({ overflow: 'auto', styledScrollbar: true, }, - props: { - 'data-id': 'Content', - }, }); export interface CubeContentProps diff --git a/src/components/content/CopySnippet/CopySnippet.tsx b/src/components/content/CopySnippet/CopySnippet.tsx index 2f715a41..66dab71c 100644 --- a/src/components/content/CopySnippet/CopySnippet.tsx +++ b/src/components/content/CopySnippet/CopySnippet.tsx @@ -1,18 +1,16 @@ import copy from 'clipboard-copy'; -import { Button } from '../../actions'; +import { Action, Button } from '../../actions'; import { Card, CubeCardProps } from '../Card/Card'; import { Grid } from '../../layout/Grid'; -import { styled } from '../../../styled'; +import { Styles, tasty } from '../../../tasty'; import { CubePrismCodeProps, PrismCode, } from '../../content/PrismCode/PrismCode'; import { notification } from '../../../services/notification'; import { CopyOutlined } from '@ant-design/icons'; -import { Styles } from '../../../styles/types'; import { CSSProperties } from 'react'; import { TooltipTrigger } from '../../overlays/Tooltip/TooltipTrigger'; -import { Action } from '../../actions'; import { Tooltip } from '../../overlays/Tooltip/Tooltip'; const POSITION_ACTION: CSSProperties = { @@ -22,7 +20,7 @@ const POSITION_ACTION: CSSProperties = { zIndex: 1, }; -const StyledBlock = styled({ +const StyledBlock = tasty({ styles: { position: 'relative', overflow: { @@ -45,7 +43,7 @@ const StyledBlock = styled({ }, }); -const ButtonContainer = styled({ +const ButtonContainer = tasty({ styles: { position: 'relative', diff --git a/src/components/content/Divider.tsx b/src/components/content/Divider.tsx index 15e2e8af..0835c55e 100644 --- a/src/components/content/Divider.tsx +++ b/src/components/content/Divider.tsx @@ -1,10 +1,15 @@ import { forwardRef } from 'react'; import { Base } from '../Base'; -import { OUTER_STYLES, BASE_STYLES, COLOR_STYLES } from '../../styles/list'; -import { extractStyles } from '../../utils/styles'; -import { filterBaseProps } from '../../utils/filterBaseProps'; +import { + BASE_STYLES, + BaseProps, + COLOR_STYLES, + extractStyles, + filterBaseProps, + OUTER_STYLES, + OuterStyleProps, +} from '../../tasty'; import { useSlotProps } from '../../utils/react'; -import { BaseProps, OuterStyleProps } from '../types'; const STYLE_LIST = [...OUTER_STYLES, ...BASE_STYLES, ...COLOR_STYLES]; diff --git a/src/components/content/Footer.tsx b/src/components/content/Footer.tsx index a9cff1ee..cb618fc3 100644 --- a/src/components/content/Footer.tsx +++ b/src/components/content/Footer.tsx @@ -1,23 +1,26 @@ import { forwardRef } from 'react'; -import { CONTAINER_STYLES, TEXT_STYLES } from '../../styles/list'; -import { extractStyles } from '../../utils/styles'; -import { filterBaseProps } from '../../utils/filterBaseProps'; +import { + BaseProps, + CONTAINER_STYLES, + ContainerStyleProps, + extractStyles, + filterBaseProps, + tasty, + TEXT_STYLES, + TextStyleProps, +} from '../../tasty'; import { useSlotProps } from '../../utils/react'; -import { BaseProps, ContainerStyleProps, TextStyleProps } from '../types'; -import { styled } from '../../styled'; const STYLE_LIST = [...CONTAINER_STYLES, ...TEXT_STYLES]; -const RawFooter = styled({ - name: 'Footer', +const RawFooter = tasty({ + qa: 'Footer', + 'data-id': 'Footer', styles: { gridArea: 'footer', display: 'block', flow: 'column', }, - props: { - 'data-id': 'Footer', - }, }); export interface CubeFooterProps diff --git a/src/components/content/Header.tsx b/src/components/content/Header.tsx index fb14fbbf..bcfa419a 100644 --- a/src/components/content/Header.tsx +++ b/src/components/content/Header.tsx @@ -1,17 +1,21 @@ import { forwardRef } from 'react'; -import { styled } from '../../styled'; -import { CONTAINER_STYLES, TEXT_STYLES } from '../../styles/list'; -import { extractStyles } from '../../utils/styles'; -import { filterBaseProps } from '../../utils/filterBaseProps'; +import { + BaseProps, + CONTAINER_STYLES, + ContainerStyleProps, + extractStyles, + filterBaseProps, + tasty, + TEXT_STYLES, + TextStyleProps, +} from '../../tasty'; import { useSlotProps } from '../../utils/react'; -import { BaseProps, ContainerStyleProps, TextStyleProps } from '../types'; const STYLE_LIST = [...CONTAINER_STYLES, ...TEXT_STYLES]; -const RawHeader = styled({ - name: 'Header', - tag: 'header', - props: { 'data-id': 'Header' }, +const RawHeader = tasty({ + qa: 'Header', + as: 'header', styles: { display: 'block', gridArea: 'header', diff --git a/src/components/content/Paragraph.tsx b/src/components/content/Paragraph.tsx index a7162297..ad139b36 100644 --- a/src/components/content/Paragraph.tsx +++ b/src/components/content/Paragraph.tsx @@ -1,9 +1,12 @@ import { forwardRef } from 'react'; import { CubeTextProps, Text } from './Text'; -import { CONTAINER_STYLES, TEXT_STYLES } from '../../styles/list'; -import { extractStyles } from '../../utils/styles'; -import { ContainerStyleProps } from '../types'; -import { Styles } from '../../styles/types'; +import { + CONTAINER_STYLES, + ContainerStyleProps, + extractStyles, + Styles, + TEXT_STYLES, +} from '../../tasty'; const DEFAULT_STYLES: Styles = { preset: 'p3', diff --git a/src/components/content/Placeholder/Placeholder.tsx b/src/components/content/Placeholder/Placeholder.tsx index e8d1b829..f8a49bca 100644 --- a/src/components/content/Placeholder/Placeholder.tsx +++ b/src/components/content/Placeholder/Placeholder.tsx @@ -1,10 +1,13 @@ import { forwardRef } from 'react'; import { Base } from '../../Base'; -import { CONTAINER_STYLES } from '../../../styles/list'; -import { extractStyles } from '../../../utils/styles'; -import { filterBaseProps } from '../../../utils/filterBaseProps'; -import { Styles } from '../../../styles/types'; -import { BaseProps, ContainerStyleProps } from '../../types'; +import { + BaseProps, + CONTAINER_STYLES, + ContainerStyleProps, + extractStyles, + filterBaseProps, + Styles, +} from '../../../tasty'; const DEFAULT_STYLES: Styles = { display: 'block', diff --git a/src/components/content/PrismCode/PrismCode.tsx b/src/components/content/PrismCode/PrismCode.tsx index b52bf578..f20b1211 100644 --- a/src/components/content/PrismCode/PrismCode.tsx +++ b/src/components/content/PrismCode/PrismCode.tsx @@ -1,15 +1,18 @@ import { forwardRef, useEffect } from 'react'; import Prism from 'prismjs'; -import { BaseProps, ContainerStyleProps } from '../../types'; -import { styled } from '../../../styled'; -import { Styles } from '../../../styles/types'; -import { CONTAINER_STYLES } from '../../../styles/list'; +import { + BaseProps, + CONTAINER_STYLES, + ContainerStyleProps, + Styles, + tasty, +} from '../../../tasty'; -const RawPre = styled({ - name: 'CodeBlock', - tag: 'pre', +const RawPre = tasty({ + as: 'pre', + qa: 'CodeBlock', styleProps: CONTAINER_STYLES.concat([]), - props: { className: 'cube-prism-code' }, + className: 'cube-prism-code', styles: { margin: 0, diff --git a/src/components/content/Result/Result.tsx b/src/components/content/Result/Result.tsx index 53c50b3a..802c0c30 100644 --- a/src/components/content/Result/Result.tsx +++ b/src/components/content/Result/Result.tsx @@ -7,11 +7,14 @@ import { } from '@ant-design/icons'; import { Title } from '../Title'; -import { styled } from '../../../styled'; -import { CONTAINER_STYLES } from '../../../styles/list'; -import { BaseProps, ContainerStyleProps } from '../../types'; -import { filterBaseProps } from '../../../utils/filterBaseProps'; -import { extractStyles } from '../../../utils/styles'; +import { + BaseProps, + CONTAINER_STYLES, + ContainerStyleProps, + extractStyles, + filterBaseProps, + tasty, +} from '../../../tasty'; import { wrapNodeIfPlain } from '../../../utils/react'; export interface CubeResultProps extends BaseProps, ContainerStyleProps { @@ -54,9 +57,9 @@ type StatusIconMap = Record< } >; -const Container = styled({ - name: 'ResultContainer', - tag: 'section', +const Container = tasty({ + qa: 'Result_Container', + as: 'section', styles: { display: 'flex', flow: 'column', @@ -78,7 +81,7 @@ const Container = styled({ }, }); -const IconWrapper = styled({ +const IconWrapper = tasty({ styles: { fontSize: '10x', }, diff --git a/src/components/content/Skeleton/Skeleton.tsx b/src/components/content/Skeleton/Skeleton.tsx index b5e3484d..e3e2b025 100644 --- a/src/components/content/Skeleton/Skeleton.tsx +++ b/src/components/content/Skeleton/Skeleton.tsx @@ -2,7 +2,7 @@ import { CubePlaceholderProps, Placeholder } from '../Placeholder/Placeholder'; import { Flow } from '../../layout/Flow'; import { Space } from '../../layout/Space'; import { CubeGridProps, Grid } from '../../layout/Grid'; -import { BaseProps, ContainerStyleProps } from '../../types'; +import { BaseProps, ContainerStyleProps } from '../../../tasty'; const LAYOUT_MAP = { page({ lines, children, ...props }) { @@ -13,8 +13,8 @@ const LAYOUT_MAP = { - {children - || Array(lines || 5) + {children || + Array(lines || 5) .fill(0) .map((item, i) => )} @@ -24,8 +24,8 @@ const LAYOUT_MAP = { content({ children, lines, ...props }) { return ( - {children - || Array(lines || 5) + {children || + Array(lines || 5) .fill(0) .map((item, i) => )} @@ -92,8 +92,8 @@ const LAYOUT_MAP = { ))} - {children - || Array(lines || 5) + {children || + Array(lines || 5) .fill(0) .map((item, i) => )} diff --git a/src/components/content/Tag/Tag.tsx b/src/components/content/Tag/Tag.tsx index 9e8c4161..5e620b27 100644 --- a/src/components/content/Tag/Tag.tsx +++ b/src/components/content/Tag/Tag.tsx @@ -1,18 +1,21 @@ import { forwardRef } from 'react'; import THEMES from '../../../data/themes'; -import { CONTAINER_STYLES } from '../../../styles/list'; -import { extractStyles } from '../../../utils/styles'; -import { filterBaseProps } from '../../../utils/filterBaseProps'; -import { BaseProps, ContainerStyleProps } from '../../types'; -import { Styles } from '../../../styles/types'; +import { + BaseProps, + CONTAINER_STYLES, + ContainerStyleProps, + extractStyles, + filterBaseProps, + tasty, +} from '../../../tasty'; import { Action } from '../../actions/Action'; import { Suffix } from '../../layout/Suffix'; import { Block } from '../../Block'; import { CloseOutlined } from '@ant-design/icons'; -import { styled } from '../../../styled'; -const RawTag = styled({ - name: 'Tag', +const RawTag = tasty({ + qa: 'Tag', + role: 'status', styles: { position: 'relative', display: 'inline-flex', @@ -53,28 +56,32 @@ const RawTag = styled({ }, {}), }, }, - props: { role: 'status' }, }); -const DEFAULT_CONTENT_STYLES: Styles = { - width: 'max 100%', - textOverflow: 'ellipsis', - overflow: 'hidden', - pointerEvents: 'none', -} as const; +const RawContent = tasty(Block, { + styles: { + width: 'max 100%', + textOverflow: 'ellipsis', + overflow: 'hidden', + pointerEvents: 'none', + }, +}); -const DEFAULT_CLOSE_STYLES: Styles = { - display: 'grid', - placeItems: 'center', - color: true, - placeSelf: 'center', - opacity: { - '': 0.85, - 'pressed | hovered': 1, +const CloseAction = tasty(Action, { + label: 'Close', + styles: { + display: 'grid', + placeItems: 'center', + color: true, + placeSelf: 'center', + opacity: { + '': 0.85, + 'pressed | hovered': 1, + }, + transition: 'opacity', + padding: '0 .5x', }, - transition: 'opacity', - padding: '0 .5x', -} as const; +}); export interface CubeTagProps extends BaseProps, ContainerStyleProps { type?: keyof typeof THEMES | string; @@ -95,18 +102,16 @@ const Tag = (allProps: CubeTagProps, ref) => { mods={{ closable: isClosable }} ref={ref} > - - {children} - + {children} {isClosable ? ( - + - + ) : undefined} diff --git a/src/components/content/Text.tsx b/src/components/content/Text.tsx index a7029365..2a2a092d 100644 --- a/src/components/content/Text.tsx +++ b/src/components/content/Text.tsx @@ -1,44 +1,22 @@ import { CSSProperties, forwardRef } from 'react'; -import { BASE_STYLES, COLOR_STYLES, TEXT_STYLES } from '../../styles/list'; -import { extractStyles, ResponsiveStyleValue } from '../../utils/styles'; -import { filterBaseProps } from '../../utils/filterBaseProps'; import { + BASE_STYLES, BaseProps, BaseStyleProps, + COLOR_STYLES, ColorStyleProps, + extractStyles, + filterBaseProps, + ResponsiveStyleValue, TagNameProps, + tasty, + TEXT_STYLES, TextStyleProps, -} from '../types'; -import { Styles } from '../../styles/types'; -import { styled } from '../../styled'; +} from '../../tasty'; import { useSlotProps } from '../../utils/react'; const STYLE_LIST = [...BASE_STYLES, ...TEXT_STYLES, ...COLOR_STYLES] as const; -const DEFAULT_STYLES: Styles = { - display: { - '': 'inline', - ellipsis: 'block', - }, - margin: '0', - whiteSpace: { - '': 'inherit', - 'nowrap | ellipsis': 'nowrap', - }, - textOverflow: { - '': false, - ellipsis: 'ellipsis', - }, - overflow: { - '': false, - ellipsis: 'hidden', - }, - width: { - '': false, - ellipsis: 'max 100%', - }, -}; - export const TEXT_PROP_MAP = { transform: 'textTransform', weight: 'fontWeight', @@ -71,17 +49,38 @@ export interface CubeTextProps transform?: ResponsiveStyleValue; } -const RawText = styled({ - name: 'Text', - tag: 'span', - styles: DEFAULT_STYLES, +const RawText = tasty({ + qa: 'Text', + as: 'span', + styles: { + display: { + '': 'inline', + ellipsis: 'block', + }, + margin: '0', + whiteSpace: { + '': 'inherit', + 'nowrap | ellipsis': 'nowrap', + }, + textOverflow: { + '': false, + ellipsis: 'ellipsis', + }, + overflow: { + '': false, + ellipsis: 'hidden', + }, + width: { + '': false, + ellipsis: 'max 100%', + }, + }, }); const _Text = forwardRef((allProps: CubeTextProps, ref) => { allProps = useSlotProps(allProps, 'text'); - const { as, qa, block, styleName, ellipsis, css, nowrap, ...props } = - allProps; + const { as, qa, block, styleName, ellipsis, nowrap, ...props } = allProps; const styles = extractStyles(props, STYLE_LIST, {}, TEXT_PROP_MAP); return ( @@ -94,7 +93,6 @@ const _Text = forwardRef((allProps: CubeTextProps, ref) => { ellipsis, }} block={!!(block || ellipsis)} - css={css} {...filterBaseProps(props, { eventProps: true })} styles={styles} ref={ref} diff --git a/src/components/content/Title.tsx b/src/components/content/Title.tsx index 80d9681b..d644ab04 100644 --- a/src/components/content/Title.tsx +++ b/src/components/content/Title.tsx @@ -1,40 +1,17 @@ import { forwardRef } from 'react'; import { CubeTextProps, TEXT_PROP_MAP } from './Text'; -import { CONTAINER_STYLES, TEXT_STYLES } from '../../styles/list'; -import { extractStyles } from '../../utils/styles'; -import { filterBaseProps } from '../../utils/filterBaseProps'; -import { useSlotProps } from '../../utils/react'; import { BaseProps, + CONTAINER_STYLES, ContainerStyleProps, + extractStyles, + filterBaseProps, PositionStyleProps, TagNameProps, -} from '../types'; -import { styled } from '../../styled'; -import { Styles } from '../../styles/types'; - -const DEFAULT_STYLES: Styles = { - gridArea: 'heading', - display: 'block', - color: '#dark', - preset: { - '': 'h6m', - '[data-level="1"]': 'h1', - '[data-level="2"]': 'h2', - '[data-level="3"]': 'h3', - '[data-level="4"]': 'h4', - '[data-level="5"]': 'h5', - '[data-level="6"]': 'h6', - }, - margin: '0', - whiteSpace: { - '': 'initial', - 'nowrap | ellipsis': 'nowrap', - }, - textOverflow: 'ellipsis', - overflow: 'hidden', - width: 'max 100%', -}; + tasty, + TEXT_STYLES, +} from '../../tasty'; +import { useSlotProps } from '../../utils/react'; const STYLE_LIST = [...TEXT_STYLES, ...CONTAINER_STYLES]; @@ -48,12 +25,30 @@ export interface CubeTitleProps level?: 1 | 2 | 3 | 4 | 5 | 6; } -const RawTitle = styled({ - name: 'Title', - tag: 'h1', // it should be dynamic - styles: DEFAULT_STYLES, - props: { - 'data-qa': 'Title', +const RawTitle = tasty({ + qa: 'Title', + as: 'h1', // it should be dynamic + styles: { + gridArea: 'heading', + display: 'block', + color: '#dark', + preset: { + '': 'h6m', + '[data-level="1"]': 'h1', + '[data-level="2"]': 'h2', + '[data-level="3"]': 'h3', + '[data-level="4"]': 'h4', + '[data-level="5"]': 'h5', + '[data-level="6"]': 'h6', + }, + margin: '0', + whiteSpace: { + '': 'initial', + 'nowrap | ellipsis': 'nowrap', + }, + textOverflow: 'ellipsis', + overflow: 'hidden', + width: 'max 100%', }, }); @@ -81,7 +76,6 @@ const _Title = forwardRef( qa={qa || 'Title'} as={as || tag} styleName={styleName} - // @ts-ignore data-level={level || 1} mods={{ nowrap, diff --git a/src/components/forms/Checkbox/Checkbox.tsx b/src/components/forms/Checkbox/Checkbox.tsx index 842211f9..42b4d25e 100644 --- a/src/components/forms/Checkbox/Checkbox.tsx +++ b/src/components/forms/Checkbox/Checkbox.tsx @@ -5,21 +5,24 @@ import { useCheckbox, useCheckboxGroupItem } from '@react-aria/checkbox'; import { useHover } from '@react-aria/interactions'; import { useToggleState } from '@react-stately/toggle'; import { useProviderProps } from '../../../provider'; -import { BLOCK_STYLES, OUTER_STYLES } from '../../../styles/list'; -import { extractStyles } from '../../../utils/styles'; +import { + BaseProps, + BLOCK_STYLES, + extractStyles, + filterBaseProps, + OUTER_STYLES, + Styles, + useContextStyles, +} from '../../../tasty'; import { Base } from '../../Base'; -import { useFocus } from '../../../utils/interactions'; +import { useFocus } from '../../../utils/react/interactions'; import { mergeProps } from '../../../utils/react'; -import { filterBaseProps } from '../../../utils/filterBaseProps'; -import { useContextStyles } from '../../../providers/StylesProvider'; import { INLINE_LABEL_STYLES, LABEL_STYLES } from '../Label'; import { HiddenInput } from '../../HiddenInput'; import { useFormProps } from '../Form/Form'; import { FieldWrapper } from '../FieldWrapper'; import { CheckboxGroup } from './CheckboxGroup'; import { CheckboxGroupContext } from './context'; -import { BaseProps } from '../../types'; -import { Styles } from '../../../styles/types'; import type { FocusableRef } from '@react-types/shared'; import { FormFieldProps } from '../../../shared'; import { diff --git a/src/components/forms/Checkbox/CheckboxGroup.tsx b/src/components/forms/Checkbox/CheckboxGroup.tsx index be56276d..1187e584 100644 --- a/src/components/forms/Checkbox/CheckboxGroup.tsx +++ b/src/components/forms/Checkbox/CheckboxGroup.tsx @@ -6,12 +6,15 @@ import { useCheckboxGroup } from '@react-aria/checkbox'; import { useCheckboxGroupState } from '@react-stately/checkbox'; import { FormContext, useFormProps } from '../Form/Form'; import { CheckboxGroupContext } from './context'; -import { extractStyles } from '../../../utils/styles'; -import { BLOCK_STYLES, OUTER_STYLES } from '../../../styles/list'; +import { + BaseProps, + BLOCK_STYLES, + extractStyles, + OUTER_STYLES, + useContextStyles, +} from '../../../tasty'; import { Base } from '../../Base'; -import { useContextStyles } from '../../../providers/StylesProvider'; import { FieldWrapper } from '../FieldWrapper'; -import { BaseProps } from '../../types'; import type { AriaCheckboxGroupProps } from '@react-types/checkbox'; import { FormFieldProps } from '../../../shared'; import { diff --git a/src/components/forms/FieldWrapper.tsx b/src/components/forms/FieldWrapper.tsx index 7cf0e06c..35ac05c8 100644 --- a/src/components/forms/FieldWrapper.tsx +++ b/src/components/forms/FieldWrapper.tsx @@ -8,16 +8,13 @@ import { NecessityIndicator, ValidationState, } from '../../shared'; -import { Styles } from '../../styles/types'; +import { Styles, tasty } from '../../tasty'; import { TooltipProvider } from '../overlays/Tooltip/TooltipProvider'; import { InfoCircleOutlined } from '@ant-design/icons'; import { wrapNodeIfPlain } from '../../utils/react'; -import { styled } from '../../styled'; -const RawField = styled({ - props: { - qa: 'Field', - }, +const RawField = tasty({ + qa: 'Field', styles: { display: 'grid', gridColumns: { @@ -49,10 +46,8 @@ const RawField = styled({ }, }); -const RawMessage = styled({ - props: { - qa: 'Field_Message', - }, +const RawMessage = tasty({ + qa: 'Field_Message', styles: { preset: 'default', color: { diff --git a/src/components/forms/FileInput/FileInput.tsx b/src/components/forms/FileInput/FileInput.tsx index f892ff86..f390c04e 100644 --- a/src/components/forms/FileInput/FileInput.tsx +++ b/src/components/forms/FileInput/FileInput.tsx @@ -8,15 +8,19 @@ import { } from 'react'; import { useProviderProps } from '../../../provider'; import { Action } from '../../actions/Action'; -import { Styles } from '../../../styles/types'; -import { BaseProps, BlockStyleProps, PositionStyleProps } from '../../types'; +import { + BaseProps, + BlockStyleProps, + CONTAINER_STYLES, + extractStyles, + PositionStyleProps, + Styles, + useContextStyles, +} from '../../../tasty'; import type { AriaTextFieldProps } from '@react-types/textfield'; import { FormFieldProps } from '../../../shared'; import { createFocusableRef } from '@react-spectrum/utils'; import { FieldWrapper } from '../FieldWrapper'; -import { extractStyles } from '../../../utils/styles'; -import { CONTAINER_STYLES } from '../../../styles/list'; -import { useContextStyles } from '../../../providers/StylesProvider'; const DEFAULT_WRAPPER_STYLES: Styles = { display: 'inline-flex', diff --git a/src/components/forms/Form/Form.tsx b/src/components/forms/Form/Form.tsx index 7ec047bc..e0669a14 100644 --- a/src/components/forms/Form/Form.tsx +++ b/src/components/forms/Form/Form.tsx @@ -2,22 +2,25 @@ import { useDOMRef } from '@react-spectrum/utils'; import { Provider, useProviderProps } from '../../../provider'; import { createContext, - useContext, - useRef, - forwardRef, FormHTMLAttributes, + forwardRef, + useContext, useEffect, + useRef, } from 'react'; import { Base } from '../../Base'; -import { extractStyles } from '../../../utils/styles'; -import { CONTAINER_STYLES } from '../../../styles/list'; -import { filterBaseProps } from '../../../utils/filterBaseProps'; -import { CubeFormInstance, useForm, CubeFormData } from './useForm'; +import { + BaseProps, + CONTAINER_STYLES, + ContainerStyleProps, + extractStyles, + filterBaseProps, + Styles, +} from '../../../tasty'; +import { CubeFormData, CubeFormInstance, useForm } from './useForm'; import { useCombinedRefs } from '../../../utils/react'; import { timeout } from '../../../utils/promise'; -import { BaseProps, ContainerStyleProps } from '../../types'; import { FormBaseProps } from '../../../shared'; -import { Styles } from '../../../styles/types'; export const FormContext = createContext({}); @@ -107,8 +110,8 @@ function Form(props: CubeFormProps, ref) { const evt = e.nativeEvent; if ( - evt.submitter - && evt.submitter.getAttribute('type') !== 'submit' + evt.submitter && + evt.submitter.getAttribute('type') !== 'submit' ) { return; } @@ -116,7 +119,7 @@ function Form(props: CubeFormProps, ref) { } return form?.validateFields().then( - async() => { + async () => { await timeout(); if (form && !form.isSubmitting) { @@ -128,7 +131,7 @@ function Form(props: CubeFormProps, ref) { } } }, - async(e) => { + async (e) => { await timeout(); if (e instanceof Error) { throw e; diff --git a/src/components/forms/Form/useForm.tsx b/src/components/forms/Form/useForm.tsx index 1821ae90..db927806 100644 --- a/src/components/forms/Form/useForm.tsx +++ b/src/components/forms/Form/useForm.tsx @@ -1,5 +1,5 @@ import { useRef, useState } from 'react'; -import { dotize } from '../../../utils/dotize'; +import { dotize } from '../../../tasty'; import { applyRules } from './validation'; export type CubeFormData = { [key: string]: any }; diff --git a/src/components/forms/Label.tsx b/src/components/forms/Label.tsx index 565c3ab4..84ee715a 100644 --- a/src/components/forms/Label.tsx +++ b/src/components/forms/Label.tsx @@ -1,18 +1,22 @@ import { useDOMRef } from '@react-spectrum/utils'; import { forwardRef, MouseEventHandler } from 'react'; import { useProviderProps } from '../../provider'; -import { extractStyles } from '../../utils/styles'; -import { CONTAINER_STYLES } from '../../styles/list'; -import { Base } from '../Base'; -import { useContextStyles } from '../../providers/StylesProvider'; -import { filterBaseProps } from '../../utils/filterBaseProps'; -import { BaseProps, ContainerStyleProps, TagNameProps } from '../types'; +import { + BaseProps, + CONTAINER_STYLES, + ContainerStyleProps, + extractStyles, + filterBaseProps, + Styles, + TagNameProps, + tasty, + useContextStyles, +} from '../../tasty'; import { LabelPosition, NecessityIndicator, ValidationState, } from '../../shared'; -import { Styles } from '../../styles/types'; const REQUIRED_ICON = ( INTL_MESSAGES[message]; let necessityLabel = isRequired @@ -135,9 +146,7 @@ function Label(props: CubeLabelProps, ref) { ); return ( - {children} - {(necessityIndicator === 'label' - || (necessityIndicator === 'icon' && isRequired)) - && ' \u200b'} + {(necessityIndicator === 'label' || + (necessityIndicator === 'icon' && isRequired)) && + ' \u200b'} {/* necessityLabel is hidden to screen readers if the field is required because * aria-required is set on the field in that case. That will already be announced, * so no need to duplicate it here. If optional, we do want it to be announced here. */} @@ -175,7 +184,7 @@ function Label(props: CubeLabelProps, ref) { {necessityIndicator === 'icon' && isRequired && icon} )} - + ); } diff --git a/src/components/forms/NumberInput/NumberInput.tsx b/src/components/forms/NumberInput/NumberInput.tsx index efd5b065..1dc8d223 100644 --- a/src/components/forms/NumberInput/NumberInput.tsx +++ b/src/components/forms/NumberInput/NumberInput.tsx @@ -10,7 +10,7 @@ import { useNumberFieldState } from '@react-stately/numberfield'; import { useNumberField } from '@react-aria/numberfield'; import { StepButton } from './StepButton'; import type { AriaNumberFieldProps } from '@react-types/numberfield'; -import { styled } from '../../../styled'; +import { tasty } from '../../../tasty'; import { castNullableNumberValue, WithNullableValue, @@ -23,7 +23,7 @@ export interface CubeNumberInputProps hideStepper?: boolean; } -const StepperContainer = styled({ +const StepperContainer = tasty({ styles: { display: 'grid', gridColumns: '1fr', diff --git a/src/components/forms/NumberInput/StepButton.tsx b/src/components/forms/NumberInput/StepButton.tsx index c54f9d6e..159b0cef 100644 --- a/src/components/forms/NumberInput/StepButton.tsx +++ b/src/components/forms/NumberInput/StepButton.tsx @@ -1,6 +1,6 @@ import { Button } from '../../actions'; import { CaretDownOutlined, CaretUpOutlined } from '@ant-design/icons'; -import { Styles } from '../../../styles/types'; +import { Styles } from '../../../tasty'; const STEP_BUTTON_STYLES: Styles = { padding: '0 .5x', diff --git a/src/components/forms/RadioGroup/Radio.tsx b/src/components/forms/RadioGroup/Radio.tsx index 43c7fa6d..419f339f 100644 --- a/src/components/forms/RadioGroup/Radio.tsx +++ b/src/components/forms/RadioGroup/Radio.tsx @@ -3,20 +3,23 @@ import { forwardRef, useRef } from 'react'; import { useHover } from '@react-aria/interactions'; import { useRadio } from '@react-aria/radio'; import { useRadioProvider } from './context'; -import { extractStyles } from '../../../utils/styles'; -import { useContextStyles } from '../../../providers/StylesProvider'; -import { BLOCK_STYLES, OUTER_STYLES } from '../../../styles/list'; +import { + BaseProps, + BLOCK_STYLES, + extractStyles, + filterBaseProps, + OUTER_STYLES, + Styles, + useContextStyles, +} from '../../../tasty'; import { Base } from '../../Base'; -import { filterBaseProps } from '../../../utils/filterBaseProps'; -import { useFocus } from '../../../utils/interactions'; +import { useFocus } from '../../../utils/react/interactions'; import { mergeProps } from '../../../utils/react'; import { useProviderProps } from '../../../provider'; import { INLINE_LABEL_STYLES } from '../Label'; import { HiddenInput } from '../../HiddenInput'; import { RadioGroup } from './RadioGroup'; import { useFormProps } from '../Form/Form'; -import { Styles } from '../../../styles/types'; -import { BaseProps } from '../../types'; import type { AriaRadioProps } from '@react-types/radio'; import { FormFieldProps } from '../../../shared'; diff --git a/src/components/forms/RadioGroup/RadioGroup.tsx b/src/components/forms/RadioGroup/RadioGroup.tsx index 5948cbfd..143f457a 100644 --- a/src/components/forms/RadioGroup/RadioGroup.tsx +++ b/src/components/forms/RadioGroup/RadioGroup.tsx @@ -6,13 +6,16 @@ import { useRadioGroup } from '@react-aria/radio'; import { useRadioGroupState } from '@react-stately/radio'; import { FormContext, useFormProps } from '../Form/Form'; import { RadioContext } from './context'; -import { extractStyles } from '../../../utils/styles'; -import { BLOCK_STYLES, OUTER_STYLES } from '../../../styles/list'; +import { + BaseProps, + BLOCK_STYLES, + extractStyles, + OUTER_STYLES, + Styles, + useContextStyles, +} from '../../../tasty'; import { Base } from '../../Base'; -import { useContextStyles } from '../../../providers/StylesProvider'; import { FieldWrapper } from '../FieldWrapper'; -import { Styles } from '../../../styles/types'; -import { BaseProps } from '../../types'; import type { AriaRadioGroupProps } from '@react-types/radio'; import { FormFieldProps } from '../../../shared'; import { diff --git a/src/components/forms/Switch/Switch.tsx b/src/components/forms/Switch/Switch.tsx index 319c6d10..0b5cde97 100644 --- a/src/components/forms/Switch/Switch.tsx +++ b/src/components/forms/Switch/Switch.tsx @@ -4,20 +4,25 @@ import { useSwitch } from '@react-aria/switch'; import { useHover } from '@react-aria/interactions'; import { useToggleState } from '@react-stately/toggle'; import { useProviderProps } from '../../../provider'; -import { BLOCK_STYLES, OUTER_STYLES } from '../../../styles/list'; -import { extractStyles } from '../../../utils/styles'; +import { + BaseProps, + BLOCK_STYLES, + BlockStyleProps, + extractStyles, + filterBaseProps, + OUTER_STYLES, + OuterStyleProps, + Styles, + useContextStyles, +} from '../../../tasty'; import { Base } from '../../Base'; -import { useFocus } from '../../../utils/interactions'; +import { useFocus } from '../../../utils/react/interactions'; import { mergeProps } from '../../../utils/react'; -import { filterBaseProps } from '../../../utils/filterBaseProps'; -import { useContextStyles } from '../../../providers/StylesProvider'; import { HiddenInput } from '../../HiddenInput'; import { INLINE_LABEL_STYLES, LABEL_STYLES } from '../Label'; import { LoadingOutlined } from '@ant-design/icons'; import { useFormProps } from '../Form/Form'; import { FieldWrapper } from '../FieldWrapper'; -import { Styles } from '../../../styles/types'; -import { BaseProps, BlockStyleProps, OuterStyleProps } from '../../types'; import type { AriaSwitchProps } from '@react-types/switch'; import { FormFieldProps } from '../../../shared'; import { diff --git a/src/components/forms/TextArea/TextArea.tsx b/src/components/forms/TextArea/TextArea.tsx index 3bb641a3..a17c0f61 100644 --- a/src/components/forms/TextArea/TextArea.tsx +++ b/src/components/forms/TextArea/TextArea.tsx @@ -52,10 +52,10 @@ function TextArea(props: WithNullableValue, ref) { input.style.height = input.scrollHeight ? `calc(${input.scrollHeight}px + (2 * var(--border-width)))` : `${ - parseFloat(computedStyle.paddingTop) - + parseFloat(computedStyle.paddingBottom) - + parseFloat(computedStyle.lineHeight) * (rows || 3) - + 2 + parseFloat(computedStyle.paddingTop) + + parseFloat(computedStyle.paddingBottom) + + parseFloat(computedStyle.lineHeight) * (rows || 3) + + 2 }px`; input.style.alignSelf = prevAlignment; } diff --git a/src/components/forms/TextInput/TextInputBase.tsx b/src/components/forms/TextInput/TextInputBase.tsx index e09796e4..71dc728b 100644 --- a/src/components/forms/TextInput/TextInputBase.tsx +++ b/src/components/forms/TextInput/TextInputBase.tsx @@ -1,7 +1,7 @@ import { - WarningOutlined, CheckOutlined, LoadingOutlined, + WarningOutlined, } from '@ant-design/icons'; import { createFocusableRef } from '@react-spectrum/utils'; import { @@ -17,27 +17,25 @@ import { useFormProps } from '../Form/Form'; import { useHover } from '@react-aria/interactions'; import { useProviderProps } from '../../../provider'; import { Base } from '../../Base'; -import { extractStyles } from '../../../utils/styles'; import { + extractStyles, + useContextStyles, + BaseProps, + BlockStyleProps, + DimensionStyleProps, + PositionStyleProps, BLOCK_STYLES, - POSITION_STYLES, DIMENSION_STYLES, -} from '../../../styles/list'; -import { useFocus } from '../../../utils/interactions'; + POSITION_STYLES, + Props, + Styles, +} from '../../../tasty'; +import { useFocus } from '../../../utils/react/interactions'; import { Prefix } from '../../layout/Prefix'; import { Suffix } from '../../layout/Suffix'; -import { useContextStyles } from '../../../providers/StylesProvider'; import { FieldWrapper } from '../FieldWrapper'; import { Space } from '../../layout/Space'; import { Block } from '../../Block'; -import { Styles } from '../../../styles/types'; -import { - BaseProps, - BlockStyleProps, - DimensionStyleProps, - PositionStyleProps, - Props, -} from '../../types'; import { FormFieldProps } from '../../../shared'; import type { AriaTextFieldProps } from '@react-types/textfield'; import { mergeProps } from '../../../utils/react'; diff --git a/src/components/layout/Flex.tsx b/src/components/layout/Flex.tsx index f8ca2705..1876eb79 100644 --- a/src/components/layout/Flex.tsx +++ b/src/components/layout/Flex.tsx @@ -1,9 +1,12 @@ import { forwardRef } from 'react'; import { Base } from '../Base'; -import { CONTAINER_STYLES } from '../../styles/list'; -import { extractStyles } from '../../utils/styles'; -import { filterBaseProps } from '../../utils/filterBaseProps'; -import { BaseProps, ContainerStyleProps } from '../types'; +import { + BaseProps, + CONTAINER_STYLES, + ContainerStyleProps, + extractStyles, + filterBaseProps, +} from '../../tasty'; const DEFAULT_STYLES = { display: 'flex', diff --git a/src/components/layout/Flow.tsx b/src/components/layout/Flow.tsx index f1643390..e52a8de0 100644 --- a/src/components/layout/Flow.tsx +++ b/src/components/layout/Flow.tsx @@ -1,9 +1,12 @@ import { forwardRef } from 'react'; import { Base } from '../Base'; -import { CONTAINER_STYLES } from '../../styles/list'; -import { extractStyles } from '../../utils/styles'; -import { filterBaseProps } from '../../utils/filterBaseProps'; -import { BaseProps, ContainerStyleProps } from '../types'; +import { + BaseProps, + CONTAINER_STYLES, + ContainerStyleProps, + extractStyles, + filterBaseProps, +} from '../../tasty'; const DEFAULT_STYLES = { display: 'block', diff --git a/src/components/layout/Grid.tsx b/src/components/layout/Grid.tsx index 5ab89c03..2ffe7bff 100644 --- a/src/components/layout/Grid.tsx +++ b/src/components/layout/Grid.tsx @@ -1,9 +1,13 @@ import { forwardRef } from 'react'; import { Base } from '../Base'; -import { CONTAINER_STYLES } from '../../styles/list'; -import { extractStyles } from '../../utils/styles'; -import { filterBaseProps } from '../../utils/filterBaseProps'; -import { BaseProps, ContainerStyleProps, ShortGridStyles } from '../types'; +import { + BaseProps, + CONTAINER_STYLES, + ContainerStyleProps, + extractStyles, + filterBaseProps, + ShortGridStyles, +} from '../../tasty'; const DEFAULT_STYLES = { display: 'grid', diff --git a/src/components/layout/Prefix.tsx b/src/components/layout/Prefix.tsx index 0057f136..9e2667b9 100644 --- a/src/components/layout/Prefix.tsx +++ b/src/components/layout/Prefix.tsx @@ -1,11 +1,15 @@ import { CSSProperties, forwardRef, useEffect } from 'react'; import { Base } from '../Base'; -import { CONTAINER_STYLES } from '../../styles/list'; -import { extractStyles, parseStyle } from '../../utils/styles'; -import { filterBaseProps } from '../../utils/filterBaseProps'; +import { + BaseProps, + CONTAINER_STYLES, + ContainerStyleProps, + extractStyles, + filterBaseProps, + parseStyle, + Styles, +} from '../../tasty'; import { useCombinedRefs } from '../../utils/react'; -import { BaseProps, ContainerStyleProps } from '../types'; -import { Styles } from '../../styles/types'; const DEFAULT_STYLES: Styles = { position: 'absolute', diff --git a/src/components/layout/Space.tsx b/src/components/layout/Space.tsx index 55555fa3..29b1b369 100644 --- a/src/components/layout/Space.tsx +++ b/src/components/layout/Space.tsx @@ -1,9 +1,12 @@ import { forwardRef } from 'react'; import { Base } from '../Base'; -import { CONTAINER_STYLES } from '../../styles/list'; -import { extractStyles } from '../../utils/styles'; -import { filterBaseProps } from '../../utils/filterBaseProps'; -import { BaseProps, ContainerStyleProps } from '../types'; +import { + BaseProps, + CONTAINER_STYLES, + ContainerStyleProps, + extractStyles, + filterBaseProps, +} from '../../tasty'; const DEFAULT_STYLES = { display: 'flex', diff --git a/src/components/layout/Suffix.tsx b/src/components/layout/Suffix.tsx index cab2c52c..e9c44655 100644 --- a/src/components/layout/Suffix.tsx +++ b/src/components/layout/Suffix.tsx @@ -1,11 +1,15 @@ import { CSSProperties, forwardRef, useEffect } from 'react'; import { Base } from '../Base'; -import { CONTAINER_STYLES } from '../../styles/list'; -import { extractStyles, parseStyle } from '../../utils/styles'; -import { filterBaseProps } from '../../utils/filterBaseProps'; +import { + BaseProps, + CONTAINER_STYLES, + ContainerStyleProps, + extractStyles, + filterBaseProps, + parseStyle, + Styles, +} from '../../tasty'; import { useCombinedRefs } from '../../utils/react'; -import { BaseProps, ContainerStyleProps } from '../types'; -import { Styles } from '../../styles/types'; const DEFAULT_STYLES: Styles = { position: 'absolute', diff --git a/src/components/navigation/LegacyTabs/LegacyTabs.tsx b/src/components/navigation/LegacyTabs/LegacyTabs.tsx index 0781d046..51a91c01 100644 --- a/src/components/navigation/LegacyTabs/LegacyTabs.tsx +++ b/src/components/navigation/LegacyTabs/LegacyTabs.tsx @@ -11,7 +11,7 @@ import { Block } from '../../Block'; import { Space } from '../../layout/Space'; import { CubeFlexProps, Flex } from '../../layout/Flex'; import { Button, CubeButtonProps } from '../../actions'; -import { Styles } from '../../../styles/types'; +import { Styles } from '../../../tasty'; export interface CubeTabData { id: string | number; diff --git a/src/components/organisms/FileTabs/FileTabs.tsx b/src/components/organisms/FileTabs/FileTabs.tsx index 46c9f1f5..8a46f483 100644 --- a/src/components/organisms/FileTabs/FileTabs.tsx +++ b/src/components/organisms/FileTabs/FileTabs.tsx @@ -11,8 +11,8 @@ import { CloseOutlined } from '@ant-design/icons'; import { Block } from '../../Block'; import { Action, CubeActionProps } from '../../actions/Action'; import { Space } from '../../layout/Space'; -import { Flex, CubeFlexProps } from '../../layout/Flex'; -import { Styles } from '../../../styles/types'; +import { CubeFlexProps, Flex } from '../../layout/Flex'; +import { Styles, tasty } from '../../../tasty'; interface TabData { id: string | number; @@ -107,13 +107,19 @@ const TABS_CONTAINER_CSS = ` } `; -const DIRTY_BADGE_CSS = ` - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - transition: all .2s linear; -`; +const DirtyBadge = tasty({ + styles: { + position: 'absolute', + top: '50%', + left: '50%', + transform: 'translate(-50%, -50%)', + transition: 'all .2s linear', + width: '1x', + height: '1x', + fill: '#dark.30', + radius: 'round', + }, +}); const TAB_STYLES: Styles = { radius: '1r 1r 0 0', @@ -232,16 +238,7 @@ const Tab = ({ ) : (
)} - {isDirty ? ( - - ) : null} + {isDirty ? : null}
)} diff --git a/src/components/other/Base64Upload/Base64Upload.tsx b/src/components/other/Base64Upload/Base64Upload.tsx index 5dc1d4af..17ac3457 100644 --- a/src/components/other/Base64Upload/Base64Upload.tsx +++ b/src/components/other/Base64Upload/Base64Upload.tsx @@ -3,12 +3,15 @@ import { Button } from '../../actions'; import { Block } from '../../Block'; import { Text } from '../../content/Text'; import styled from 'styled-components'; -import { extractStyles } from '../../../utils/styles'; -import { POSITION_STYLES } from '../../../styles/list'; -import { filterBaseProps } from '../../../utils/filterBaseProps'; -import { BaseProps, PositionStyleProps } from '../../types'; +import { + BaseProps, + extractStyles, + filterBaseProps, + POSITION_STYLES, + PositionStyleProps, + Styles, +} from '../../../tasty'; import { FocusableRef } from '@react-types/shared'; -import { Styles } from '../../../styles/types'; const DEFAULT_STYLES: Styles = { display: 'inline-flex', diff --git a/src/components/overlays/AlertDialog/types.ts b/src/components/overlays/AlertDialog/types.ts index 1196688a..8cd0d97b 100644 --- a/src/components/overlays/AlertDialog/types.ts +++ b/src/components/overlays/AlertDialog/types.ts @@ -3,7 +3,7 @@ import { BaseStyleProps, BlockStyleProps, DimensionStyleProps, -} from '../../types'; +} from '../../../tasty'; import { AriaDialogProps } from '@react-types/dialog'; import { ReactNode } from 'react'; import { CubeDialogContainerProps } from '../Dialog'; @@ -13,6 +13,7 @@ export interface Dialog { props: DialogProps; meta: AlertDialogMeta; } + export interface DialogProps extends Omit, Omit { diff --git a/src/components/overlays/Dialog/Dialog.tsx b/src/components/overlays/Dialog/Dialog.tsx index 4123ff9b..560fe90c 100644 --- a/src/components/overlays/Dialog/Dialog.tsx +++ b/src/components/overlays/Dialog/Dialog.tsx @@ -8,21 +8,19 @@ import { useDialog } from '@react-aria/dialog'; import { useMessageFormatter } from '@react-aria/i18n'; import { Base } from '../../Base'; import { CloseOutlined } from '@ant-design/icons'; -import { extractStyles } from '../../../utils/styles'; import { BASE_STYLES, - BLOCK_STYLES, - DIMENSION_STYLES, -} from '../../../styles/list'; -import { mergeProps, SlotProvider } from '../../../utils/react'; -import { useContextStyles } from '../../../providers/StylesProvider'; -import { Styles } from '../../../styles/types'; -import { BaseProps, BaseStyleProps, + BLOCK_STYLES, BlockStyleProps, + DIMENSION_STYLES, DimensionStyleProps, -} from '../../types'; + extractStyles, + Styles, + useContextStyles, +} from '../../../tasty'; +import { mergeProps, SlotProvider } from '../../../utils/react'; import type { AriaDialogProps } from '@react-types/dialog'; import { DOMRef } from '@react-types/shared'; diff --git a/src/components/overlays/Dialog/DialogTrigger.tsx b/src/components/overlays/Dialog/DialogTrigger.tsx index bde2cba8..f3969346 100644 --- a/src/components/overlays/Dialog/DialogTrigger.tsx +++ b/src/components/overlays/Dialog/DialogTrigger.tsx @@ -5,7 +5,7 @@ import { useMediaQuery } from '@react-spectrum/utils'; import { useOverlayPosition, useOverlayTrigger } from '@react-aria/overlays'; import { DialogContext } from './context'; import { Modal, Popover, Tray } from '../Modal'; -import { Styles } from '../../../styles/types'; +import { Styles } from '../../../tasty'; export type CubeDialogClose = (close: () => void) => ReactElement; @@ -86,9 +86,9 @@ function DialogTrigger(props) { useEffect(() => { return () => { if ( - (wasOpen.current || isExiting.current) - && type !== 'popover' - && type !== 'tray' + (wasOpen.current || isExiting.current) && + type !== 'popover' && + type !== 'tray' ) { console.warn( 'CubeUIKit: A DialogTrigger unmounted while open. This is likely due to being placed within a trigger that unmounts or inside a conditional. Consider using a DialogContainer instead.', @@ -266,10 +266,10 @@ function DialogTriggerBase(props) { {...triggerProps} onPress={state.toggle} isPressed={ - state.isOpen - && type !== 'modal' - && type !== 'fullscreen' - && type !== 'fullscreenTakeover' + state.isOpen && + type !== 'modal' && + type !== 'fullscreen' && + type !== 'fullscreenTakeover' } > {trigger} diff --git a/src/components/overlays/Modal/Modal.tsx b/src/components/overlays/Modal/Modal.tsx index fedb7b89..adef82d2 100644 --- a/src/components/overlays/Modal/Modal.tsx +++ b/src/components/overlays/Modal/Modal.tsx @@ -5,9 +5,7 @@ import { forwardRef, ReactNode } from 'react'; import { Underlay } from './Underlay'; import { useModal, useOverlay, usePreventScroll } from '@react-aria/overlays'; import { Base } from '../../Base'; -import { useContextStyles } from '../../../providers/StylesProvider'; -import { Styles } from '../../../styles/types'; -import { BaseProps, Props } from '../../types'; +import { BaseProps, Props, Styles, useContextStyles } from '../../../tasty'; import { mergeProps } from '../../../utils/react'; import type { ModalProps } from '@react-types/overlays'; diff --git a/src/components/overlays/Modal/Overlay.tsx b/src/components/overlays/Modal/Overlay.tsx index f54bf96f..8468a26c 100644 --- a/src/components/overlays/Modal/Overlay.tsx +++ b/src/components/overlays/Modal/Overlay.tsx @@ -3,7 +3,7 @@ import { forwardRef, useCallback, useState } from 'react'; import { Provider, useProviderProps } from '../../../provider'; import type { OverlayProps } from '@react-types/overlays'; import { createPortal } from 'react-dom'; -import { Props } from '../../types'; +import { Props } from '../../../tasty'; export interface CubeOverlayProps extends Omit { container?: HTMLElement | null; diff --git a/src/components/overlays/Modal/Popover.tsx b/src/components/overlays/Modal/Popover.tsx index 5ebb5346..eb4f1cf3 100644 --- a/src/components/overlays/Modal/Popover.tsx +++ b/src/components/overlays/Modal/Popover.tsx @@ -3,11 +3,9 @@ import { Overlay } from './Overlay'; import { forwardRef, HTMLAttributes } from 'react'; import { useModal, useOverlay } from '@react-aria/overlays'; import { Base } from '../../Base'; -import { useContextStyles } from '../../../providers/StylesProvider'; +import { BaseProps, Styles, useContextStyles } from '../../../tasty'; import { OverlayProps } from '@react-types/overlays'; -import { BaseProps } from '../../types'; import { PlacementAxis } from '../../../shared'; -import { Styles } from '../../../styles/types'; const POPOVER_STYLES: Styles = { pointerEvents: 'auto', diff --git a/src/components/overlays/Modal/Tray.tsx b/src/components/overlays/Modal/Tray.tsx index 4fe3c385..6155dfa9 100644 --- a/src/components/overlays/Modal/Tray.tsx +++ b/src/components/overlays/Modal/Tray.tsx @@ -6,9 +6,7 @@ import { Underlay } from './Underlay'; import { useModal, useOverlay, usePreventScroll } from '@react-aria/overlays'; import { OVERLAY_WRAPPER_STYLES } from './Modal'; import { Base } from '../../Base'; -import { useContextStyles } from '../../../providers/StylesProvider'; -import { Styles } from '../../../styles/types'; -import { BaseProps, Props } from '../../types'; +import { BaseProps, Props, Styles, useContextStyles } from '../../../tasty'; import { mergeProps } from '../../../utils/react'; import type { TrayProps } from '@react-types/overlays'; @@ -74,7 +72,7 @@ function Tray(props: CubeTrayProps, ref) { ); } -let TrayWrapper = forwardRef(function(props: CubeTrayWrapperProps, ref) { +let TrayWrapper = forwardRef(function (props: CubeTrayWrapperProps, ref) { let { qa, children, diff --git a/src/components/overlays/Modal/Underlay.tsx b/src/components/overlays/Modal/Underlay.tsx index 236c5fe1..9f606cb3 100644 --- a/src/components/overlays/Modal/Underlay.tsx +++ b/src/components/overlays/Modal/Underlay.tsx @@ -1,7 +1,6 @@ import { forwardRef, HTMLAttributes } from 'react'; import { Base } from '../../Base'; -import { useContextStyles } from '../../../providers/StylesProvider'; -import { Styles } from '../../../styles/types'; +import { Styles, useContextStyles } from '../../../tasty'; const UNDERLAY_STYLES: Styles = { position: 'fixed', diff --git a/src/components/overlays/Tooltip/Tooltip.tsx b/src/components/overlays/Tooltip/Tooltip.tsx index eb47a7f9..2f10e71e 100644 --- a/src/components/overlays/Tooltip/Tooltip.tsx +++ b/src/components/overlays/Tooltip/Tooltip.tsx @@ -4,12 +4,15 @@ import { createDOMRef } from '@react-spectrum/utils'; import { TooltipContext } from './context'; import { useTooltip } from '@react-aria/tooltip'; import { Base } from '../../Base'; -import { extractStyles } from '../../../utils/styles'; -import { CONTAINER_STYLES } from '../../../styles/list'; -import { useContextStyles } from '../../../providers/StylesProvider'; +import { + BaseProps, + CONTAINER_STYLES, + ContainerStyleProps, + extractStyles, + Styles, + useContextStyles, +} from '../../../tasty'; import { getOverlayTransitionCSS } from '../../../utils/transitions'; -import { Styles } from '../../../styles/types'; -import { BaseProps, ContainerStyleProps } from '../../types'; import type { AriaTooltipProps } from '@react-types/tooltip'; import { PlacementAxis } from '../../../shared'; diff --git a/src/components/overlays/Tooltip/TooltipProvider.tsx b/src/components/overlays/Tooltip/TooltipProvider.tsx index 9b78ce23..bdefa8e5 100644 --- a/src/components/overlays/Tooltip/TooltipProvider.tsx +++ b/src/components/overlays/Tooltip/TooltipProvider.tsx @@ -1,7 +1,7 @@ import { CubeTooltipTriggerProps, TooltipTrigger } from './TooltipTrigger'; import { CubeTooltipProps, Tooltip } from './Tooltip'; import { ReactNode, useEffect, useState } from 'react'; -import { Styles } from '../../../styles/types'; +import { Styles } from '../../../tasty'; export interface CubeTooltipProviderProps extends Omit { diff --git a/src/components/overlays/Tooltip/context.ts b/src/components/overlays/Tooltip/context.ts index f1a926e4..ccd05c47 100644 --- a/src/components/overlays/Tooltip/context.ts +++ b/src/components/overlays/Tooltip/context.ts @@ -1,7 +1,7 @@ import React, { HTMLAttributes, RefObject } from 'react'; import { TooltipTriggerState } from '@react-stately/tooltip'; import { PlacementAxis } from '../../../shared'; -import { Props } from '../../types'; +import { Props } from '../../../tasty'; interface TooltipContextProps { state?: TooltipTriggerState; diff --git a/src/components/pickers/ComboBox/ComboBox.tsx b/src/components/pickers/ComboBox/ComboBox.tsx index 778eb48b..cc13b8e2 100644 --- a/src/components/pickers/ComboBox/ComboBox.tsx +++ b/src/components/pickers/ComboBox/ComboBox.tsx @@ -13,10 +13,14 @@ import { useHover } from '@react-aria/interactions'; import { useProviderProps } from '../../../provider'; import { useFilter } from '@react-aria/i18n'; import { Base } from '../../Base'; -import { extractStyles } from '../../../utils/styles'; -import { BLOCK_STYLES, OUTER_STYLES } from '../../../styles/list'; -import { useFocus } from '../../../utils/interactions'; -import { useContextStyles } from '../../../providers/StylesProvider'; +import { + BLOCK_STYLES, + extractStyles, + OUTER_STYLES, + Styles, + useContextStyles, +} from '../../../tasty'; +import { useFocus } from '../../../utils/react/interactions'; import { modAttrs, useCombinedRefs } from '../../../utils/react'; import { FieldWrapper } from '../../forms/FieldWrapper'; import { CubeSelectBaseProps, ListBoxPopup } from '../Select/Select'; @@ -27,7 +31,6 @@ import { Item } from '@react-stately/collections'; import { DEFAULT_INPUT_STYLES } from '../../forms/TextInput/TextInputBase'; import { useOverlayPosition } from '@react-aria/overlays'; import { OverlayWrapper } from '../../overlays/OverlayWrapper'; -import { Styles } from '../../../styles/types'; import type { CollectionBase, KeyboardDelegate, diff --git a/src/components/pickers/Menu/Menu.tsx b/src/components/pickers/Menu/Menu.tsx index 5f78d6c5..357a0eae 100644 --- a/src/components/pickers/Menu/Menu.tsx +++ b/src/components/pickers/Menu/Menu.tsx @@ -1,4 +1,4 @@ -import React, { ReactNode, ReactElement } from 'react'; +import React, { ReactElement, ReactNode } from 'react'; import { DOMRef, ItemProps } from '@react-types/shared'; import { Item as BaseItem, @@ -10,11 +10,13 @@ import { useDOMRef } from '@react-spectrum/utils'; import { useTreeState } from '@react-stately/tree'; import type { AriaMenuProps } from '@react-types/menu'; -import { ContainerStyleProps } from '../../types'; -import { useContextStyles } from '../../../providers/StylesProvider'; -import { Styles } from '../../../styles/types'; -import { CONTAINER_STYLES } from '../../../styles/list'; -import { extractStyles } from '../../../utils/styles'; +import { + CONTAINER_STYLES, + ContainerStyleProps, + extractStyles, + Styles, + useContextStyles, +} from '../../../tasty'; import { StyledMenu, StyledMenuHeader } from './styled'; import { MenuItem } from './MenuItem'; import { MenuSection } from './MenuSection'; diff --git a/src/components/pickers/Menu/MenuButton.tsx b/src/components/pickers/Menu/MenuButton.tsx index 76e563e2..9a2c0340 100644 --- a/src/components/pickers/Menu/MenuButton.tsx +++ b/src/components/pickers/Menu/MenuButton.tsx @@ -1,7 +1,7 @@ import { ReactNode } from 'react'; import { Button, CubeButtonProps } from '../../actions'; import { Text } from '../../content/Text'; -import { Styles } from '../../../styles/types'; +import { Styles } from '../../../tasty'; import { Space } from '../../layout/Space'; import { CheckOutlined } from '@ant-design/icons'; diff --git a/src/components/pickers/Menu/styled.tsx b/src/components/pickers/Menu/styled.tsx index 6cfcd415..40f11ed6 100644 --- a/src/components/pickers/Menu/styled.tsx +++ b/src/components/pickers/Menu/styled.tsx @@ -1,9 +1,9 @@ -import { styled } from '../../../styled'; +import { tasty } from '../../../tasty'; import { Space } from '../../layout/Space'; -export const StyledMenu = styled({ - tag: 'ul', - name: 'Menu', +export const StyledMenu = tasty({ + as: 'ul', + qa: 'Menu', styles: { display: 'flex', flow: 'column', @@ -31,8 +31,8 @@ export const StyledMenu = styled({ }, }); -export const StyledDivider = styled({ - tag: 'li', +export const StyledDivider = tasty({ + as: 'li', styles: { display: 'flex', flow: 'column', @@ -43,8 +43,8 @@ export const StyledDivider = styled({ }, }); -export const StyledMenuHeader = styled(Space, { - tag: 'li', +export const StyledMenuHeader = tasty(Space, { + as: 'li', styles: { fill: '#light', color: '#dark-02', @@ -58,8 +58,8 @@ export const StyledMenuHeader = styled(Space, { }, }); -export const StyledMenuSection = styled({ - tag: 'li', +export const StyledMenuSection = tasty({ + as: 'li', styles: { display: 'flex', flow: 'column', @@ -75,8 +75,8 @@ export const StyledMenuSection = styled({ }, }); -export const StyledMenuItem = styled({ - tag: 'li', +export const StyledMenuItem = tasty({ + as: 'li', styles: { display: 'flex', flow: 'column', @@ -92,8 +92,8 @@ export const StyledMenuItem = styled({ }, }); -export const StyledMenuSectionHeading = styled(Space, { - tag: 'header', +export const StyledMenuSectionHeading = tasty(Space, { + as: 'header', styles: { color: '#dark-03', preset: 'c1', diff --git a/src/components/pickers/Select/Select.tsx b/src/components/pickers/Select/Select.tsx index 0fba17da..ce675070 100644 --- a/src/components/pickers/Select/Select.tsx +++ b/src/components/pickers/Select/Select.tsx @@ -3,7 +3,7 @@ import { LoadingOutlined, WarningOutlined, } from '@ant-design/icons'; -import { mergeProps } from '../../../utils/react'; +import { mergeProps, useCombinedRefs } from '../../../utils/react'; import { cloneElement, forwardRef, @@ -26,21 +26,21 @@ import { useFormProps } from '../../forms/Form/Form'; import { useFocus as useAriaFocus, useHover } from '@react-aria/interactions'; import { useProviderProps } from '../../../provider'; import { Base } from '../../Base'; -import { extractStyles } from '../../../utils/styles'; -import { BLOCK_STYLES, OUTER_STYLES } from '../../../styles/list'; -import { useFocus } from '../../../utils/interactions'; -import { useContextStyles } from '../../../providers/StylesProvider'; -import { useCombinedRefs } from '../../../utils/react'; -import { FieldWrapper } from '../../forms/FieldWrapper'; -import { Item } from '@react-stately/collections'; -import { OverlayWrapper } from '../../overlays/OverlayWrapper'; -import { Styles } from '../../../styles/types'; import { BasePropsWithoutChildren, + BLOCK_STYLES, BlockStyleProps, + extractStyles, + OUTER_STYLES, OuterStyleProps, Props, -} from '../../types'; + Styles, + useContextStyles, +} from '../../../tasty'; +import { useFocus } from '../../../utils/react/interactions'; +import { FieldWrapper } from '../../forms/FieldWrapper'; +import { Item } from '@react-stately/collections'; +import { OverlayWrapper } from '../../overlays/OverlayWrapper'; import type { AriaSelectProps } from '@react-types/select'; import { DOMRef } from '@react-types/shared'; import { FormFieldProps } from '../../../shared'; diff --git a/src/index.ts b/src/index.ts index 006acc25..d59c6db2 100644 --- a/src/index.ts +++ b/src/index.ts @@ -141,7 +141,7 @@ export type { CubeAlertDialogProps } from './components/overlays/AlertDialog'; export { notification } from './services/notification'; export type { CubeNotificationOptions } from './services/notification'; -export * from './providers/BreakpointsProvider'; +export * from './tasty'; export const Typography = { Text, @@ -152,7 +152,7 @@ export const Typography = { export { Text, Title, Paragraph }; export type { CubeTextProps, CubeTitleProps, CubeParagraphProps }; -export { useContextStyles, StyleProvider } from './providers/StylesProvider'; +export { useContextStyles, StyleProvider } from './tasty'; export { Provider } from './provider'; export type { useProviderProps } from './provider'; @@ -177,14 +177,13 @@ export type { Props, FlowStyleProps, ShortGridStyles, -} from './components/types'; -export * from './styles/types'; -export * from './styles/list'; -export * from './styles/index'; +} from './tasty'; +export * from './tasty'; export { ModalProvider } from '@react-aria/overlays'; export * from './utils/react'; export * from './styled'; +export * from './tasty'; export { default as copy } from 'clipboard-copy'; export * from '@react-aria/ssr'; export * from './components/forms/Form'; diff --git a/src/provider.tsx b/src/provider.tsx index 61e780ae..b6dcab5c 100644 --- a/src/provider.tsx +++ b/src/provider.tsx @@ -4,10 +4,12 @@ import { PropsWithChildren, useContext, } from 'react'; -import { StyleProvider } from './providers/StylesProvider'; -import { BreakpointsProvider } from './providers/BreakpointsProvider'; -import { ResponsiveStyleValue } from './utils/styles'; -import { Props } from './components/types'; +import { + BreakpointsProvider, + Props, + ResponsiveStyleValue, + StyleProvider, +} from './tasty'; export interface ProviderProps extends Props { breakpoints?: number[]; diff --git a/src/shared/form.ts b/src/shared/form.ts index a9ae6fa7..cab1a55d 100644 --- a/src/shared/form.ts +++ b/src/shared/form.ts @@ -1,5 +1,4 @@ -import { Props } from '../components/types'; -import { Styles } from '../styles/types'; +import { Props, Styles } from '../tasty'; import { ReactNode } from 'react'; /** Where to place label relative to input */ diff --git a/src/stories/Styled.stories.mdx b/src/stories/Styled.stories.mdx index 490317d5..8f193791 100644 --- a/src/stories/Styled.stories.mdx +++ b/src/stories/Styled.stories.mdx @@ -19,13 +19,11 @@ import { StyledButton, GlobalStyledHeading } from './components/StyledButton'; Let's look at styled API: ```typescript jsx -import { styled } from '@cube-dev/ui-kit'; +import { tasty } from '@cube-dev/ui-kit'; -const Element = styled({ - /** The name of the element. It can be used to override styles in context. */ - name: 'Article', +const Element = tasty({ /** The tag name of the element. */ - tag: 'span', + as: 'span', /** Default styles of the element. */ styles: { // tokens @@ -44,10 +42,8 @@ const Element = styled({ css: ` appearance: none; `, - /** Default attributes */ - props: { - role: 'article', - }, + /** Default attributes (example) */ + role: 'article', /** The list of styles that can be provided by props */ styleProps: ['align'], }); @@ -68,22 +64,18 @@ export default function Component({ title, children }) { ## Extend base options -You can use `styled()` function to extend styling of the existing component. +You can use `tasty()` function to extend styling of the existing component. ```typescript jsx -const CustomElement = styled(Element, { - /** Change style name */ - name: 'BigBlock', +const CustomElement = tasty(Element, { /** Change tag name */ - tag: 'input', + as: 'input', /** Extend or rewrite styles */ styles: { color: '#purple', }, /** Add more default properties/attributes */ - props: { - role: 'article', - }, + role: 'article', }); ``` @@ -93,7 +85,7 @@ An example of styled component. import { styled } from '../../styled'; import { Button } from '../../components/actions'; -const StyledButton = styled(Button, { +const StyledButton = tasty(Button, { styles: { padding: '3x 6x', preset: 't1', @@ -109,12 +101,12 @@ const StyledButton = styled(Button, { ## Define global styles -Use `styled()` to define global styles for elements: +Use `tasty()` to define global styles for elements: ```typescript jsx -import { styled } from '../../styled'; +import { tasty } from '../../styled'; -const GlobalStyledHeading = styled('div.myButton', { +const GlobalStyledHeading = tasty('div.myButton', { display: 'inline-block', padding: '1x 2x', preset: 't2', diff --git a/src/stories/components/StyledButton.tsx b/src/stories/components/StyledButton.tsx index 82419149..1f9712f0 100644 --- a/src/stories/components/StyledButton.tsx +++ b/src/stories/components/StyledButton.tsx @@ -1,14 +1,14 @@ -import { styled } from '../../styled'; +import { tasty } from '../../tasty'; import { Button } from '../../components/actions'; -export const StyledButton = styled(Button, { +export const StyledButton = tasty(Button, { styles: { padding: '3x 6x', preset: 't1', }, }); -export const GlobalStyledHeading = styled('div.myButton', { +export const GlobalStyledHeading = tasty('div.myButton', { display: 'inline-block', padding: '1x 2x', preset: 't2', diff --git a/src/stories/lists/baseProps.ts b/src/stories/lists/baseProps.ts index 0376fdfe..9e92b444 100644 --- a/src/stories/lists/baseProps.ts +++ b/src/stories/lists/baseProps.ts @@ -1,14 +1,14 @@ import { BASE_STYLES, - CONTAINER_STYLES, BLOCK_STYLES, COLOR_STYLES, + CONTAINER_STYLES, + DIMENSION_STYLES, FLOW_STYLES, OUTER_STYLES, - DIMENSION_STYLES, - TEXT_STYLES, POSITION_STYLES, -} from '../../styles/list'; + TEXT_STYLES, +} from '../../tasty'; const allStyles: string[] = Array.from( new Set([ diff --git a/src/styled/__snapshots__/styled.test.tsx.snap b/src/styled/__snapshots__/styled.test.tsx.snap index e782c6e6..4461fc8f 100644 --- a/src/styled/__snapshots__/styled.test.tsx.snap +++ b/src/styled/__snapshots__/styled.test.tsx.snap @@ -10,23 +10,11 @@ exports[`styled() API should be able to override styles 1`] = ` } .c0 { - display: block; -} - -.c0 { - color: var(--black-color); + color: rgba(var(--black-color-rgb),0.1); --current-color: var(--black-color,black); --current-color-rgb: var(--black-color-rgb); } -@media (min-width:980px) { - -} - -@media (max-width:979px) { - -} -
{ it('should be able to override styles', () => { const StyledBlock = styled(Block, { styles: { color: '#clear.1' } }); const { container } = render( - , + , ); expect(container).toMatchSnapshot(); diff --git a/src/styled/styled.tsx b/src/styled/styled.tsx index 6f56d75a..ba7ed521 100644 --- a/src/styled/styled.tsx +++ b/src/styled/styled.tsx @@ -1,22 +1,36 @@ import styledComponents, { createGlobalStyle } from 'styled-components'; import { ComponentType, FC, forwardRef, useContext, useMemo } from 'react'; import { isValidElementType } from 'react-is'; -import { BreakpointsContext } from '../providers/BreakpointsProvider'; -import { modAttrs } from '../utils/react'; -import { useContextStyles } from '../providers/StylesProvider'; import { AllBaseProps, + BASE_STYLES, BaseStyleProps, - StyledProps, + BreakpointsContext, GlobalStyledProps, -} from '../components/types'; -import { renderStyles } from '../utils/renderStyles'; -import { pointsToZones } from '../utils/responsive'; -import { Styles, StylesInterface } from '../styles/types'; -import { BASE_STYLES } from '../styles/list'; -import { ResponsiveStyleValue } from '../utils/styles'; -import { mergeStyles } from '../utils/mergeStyles'; -import { deprecationWarning } from '../utils/warnings'; + modAttrs, + pointsToZones, + renderStyles, + ResponsiveStyleValue, + Styles, + StylesInterface, + useContextStyles, +} from '../tasty'; +import { mergeStyles } from '../tasty'; +import { deprecationWarning } from '../tasty'; + +export type StyledProps = { + /** The name of the element. It can be used to override styles in context. */ + name?: string; + /** The tag name of the element. */ + tag?: string; + /** Default styles of the element. */ + styles?: Styles; + /** Default css of the element. */ + css?: string; + props?: DefaultProps; + /** The list of styles that can be provided by props */ + styleProps?: K; +}; export type AllBasePropsWithMods = AllBaseProps & { @@ -50,12 +64,21 @@ type EitherLegacyPropsOrInlined< props?: 'You Should use either legacy props field or inline props'; } & DefaultProps); +/** + * @deprecated Use `tasty()` helper instead. + */ function styled< K extends (keyof StylesInterface)[], Props, DefaultProps extends Partial = Partial, >(options: StyledProps, secondArg?: never); +/** + * @deprecated Use `tasty()` helper instead. + */ function styled(selector: string, styles?: Styles); +/** + * @deprecated Use `tasty()` helper instead. + */ function styled< K extends (keyof StylesInterface)[], Props extends { styles?: Styles }, @@ -200,12 +223,12 @@ function styled< let contextBreakpoints = useContext(BreakpointsContext); let zones = pointsToZones(breakpoints ?? contextBreakpoints); + let renderedStyles = useMemo( + () => renderStyles(allStyles, zones), + [allStyles, zones], + ); - css = `${ - typeof defaultCSS === 'function' ? defaultCSS(props) : defaultCSS ?? '' - }${typeof css === 'function' ? css(props) : css ?? ''}${ - allStyles ? renderStyles(allStyles, zones) : '' - }`; + css = `${defaultCSS ?? ''}${css ?? ''}${allStyles ? renderedStyles : ''}`; if (mods) { Object.assign(props, modAttrs(mods)); @@ -233,6 +256,4 @@ function styled< return _StyledComponent; } -const tasty = styled; - -export { styled, tasty }; +export { styled }; diff --git a/src/tasty/__snapshots__/tasty.test.tsx.snap b/src/tasty/__snapshots__/tasty.test.tsx.snap new file mode 100644 index 00000000..120c0a62 --- /dev/null +++ b/src/tasty/__snapshots__/tasty.test.tsx.snap @@ -0,0 +1,76 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`tasty() API should be able to override styles 1`] = ` +.c0 { + outline: none; +} + +.c0[hidden] { + display: none !important; +} + +.c0 { + color: rgba(var(--black-color-rgb),0.1); + --current-color: var(--black-color,black); + --current-color-rgb: var(--black-color-rgb); +} + +
+
+
+`; + +exports[`tasty() API should create responsive styles 1`] = ` +.c0 { + outline: none; +} + +.c0[hidden] { + display: none !important; +} + +@media (min-width:980px) { + .c0 { + display: grid; + } +} + +@media (max-width:979px) { + .c0 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + } +} + +
+
+
+`; + +exports[`tasty() API should pass styles from tasty 1`] = ` +.c0 { + outline: none; +} + +.c0[hidden] { + display: none !important; +} + +.c0 { + color: rgba(var(--clear-color-rgb),0.1); + --current-color: var(--clear-color,clear); + --current-color-rgb: var(--clear-color-rgb); +} + +
+
+
+`; diff --git a/src/tasty/index.ts b/src/tasty/index.ts new file mode 100644 index 00000000..844ad9d5 --- /dev/null +++ b/src/tasty/index.ts @@ -0,0 +1,47 @@ +export * from '../styled/styled'; +export { tasty } from './tasty'; +export * from './utils/filterBaseProps'; +export * from './utils/colors'; +export * from './utils/styles'; +export * from './utils/modAttrs'; +export * from './utils/responsive'; +export * from './utils/renderStyles'; +export * from './utils/dotize'; +export * from './styles/list'; +export * from './providers/BreakpointsProvider'; +export * from './providers/StylesProvider'; +export * from './utils/mergeStyles'; +export * from './utils/warnings'; +export type { + TastyProps, + GlobalTastyProps, + AllBasePropsWithMods, +} from './tasty'; +export type { + AllBaseProps, + BaseProps, + BaseStyleProps, + DimensionStyleProps, + ColorStyleProps, + OuterStyleProps, + PositionStyleProps, + TextStyleProps, + BlockStyleProps, + ContainerStyleProps, + BasePropsWithoutChildren, + Props, + FlowStyleProps, + ShortGridStyles, + GlobalStyledProps, + TagNameProps, + TagName, +} from './types'; +export type { + StylesInterface, + Styles, + StylesWithoutSelectors, + NoType, + Selector, + SuffixForSelector, + NotSelector, +} from './styles/types'; diff --git a/src/providers/BreakpointsProvider.tsx b/src/tasty/providers/BreakpointsProvider.tsx similarity index 100% rename from src/providers/BreakpointsProvider.tsx rename to src/tasty/providers/BreakpointsProvider.tsx diff --git a/src/providers/StylesProvider.tsx b/src/tasty/providers/StylesProvider.tsx similarity index 100% rename from src/providers/StylesProvider.tsx rename to src/tasty/providers/StylesProvider.tsx diff --git a/src/styles/align.ts b/src/tasty/styles/align.ts similarity index 100% rename from src/styles/align.ts rename to src/tasty/styles/align.ts diff --git a/src/styles/border.ts b/src/tasty/styles/border.ts similarity index 100% rename from src/styles/border.ts rename to src/tasty/styles/border.ts diff --git a/src/styles/boxShadow.combinator.ts b/src/tasty/styles/boxShadow.combinator.ts similarity index 100% rename from src/styles/boxShadow.combinator.ts rename to src/tasty/styles/boxShadow.combinator.ts diff --git a/src/styles/color.ts b/src/tasty/styles/color.ts similarity index 100% rename from src/styles/color.ts rename to src/tasty/styles/color.ts diff --git a/src/styles/createStyle.ts b/src/tasty/styles/createStyle.ts similarity index 100% rename from src/styles/createStyle.ts rename to src/tasty/styles/createStyle.ts diff --git a/src/styles/dimension.ts b/src/tasty/styles/dimension.ts similarity index 100% rename from src/styles/dimension.ts rename to src/tasty/styles/dimension.ts diff --git a/src/styles/display.ts b/src/tasty/styles/display.ts similarity index 100% rename from src/styles/display.ts rename to src/tasty/styles/display.ts diff --git a/src/styles/fill.ts b/src/tasty/styles/fill.ts similarity index 100% rename from src/styles/fill.ts rename to src/tasty/styles/fill.ts diff --git a/src/styles/flow.ts b/src/tasty/styles/flow.ts similarity index 100% rename from src/styles/flow.ts rename to src/tasty/styles/flow.ts diff --git a/src/styles/font.ts b/src/tasty/styles/font.ts similarity index 87% rename from src/styles/font.ts rename to src/tasty/styles/font.ts index 6cb59132..3c7cd5a7 100644 --- a/src/styles/font.ts +++ b/src/tasty/styles/font.ts @@ -1,8 +1,8 @@ export function fontStyle({ font }) { if (font == null || font === false) return null; - const fontFamily - = font === 'monospace' + const fontFamily = + font === 'monospace' ? 'var(--monospace-font)' : font === true ? 'var(--font)' diff --git a/src/styles/fontStyle.ts b/src/tasty/styles/fontStyle.ts similarity index 100% rename from src/styles/fontStyle.ts rename to src/tasty/styles/fontStyle.ts diff --git a/src/styles/gap.ts b/src/tasty/styles/gap.ts similarity index 100% rename from src/styles/gap.ts rename to src/tasty/styles/gap.ts diff --git a/src/styles/groupRadius.ts b/src/tasty/styles/groupRadius.ts similarity index 100% rename from src/styles/groupRadius.ts rename to src/tasty/styles/groupRadius.ts diff --git a/src/styles/height.ts b/src/tasty/styles/height.ts similarity index 100% rename from src/styles/height.ts rename to src/tasty/styles/height.ts diff --git a/src/styles/index.ts b/src/tasty/styles/index.ts similarity index 100% rename from src/styles/index.ts rename to src/tasty/styles/index.ts diff --git a/src/styles/justify.ts b/src/tasty/styles/justify.ts similarity index 100% rename from src/styles/justify.ts rename to src/tasty/styles/justify.ts diff --git a/src/styles/list.ts b/src/tasty/styles/list.ts similarity index 100% rename from src/styles/list.ts rename to src/tasty/styles/list.ts diff --git a/src/styles/margin.ts b/src/tasty/styles/margin.ts similarity index 88% rename from src/styles/margin.ts rename to src/tasty/styles/margin.ts index e95faee3..d364a5a7 100644 --- a/src/styles/margin.ts +++ b/src/tasty/styles/margin.ts @@ -35,9 +35,9 @@ export function marginStyle({ const index = DIRECTIONS.indexOf(dir); if ( - ((!!(index % 2) && marginInline == null) - || (!(index % 2) && marginBlock == null)) - && marginDirs[index] == null + ((!!(index % 2) && marginInline == null) || + (!(index % 2) && marginBlock == null)) && + marginDirs[index] == null ) { styles[`margin-${dir}`] = values[index] || values[index % 2] || values[0]; } diff --git a/src/styles/marginBlock.ts b/src/tasty/styles/marginBlock.ts similarity index 100% rename from src/styles/marginBlock.ts rename to src/tasty/styles/marginBlock.ts diff --git a/src/styles/marginInline.ts b/src/tasty/styles/marginInline.ts similarity index 100% rename from src/styles/marginInline.ts rename to src/tasty/styles/marginInline.ts diff --git a/src/styles/outline.ts b/src/tasty/styles/outline.ts similarity index 100% rename from src/styles/outline.ts rename to src/tasty/styles/outline.ts diff --git a/src/styles/padding.ts b/src/tasty/styles/padding.ts similarity index 80% rename from src/styles/padding.ts rename to src/tasty/styles/padding.ts index 3fe120a5..3d46f905 100644 --- a/src/styles/padding.ts +++ b/src/tasty/styles/padding.ts @@ -35,12 +35,12 @@ export function paddingStyle({ const index = DIRECTIONS.indexOf(dir); if ( - ((!!(index % 2) && paddingInline == null) - || (!(index % 2) && paddingBlock == null)) - && paddingDirs[index] == null + ((!!(index % 2) && paddingInline == null) || + (!(index % 2) && paddingBlock == null)) && + paddingDirs[index] == null ) { - styles[`padding-${dir}`] - = values[index] || values[index % 2] || values[0]; + styles[`padding-${dir}`] = + values[index] || values[index % 2] || values[0]; } return styles; diff --git a/src/styles/paddingBlock.ts b/src/tasty/styles/paddingBlock.ts similarity index 100% rename from src/styles/paddingBlock.ts rename to src/tasty/styles/paddingBlock.ts diff --git a/src/styles/paddingInline.ts b/src/tasty/styles/paddingInline.ts similarity index 100% rename from src/styles/paddingInline.ts rename to src/tasty/styles/paddingInline.ts diff --git a/src/styles/predefined.ts b/src/tasty/styles/predefined.ts similarity index 100% rename from src/styles/predefined.ts rename to src/tasty/styles/predefined.ts diff --git a/src/styles/preset.ts b/src/tasty/styles/preset.ts similarity index 100% rename from src/styles/preset.ts rename to src/tasty/styles/preset.ts diff --git a/src/styles/radius.ts b/src/tasty/styles/radius.ts similarity index 100% rename from src/styles/radius.ts rename to src/tasty/styles/radius.ts diff --git a/src/styles/reset.ts b/src/tasty/styles/reset.ts similarity index 100% rename from src/styles/reset.ts rename to src/tasty/styles/reset.ts diff --git a/src/styles/shadow.ts b/src/tasty/styles/shadow.ts similarity index 100% rename from src/styles/shadow.ts rename to src/tasty/styles/shadow.ts diff --git a/src/styles/styledScrollbar.ts b/src/tasty/styles/styledScrollbar.ts similarity index 100% rename from src/styles/styledScrollbar.ts rename to src/tasty/styles/styledScrollbar.ts diff --git a/src/styles/transition.ts b/src/tasty/styles/transition.ts similarity index 100% rename from src/styles/transition.ts rename to src/tasty/styles/transition.ts diff --git a/src/styles/types.ts b/src/tasty/styles/types.ts similarity index 100% rename from src/styles/types.ts rename to src/tasty/styles/types.ts diff --git a/src/styles/width.ts b/src/tasty/styles/width.ts similarity index 100% rename from src/styles/width.ts rename to src/tasty/styles/width.ts diff --git a/src/tasty/tasty.test.tsx b/src/tasty/tasty.test.tsx new file mode 100644 index 00000000..d891dd5f --- /dev/null +++ b/src/tasty/tasty.test.tsx @@ -0,0 +1,56 @@ +import { getByTestId, render } from '@testing-library/react'; +import { tasty } from './tasty'; +import { Button } from '../components/actions'; +import { Block } from '../components/Block'; + +describe('tasty() API', () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + + afterAll(() => { + jest.restoreAllMocks(); + }); + + it('should provide defaults and give ability to override', () => { + const SButton = tasty(Button, { type: 'primary' }); + + const { getByTestId, rerender } = render( + , + ); + expect(getByTestId('button').dataset.type).toBe('primary'); + + rerender(); + expect(getByTestId('button').dataset.type).toBe('secondary'); + }); + + it('should pass styles from tasty', () => { + const StyledBlock = tasty(Block, { styles: { color: '#clear.1' } }); + const { container } = render(); + + expect(container).toMatchSnapshot(); + }); + + it('should be able to override styles', () => { + const StyledBlock = tasty(Block, { styles: { color: '#clear.1' } }); + const { container } = render( + , + ); + + expect(container).toMatchSnapshot(); + }); + + it('should pass qa prop', () => { + const StyledBlock = tasty({ qa: 'Field' }); + const { container } = render(); + + expect(getByTestId(container, 'Field', {})).toBeDefined(); + }); + + it('should create responsive styles', () => { + const StyledBlock = tasty(Block, { styles: { display: ['grid', 'flex'] } }); + const { container } = render(); + + expect(container).toMatchSnapshot(); + }); +}); diff --git a/src/tasty/tasty.tsx b/src/tasty/tasty.tsx new file mode 100644 index 00000000..e6d3bfae --- /dev/null +++ b/src/tasty/tasty.tsx @@ -0,0 +1,215 @@ +import styledComponents, { createGlobalStyle } from 'styled-components'; +import { ComponentType, FC, forwardRef, useContext, useMemo } from 'react'; +import { isValidElementType } from 'react-is'; +import { BreakpointsContext } from './providers/BreakpointsProvider'; +import { modAttrs } from './utils/modAttrs'; +import { AllBaseProps, BaseStyleProps, Props } from './types'; +import { renderStyles } from './utils/renderStyles'; +import { pointsToZones } from './utils/responsive'; +import { Styles, StylesInterface } from './styles/types'; +import { BASE_STYLES } from './styles/list'; +import { ResponsiveStyleValue } from './utils/styles'; +import { mergeStyles } from './utils/mergeStyles'; + +export type TastyProps< + K extends (keyof StylesInterface)[], + DefaultProps = Props, +> = { + /** The tag name of the element. */ + as?: string; + /** Default styles of the element. */ + styles?: Styles; + /** The list of styles that can be provided by props */ + styleProps?: K; +} & Omit; + +export interface GlobalTastyProps { + breakpoints?: number[]; +} + +export type AllBasePropsWithMods = + AllBaseProps & { + [key in K[number]]?: ResponsiveStyleValue; + } & BaseStyleProps; + +type TastyPropsWithDefaults< + Props extends { styles?: Styles }, + DefaultProps extends Partial, +> = keyof DefaultProps extends never + ? Props + : { + [key in Extract]?: Props[key]; + } & { + [key in keyof Omit]: Props[key]; + }; + +function tasty( + options: TastyProps, + secondArg?: never, +); +function tasty(selector: string, styles?: Styles); +function tasty< + Props extends { styles?: Styles }, + DefaultProps extends Partial = Partial, +>( + Component: ComponentType, + options?: TastyProps, +): ComponentType>; + +// Implementation +function tasty< + K extends (keyof StylesInterface)[], + C = Record, +>(Component, options) { + if (typeof Component === 'string') { + let selector = Component; + let styles = options; + let Element = createGlobalStyle`${(css) => css}`; + + const _StyleDeclarationComponent: FC = ({ + breakpoints, + }) => { + let contextBreakpoints = useContext(BreakpointsContext); + + breakpoints = breakpoints ?? contextBreakpoints; + + let css = useMemo( + () => + styles + ? `\n{}${selector}{${renderStyles( + styles, + pointsToZones(breakpoints || contextBreakpoints), + )}}` + : '', + [breakpoints.join(',')], + ); + + return ; + }; + + _StyleDeclarationComponent.displayName = `TastyStyleDeclaration(${Component})`; + + return _StyleDeclarationComponent; + } + + if (isValidElementType(Component)) { + let { as: extendTag, ...defaultProps } = options ?? {}; + + let propsWithStyles = ['styles'].concat( + Object.keys(defaultProps).filter((prop) => prop.endsWith('Styles')), + ); + + let _WrappedComponent = forwardRef((props: C, ref) => { + const { as, ...restProps } = props as AllBasePropsWithMods; + const propsWithStylesValues = propsWithStyles.map((prop) => props[prop]); + + const mergedStylesMap: Styles | undefined = useMemo(() => { + return propsWithStylesValues.reduce((map, prop) => { + if (restProps[prop] != null && defaultProps[prop] != null) { + map[prop] = mergeStyles(restProps[prop], defaultProps[prop]); + } + + return map; + }, {}); + }, propsWithStylesValues); + + return ( + + ); + }); + + _WrappedComponent.displayName = `TastyWrappedComponent(${ + Component.displayName ?? + Component.name ?? + defaultProps.qa ?? + extendTag ?? + 'Anonymous' + })`; + + return _WrappedComponent; + } + + options = Component; + + let { + as: originalAs = 'div', + styles: defaultStyles, + styleProps, + ...defaultProps + } = options; + + let Element = styledComponents[originalAs](({ css }) => css); + + let _TastyComponent = forwardRef((allProps: AllBasePropsWithMods, ref) => { + let { as, styles, breakpoints, mods, element, qa, qaVal, ...otherProps } = + allProps; + + let { + qa: defaultQa, + qaVal: defaultQaVal, + ...otherDefaultProps + } = defaultProps ?? {}; + + let propStyles: Styles = ( + (styleProps + ? (styleProps as (keyof StylesInterface)[]).concat(BASE_STYLES) + : BASE_STYLES) as (keyof StylesInterface)[] + ).reduce((map, prop) => { + if (prop in otherProps) { + map[prop] = otherProps[prop]; + + delete otherProps[prop]; + } + + return map; + }, {}); + + let allStyles: Styles = useMemo( + () => mergeStyles(defaultStyles, styles, propStyles), + [styles, propStyles], + ); + + let contextBreakpoints = useContext(BreakpointsContext); + + breakpoints = breakpoints ?? contextBreakpoints; + + let renderedStyles = useMemo( + () => + allStyles + ? renderStyles(allStyles, pointsToZones(breakpoints as number[])) + : '', + [allStyles, breakpoints], + ); + + if (mods) { + Object.assign(otherProps, modAttrs(mods)); + } + + return ( + + ); + }); + + _TastyComponent.displayName = `TastyComponent(${ + defaultProps.qa || originalAs + })`; + + return _TastyComponent; +} + +export { tasty }; diff --git a/src/components/types.ts b/src/tasty/types.ts similarity index 83% rename from src/components/types.ts rename to src/tasty/types.ts index 105cd52d..061edad6 100644 --- a/src/components/types.ts +++ b/src/tasty/types.ts @@ -1,5 +1,5 @@ import { AllHTMLAttributes, CSSProperties } from 'react'; -import { Styles, StylesInterface } from '../styles/types'; +import { Styles } from './styles/types'; import { BASE_STYLES, BLOCK_STYLES, @@ -10,26 +10,12 @@ import { OUTER_STYLES, POSITION_STYLES, TEXT_STYLES, -} from '../styles/list'; +} from './styles/list'; export interface GlobalStyledProps { breakpoints?: number[]; } -export type StyledProps = { - /** The name of the element. It can be used to override styles in context. */ - name?: string; - /** The tag name of the element. */ - tag?: string; - /** Default styles of the element. */ - styles?: Styles; - /** Default css of the element. */ - css?: string | ((props: Props) => string); - props?: DefaultProps; - /** The list of styles that can be provided by props */ - styleProps?: K; -}; - export interface BasePropsWithoutChildren extends Pick, 'className' | 'role' | 'id'> { /** QA ID for e2e testing. An alias for `data-qa` attribute. */ @@ -53,7 +39,7 @@ export interface BasePropsWithoutChildren /** Whether the element is disabled (`disabled` attribute is set) */ isDisabled?: boolean; /** Plain css for the element */ - css?: string | ((props: Props) => string); + css?: string; /** The element name for using in style overriding */ styleName?: string; /** The CSS style map */ diff --git a/src/utils/colors.ts b/src/tasty/utils/colors.ts similarity index 100% rename from src/utils/colors.ts rename to src/tasty/utils/colors.ts diff --git a/src/utils/dotize.ts b/src/tasty/utils/dotize.ts similarity index 100% rename from src/utils/dotize.ts rename to src/tasty/utils/dotize.ts diff --git a/src/utils/filterBaseProps.ts b/src/tasty/utils/filterBaseProps.ts similarity index 100% rename from src/utils/filterBaseProps.ts rename to src/tasty/utils/filterBaseProps.ts diff --git a/src/utils/index.ts b/src/tasty/utils/index.ts similarity index 93% rename from src/utils/index.ts rename to src/tasty/utils/index.ts index bb3a9afb..0e437311 100644 --- a/src/utils/index.ts +++ b/src/tasty/utils/index.ts @@ -31,7 +31,7 @@ export function getModCombinations(array: string[], allowEmpty?: boolean) { return result.concat([array]); } - const f = function(prefix: string[] = [], array: string[]) { + const f = function (prefix: string[] = [], array: string[]) { for (let i = 0; i < array.length; i++) { result.push([...prefix, array[i]]); f([...prefix, array[i]], array.slice(i + 1)); diff --git a/src/utils/mergeStyles.ts b/src/tasty/utils/mergeStyles.ts similarity index 100% rename from src/utils/mergeStyles.ts rename to src/tasty/utils/mergeStyles.ts diff --git a/src/utils/react/modAttrs.ts b/src/tasty/utils/modAttrs.ts similarity index 100% rename from src/utils/react/modAttrs.ts rename to src/tasty/utils/modAttrs.ts diff --git a/src/utils/renderStyles.ts b/src/tasty/utils/renderStyles.ts similarity index 95% rename from src/utils/renderStyles.ts rename to src/tasty/utils/renderStyles.ts index 77623808..bafc9e0e 100644 --- a/src/utils/renderStyles.ts +++ b/src/tasty/utils/renderStyles.ts @@ -155,15 +155,17 @@ export function renderStyles( responsiveStyles[i] += rules || ''; }); } else { - rawStyles - += handler(styleMap as StyleValueStateMap, suffix) || ''; + rawStyles += + handler(styleMap as StyleValueStateMap, suffix) || ''; } }); STYLE_CACHE[ cacheKey ] = `outline: none;\n&[hidden]{display: none !important;}${rawStyles}${ - responsive && responsive.length + responsive && + responsive.length && + responsiveStyles.filter((s) => s).length ? mediaWrapper(responsiveStyles, zones) : '' }${innerStyles}`; diff --git a/src/utils/responsive.ts b/src/tasty/utils/responsive.ts similarity index 100% rename from src/utils/responsive.ts rename to src/tasty/utils/responsive.ts diff --git a/src/utils/string.ts b/src/tasty/utils/string.ts similarity index 100% rename from src/utils/string.ts rename to src/tasty/utils/string.ts diff --git a/src/utils/styles.test.ts b/src/tasty/utils/styles.test.ts similarity index 100% rename from src/utils/styles.test.ts rename to src/tasty/utils/styles.test.ts diff --git a/src/utils/styles.ts b/src/tasty/utils/styles.ts similarity index 100% rename from src/utils/styles.ts rename to src/tasty/utils/styles.ts diff --git a/src/tasty/utils/warnings.ts b/src/tasty/utils/warnings.ts new file mode 100644 index 00000000..be7dd036 --- /dev/null +++ b/src/tasty/utils/warnings.ts @@ -0,0 +1,46 @@ +const PREFIX = 'Tasty'; + +export function warn(...args) { + console.warn(`${PREFIX}:`, ...args); +} + +export function deprecationWarning( + // eslint-disable-next-line @typescript-eslint/no-explicit-any + condition: any, + { + property, + name, + betterAlternative, + reason, + }: { + property: string; + name: string; + betterAlternative: (() => string) | string; + reason?: (() => string) | string; + }, +) { + if (condition) return; + + if (process.env.NODE_ENV === 'production') { + return warn( + `DEPRECATION ${name} "${property}" -> ${ + typeof betterAlternative === 'function' + ? betterAlternative() + : betterAlternative + }`, + ); + } + + // we can make deprecations even better if we add the md syntax in the console. + // anyway, everything down below will be stripped in the production build + console.group(`⚠️ ${PREFIX}: Deprecation in ${name}`); + warn( + `"${property}" is deprecated, consider better alternative: ${ + typeof betterAlternative === 'function' + ? betterAlternative() + : betterAlternative + }`, + ); + reason && warn(`Reason: ${typeof reason === 'function' ? reason() : reason}`); + console.groupEnd(); +} diff --git a/src/tokens.ts b/src/tokens.ts index dbb46e94..c2573d8f 100644 --- a/src/tokens.ts +++ b/src/tokens.ts @@ -144,6 +144,11 @@ const TOKENS = { 't3m-line-height': '20px', 't3m-letter-spacing': '0.015em', 't3m-font-weight': '500', + // t3s + 't3s-font-size': '14px', + 't3s-line-height': '20px', + 't3s-letter-spacing': '0.015em', + 't3s-font-weight': '600', // t4 't4-font-size': '12px', 't4-line-height': '18px', diff --git a/src/utils/escape-string.ts b/src/utils/escape-string.ts deleted file mode 100644 index 4f0589c3..00000000 --- a/src/utils/escape-string.ts +++ /dev/null @@ -1,10 +0,0 @@ -// https://github.com/sindresorhus/escape-string-regexp/blob/main/index.js -export default function escapeStringRegexp(string) { - if (typeof string !== 'string') { - throw new TypeError('Expected a string'); - } - - // Escape characters with special meaning either inside or outside character sets. - // Use a simple backslash escape when it’s always valid, and a `\xnn` escape when the simpler form would be disallowed by Unicode patterns’ stricter grammar. - return string.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&').replace(/-/g, '\\x2d'); -} diff --git a/src/utils/react/Slots.tsx b/src/utils/react/Slots.tsx index 9e7533a3..6ec56b78 100644 --- a/src/utils/react/Slots.tsx +++ b/src/utils/react/Slots.tsx @@ -1,4 +1,4 @@ -import { mergeProps } from '../../utils/react/mergeProps'; +import { mergeProps } from './mergeProps'; import { createContext, Children, diff --git a/src/utils/react/index.ts b/src/utils/react/index.ts index ef064df5..5745b0c4 100644 --- a/src/utils/react/index.ts +++ b/src/utils/react/index.ts @@ -1,7 +1,7 @@ export { chain } from './chain'; export { isTextOnly } from './isTextOnly'; export { mergeProps } from './mergeProps'; -export { modAttrs } from './modAttrs'; +export { modAttrs } from '../../tasty'; export { useSlotProps, SlotProvider, ClearSlots } from './Slots'; export { useLayoutEffect } from './useLayoutEffect'; export { useCombinedRefs } from './useCombinedRefs'; diff --git a/src/utils/interactions.ts b/src/utils/react/interactions.ts similarity index 100% rename from src/utils/interactions.ts rename to src/utils/react/interactions.ts diff --git a/src/utils/react/mergeProps.tsx b/src/utils/react/mergeProps.tsx index 219f9010..75cf7c60 100644 --- a/src/utils/react/mergeProps.tsx +++ b/src/utils/react/mergeProps.tsx @@ -1,6 +1,6 @@ import clsx from 'clsx'; import { chain, mergeIds } from '@react-aria/utils'; -import { Props } from '../../components/types'; +import { Props } from '../../tasty'; /** * Merges multiple props objects together. Event handlers are chained, @@ -16,34 +16,34 @@ export function mergeProps(...args: (Props | undefined)[]) { for (let key in result) { // Chain events if ( - /^on[A-Z]/.test(key) - && typeof result[key] === 'function' - && props - && typeof props[key] === 'function' + /^on[A-Z]/.test(key) && + typeof result[key] === 'function' && + props && + typeof props[key] === 'function' ) { result[key] = chain(result[key], props[key]); // Merge classnames, sometimes classNames are empty string which eval to false, so we just need to do a type check } else if ( - key === 'className' - && typeof result.className === 'string' - && props - && typeof props.className === 'string' + key === 'className' && + typeof result.className === 'string' && + props && + typeof props.className === 'string' ) { result[key] = clsx(result.className, props.className); } else if ( - key === 'styles' - && typeof result.styles === 'object' - && props - && typeof props.styles === 'object' + key === 'styles' && + typeof result.styles === 'object' && + props && + typeof props.styles === 'object' ) { result[key] = { ...result.styles, ...props.styles }; } else if (key === 'id' && result.id && props?.id) { result.id = mergeIds(result.id, props?.id); // Override others } else { - result[key] - = props && props[key] !== undefined ? props[key] : result[key]; + result[key] = + props && props[key] !== undefined ? props[key] : result[key]; } } diff --git a/src/utils/react/nullableValue.ts b/src/utils/react/nullableValue.ts index d7f0b797..4c14cd24 100644 --- a/src/utils/react/nullableValue.ts +++ b/src/utils/react/nullableValue.ts @@ -1,4 +1,4 @@ -import { Props } from '../../components/types'; +import { Props } from '../../tasty'; export function castNullableStringValue(props: T): T { return castNullableField(props, ['value', 'defaultValue'], 'string', (v) =>