diff --git a/.changeset/popular-plants-fold.md b/.changeset/popular-plants-fold.md new file mode 100644 index 000000000..b4b1bc8ba --- /dev/null +++ b/.changeset/popular-plants-fold.md @@ -0,0 +1,9 @@ +--- +"@interlay/system": major +"@interlay/ui": major +"@interlay/theme": major +"@interlay/hooks": major +"@interlay/icons": major +--- + +feat: rebranding diff --git a/.changeset/pre.json b/.changeset/pre.json new file mode 100644 index 000000000..3575738bc --- /dev/null +++ b/.changeset/pre.json @@ -0,0 +1,15 @@ +{ + "mode": "pre", + "tag": "next", + "initialVersions": { + "@interlay/ui": "0.0.13", + "@interlay/system": "0.0.1", + "@interlay/theme": "0.0.7", + "@interlay/hooks": "0.0.8", + "@interlay/icons": "0.0.7", + "@interlay/test-utils": "0.0.0" + }, + "changesets": [ + "popular-plants-fold" + ] +} diff --git a/.storybook/preview-body.html b/.storybook/preview-body.html new file mode 100644 index 000000000..dd62e467e --- /dev/null +++ b/.storybook/preview-body.html @@ -0,0 +1,5 @@ + diff --git a/.storybook/preview.tsx b/.storybook/preview.tsx index 4f19d2d76..dcdf21ff6 100644 --- a/.storybook/preview.tsx +++ b/.storybook/preview.tsx @@ -4,7 +4,8 @@ import React from 'react'; import { InterlayUIProvider } from '../packages/core/system/src'; import { CSSReset } from '../packages/components/src'; -import '../packages/core/theme/src/css/theme.interlay.css'; +import '../packages/core/theme/src/temp/css/theme.interlay.css'; +import { bobTheme } from '../packages/core/theme/src'; import './style.css'; const preview: Preview = { @@ -15,6 +16,19 @@ const preview: Preview = { color: /(background|color)$/i, date: /Date$/ } + }, + backgrounds: { + default: 'dark', + values: [ + { + name: 'dark', + value: bobTheme.color('dark') + }, + { + name: 'light', + value: bobTheme.color('light') + } + ] } }, decorators: [ @@ -24,7 +38,7 @@ const preview: Preview = { locale && new Intl.Locale(locale)?.textInfo?.direction === 'rtl' ? 'rtl' : undefined; return ( - +
diff --git a/.storybook/storybook-theme.js b/.storybook/storybook-theme.js index 655ffc711..7522a923a 100644 --- a/.storybook/storybook-theme.js +++ b/.storybook/storybook-theme.js @@ -3,7 +3,7 @@ import { create } from '@storybook/theming'; import brandImage from './storybook-logo.svg'; export default create({ - base: 'light', + base: 'dark', brandTitle: 'Interlay UI', brandUrl: 'https://github.com/interlay/ui', brandImage diff --git a/README.md b/README.md index 5bb3efb40..c1c97c773 100644 --- a/README.md +++ b/README.md @@ -60,10 +60,10 @@ function App({ children }) { 2. Now you can start using components like so!: ```jsx -import { CTA } from '@interlay/ui'; +import { Button } from '@interlay/ui'; function Example() { - return I am using Interlay UI; + return ; } ``` diff --git a/packages/components/CHANGELOG.md b/packages/components/CHANGELOG.md index aa43fbb8e..d30fbbb06 100644 --- a/packages/components/CHANGELOG.md +++ b/packages/components/CHANGELOG.md @@ -1,5 +1,19 @@ # @interlay/ui +## 1.0.0-next.0 + +### Major Changes + +- feat: rebranding + +### Patch Changes + +- Updated dependencies []: + - @interlay/system@1.0.0-next.0 + - @interlay/theme@1.0.0-next.0 + - @interlay/hooks@1.0.0-next.0 + - @interlay/icons@1.0.0-next.0 + ## 0.0.13 ### Patch Changes @@ -28,7 +42,7 @@ ### Patch Changes -- [#42](https://github.com/interlay/ui/pull/42) [`4f38fec0481cd7b1134457932dc23a94c9665511`](https://github.com/interlay/ui/commit/4f38fec0481cd7b1134457932dc23a94c9665511) Thanks [@danielsimao](https://github.com/danielsimao)! - refactor(components): Spinner (LoadingSpinner) and CTA +- [#42](https://github.com/interlay/ui/pull/42) [`4f38fec0481cd7b1134457932dc23a94c9665511`](https://github.com/interlay/ui/commit/4f38fec0481cd7b1134457932dc23a94c9665511) Thanks [@danielsimao](https://github.com/danielsimao)! - refactor(components): Spinner (LoadingSpinner) and Button - [#46](https://github.com/interlay/ui/pull/46) [`95c75c1968cda23b75ff5f7aaaa13d5c4cbe6c0e`](https://github.com/interlay/ui/commit/95c75c1968cda23b75ff5f7aaaa13d5c4cbe6c0e) Thanks [@danielsimao](https://github.com/danielsimao)! - fix(components): Radio and RadioGroup diff --git a/packages/components/README.md b/packages/components/README.md index 3c22d30b2..038466168 100644 --- a/packages/components/README.md +++ b/packages/components/README.md @@ -60,10 +60,10 @@ function App({ children }) { 2. Now you can start using components like so!: ```jsx -import { CTA } from '@interlay/ui'; +import { Button } from '@interlay/ui'; function Example() { - return I am using Interlay UI; + return ; } ``` diff --git a/packages/components/package.json b/packages/components/package.json index 9d5e7eb72..31e37a11c 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -1,6 +1,6 @@ { "name": "@interlay/ui", - "version": "0.0.13", + "version": "1.0.0-next.0", "description": "Interlay UI library.", "homepage": "https://github.com/interlay/ui#readme", "license": "MIT", @@ -38,11 +38,11 @@ "postpack": "clean-package restore" }, "dependencies": { - "@interlay/coin-icons": "workspace:*", "@interlay/hooks": "workspace:*", "@interlay/icons": "workspace:*", "@interlay/system": "workspace:*", "@interlay/theme": "workspace:*", + "@radix-ui/react-slot": "^1.0.2", "@react-aria/accordion": "3.0.0-alpha.20", "@react-aria/breadcrumbs": "^3.5.4", "@react-aria/button": "^3.8.1", diff --git a/packages/components/src/Accordion/Accordion.stories.tsx b/packages/components/src/Accordion/Accordion.stories.tsx index e999260a3..560d11ebc 100644 --- a/packages/components/src/Accordion/Accordion.stories.tsx +++ b/packages/components/src/Accordion/Accordion.stories.tsx @@ -29,6 +29,8 @@ export default { export const Default: StoryObj = {}; +export const Splitted: StoryObj = { args: { variant: 'splitted' } }; + export const DefaultExpanded: StoryObj = { args: { defaultExpandedKeys: ['1'] diff --git a/packages/components/src/Accordion/Accordion.style.tsx b/packages/components/src/Accordion/Accordion.style.tsx index cec271b27..b9f81cce8 100644 --- a/packages/components/src/Accordion/Accordion.style.tsx +++ b/packages/components/src/Accordion/Accordion.style.tsx @@ -1,11 +1,14 @@ -import styled from 'styled-components'; +import styled, { css } from 'styled-components'; import { ChevronDown } from '@interlay/icons'; -import { theme } from '@interlay/theme'; +import { AccordionVariants } from '@interlay/theme'; -import { H3 } from '../Text'; +import { H3, Span } from '../Text'; type StyledAccordionProps = { - $isDisabled: boolean; + $variant: AccordionVariants; +}; + +type StyledChevronDownProps = { $isExpanded: boolean; }; @@ -22,22 +25,33 @@ type StyledAccordionItemContentProps = { $isExpanded: boolean; }; -const StyledAccordionItemWrapper = styled.div>` +type StyledAccordionItemWrapperProps = { + $isDisabled: boolean; + $variant: AccordionVariants; +}; + +const StyledAccordion = styled.div` + display: flex; + flex-direction: column; + ${({ theme, $variant }) => theme.accordion.variant[$variant].base} +`; + +const StyledAccordionItemWrapper = styled.div` z-index: inherit; position: relative; opacity: ${({ $isDisabled }) => $isDisabled && '0.5'}; + ${({ theme, $variant }) => theme.accordion.variant[$variant].item.base} `; const StyledAccordionItemHeading = styled(H3)` margin: 0; - font-weight: ${theme.fontWeight.semibold}; + ${({ theme }) => theme.accordion.item.heading} `; const StyledAccordionItemButton = styled.button` display: flex; align-items: center; justify-content: space-between; - padding: ${theme.spacing.spacing4}; min-height: 3.25rem; text-overflow: ellipsis; cursor: ${({ $isDisabled }) => ($isDisabled ? 'default' : 'pointer')}; @@ -48,11 +62,13 @@ const StyledAccordionItemButton = styled.button` color: inherit; font: inherit; outline: ${({ $isFocusVisible }) => !$isFocusVisible && 'none'}; + + ${({ theme }) => theme.accordion.item.button} `; -const StyledChevronDown = styled(ChevronDown)>` +const StyledChevronDown = styled(ChevronDown)` transform: ${({ $isExpanded }) => $isExpanded && 'rotate(-180deg)'}; - transition: transform ${theme.transition.duration.duration150}ms ease; + transition: transform 150ms ease; `; const StyledAccordionItemRegion = styled.div` @@ -64,10 +80,24 @@ const StyledAccordionItemRegion = styled.div` const StyledAccordionItemContent = styled.div` overflow: hidden; padding-top: 0; - padding-left: ${theme.spacing.spacing4}; - padding-right: ${theme.spacing.spacing4}; - padding-bottom: ${({ $isExpanded }) => ($isExpanded ? theme.spacing.spacing4 : 0)}; transition: all 200ms ease 0ms; + + ${({ theme, $isExpanded }) => { + const { paddingTop, paddingBottom, paddingLeft, paddingRight } = theme.accordion.item.content || {}; + + return css` + padding-top: ${paddingTop}; + padding-left: ${paddingLeft}; + padding-right: ${paddingRight}; + padding-bottom: ${$isExpanded ? paddingBottom : 0}; + `; + }} +`; + +const StyledSpan = styled(Span)` + font-weight: inherit; + font-size: inherit; + line-height: inherit; `; export { @@ -76,5 +106,7 @@ export { StyledAccordionItemHeading, StyledAccordionItemRegion, StyledAccordionItemWrapper, - StyledChevronDown + StyledChevronDown, + StyledAccordion, + StyledSpan }; diff --git a/packages/components/src/Accordion/Accordion.tsx b/packages/components/src/Accordion/Accordion.tsx index a03dd58f3..ad39c7555 100644 --- a/packages/components/src/Accordion/Accordion.tsx +++ b/packages/components/src/Accordion/Accordion.tsx @@ -2,13 +2,14 @@ import { AriaAccordionProps, useAccordion } from '@react-aria/accordion'; import { mergeProps } from '@react-aria/utils'; import { useTreeState } from '@react-stately/tree'; import { forwardRef, HTMLAttributes, Ref } from 'react'; -import { FontSize } from '@interlay/theme'; import { useDOMRef } from '@interlay/hooks'; +import { AccordionVariants } from '@interlay/theme'; import { AccordionItem } from './AccordionItem'; +import { StyledAccordion } from './Accordion.style'; type Props = { - size?: FontSize; + variant?: AccordionVariants; }; type InheritAttrs = Omit, keyof Props>; @@ -18,7 +19,7 @@ type NativeAttrs = Omit, (keyof InheritAttrs & Pro type AccordionProps = Props & InheritAttrs & NativeAttrs; const Accordion = >( - { size = 'base', ...props }: AccordionProps, + { variant = 'light', ...props }: AccordionProps, ref: Ref ): JSX.Element => { const state = useTreeState(props); @@ -26,11 +27,11 @@ const Accordion = >( const { accordionProps } = useAccordion(props, state, accordionRef); return ( -
+ {[...state.collection].map((item) => ( - key={item.key} item={item} size={size} state={state} /> + key={item.key} item={item} state={state} variant={variant} /> ))} -
+ ); }; diff --git a/packages/components/src/Accordion/AccordionItem.tsx b/packages/components/src/Accordion/AccordionItem.tsx index ff7d8dd58..9b338aa2c 100644 --- a/packages/components/src/Accordion/AccordionItem.tsx +++ b/packages/components/src/Accordion/AccordionItem.tsx @@ -4,25 +4,24 @@ import { mergeProps } from '@react-aria/utils'; import { TreeState } from '@react-stately/tree'; import { Node } from '@react-types/shared'; import { useRef } from 'react'; -import { FontSize } from '@interlay/theme'; - -import { Span } from '..'; +import { AccordionVariants } from '@interlay/theme'; import { StyledAccordionItemButton, StyledAccordionItemHeading, StyledAccordionItemWrapper, - StyledChevronDown + StyledChevronDown, + StyledSpan } from './Accordion.style'; import { AccordionItemRegion } from './AccordionItemRegion'; type AccordionItemProps = { item: Node; state: TreeState; - size?: FontSize; + variant?: AccordionVariants; }; const AccordionItem = >({ - size = 'base', + variant = 'light', ...props }: AccordionItemProps): JSX.Element => { const ref = useRef(null); @@ -33,8 +32,8 @@ const AccordionItem = >({ const { isFocusVisible, focusProps } = useFocusRing(); return ( - - + + >({ $isDisabled={isDisabled} $isFocusVisible={isFocusVisible} > - {item.props.title} + {item.props.title} diff --git a/packages/components/src/Accordion/__tests__/Accordion.test.tsx b/packages/components/src/Accordion/__tests__/Accordion.test.tsx index 579218545..4fe86f8d2 100644 --- a/packages/components/src/Accordion/__tests__/Accordion.test.tsx +++ b/packages/components/src/Accordion/__tests__/Accordion.test.tsx @@ -1,6 +1,5 @@ -import { render } from '@testing-library/react'; import * as React from 'react'; -import { testA11y } from '@interlay/test-utils'; +import { testA11y, render } from '@interlay/test-utils'; import { Accordion, AccordionItem } from '..'; diff --git a/packages/components/src/Alert/Alert.style.tsx b/packages/components/src/Alert/Alert.style.tsx index 381667719..038c5469f 100644 --- a/packages/components/src/Alert/Alert.style.tsx +++ b/packages/components/src/Alert/Alert.style.tsx @@ -1,28 +1,38 @@ -import { Warning } from '@interlay/icons'; -import styled from 'styled-components'; -import { theme } from '@interlay/theme'; -import { Status } from '@interlay/theme'; +import { CheckCircle, InformationCircle, Warning } from '@interlay/icons'; +import styled, { css } from 'styled-components'; +import { AlertStatus } from '@interlay/theme'; import { Flex } from '../Flex'; type StyledAlertProps = { - $status: Status; + $status: AlertStatus; }; +// FIXME: waiting on JAy const StyledAlert = styled(Flex)` - padding: ${theme.spacing.spacing2}; - color: ${({ $status }) => theme.alert.status[$status]}; - border: 1px solid ${({ $status }) => theme.alert.status[$status]}; - background-color: ${({ $status }) => theme.alert.bg[$status]}; - border-radius: ${theme.rounded.md}; - font-size: ${theme.text.xs}; + ${({ $status, theme }) => css` + ${theme.alert.base} + ${theme.alert.status[$status]} + `} `; -const StyledWarningIcon = styled(Warning)` - color: inherit; - width: ${theme.spacing.spacing5}; - height: ${theme.spacing.spacing5}; - flex-shrink: 0; +const StyledInformationCircle = styled(InformationCircle)` + ${({ $status, theme }) => css` + ${theme.alert.status[$status]} + `} `; -export { StyledAlert, StyledWarningIcon }; +const StyledCheckCircle = styled(CheckCircle)` + ${({ $status, theme }) => css` + ${theme.alert.base} + ${theme.alert.status[$status]} + `} +`; + +const StyledWarning = styled(Warning)` + ${({ $status, theme }) => css` + ${theme.alert.status[$status].color} + `} +`; + +export { StyledAlert, StyledInformationCircle, StyledCheckCircle, StyledWarning }; diff --git a/packages/components/src/Alert/Alert.tsx b/packages/components/src/Alert/Alert.tsx index 1ae3c138d..9f0675a33 100644 --- a/packages/components/src/Alert/Alert.tsx +++ b/packages/components/src/Alert/Alert.tsx @@ -1,23 +1,35 @@ -import { Status } from '@interlay/theme'; +import { AlertStatus } from '@interlay/theme'; +import { ForwardRefExoticComponent } from 'react'; import { FlexProps } from '../Flex'; -import { StyledAlert, StyledWarningIcon } from './Alert.style'; +import { StyledAlert, StyledCheckCircle, StyledInformationCircle, StyledWarning } from './Alert.style'; + +const iconMap: Record> = { + info: StyledInformationCircle, + success: StyledCheckCircle, + error: StyledWarning, + warning: StyledWarning +}; type Props = { - status?: Status; + status?: AlertStatus; }; type InheritAttrs = Omit; type AlertProps = Props & InheritAttrs; -const Alert = ({ status = 'success', children, ...props }: AlertProps): JSX.Element => ( - - -
{children}
-
-); +const Alert = ({ status = 'success', children, ...props }: AlertProps): JSX.Element => { + const Icon = iconMap[status]; + + return ( + + +
{children}
+
+ ); +}; export { Alert }; export type { AlertProps }; diff --git a/packages/components/src/Alert/__tests__/Alert.test.tsx b/packages/components/src/Alert/__tests__/Alert.test.tsx index 1360ad6bc..a1815edd1 100644 --- a/packages/components/src/Alert/__tests__/Alert.test.tsx +++ b/packages/components/src/Alert/__tests__/Alert.test.tsx @@ -1,5 +1,4 @@ -import { render } from '@testing-library/react'; -import { testA11y } from '@interlay/test-utils'; +import { testA11y, render } from '@interlay/test-utils'; import { Alert } from '..'; diff --git a/packages/components/src/Breadcrumbs/BreadcrumbItem.tsx b/packages/components/src/Breadcrumbs/BreadcrumbItem.tsx index 6cde82b38..215ff8b88 100644 --- a/packages/components/src/Breadcrumbs/BreadcrumbItem.tsx +++ b/packages/components/src/Breadcrumbs/BreadcrumbItem.tsx @@ -32,7 +32,7 @@ const BreadcrumbItem = ({ children, isDisabled, isCurrent, href, ...props }: Bre const commonProps: Pick = { size: 's', - color: isCurrent ? 'secondary' : 'tertiary' + color: isCurrent ? 'light' : 'green-300' }; return ( @@ -51,7 +51,7 @@ const BreadcrumbItem = ({ children, isDisabled, isCurrent, href, ...props }: Bre {children} )} - {isCurrent === false && } + {isCurrent === false && } ); }; diff --git a/packages/components/src/Breadcrumbs/Breadcrumbs.style.tsx b/packages/components/src/Breadcrumbs/Breadcrumbs.style.tsx index 8f945bc63..48bd1ff1b 100644 --- a/packages/components/src/Breadcrumbs/Breadcrumbs.style.tsx +++ b/packages/components/src/Breadcrumbs/Breadcrumbs.style.tsx @@ -1,5 +1,4 @@ import styled from 'styled-components'; -import { theme } from '@interlay/theme'; import { Span } from '../Text'; import { TextLink } from '../TextLink'; @@ -28,12 +27,12 @@ const StyledListItem = styled.li` `; const StyledSpanBreadcrumb = styled(Span)` - padding: 0 ${theme.spacing.spacing2}; + padding: 0 ${({ theme }) => theme.spacing('s')}; cursor: default; `; const StyledLinkBreadcrumb = styled(TextLink)` - padding: 0 ${theme.spacing.spacing2}; + padding: 0 ${({ theme }) => theme.spacing('s')}; text-decoration: none; `; diff --git a/packages/components/src/Breadcrumbs/__tests__/Breadcrumbs.test.tsx b/packages/components/src/Breadcrumbs/__tests__/Breadcrumbs.test.tsx index 3ed6a53ba..eb4098594 100644 --- a/packages/components/src/Breadcrumbs/__tests__/Breadcrumbs.test.tsx +++ b/packages/components/src/Breadcrumbs/__tests__/Breadcrumbs.test.tsx @@ -1,6 +1,5 @@ -import { render } from '@testing-library/react'; import { createRef } from 'react'; -import { testA11y } from '@interlay/test-utils'; +import { testA11y, render } from '@interlay/test-utils'; import { BreadcrumbItem, Breadcrumbs } from '..'; diff --git a/packages/components/src/Button/Button.stories.tsx b/packages/components/src/Button/Button.stories.tsx new file mode 100644 index 000000000..8a24ac2c8 --- /dev/null +++ b/packages/components/src/Button/Button.stories.tsx @@ -0,0 +1,99 @@ +import { Meta, StoryObj } from '@storybook/react'; +import { XMark } from '@interlay/icons'; + +import { Button, ButtonProps } from '.'; + +export default { + title: 'Buttons/Button', + component: Button, + parameters: { + layout: 'centered' + }, + args: { + children: 'Button' + } +} as Meta; + +export const Solid: StoryObj = { + args: { + variant: 'solid' + } +}; + +export const Outline: StoryObj = { + args: { + variant: 'outline' + } +}; + +export const Ghost: StoryObj = { + args: { + variant: 'ghost' + } +}; + +export const Icon: StoryObj = { + args: { + isIconOnly: true, + children: + } +}; + +export const Link: StoryObj = { + args: { + asChild: true, + // eslint-disable-next-line jsx-a11y/anchor-is-valid + children: Link + } +}; + +// export const Secondary: StoryObj = { +// args: { +// variant: 'secondary' +// } +// }; + +// export const Outlined: StoryObj = { +// args: { +// variant: 'outlined' +// } +// }; + +// export const Text: StoryObj = { +// args: { +// variant: 'text' +// } +// }; + +// export const XSmall: StoryObj = { +// args: { +// size: 'x-small' +// } +// };4 + +// export const Small: StoryObj = { +// args: { +// size: 'small' +// } +// }; + +// export const Large: StoryObj = { +// args: { +// size: 'large' +// } +// }; + +// export const Loading: StoryObj = { +// render: (args) => ( +// +// ); + + expect(() => wrapper.unmount()).not.toThrow(); + }); + + it('ref should be forwarded', () => { + const ref = createRef(); + + render(); + + expect(ref.current).not.toBeNull(); + }); + + it('should pass a11y', async () => { + await testA11y(); + }); +}); diff --git a/packages/components/src/Button/index.tsx b/packages/components/src/Button/index.tsx new file mode 100644 index 000000000..9cad84da1 --- /dev/null +++ b/packages/components/src/Button/index.tsx @@ -0,0 +1,2 @@ +export type { ButtonProps } from './Button'; +export { Button } from './Button'; diff --git a/packages/components/src/CSSReset/__tests__/CSSReset.test.tsx b/packages/components/src/CSSReset/__tests__/CSSReset.test.tsx index 110fefadf..5b0ae879c 100644 --- a/packages/components/src/CSSReset/__tests__/CSSReset.test.tsx +++ b/packages/components/src/CSSReset/__tests__/CSSReset.test.tsx @@ -1,4 +1,4 @@ -import { render } from '@testing-library/react'; +import { render } from '@interlay/test-utils'; import { CSSReset } from '..'; diff --git a/packages/components/src/CTA/CTA.stories.tsx b/packages/components/src/CTA/CTA.stories.tsx index 001d30afb..efa9babbf 100644 --- a/packages/components/src/CTA/CTA.stories.tsx +++ b/packages/components/src/CTA/CTA.stories.tsx @@ -15,7 +15,7 @@ export default { children: 'Button' }, render: (args) => ( - + @@ -66,7 +66,7 @@ export const Large: StoryObj = { export const Loading: StoryObj = { render: (args) => ( - + diff --git a/packages/components/src/CTA/CTA.style.tsx b/packages/components/src/CTA/CTA.style.tsx index 598b72cf2..0a4f61f97 100644 --- a/packages/components/src/CTA/CTA.style.tsx +++ b/packages/components/src/CTA/CTA.style.tsx @@ -1,8 +1,7 @@ import styled from 'styled-components'; import { ArrowTopRightOnSquare } from '@interlay/icons'; +import { theme, CTASizes, CTAVariants } from '@interlay/theme'; -import { theme } from '../../../core/theme/src'; -import { CTASizes, CTAVariants } from '../../../core/theme/src'; import { Spinner } from '../Spinner'; interface StyledCTAProps { diff --git a/packages/components/src/CTA/CTA.tsx b/packages/components/src/CTA/CTA.tsx index 5b6345640..216767827 100644 --- a/packages/components/src/CTA/CTA.tsx +++ b/packages/components/src/CTA/CTA.tsx @@ -5,12 +5,12 @@ import { PressEvent } from '@react-types/shared'; import { ButtonHTMLAttributes, forwardRef } from 'react'; import { useDOMRef } from '@interlay/hooks'; -import { CTASizes, IconSize } from '../../../core/theme/src'; +import { CTASizes, IconsSizes } from '../../../core/theme/src'; import { BaseCTA, BaseCTAProps } from './BaseCTA'; import { LoadingWrapper, StyledSpinner } from './CTA.style'; -const loadingSizes: Record = { +const loadingSizes: Record = { 'x-small': 'xs', small: 'xs', medium: 's', diff --git a/packages/components/src/CTA/CTALink.stories.tsx b/packages/components/src/CTA/CTALink.stories.tsx index df79e53ee..b1fec9fa4 100644 --- a/packages/components/src/CTA/CTALink.stories.tsx +++ b/packages/components/src/CTA/CTALink.stories.tsx @@ -15,7 +15,7 @@ export default { children: 'Button' }, render: (args) => ( - + diff --git a/packages/components/src/CTA/CTALink.tsx b/packages/components/src/CTA/CTALink.tsx index 8764ee569..8693e0877 100644 --- a/packages/components/src/CTA/CTALink.tsx +++ b/packages/components/src/CTA/CTALink.tsx @@ -44,7 +44,7 @@ const CTALink = forwardRef( })} > {children} - {icon && } + {icon && } ); } diff --git a/packages/components/src/CTA/__tests__/CTA.test.tsx b/packages/components/src/CTA/__tests__/CTA.test.tsx index ac084b549..17cd5db75 100644 --- a/packages/components/src/CTA/__tests__/CTA.test.tsx +++ b/packages/components/src/CTA/__tests__/CTA.test.tsx @@ -1,6 +1,5 @@ -import { render } from '@testing-library/react'; +import { render, testA11y } from '@interlay/test-utils'; import { createRef } from 'react'; -import { testA11y } from '@interlay/test-utils'; import { CTA } from '..'; diff --git a/packages/components/src/Card/Card.stories.tsx b/packages/components/src/Card/Card.stories.tsx index d9c4c4bd0..a4e2e0ab4 100644 --- a/packages/components/src/Card/Card.stories.tsx +++ b/packages/components/src/Card/Card.stories.tsx @@ -1,22 +1,17 @@ import { Meta, StoryObj } from '@storybook/react'; -import { H1, H2, P, Span, CoinIcon, Flex } from '..'; +import { H1, H2, P, Span, Flex } from '..'; import { Card, CardProps } from '.'; const children = ( <>

BTC Passive Income

- - + Earn up to

0.3% APY

-

+

Generate passive income by offering your BTC to lending markets and benefit from automatic compounding rewards.

@@ -28,7 +23,7 @@ export default { parameters: { layout: 'centered' }, - args: { style: { maxWidth: 300 }, gap: 'spacing4', alignItems: 'center', children } + args: { style: { maxWidth: 300 }, gap: 'md', alignItems: 'center', children } } as Meta; export const Default: StoryObj = {}; diff --git a/packages/components/src/Card/Card.style.tsx b/packages/components/src/Card/Card.style.tsx index 21abfc331..c8308921a 100644 --- a/packages/components/src/Card/Card.style.tsx +++ b/packages/components/src/Card/Card.style.tsx @@ -1,50 +1,39 @@ import styled, { css } from 'styled-components'; -import { theme } from '@interlay/theme'; -import { BorderRadius, CardVariants, Spacing, Variants } from '@interlay/theme'; +import { Color, Rounded, Spacing } from '@interlay/theme'; import { Flex } from '../Flex'; type StyledCardProps = { - $variant: CardVariants; - $rounded: BorderRadius; + $bordered: boolean | Color; + $rounded: Rounded; $padding: Spacing; $shadowed: boolean; - $background: Variants; + $background?: Color; $isHoverable?: boolean; $isPressable?: boolean; }; const StyledCard = styled(Flex)` - color: ${theme.colors.textPrimary}; - background-color: ${({ $background }) => theme.card.bg[$background]}; - border: ${({ $variant }) => ($variant === 'bordered' ? theme.border.default : theme.card.outlined.border)}; - border-radius: ${({ $rounded }) => theme.rounded[$rounded]}; - padding: ${({ $padding }) => theme.spacing[$padding]}; + border-radius: ${({ $rounded, theme }) => theme.rounded($rounded)}; + padding: ${({ $padding, theme }) => theme.spacing($padding)}; cursor: ${({ $isPressable }) => $isPressable && 'pointer'}; outline: none; - ${({ $shadowed }) => - $shadowed && - css` - box-shadow: ${theme.boxShadow.default}; - `} + // TODO: add isHoverable + ${({ $bordered, $isPressable, $shadowed, $background, theme }) => { + const { border, boxShadow, backgroundColor, ...baseCss } = theme.card.base; - ${({ $isHoverable }) => - $isHoverable && - css` - &:hover { - border: ${theme.border.hover}; - } - `} + return css` + border: ${typeof $bordered === 'boolean' ? border : `1px solid ${$bordered}`}; + box-shadow: ${$shadowed && boxShadow}; + background-color: ${$background ? theme.color($background) : backgroundColor}; + ${baseCss} - ${({ $isPressable }) => - $isPressable && - css` &:focus { - border: ${theme.border.focus}; - box-shadow: ${theme.boxShadow.focus}; + ${$isPressable && theme.card.focus} } - `} + `; + }} `; export { StyledCard }; diff --git a/packages/components/src/Card/Card.tsx b/packages/components/src/Card/Card.tsx index 56551e48f..859072189 100644 --- a/packages/components/src/Card/Card.tsx +++ b/packages/components/src/Card/Card.tsx @@ -2,20 +2,20 @@ import { useButton } from '@react-aria/button'; import { mergeProps } from '@react-aria/utils'; import { PressEvent } from '@react-types/shared'; import { forwardRef } from 'react'; -import { BorderRadius, CardVariants, Spacing, Variants } from '@interlay/theme'; import { useDOMRef } from '@interlay/hooks'; +import { Color, Rounded, Spacing } from '@interlay/theme'; import { FlexProps } from '../Flex'; import { StyledCard } from './Card.style'; type Props = { - variant?: CardVariants; - background?: Variants; isHoverable?: boolean; isPressable?: boolean; isDisabled?: boolean; - rounded?: BorderRadius; + background?: Color; + bordered?: boolean | Color; + rounded?: Rounded; padding?: Spacing; shadowed?: boolean; onPress?: (e: PressEvent) => void; @@ -28,17 +28,17 @@ type CardProps = Props & InheritAttrs; const Card = forwardRef( ( { - variant = 'default', direction = 'column', - background = 'primary', + background, isHoverable, isPressable, children, elementType, isDisabled, rounded = 'xl', - padding = 'spacing6', - shadowed = true, + padding = 'md', + shadowed = false, + bordered = true, ...props }, ref @@ -53,12 +53,12 @@ const Card = forwardRef( ; - -export const Default: StoryObj = { - args: { - ticker: 'BTC' - }, - argTypes: { - ticker: { control: 'select', options: Object.keys(coins) } - } -}; - -export const LPTokens: StoryFn = (args) => { - return ( - - - - - - ); -}; diff --git a/packages/components/src/CoinIcon/CoinIcon.style.tsx b/packages/components/src/CoinIcon/CoinIcon.style.tsx deleted file mode 100644 index 98d0e79ff..000000000 --- a/packages/components/src/CoinIcon/CoinIcon.style.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import styled from 'styled-components'; -import { Icon } from '@interlay/icons'; -import { theme } from '@interlay/theme'; - -const StyledFallbackIcon = styled(Icon)` - stroke: ${theme.icon.fallback.stroke}; - color: ${theme.icon.fallback.color}; -`; - -export { StyledFallbackIcon }; diff --git a/packages/components/src/CoinIcon/CoinIcon.tsx b/packages/components/src/CoinIcon/CoinIcon.tsx deleted file mode 100644 index 2ec3b2f0c..000000000 --- a/packages/components/src/CoinIcon/CoinIcon.tsx +++ /dev/null @@ -1,40 +0,0 @@ -import { forwardRef } from 'react'; -import { IconProps } from '@interlay/icons'; - -import * as coins from '../../../icons/coin/src'; - -import { FallbackIcon } from './FallbackIcon'; -import { LPCoinIcon } from './LPCoinIcon'; -import { CoinComponent } from './types'; - -const DATA = coins as unknown as Record; - -type Props = { - ticker: string; - // Multi tickers icons - tickers?: string[]; -}; - -type NativeAttrs = Omit; - -type CoinIconProps = Props & NativeAttrs; - -const CoinIcon = forwardRef(({ ticker, tickers, ...props }, ref): JSX.Element => { - // Only want to render multi-token if has more than 1 ticker - if (tickers && tickers?.length > 1) { - return ; - } - - const CoinIcon = DATA[ticker]; - - if (!CoinIcon) { - return ; - } - - return ; -}); - -CoinIcon.displayName = 'CoinIcon'; - -export { CoinIcon }; -export type { CoinIconProps }; diff --git a/packages/components/src/CoinIcon/FallbackIcon.tsx b/packages/components/src/CoinIcon/FallbackIcon.tsx deleted file mode 100644 index 1d11f7a8f..000000000 --- a/packages/components/src/CoinIcon/FallbackIcon.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import { forwardRef } from 'react'; - -import { CoinIconProps } from './CoinIcon'; -import { StyledFallbackIcon } from './CoinIcon.style'; - -const FallbackIcon = forwardRef( - ({ ticker, ...props }, ref): JSX.Element => ( - - {ticker} - - - ) -); - -FallbackIcon.displayName = 'FallbackIcon'; - -export { FallbackIcon }; diff --git a/packages/components/src/CoinIcon/LPCoinIcon.tsx b/packages/components/src/CoinIcon/LPCoinIcon.tsx deleted file mode 100644 index 43bb77061..000000000 --- a/packages/components/src/CoinIcon/LPCoinIcon.tsx +++ /dev/null @@ -1,65 +0,0 @@ -import { forwardRef, useCallback } from 'react'; -import { Icon } from '@interlay/icons'; - -import { CoinIconProps } from './CoinIcon'; -import { FallbackIcon } from './FallbackIcon'; -import { CoinComponent } from './types'; - -type Props = { - tickers: string[]; - data: Record; -}; - -type InheritAttrs = Omit; - -type LPCoinIconProps = Props & InheritAttrs; - -const LPCoinIcon = forwardRef( - ({ tickers, size = 'md', ticker, data, ...props }, ref): JSX.Element => { - const [tickerA, tickerB, tickerC, tickerD] = tickers; - - const getIcon = useCallback( - (ticker: string) => data[ticker] || (() => ), - [size] - ); - - const IconA = getIcon(tickerA); - const IconB = getIcon(tickerB); - - if (tickers.length === 2) { - return ( - - {ticker} - - - - ); - } - - const IconC = getIcon(tickerC); - - const hasIconD = !!tickerD; - - const IconD = hasIconD && getIcon(tickerD); - - const commonSize = { - width: '60%', - height: '60%' - }; - - return ( - - {ticker} - - - - {IconD && } - - ); - } -); - -LPCoinIcon.displayName = 'LPCoinIcon'; - -export { LPCoinIcon }; -export type { LPCoinIconProps }; diff --git a/packages/components/src/CoinIcon/__tests__/Card.test.tsx b/packages/components/src/CoinIcon/__tests__/Card.test.tsx deleted file mode 100644 index 634140e42..000000000 --- a/packages/components/src/CoinIcon/__tests__/Card.test.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import { render } from '@testing-library/react'; -import { createRef } from 'react'; -import { testA11y } from '@interlay/test-utils'; - -import { CoinIcon } from '..'; - -describe('CoinIcon', () => { - it('should render correctly', () => { - const wrapper = render(); - - expect(() => wrapper.unmount()).not.toThrow(); - }); - - it('ref should be forwarded', () => { - const ref = createRef(); - - render( - - content - - ); - - expect(ref.current).not.toBeNull(); - }); - - it('should pass a11y', async () => { - await testA11y(); - }); -}); diff --git a/packages/components/src/CoinIcon/index.tsx b/packages/components/src/CoinIcon/index.tsx deleted file mode 100644 index ab9ba1d84..000000000 --- a/packages/components/src/CoinIcon/index.tsx +++ /dev/null @@ -1,2 +0,0 @@ -export type { CoinIconProps } from './CoinIcon'; -export { CoinIcon } from './CoinIcon'; diff --git a/packages/components/src/CoinIcon/types.ts b/packages/components/src/CoinIcon/types.ts deleted file mode 100644 index 16b884c64..000000000 --- a/packages/components/src/CoinIcon/types.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { ForwardRefExoticComponent, RefAttributes } from 'react'; -import { IconProps } from '@interlay/icons'; - -export type CoinComponent = ForwardRefExoticComponent>; diff --git a/packages/components/src/Dialog/Dialog.style.tsx b/packages/components/src/Dialog/Dialog.style.tsx index b8c99f851..9a6bc13a8 100644 --- a/packages/components/src/Dialog/Dialog.style.tsx +++ b/packages/components/src/Dialog/Dialog.style.tsx @@ -1,54 +1,55 @@ -import styled from 'styled-components'; +import styled, { css } from 'styled-components'; +import { DialogSize, Spacing } from '@interlay/theme'; -import { theme } from '../../../core/theme/src'; -import { Sizes } from '../../../core/theme/src'; -import { CTA } from '../CTA'; -import { Divider } from '../Divider'; import { Flex } from '../Flex'; import { H3 } from '../Text'; +import { Button } from '../Button'; type StyledDialogProps = { - $size: Sizes; + $size: DialogSize; +}; + +type StyledDialogBodyProps = { + $maxHeight?: Spacing; }; const StyledDialog = styled.section` - background: ${theme.colors.bgPrimary}; - border: ${theme.border.default}; - border-radius: ${theme.rounded.md}; - color: ${theme.colors.textPrimary}; - max-width: 100%; - width: ${({ $size }) => theme.dialog[$size].width}; display: flex; flex-direction: column; position: relative; outline: none; + overflow: hidden; + + width: 100%; + ${({ theme, $size }) => css` + ${theme.dialog.base} + ${theme.dialog.size[$size]} + `} `; -const StyledCloseCTA = styled(CTA)` +const StyledCloseBtn = styled(Button)` position: absolute; - top: ${theme.spacing.spacing2}; - right: ${theme.spacing.spacing2}; - z-index: ${theme.dialog.closeBtn.zIndex}; + top: ${({ theme }) => theme.spacing('md')}; + right: ${({ theme }) => theme.spacing('md')}; + z-index: 100; `; -const StyledDialogHeader = styled(H3)` - padding: ${({ $size }) => theme.dialog[$size].header.padding}; +const StyledDialogHeader = styled(H3)` + ${({ theme }) => theme.dialog.header}; + overflow: hidden; flex-shrink: 0; `; -const StyledDialogDivider = styled(Divider)` - margin: ${({ $size }) => `0 ${theme.dialog[$size].divider.marginX} ${theme.dialog[$size].divider.marginBottom}`}; - flex-shrink: 0; -`; +const StyledDialogBody = styled(Flex)` + ${({ theme }) => theme.dialog.body}; + max-height: ${({ theme, $maxHeight }) => $maxHeight && theme.spacing($maxHeight)}; -const StyledDialogBody = styled(Flex)` - padding: ${({ $size }) => `${theme.dialog[$size].body.paddingY} ${theme.dialog[$size].body.paddingX}`}; flex: 1 1 auto; `; -const StyledDialogFooter = styled(Flex)` - padding: ${({ $size }) => theme.dialog[$size].footer.padding}; +const StyledDialogFooter = styled(Flex)` + ${({ theme }) => theme.dialog.footer}; `; -export { StyledCloseCTA, StyledDialog, StyledDialogBody, StyledDialogDivider, StyledDialogFooter, StyledDialogHeader }; +export { StyledCloseBtn, StyledDialog, StyledDialogBody, StyledDialogFooter, StyledDialogHeader }; diff --git a/packages/components/src/Dialog/Dialog.tsx b/packages/components/src/Dialog/Dialog.tsx index 8eb4fcb6f..da92d155f 100644 --- a/packages/components/src/Dialog/Dialog.tsx +++ b/packages/components/src/Dialog/Dialog.tsx @@ -4,19 +4,17 @@ import { PressEvent } from '@react-types/shared'; import { forwardRef, ReactNode } from 'react'; import { XMark } from '@interlay/icons'; import { useDOMRef } from '@interlay/hooks'; +import { DialogSize } from '@interlay/theme'; -import { CTASizes, Sizes } from '../../../core/theme/src'; import { ElementTypeProp } from '../utils/types'; -import { StyledCloseCTA, StyledDialog } from './Dialog.style'; +import { StyledCloseBtn, StyledDialog } from './Dialog.style'; import { DialogContext } from './DialogContext'; -const closeCTASizeMap: Record = { small: 'x-small', medium: 'small', large: 'small' }; - type Props = { children?: ReactNode; onClose?: (e: PressEvent) => void; - size?: Sizes; + size?: DialogSize; }; type InheritAttrs = Omit; @@ -24,21 +22,19 @@ type InheritAttrs = Omit; type DialogProps = Props & InheritAttrs & ElementTypeProp; const Dialog = forwardRef( - ({ children, onClose, size = 'medium', elementType, role = 'dialog', ...props }, ref): JSX.Element => { + ({ children, onClose, size = 'md', elementType, role = 'dialog', ...props }, ref): JSX.Element => { const dialogRef = useDOMRef(ref); // Get props for the dialog and its title const { dialogProps, titleProps } = useDialog(props, dialogRef); - const closeCTASize = closeCTASizeMap[size]; - return ( {onClose && ( - - - + + + )} {children} diff --git a/packages/components/src/Dialog/DialogBody.tsx b/packages/components/src/Dialog/DialogBody.tsx index 91612834e..c81291c5d 100644 --- a/packages/components/src/Dialog/DialogBody.tsx +++ b/packages/components/src/Dialog/DialogBody.tsx @@ -1,14 +1,19 @@ +import { Spacing } from '@interlay/theme'; + import { FlexProps } from '../Flex'; import { StyledDialogBody } from './Dialog.style'; -import { useDialogContext } from './DialogContext'; -type DialogBodyProps = FlexProps; +type Props = { + maxHeight?: Spacing; +}; + +type InheritAttrs = Omit; -const DialogBody = ({ direction = 'column', ...props }: DialogBodyProps): JSX.Element => { - const { size } = useDialogContext(); +type DialogBodyProps = Props & InheritAttrs; - return ; +const DialogBody = ({ direction = 'column', maxHeight, ...props }: DialogBodyProps): JSX.Element => { + return ; }; export { DialogBody }; diff --git a/packages/components/src/Dialog/DialogContext.tsx b/packages/components/src/Dialog/DialogContext.tsx index bbd1cc2f9..f8b4897d7 100644 --- a/packages/components/src/Dialog/DialogContext.tsx +++ b/packages/components/src/Dialog/DialogContext.tsx @@ -1,14 +1,13 @@ import { DOMAttributes } from '@react-types/shared'; import React from 'react'; - -import { Sizes } from '../../../core/theme/src'; +import { DialogSize } from '@interlay/theme'; interface DialogConfig { titleProps?: DOMAttributes; - size: Sizes; + size: DialogSize; } -const defaultContext: DialogConfig = { size: 'medium' }; +const defaultContext: DialogConfig = { size: 'md' }; const DialogContext = React.createContext(defaultContext); diff --git a/packages/components/src/Dialog/DialogDivider.tsx b/packages/components/src/Dialog/DialogDivider.tsx deleted file mode 100644 index 4a37a37e9..000000000 --- a/packages/components/src/Dialog/DialogDivider.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import { DividerProps } from '../Divider'; - -import { StyledDialogDivider } from './Dialog.style'; -import { useDialogContext } from './DialogContext'; - -type DialogDividerProps = Omit; - -const DialogDivider = (props: DialogDividerProps): JSX.Element => { - const { size } = useDialogContext(); - - return ; -}; - -export { DialogDivider }; -export type { DialogDividerProps }; diff --git a/packages/components/src/Dialog/DialogFooter.tsx b/packages/components/src/Dialog/DialogFooter.tsx index 0702a39c9..a0347b019 100644 --- a/packages/components/src/Dialog/DialogFooter.tsx +++ b/packages/components/src/Dialog/DialogFooter.tsx @@ -1,16 +1,13 @@ import { FlexProps } from '../Flex'; import { StyledDialogFooter } from './Dialog.style'; -import { useDialogContext } from './DialogContext'; type InheritAttrs = FlexProps; type DialogFooterProps = InheritAttrs; const DialogFooter = (props: DialogFooterProps): JSX.Element => { - const { size } = useDialogContext(); - - return ; + return ; }; export { DialogFooter }; diff --git a/packages/components/src/Dialog/DialogHeader.tsx b/packages/components/src/Dialog/DialogHeader.tsx index 031bda8b1..fc3a56c3f 100644 --- a/packages/components/src/Dialog/DialogHeader.tsx +++ b/packages/components/src/Dialog/DialogHeader.tsx @@ -1,18 +1,11 @@ import { mergeProps } from '@react-aria/utils'; import { ElementType } from 'react'; -import { FontSize, Sizes } from '../../../core/theme/src'; import { TextProps } from '../Text'; import { StyledDialogHeader } from './Dialog.style'; import { useDialogContext } from './DialogContext'; -const sizeMap: Record = { - small: 'base', - medium: 'xl', - large: 'xl' -}; - type Props = { elementType?: ElementType; }; @@ -21,11 +14,11 @@ type InheritAttrs = Omit; type DialogHeaderProps = Props & InheritAttrs; -const DialogHeader = ({ elementType, children, ...props }: DialogHeaderProps): JSX.Element => { - const { titleProps, size } = useDialogContext(); +const DialogHeader = ({ elementType, children, align = 'start', ...props }: DialogHeaderProps): JSX.Element => { + const { titleProps } = useDialogContext(); return ( - + {children} ); diff --git a/packages/components/src/Dialog/__tests__/Dialog.test.tsx b/packages/components/src/Dialog/__tests__/Dialog.test.tsx index f71c3ac18..04193234e 100644 --- a/packages/components/src/Dialog/__tests__/Dialog.test.tsx +++ b/packages/components/src/Dialog/__tests__/Dialog.test.tsx @@ -1,15 +1,13 @@ -import { render } from '@testing-library/react'; +import { render, testA11y } from '@interlay/test-utils'; import { createRef } from 'react'; -import { testA11y } from '@interlay/test-utils'; -import { Dialog, DialogBody, DialogDivider, DialogFooter, DialogHeader } from '..'; +import { Dialog, DialogBody, DialogFooter, DialogHeader } from '..'; describe('Dialog', () => { it('should render correctly', () => { const wrapper = render( title - body footer @@ -24,7 +22,6 @@ describe('Dialog', () => { render( title - body footer @@ -37,7 +34,6 @@ describe('Dialog', () => { await testA11y( title - body footer diff --git a/packages/components/src/Dialog/index.tsx b/packages/components/src/Dialog/index.tsx index b5980d46c..328100e8d 100644 --- a/packages/components/src/Dialog/index.tsx +++ b/packages/components/src/Dialog/index.tsx @@ -2,8 +2,6 @@ export type { DialogProps } from './Dialog'; export { Dialog } from './Dialog'; export type { DialogBodyProps } from './DialogBody'; export { DialogBody } from './DialogBody'; -export type { DialogDividerProps } from './DialogDivider'; -export { DialogDivider } from './DialogDivider'; export type { DialogFooterProps } from './DialogFooter'; export { DialogFooter } from './DialogFooter'; export type { DialogHeaderProps } from './DialogHeader'; diff --git a/packages/components/src/Divider/Divider.stories.tsx b/packages/components/src/Divider/Divider.stories.tsx index a89608a6c..7da3dc2d1 100644 --- a/packages/components/src/Divider/Divider.stories.tsx +++ b/packages/components/src/Divider/Divider.stories.tsx @@ -15,11 +15,11 @@ export default { -

Divider

+

Divider

Divides content

diff --git a/packages/components/src/Divider/Divider.style.tsx b/packages/components/src/Divider/Divider.style.tsx index 08288fb05..889d69b06 100644 --- a/packages/components/src/Divider/Divider.style.tsx +++ b/packages/components/src/Divider/Divider.style.tsx @@ -1,20 +1,20 @@ import styled from 'styled-components'; import { StyledMarginProps } from '@interlay/hooks'; +import { Color, DividerSizes } from '@interlay/theme'; -import { theme, resolveColor } from '../../../core/theme/src'; -import { DividerVariants, Orientation, Sizes } from '../../../core/theme/src'; +import { Orientation } from '../../../core/theme/src'; import { marginCSS } from '../utils/margin'; type StyledDividerProps = { - $color: DividerVariants; + $color: Color; $orientation: Orientation; - $size: Sizes; + $size: DividerSizes; } & StyledMarginProps; const StyledDivider = styled.hr` - background-color: ${({ $color }) => ($color === 'default' ? 'var(--colors-border)' : resolveColor($color))}; - height: ${({ $orientation, $size }) => ($orientation === 'horizontal' ? theme.divider.size[$size] : 'auto')}; - width: ${({ $orientation, $size }) => ($orientation === 'horizontal' ? '' : theme.divider.size[$size])}; + background-color: ${({ $color, theme }) => theme.color($color)}; + height: ${({ $orientation, $size, theme }) => ($orientation === 'horizontal' ? theme.divider.size[$size] : 'auto')}; + width: ${({ $orientation, $size, theme }) => ($orientation === 'horizontal' ? '' : theme.divider.size[$size])}; border: 0; margin: 0; align-self: stretch; diff --git a/packages/components/src/Divider/Divider.tsx b/packages/components/src/Divider/Divider.tsx index 633aa17f5..e6972b635 100644 --- a/packages/components/src/Divider/Divider.tsx +++ b/packages/components/src/Divider/Divider.tsx @@ -2,16 +2,17 @@ import { useSeparator } from '@react-aria/separator'; import { mergeProps } from '@react-aria/utils'; import { forwardRef, HTMLAttributes } from 'react'; import { useStyleProps } from '@interlay/hooks'; +import { Color, DividerSizes } from '@interlay/theme'; -import { DividerVariants, MarginProps, Orientation, Sizes } from '../../../core/theme/src'; +import { MarginProps, Orientation } from '../../../core/theme/src'; import { ElementTypeProp } from '../utils/types'; import { StyledDivider } from './Divider.style'; type Props = { orientation?: Orientation; - color?: DividerVariants; - size?: Sizes; + color?: Color; + size?: DividerSizes; }; type NativeAttrs = Omit, keyof Props>; @@ -20,7 +21,7 @@ type DividerProps = Props & NativeAttrs & ElementTypeProp & MarginProps; const Divider = forwardRef( ( - { elementType: elementTypeProp, orientation = 'horizontal', color = 'primary', size = 'small', ...props }, + { elementType: elementTypeProp, orientation = 'horizontal', color = 'grey-400', size = 's', ...props }, ref ): JSX.Element => { const elementType = elementTypeProp || orientation === 'vertical' ? 'div' : 'hr'; diff --git a/packages/components/src/Divider/__tests__/Divider.test.tsx b/packages/components/src/Divider/__tests__/Divider.test.tsx index 7d8ff2c30..ef227d09b 100644 --- a/packages/components/src/Divider/__tests__/Divider.test.tsx +++ b/packages/components/src/Divider/__tests__/Divider.test.tsx @@ -1,6 +1,5 @@ -import { render } from '@testing-library/react'; +import { render, testA11y } from '@interlay/test-utils'; import { createRef } from 'react'; -import { testA11y } from '@interlay/test-utils'; import { Divider } from '..'; diff --git a/packages/components/src/Drawer/Drawer.stories.tsx b/packages/components/src/Drawer/Drawer.stories.tsx index bc31a0a2a..dba04eea5 100644 --- a/packages/components/src/Drawer/Drawer.stories.tsx +++ b/packages/components/src/Drawer/Drawer.stories.tsx @@ -1,7 +1,7 @@ import { Meta, StoryObj } from '@storybook/react'; import { useState } from 'react'; -import { CTA } from '..'; +import { Button } from '..'; import { Drawer, DrawerProps } from '.'; @@ -18,7 +18,7 @@ const Render = () => { return ( <> - setOpen(true)}>Open + setOpen(false)}> Drawer diff --git a/packages/components/src/Drawer/Drawer.style.tsx b/packages/components/src/Drawer/Drawer.style.tsx index d624d0fc8..c698b0a62 100644 --- a/packages/components/src/Drawer/Drawer.style.tsx +++ b/packages/components/src/Drawer/Drawer.style.tsx @@ -1,5 +1,4 @@ import styled from 'styled-components'; -import { theme } from '@interlay/theme'; import { overlayCSS } from '../utils/overlay'; import { Dialog } from '../Dialog'; @@ -23,7 +22,7 @@ const StyledModal = styled.div` opacity: 1; overflow-y: scroll; - z-index: ${theme.modal.zIndex}; + z-index: 2; position: fixed; top: 0; bottom: 0; @@ -31,11 +30,10 @@ const StyledModal = styled.div` right: 100%; height: 100%; - background: ${theme.colors.bgPrimary}; - transition: transform - ${({ $isOpen }) => ($isOpen ? theme.transition.duration.duration250 : theme.transition.duration.duration100)}ms - ease-in-out; + transition: transform ${({ $isOpen }) => ($isOpen ? '250ms' : '100ms')} ease-in-out; + + ${({ theme }) => theme.drawer}; `; const StyledDialog = styled(Dialog)` @@ -48,7 +46,7 @@ const StyledDialog = styled(Dialog)` flex-direction: column; position: relative; outline: none; - padding: ${theme.spacing.spacing4}; + padding: ${({ theme }) => theme.spacing('md')}; `; export { StyledDialog, StyledModal }; diff --git a/packages/components/src/Drawer/__tests__/Drawer.test.tsx b/packages/components/src/Drawer/__tests__/Drawer.test.tsx index 77eda62ce..856616c6a 100644 --- a/packages/components/src/Drawer/__tests__/Drawer.test.tsx +++ b/packages/components/src/Drawer/__tests__/Drawer.test.tsx @@ -1,6 +1,5 @@ -import { render } from '@testing-library/react'; +import { render, testA11y } from '@interlay/test-utils'; import { createRef } from 'react'; -import { testA11y } from '@interlay/test-utils'; import { Drawer } from '..'; diff --git a/packages/components/src/Field/Field.style.tsx b/packages/components/src/Field/Field.style.tsx index 05a57a42a..1dbe228fa 100644 --- a/packages/components/src/Field/Field.style.tsx +++ b/packages/components/src/Field/Field.style.tsx @@ -1,16 +1,22 @@ -import styled from 'styled-components'; -import { Spacing, theme } from '@interlay/theme'; +import styled, { CSSProperties } from 'styled-components'; + +import { Flex } from '../Flex'; type StyledFieldProps = { - $maxWidth?: Spacing; + $maxWidth?: CSSProperties['maxWidth']; + $fullWidth?: boolean; }; -const StyledField = styled.div` +const StyledFieldElWrapper = styled.div` position: relative; - color: ${theme.colors.textPrimary}; box-sizing: border-box; display: inline-flex; - max-width: ${({ $maxWidth }) => $maxWidth && theme.spacing[$maxWidth]}; + height: 100%; +`; + +const StyledField = styled(Flex)` + max-width: ${({ $maxWidth }) => $maxWidth}; + width: ${({ $fullWidth, $maxWidth }) => ($fullWidth || $maxWidth) && '100%'}; `; -export { StyledField }; +export { StyledField, StyledFieldElWrapper }; diff --git a/packages/components/src/Field/Field.tsx b/packages/components/src/Field/Field.tsx index f65fe530f..20a1a8b42 100644 --- a/packages/components/src/Field/Field.tsx +++ b/packages/components/src/Field/Field.tsx @@ -1,18 +1,20 @@ import { forwardRef, HTMLAttributes, ReactNode } from 'react'; -import { LabelPosition, Spacing } from '@interlay/theme'; +import { LabelPosition } from '@interlay/theme'; +import { CSSProperties } from 'styled-components'; import { Flex, FlexProps } from '../Flex'; import { HelperText, HelperTextProps } from '../HelperText'; import { Label, LabelProps } from '../Label'; import { hasError } from '../utils/input'; -import { StyledField } from './Field.style'; +import { StyledField, StyledFieldElWrapper } from './Field.style'; type Props = { label?: ReactNode; labelPosition?: LabelPosition; labelProps?: LabelProps; - maxWidth?: Spacing; + maxWidth?: CSSProperties['maxWidth']; + fullWidth?: boolean; }; type NativeAttrs = Omit, keyof Props>; @@ -33,6 +35,7 @@ const Field = forwardRef( descriptionProps, children, maxWidth, + fullWidth, ...props }, ref @@ -42,7 +45,7 @@ const Field = forwardRef( const element = ( <> - {children} + {children} {hasHelpText && ( ( ); return ( - + {label && ( )} -
+ ); } ); diff --git a/packages/components/src/Field/__tests__/Field.test.tsx b/packages/components/src/Field/__tests__/Field.test.tsx index f42892b4d..7d81d08fd 100644 --- a/packages/components/src/Field/__tests__/Field.test.tsx +++ b/packages/components/src/Field/__tests__/Field.test.tsx @@ -1,6 +1,5 @@ -import { render } from '@testing-library/react'; +import { render, testA11y } from '@interlay/test-utils'; import { createRef } from 'react'; -import { testA11y } from '@interlay/test-utils'; import { Field } from '..'; diff --git a/packages/components/src/Flex/Flex.stories.tsx b/packages/components/src/Flex/Flex.stories.tsx index aed111c59..6fc61a05f 100644 --- a/packages/components/src/Flex/Flex.stories.tsx +++ b/packages/components/src/Flex/Flex.stories.tsx @@ -7,7 +7,7 @@ export default { component: Flex, args: { - gap: 'spacing2' + gap: 'md' }, render: (args: FlexProps) => ( diff --git a/packages/components/src/Flex/Flex.style.tsx b/packages/components/src/Flex/Flex.style.tsx index 09a3421d0..cec5757f1 100644 --- a/packages/components/src/Flex/Flex.style.tsx +++ b/packages/components/src/Flex/Flex.style.tsx @@ -1,13 +1,12 @@ -import type { AlignItems, AlignSelf, Direction, JustifyContent, Spacing, Wrap } from '../../../core/theme/src'; +import type { AlignItems, AlignSelf, Direction, JustifyContent, Spacing, Wrap } from '@interlay/theme'; import { styled } from 'styled-components'; import { StyledMarginProps } from '@interlay/hooks'; -import { theme } from '../../../core/theme/src'; import { marginCSS } from '../utils/margin'; type StyledFlexProps = { - $gap: Spacing; + $gap?: Spacing; $justifyContent?: JustifyContent; $alignItems?: AlignItems; $direction?: Direction; @@ -21,7 +20,7 @@ const StyledFlex = styled.div` flex-direction: ${(props) => props.$direction}; justify-content: ${(props) => props.$justifyContent}; align-items: ${(props) => props.$alignItems}; - gap: ${(props) => theme.spacing[props.$gap]}; + gap: ${({ theme, $gap }) => $gap && theme.spacing($gap)}; flex: ${(props) => props.$flex}; flex-wrap: ${(props) => (typeof props.$wrap === 'boolean' ? 'wrap' : props.$wrap)}; align-self: ${(props) => props.$alignSelf}; diff --git a/packages/components/src/Flex/Flex.tsx b/packages/components/src/Flex/Flex.tsx index 0500f8a4e..ef3f58710 100644 --- a/packages/components/src/Flex/Flex.tsx +++ b/packages/components/src/Flex/Flex.tsx @@ -1,16 +1,8 @@ import type { HTMLAttributes } from 'react'; -import type { - AlignItems, - AlignSelf, - Direction, - JustifyContent, - MarginProps, - Spacing, - Wrap -} from '../../../core/theme/src'; import { forwardRef } from 'react'; import { useStyleProps } from '@interlay/hooks'; +import { AlignItems, AlignSelf, Direction, JustifyContent, MarginProps, Spacing, Wrap } from '@interlay/theme'; import { ElementTypeProp } from '../utils/types'; diff --git a/packages/components/src/Flex/__tests__/Flex.test.tsx b/packages/components/src/Flex/__tests__/Flex.test.tsx index b322c4666..da81e9520 100644 --- a/packages/components/src/Flex/__tests__/Flex.test.tsx +++ b/packages/components/src/Flex/__tests__/Flex.test.tsx @@ -1,6 +1,5 @@ -import { render } from '@testing-library/react'; import { createRef } from 'react'; -import { testA11y } from '@interlay/test-utils'; +import { testA11y, render } from '@interlay/test-utils'; import { Flex } from '..'; diff --git a/packages/components/src/Grid/Grid.stories.tsx b/packages/components/src/Grid/Grid.stories.tsx deleted file mode 100644 index 6af771933..000000000 --- a/packages/components/src/Grid/Grid.stories.tsx +++ /dev/null @@ -1,30 +0,0 @@ -import { Meta, StoryFn } from '@storybook/react'; - -import { Grid, GridItem, GridProps } from '.'; - -export default { - title: 'Layout/Grid', - component: Grid, - subcomponents: { GridItem } -} as Meta; - -export const Default: StoryFn = (args) => ( - - -

Grid content

-

- Lorem ipsum dolor sit amet consectetur adipisicing elit. Nobis nam minima non modi consequuntur corporis est - itaque, exercitationem amet, fugiat optio, facilis repellendus inventore vero perferendis. Possimus porro eaque - facere. -

-
- -

Grid content

-

- Lorem ipsum dolor sit amet consectetur adipisicing elit. Nobis nam minima non modi consequuntur corporis est - itaque, exercitationem amet, fugiat optio, facilis repellendus inventore vero perferendis. Possimus porro eaque - facere. -

-
-
-); diff --git a/packages/components/src/Grid/Grid.style.tsx b/packages/components/src/Grid/Grid.style.tsx deleted file mode 100644 index b4775fb27..000000000 --- a/packages/components/src/Grid/Grid.style.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import styled from 'styled-components'; -import { theme } from '@interlay/theme'; - -export const GridContainer = styled.div` - display: grid; - gap: ${theme.spacing.spacing5}; - grid-template-columns: repeat(4, 1fr); - - @media screen and (min-width: 48em) { - grid-template-columns: repeat(12, 1fr); - } -`; diff --git a/packages/components/src/Grid/Grid.tsx b/packages/components/src/Grid/Grid.tsx deleted file mode 100644 index c3ab5371e..000000000 --- a/packages/components/src/Grid/Grid.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import { GridContainer } from './Grid.style'; - -interface GridProps { - children: React.ReactNode; - className?: string; -} - -const Grid = ({ className, children }: GridProps): JSX.Element => ( - {children} -); - -export { Grid }; -export type { GridProps }; diff --git a/packages/components/src/Grid/GridItem.style.tsx b/packages/components/src/Grid/GridItem.style.tsx deleted file mode 100644 index 44e438bf5..000000000 --- a/packages/components/src/Grid/GridItem.style.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import styled from 'styled-components'; - -import { GridItemProps } from './GridItem'; - -export const GridItemContainer = styled.div` - grid-column: ${(props) => - props.mobile.start ? `${props.mobile.start} / span ${props.mobile.span}` : `span ${props.mobile.span}`}; - grid-row: ${(props) => props.mobile.row || 'auto'}; - justify-self: ${(props) => props.mobile.justify || 'auto'}; - - @media (min-width: 48em) { - grid-column: ${(props) => - props.desktop.start ? `${props.desktop.start} / span ${props.desktop.span}` : `span ${props.desktop.span}`}; - grid-row: ${(props) => props.desktop.row || 'auto'}; - justify-self: ${(props) => props.desktop.justify || 'auto'}; - } -`; diff --git a/packages/components/src/Grid/GridItem.tsx b/packages/components/src/Grid/GridItem.tsx deleted file mode 100644 index 3ecdfe568..000000000 --- a/packages/components/src/Grid/GridItem.tsx +++ /dev/null @@ -1,30 +0,0 @@ -import { GridItemContainer } from './GridItem.style'; - -type Justify = 'start' | 'center' | 'end'; - -type GridColumnsWide = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12; -type GridColumnsNarrow = 1 | 2 | 3 | 4; - -interface GridItemProps extends React.HTMLAttributes { - mobile: { - span: GridColumnsNarrow; - start?: GridColumnsNarrow; - row?: number; - justify?: Justify; - }; - desktop: { - span: GridColumnsWide; - start?: GridColumnsWide; - row?: number; - justify?: Justify; - }; -} - -const GridItem = ({ mobile, desktop, className, children }: GridItemProps): JSX.Element => ( - - {children} - -); - -export { GridItem }; -export type { GridItemProps }; diff --git a/packages/components/src/Grid/__tests__/Grid.test.tsx b/packages/components/src/Grid/__tests__/Grid.test.tsx deleted file mode 100644 index ae83a76f5..000000000 --- a/packages/components/src/Grid/__tests__/Grid.test.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import { render } from '@testing-library/react'; - -import { Grid, GridItem } from '..'; - -describe('Grid', () => { - it('should render correctly', () => { - const wrapper = render( - - - item - - - ); - - expect(() => wrapper.unmount()).not.toThrow(); - }); -}); diff --git a/packages/components/src/Grid/index.ts b/packages/components/src/Grid/index.ts deleted file mode 100644 index 4de7077e0..000000000 --- a/packages/components/src/Grid/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -export type { GridProps } from './Grid'; -export { Grid } from './Grid'; -export type { GridItemProps } from './GridItem'; -export { GridItem } from './GridItem'; diff --git a/packages/components/src/HelperText/HelperText.style.tsx b/packages/components/src/HelperText/HelperText.style.tsx index bf979bbe1..d9e733c6f 100644 --- a/packages/components/src/HelperText/HelperText.style.tsx +++ b/packages/components/src/HelperText/HelperText.style.tsx @@ -1,5 +1,4 @@ import styled from 'styled-components'; -import { theme } from '@interlay/theme'; import { visuallyHidden } from '../utils/visually-hidden'; @@ -9,16 +8,15 @@ type StyledHelperTextProps = { }; const StyledHelperText = styled.div` - font-weight: ${theme.fontWeight.medium}; - line-height: ${theme.lineHeight.lg}; - font-size: ${theme.text.xs}; - color: ${(props) => (props.$hasError ? theme.input.helperText.error.color : theme.colors.textTertiary)}; - padding: ${theme.spacing.spacing1} 0; + font-weight: ${({ theme }) => theme.fontWeight('medium')}; + ${({ theme }) => theme.typography('xs')} + color: ${({ $hasError, theme }) => ($hasError ? theme.color('red-500') : theme.color('grey-100'))}; + padding: ${({ theme }) => theme.spacing('xs')} 0; ${({ $isHidden }) => $isHidden && visuallyHidden()} `; const StyledSubHelperText = styled.p` - line-height: ${theme.lineHeight.s}; + line-height: ${({ theme }) => theme.lineHeight('s')}; `; export { StyledHelperText, StyledSubHelperText }; diff --git a/packages/components/src/HelperText/__tests__/HelperText.test.tsx b/packages/components/src/HelperText/__tests__/HelperText.test.tsx index f684d9582..347f3ba24 100644 --- a/packages/components/src/HelperText/__tests__/HelperText.test.tsx +++ b/packages/components/src/HelperText/__tests__/HelperText.test.tsx @@ -1,6 +1,5 @@ -import { render } from '@testing-library/react'; import { createRef } from 'react'; -import { testA11y } from '@interlay/test-utils'; +import { testA11y, render } from '@interlay/test-utils'; import { HelperText } from '..'; diff --git a/packages/components/src/Input/BaseInput.tsx b/packages/components/src/Input/BaseInput.tsx index d81825f9d..f4370a9e7 100644 --- a/packages/components/src/Input/BaseInput.tsx +++ b/packages/components/src/Input/BaseInput.tsx @@ -1,22 +1,13 @@ -import { Sizes, Spacing } from '@interlay/theme'; -import { - FocusEvent, - forwardRef, - InputHTMLAttributes, - ReactNode, - TextareaHTMLAttributes, - useEffect, - useRef, - useState -} from 'react'; +import { Spacing, InputSizes } from '@interlay/theme'; +import { FocusEvent, forwardRef, InputHTMLAttributes, ReactNode, TextareaHTMLAttributes } from 'react'; -import { ElementTypeProp } from '../utils/types'; import { Field, FieldProps, useFieldProps } from '../Field'; import { HelperTextProps } from '../HelperText'; import { LabelProps } from '../Label'; import { hasError } from '../utils/input'; +import { ElementTypeProp } from '../utils/types'; -import { Adornment, StyledBaseInput } from './Input.style'; +import { StyledAdornmentLeft, StyledAdornmentRight, StyledBaseInput } from './Input.style'; // TODO: might need to consolidate this later interface HTMLInputProps extends ElementTypeProp { @@ -36,10 +27,9 @@ type Props = { labelProps?: LabelProps; startAdornment?: ReactNode; endAdornment?: ReactNode; - bottomAdornment?: ReactNode; value?: string | ReadonlyArray | number; defaultValue?: string | ReadonlyArray | number; - size?: Sizes; + size?: InputSizes; isInvalid?: boolean; minHeight?: Spacing; onFocus?: (e: FocusEvent) => void; @@ -51,57 +41,33 @@ type InheritAttrs = Omit< Pick, keyof Props >; + type BaseInputProps = Props & InheritAttrs; const BaseInput = forwardRef( ( - { - startAdornment, - endAdornment, - bottomAdornment, - size = 'medium', - isInvalid, - inputProps, - minHeight, - elementType = 'input', - ...props - }, + { startAdornment, endAdornment, size = 'md', isInvalid, inputProps, minHeight, elementType = 'input', ...props }, ref ): JSX.Element => { - const endAdornmentRef = useRef(null); - const [endAdornmentWidth, setEndAdornmentWidth] = useState(0); - // FIXME: move this into Field const { fieldProps } = useFieldProps(props); - useEffect(() => { - if (!endAdornmentRef.current || !endAdornment) return; - - setEndAdornmentWidth(endAdornmentRef.current.getBoundingClientRect().width); - }, [endAdornment]); - const error = hasError({ isInvalid, errorMessage: props.errorMessage }); return ( - {startAdornment && {startAdornment}} + {startAdornment && {startAdornment}} - {bottomAdornment && {bottomAdornment}} - {endAdornment && ( - - {endAdornment} - - )} + {endAdornment && {endAdornment}} ); } diff --git a/packages/components/src/Input/Input.stories.tsx b/packages/components/src/Input/Input.stories.tsx index 0ac6c7be4..c871d8bf8 100644 --- a/packages/components/src/Input/Input.stories.tsx +++ b/packages/components/src/Input/Input.stories.tsx @@ -1,8 +1,7 @@ import { Meta, StoryFn, StoryObj } from '@storybook/react'; -import { useState } from 'react'; import { InformationCircle } from '@interlay/icons'; -import { Flex, Span } from '..'; +import { Flex } from '../Flex'; import { Input, InputProps } from '.'; @@ -19,17 +18,17 @@ export default { export const Default: StoryObj = {}; -export const Controlled: StoryFn = (args) => { - const [state, setState] = useState(); +// export const Controlled: StoryFn = (args) => { +// const [state, setState] = useState(); - return setState(e.target.value)} />; -}; +// return setState(e.target.value)} />; +// }; -export const DefaultValue: StoryObj = { - args: { - defaultValue: 'Sesame Street' - } -}; +// export const DefaultValue: StoryObj = { +// args: { +// defaultValue: 'Sesame Street' +// } +// }; export const WithDescription: StoryObj = { args: { @@ -43,47 +42,44 @@ export const WithErrorMessage: StoryObj = { } }; -export const WithMultipleErrorMessage: StoryObj = { - args: { - errorMessage: ['Please enter your street address', 'Please enter your street address'] - } -}; +// export const WithMultipleErrorMessage: StoryObj = { +// args: { +// errorMessage: ['Please enter your street address', 'Please enter your street address'] +// } +// }; -export const SideLabel: StoryObj = { - args: { - labelPosition: 'side' - } -}; +// export const SideLabel: StoryObj = { +// args: { +// labelPosition: 'side' +// } +// }; -export const MaxWidth: StoryObj = { - args: { - maxWidth: 'spacing28' - } -}; +// export const MaxWidth: StoryObj = { +// args: { +// maxWidth: 'spacing28' +// } +// }; export const Adornments: StoryFn = (args) => ( } /> } label='End Adornment' /> - - $0.00 - - } - label='Bottom Adornment' - /> ); -export const Sizes: StoryFn = (args) => ( - - - - - -); +// export const Sizes: StoryFn = (args) => ( +// +// +// +// +// +// ); + +export const Placeholder: StoryObj = { + args: { + placeholder: 'Enter address' + } +}; export const Disabled: StoryObj = { args: { diff --git a/packages/components/src/Input/Input.style.tsx b/packages/components/src/Input/Input.style.tsx index 6976bfcfc..200d7e5b8 100644 --- a/packages/components/src/Input/Input.style.tsx +++ b/packages/components/src/Input/Input.style.tsx @@ -1,20 +1,14 @@ -import styled from 'styled-components'; -import { Spacing, theme } from '@interlay/theme'; -import { Placement, Sizes } from '@interlay/theme'; +import { InputSizes, Spacing } from '@interlay/theme'; +import styled, { css } from 'styled-components'; type BaseInputProps = { - $size: Sizes; - $adornments: { bottom: boolean; left: boolean; right: boolean }; + $size: InputSizes; + $adornments: { left: boolean; right: boolean }; $isDisabled: boolean; $hasError: boolean; - $endAdornmentWidth: number; $minHeight?: Spacing; }; -type AdornmentProps = { - $position: Placement; -}; - const StyledBaseInput = styled.input` display: block; width: 100%; @@ -25,58 +19,49 @@ const StyledBaseInput = styled.input` letter-spacing: inherit; background: none; - color: ${(props) => (props.disabled ? theme.input.disabled.color : theme.input.color)}; - font-size: ${({ $size, $adornments }) => - $adornments.bottom ? theme.input.overflow.large.text : theme.input[$size].text}; - line-height: ${theme.lineHeight.base}; - font-weight: ${({ $size }) => theme.input[$size].weight}; text-overflow: ellipsis; - background-color: ${({ $isDisabled }) => ($isDisabled ? theme.input.disabled.bg : theme.input.background)}; - overflow: hidden; - - border: ${(props) => - props.$isDisabled - ? theme.input.disabled.border - : props.$hasError - ? theme.input.error.border - : theme.border.default}; - border-radius: ${theme.rounded.lg}; - transition: - border-color ${theme.transition.duration.duration150}ms ease-in-out, - box-shadow ${theme.transition.duration.duration150}ms ease-in-out; - - padding-top: ${theme.spacing.spacing2}; - padding-left: ${({ $adornments }) => ($adornments.left ? theme.input.paddingX.md : theme.spacing.spacing2)}; + // Properties for textarea + min-height: ${({ $minHeight, theme, as }) => + $minHeight ? theme.spacing($minHeight) : as === 'textarea' && theme.spacing('7xl')}; + resize: ${({ as }) => as === 'textarea' && 'vertical'}; - padding-right: ${({ $adornments, $endAdornmentWidth }) => { - if (!$adornments.right) theme.spacing.spacing2; + ${({ theme, $size, $adornments, $hasError }) => { + const { paddingRight, paddingTop, paddingBottom, paddingLeft, ...sizeCss } = theme.input.size[$size]; // MEMO: adding `spacing6` is a hacky solution because // the `endAdornmentWidth` does not update width correctly // after fonts are loaded. Instead of falling back to a more // complex solution, an extra offset does the job of not allowing // the input overlap the adornment. - return `calc(${$endAdornmentWidth}px + ${theme.spacing.spacing6})`; - }}; - padding-bottom: ${({ $adornments }) => ($adornments.bottom ? theme.spacing.spacing6 : theme.spacing.spacing2)}; + return css` + padding-top: ${paddingTop}; + padding-bottom: ${paddingBottom}; + padding-left: ${$adornments.left ? theme.spacing('5xl') : paddingLeft}; + padding-right: ${$adornments.right ? theme.spacing('5xl') : paddingRight}; - min-height: ${({ $minHeight, as }) => - $minHeight ? theme.spacing[$minHeight] : as === 'textarea' && theme.spacing.spacing16}; - resize: ${({ as }) => as === 'textarea' && 'vertical'}; + ${sizeCss} + ${theme.input.base} + ${$hasError && theme.input.error.base} - &:hover:not(:disabled):not(:focus) { - border: ${(props) => !props.$isDisabled && !props.$hasError && theme.border.focus}; - } - &:focus { - border: ${(props) => !props.$isDisabled && theme.border.focus}; - box-shadow: ${(props) => !props.$isDisabled && theme.boxShadow.focus}; - } + &:hover:not(:disabled):not(:focus) { + ${$hasError ? theme.input.error.hover : theme.input.hover} + } - &::placeholder { - color: ${(props) => (props.disabled ? theme.input.disabled.color : theme.colors.textTertiary)}; - } + &:focus:not(:disabled) { + ${$hasError ? theme.input.error.focus : theme.input.focus} + } + + &::placeholder { + ${theme.input.placeholder} + } + + &:disabled { + ${theme.input.disabled} + } + `; + }} /* MEMO: inspired by https://www.w3schools.com/howto/howto_css_hide_arrow_number.asp */ /* Chrome, Safari, Edge, Opera */ @@ -91,26 +76,36 @@ const StyledBaseInput = styled.input` } `; -const BaseInputWrapper = styled.div` +const StyledWrapper = styled.div` position: relative; - color: ${theme.colors.textPrimary}; box-sizing: border-box; display: flex; align-items: center; `; -// TODO: simplify this (put into theme) -const Adornment = styled.div` +type StyledAdornmentProps = { + $size: InputSizes; +}; + +const StyledAdornment = styled.div` display: inline-flex; align-items: center; position: absolute; - top: ${({ $position }) => ($position === 'left' || $position === 'right') && '50%'}; - left: ${({ $position }) => ($position === 'left' || $position === 'bottom') && theme.spacing.spacing2}; - right: ${({ $position }) => $position === 'right' && theme.spacing.spacing2}; - transform: ${({ $position }) => ($position === 'left' || $position === 'right') && 'translateY(-50%)'}; - bottom: ${({ $position }) => $position === 'bottom' && theme.spacing.spacing1}; // to not allow adornment to take more than 50% of the input. We might want to reduce this in the future. max-width: 50%; + ${({ theme }) => theme.input.adornment}; +`; + +const StyledAdornmentRight = styled(StyledAdornment)` + top: 50%; + right: ${({ theme }) => theme.spacing('md')}; + transform: translateY(-50%); +`; + +const StyledAdornmentLeft = styled(StyledAdornment)` + top: 50%; + left: ${({ theme }) => theme.spacing('md')}; + transform: translateY(-50%); `; const Wrapper = styled.div` @@ -118,4 +113,4 @@ const Wrapper = styled.div` flex-direction: column; `; -export { Adornment, BaseInputWrapper, StyledBaseInput, Wrapper }; +export { StyledAdornmentLeft, StyledAdornmentRight, StyledBaseInput, StyledWrapper, Wrapper }; diff --git a/packages/components/src/Input/__tests__/Input.test.tsx b/packages/components/src/Input/__tests__/Input.test.tsx index ed5c601f2..b6b1edbca 100644 --- a/packages/components/src/Input/__tests__/Input.test.tsx +++ b/packages/components/src/Input/__tests__/Input.test.tsx @@ -1,5 +1,5 @@ -import { blur, focus, testA11y } from '@interlay/test-utils'; -import { render, screen, waitFor } from '@testing-library/react'; +import { blur, focus, testA11y, render } from '@interlay/test-utils'; +import { screen, waitFor } from '@testing-library/react'; import { userEvent } from '@testing-library/user-event'; import { createRef, useState } from 'react'; diff --git a/packages/components/src/Label/Label.style.tsx b/packages/components/src/Label/Label.style.tsx index 706ae80dd..6e49e342d 100644 --- a/packages/components/src/Label/Label.style.tsx +++ b/packages/components/src/Label/Label.style.tsx @@ -1,19 +1,18 @@ import styled from 'styled-components'; -import { LabelPosition, theme } from '@interlay/theme'; +import { LabelPosition } from '@interlay/theme'; type StyledLabelProps = { $position: LabelPosition; }; const StyledLabel = styled.label` - font-weight: ${theme.fontWeight.medium}; - line-height: ${theme.lineHeight.lg}; - font-size: ${theme.text.xs}; - color: ${theme.label.text}; - padding: ${({ $position }) => - $position === 'top' - ? `${theme.spacing.spacing1} 0` - : `${theme.spacing.spacing2} ${theme.spacing.spacing1} 0.438rem 0`}; + ${({ theme }) => theme.typography('xs')} + color: ${({ theme }) => theme.color('light')}; + font-weight: ${({ theme }) => theme.fontWeight('medium')}; + + // FIXME: padding bottom when position is on side + padding: ${({ theme, $position }) => + $position === 'top' ? `${theme.spacing('xs')} 0` : `${theme.spacing('s')} ${theme.spacing('xs')} 0.625rem 0`}; align-self: flex-start; `; diff --git a/packages/components/src/Label/Label.tsx b/packages/components/src/Label/Label.tsx index d7bf4e9a0..a2c0cbdfa 100644 --- a/packages/components/src/Label/Label.tsx +++ b/packages/components/src/Label/Label.tsx @@ -13,7 +13,7 @@ type LabelProps = Props & NativeAttrs; const Label = forwardRef( ({ children, position = 'top', ...props }, ref): JSX.Element => ( - + {children} ) diff --git a/packages/components/src/Label/__tests__/Label.test.tsx b/packages/components/src/Label/__tests__/Label.test.tsx index 9ea9db6eb..5605fd4dc 100644 --- a/packages/components/src/Label/__tests__/Label.test.tsx +++ b/packages/components/src/Label/__tests__/Label.test.tsx @@ -1,6 +1,5 @@ -import { render } from '@testing-library/react'; import { createRef } from 'react'; -import { testA11y } from '@interlay/test-utils'; +import { testA11y, render } from '@interlay/test-utils'; import { Label } from '..'; diff --git a/packages/components/src/List/List.stories.tsx b/packages/components/src/List/List.stories.tsx index 127893a25..f71effb3f 100644 --- a/packages/components/src/List/List.stories.tsx +++ b/packages/components/src/List/List.stories.tsx @@ -28,18 +28,6 @@ export default { export const Default: StoryObj = {}; -export const Secondary: StoryObj = { - args: { - variant: 'secondary' - } -}; - -export const Card: StoryObj = { - args: { - variant: 'card' - } -}; - export const Horizontal: StoryObj = { args: { direction: 'row' diff --git a/packages/components/src/List/List.style.tsx b/packages/components/src/List/List.style.tsx index 49e6892a5..b0381a6ac 100644 --- a/packages/components/src/List/List.style.tsx +++ b/packages/components/src/List/List.style.tsx @@ -1,22 +1,16 @@ -import styled, { css } from 'styled-components'; -import { theme } from '@interlay/theme'; -import { ListVariants } from '@interlay/theme'; +import styled, { CSSProperties, css } from 'styled-components'; import { Flex } from '../Flex'; type StyledListProps = { - $variant: ListVariants; + $maxHeight?: CSSProperties['maxHeight']; }; const StyledList = styled(Flex)` - background-color: ${({ $variant }) => theme.list?.[$variant]?.bg}; - border-radius: ${({ $variant }) => theme.list[$variant].rounded}; - border: ${({ $variant }) => theme.list[$variant].border}; - overflow: hidden; + max-height: ${({ $maxHeight }) => $maxHeight}; `; type StyledListItemProps = { - $variant: ListVariants; $isDisabled: boolean; $isHovered: boolean; $isInteractable: boolean; @@ -26,31 +20,18 @@ type StyledListItemProps = { const StyledListItem = styled.div` flex: 1; align-self: stretch; - padding: ${theme.spacing.spacing3}; - border-radius: ${({ $variant }) => theme.list.item[$variant].rounded}; - background-color: ${({ $variant, $isHovered, $isFocusVisible }) => - $isHovered || $isFocusVisible ? theme.list.item[$variant].hover.bg : theme.list.item[$variant].bg}; - border: ${({ $variant }) => $variant !== 'card' && theme.list.item[$variant].border}; - color: ${theme.colors.textPrimary}; cursor: ${({ $isInteractable }) => $isInteractable && 'pointer'}; outline: ${({ $isFocusVisible }) => !$isFocusVisible && 'none'}; opacity: ${({ $isDisabled }) => $isDisabled && 0.5}; white-space: nowrap; - ${({ $variant }) => { - if ($variant === 'card') { - return css` - &:not(:first-of-type) { - border-top: ${theme.list.item.card.border}; - } - `; - } - + ${({ theme, $isHovered }) => { return css` + ${theme.list.item.base} + ${$isHovered && theme.list.item.hover} + &[aria-selected='true'] { - background-color: ${theme.list.item[$variant].selected.bg}; - color: ${theme.list.text}; - border-color: ${theme.list.item[$variant].selected.bg}; + ${theme.list.item.selected}; } `; }} diff --git a/packages/components/src/List/List.tsx b/packages/components/src/List/List.tsx index be30d5d3e..c471d6d82 100644 --- a/packages/components/src/List/List.tsx +++ b/packages/components/src/List/List.tsx @@ -2,9 +2,9 @@ import { AriaGridListOptions, useGridList } from '@react-aria/gridlist'; import { mergeProps } from '@react-aria/utils'; import { ListProps as StatelyListProps, useListState } from '@react-stately/list'; import { forwardRef } from 'react'; -import { ListVariants } from '@interlay/theme'; import { Selection } from '@react-types/shared'; import { useDOMRef } from '@interlay/hooks'; +import { CSSProperties } from 'styled-components'; import { FlexProps } from '../Flex'; @@ -12,7 +12,7 @@ import { StyledList } from './List.style'; import { ListItem } from './ListItem'; type Props = { - variant?: ListVariants; + maxHeight?: CSSProperties['maxHeight']; }; type InheritAttrs = Omit< @@ -27,7 +27,19 @@ type ListProps = Props & NativeAttrs & InheritAttrs; // FIXME: use keyboardDelegate for horizontal list (see TagGroup from spectrum) const List = forwardRef( ( - { variant = 'primary', direction = 'column', onSelectionChange, selectionMode, selectedKeys, ...props }, + { + maxHeight, + direction = 'column', + onSelectionChange, + selectionMode, + selectedKeys, + disabledBehavior, + disabledKeys, + disallowEmptySelection, + defaultSelectedKeys, + selectionBehavior, + ...props + }, ref ): JSX.Element => { const listRef = useDOMRef(ref); @@ -36,22 +48,20 @@ const List = forwardRef( onSelectionChange, selectionMode, selectedKeys, + disabledBehavior, + defaultSelectedKeys, + disabledKeys, + disallowEmptySelection, ...props }; - const state = useListState(ariaProps); + const state = useListState({ selectionBehavior, ...ariaProps }); const { gridProps } = useGridList(ariaProps, state, listRef); return ( - + {[...state.collection].map((item) => ( - + ))} ); diff --git a/packages/components/src/List/ListItem.tsx b/packages/components/src/List/ListItem.tsx index 46cd298d7..d7931ade3 100644 --- a/packages/components/src/List/ListItem.tsx +++ b/packages/components/src/List/ListItem.tsx @@ -6,15 +6,12 @@ import { mergeProps } from '@react-aria/utils'; import { ListState } from '@react-stately/list'; import { Node } from '@react-types/shared'; import { useMemo, useRef } from 'react'; -import { ListVariants } from '@interlay/theme'; import { Flex, FlexProps } from '../Flex'; import { StyledListItem } from './List.style'; -type Props = { - variant?: ListVariants; -}; +type Props = {}; type InheritAttrs = Omit; @@ -22,7 +19,7 @@ type ListItemProps = Props & InheritAttrs; type InternalProps = ListItemProps & { item: Node; state: ListState }; -const ListItem = ({ item, state, variant = 'primary' }: InternalProps): JSX.Element => { +const ListItem = ({ item, state }: InternalProps): JSX.Element => { const ref = useRef(null); const { rowProps, gridCellProps, isDisabled } = useGridListItem({ node: item }, state, ref); @@ -44,7 +41,6 @@ const ListItem = ({ item, state, variant = 'primary' }: Intern $isFocusVisible={isFocusVisible} $isHovered={isHovered} $isInteractable={isInteractable} - $variant={variant} > {item.rendered} diff --git a/packages/components/src/List/__tests__/List.test.tsx b/packages/components/src/List/__tests__/List.test.tsx index e1b553297..3eb79047b 100644 --- a/packages/components/src/List/__tests__/List.test.tsx +++ b/packages/components/src/List/__tests__/List.test.tsx @@ -1,6 +1,5 @@ -import { render } from '@testing-library/react'; import { createRef } from 'react'; -import { testA11y } from '@interlay/test-utils'; +import { testA11y, render } from '@interlay/test-utils'; import { List, ListItem } from '..'; diff --git a/packages/components/src/Meter/Meter.stories.tsx b/packages/components/src/Meter/Meter.stories.tsx index 9e81dc520..75bc8ef69 100644 --- a/packages/components/src/Meter/Meter.stories.tsx +++ b/packages/components/src/Meter/Meter.stories.tsx @@ -10,8 +10,8 @@ const Render = (args: MeterProps) => { const [error, setError] = useState(80); return ( - - + + diff --git a/packages/components/src/Meter/__tests__/Meter.test.tsx b/packages/components/src/Meter/__tests__/Meter.test.tsx index 9d211f3ed..ee83fdb23 100644 --- a/packages/components/src/Meter/__tests__/Meter.test.tsx +++ b/packages/components/src/Meter/__tests__/Meter.test.tsx @@ -1,5 +1,4 @@ -import { render } from '@testing-library/react'; -import { testA11y } from '@interlay/test-utils'; +import { testA11y, render } from '@interlay/test-utils'; import { Meter } from '..'; diff --git a/packages/components/src/Modal/Modal.stories.tsx b/packages/components/src/Modal/Modal.stories.tsx index 758b77220..b29b55501 100644 --- a/packages/components/src/Modal/Modal.stories.tsx +++ b/packages/components/src/Modal/Modal.stories.tsx @@ -1,7 +1,7 @@ import { Meta, StoryObj } from '@storybook/react'; import { useState } from 'react'; -import { CTA } from '../CTA'; +import { Button } from '../Button'; import { Modal, ModalProps } from './Modal'; import { ModalHeader } from './ModalHeader'; @@ -15,19 +15,17 @@ const Render = ({ title, footer, children, ...args }: StoryProps) => { return ( <> - setState(true)}>Open Modal + setState(false)}> {title && ( <> - - {title} - + {title} )} {children} {footer && ( - Procced + )} @@ -85,11 +83,132 @@ export const BodyWithFooter: StoryObj = { } }; -export const LargeContent: StoryObj = { +export const ScrollBehaviour: StoryObj = { args: { title: 'Title', footer: true, - hasMaxHeight: true, + children: ( + <> + Cras mattis consectetur purus sit amet fermentum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. + Morbi leo risus, porta ac consectetur ac, vestibulum at eros. Praesent commodo cursus magna, vel scelerisque + nisl consectetur et. Cras mattis consectetur purus sit amet fermentum. Cras justo odio, dapibus ac facilisis in, + egestas eget quam. Morbi leo risus, porta ac consectetur ac, vestibulum at eros. Praesent commodo cursus magna, + vel scelerisque nisl consectetur et. Cras mattis consectetur purus sit amet fermentum. Cras justo odio, dapibus + ac facilisis in, egestas eget quam. Morbi leo risus, porta ac consectetur ac, vestibulum at eros. Praesent + commodo cursus magna, vel scelerisque nisl consectetur et. Cras mattis consectetur purus sit amet fermentum. + Cras justo odio, dapibus ac facilisis in, egestas eget quam. Morbi leo risus, porta ac consectetur ac, + vestibulum at eros. Praesent commodo cursus magna, vel scelerisque nisl consectetur et. Cras mattis consectetur + purus sit amet fermentum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Morbi leo risus, porta ac + consectetur ac, vestibulum at eros. Praesent commodo cursus magna, vel scelerisque nisl consectetur et. Cras + mattis consectetur purus sit amet fermentum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Morbi + leo risus, porta ac consectetur ac, vestibulum at eros. Praesent commodo cursus magna, vel scelerisque nisl + consectetur et. Cras mattis consectetur purus sit amet fermentum. Cras justo odio, dapibus ac facilisis in, + egestas eget quam. Morbi leo risus, porta ac consectetur ac, vestibulum at eros. Praesent commodo cursus magna, + vel scelerisque nisl consectetur et. Cras mattis consectetur purus sit amet fermentum. Cras justo odio, dapibus + ac facilisis in, egestas eget quam. Morbi leo risus, porta ac consectetur ac, vestibulum at eros. Praesent + commodo cursus magna, vel scelerisque nisl consectetur et. Cras mattis consectetur purus sit amet fermentum. + Cras justo odio, dapibus ac facilisis in, egestas eget quam. Morbi leo risus, porta ac consectetur ac, + vestibulum at eros. Praesent commodo cursus magna, vel scelerisque nisl consectetur et. Cras mattis consectetur + purus sit amet fermentum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Morbi leo risus, porta ac + consectetur ac, vestibulum at eros. Praesent commodo cursus magna, vel scelerisque nisl consectetur et. Cras + mattis consectetur purus sit amet fermentum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Morbi + leo risus, porta ac consectetur ac, vestibulum at eros. Praesent commodo cursus magna, vel scelerisque nisl + consectetur et. Cras mattis consectetur purus sit amet fermentum. Cras justo odio, dapibus ac facilisis in, + egestas eget quam. Morbi leo risus, porta ac consectetur ac, vestibulum at eros. Praesent commodo cursus magna, + vel scelerisque nisl consectetur et. Cras mattis consectetur purus sit amet fermentum. Cras justo odio, dapibus + ac facilisis in, egestas eget quam. Morbi leo risus, porta ac consectetur ac, vestibulum at eros. Praesent + commodo cursus magna, vel scelerisque nisl consectetur et. Cras mattis consectetur purus sit amet fermentum. + Cras justo odio, dapibus ac facilisis in, egestas eget quam. Morbi leo risus, porta ac consectetur ac, + vestibulum at eros. Praesent commodo cursus magna, vel scelerisque nisl consectetur et. Cras mattis consectetur + purus sit amet fermentum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Morbi leo risus, porta ac + consectetur ac, vestibulum at eros. Praesent commodo cursus magna, vel scelerisque nisl consectetur et. Cras + mattis consectetur purus sit amet fermentum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Morbi + leo risus, porta ac consectetur ac, vestibulum at eros. Praesent commodo cursus magna, vel scelerisque nisl + consectetur et. Cras mattis consectetur purus sit amet fermentum. Cras justo odio, dapibus ac facilisis in, + egestas eget quam. Morbi leo risus, porta ac consectetur ac, vestibulum at eros. Praesent commodo cursus magna, + vel scelerisque nisl consectetur et. Cras mattis consectetur purus sit amet fermentum. Cras justo odio, dapibus + ac facilisis in, egestas eget quam. Morbi leo risus, porta ac consectetur ac, vestibulum at eros. Praesent + commodo cursus magna, vel scelerisque nisl consectetur et. Cras mattis consectetur purus sit amet fermentum. + Cras justo odio, dapibus ac facilisis in, egestas eget quam. Morbi leo risus, porta ac consectetur ac, + vestibulum at eros. Praesent commodo cursus magna, vel scelerisque nisl consectetur et. Cras mattis consectetur + purus sit amet fermentum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Morbi leo risus, porta ac + consectetur ac, vestibulum at eros. Praesent commodo cursus magna, vel scelerisque nisl consectetur et. Cras + mattis consectetur purus sit amet fermentum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Morbi + leo risus, porta ac consectetur ac, vestibulum at eros. Praesent commodo cursus magna, vel scelerisque nisl + consectetur et. Cras mattis consectetur purus sit amet fermentum. Cras justo odio, dapibus ac facilisis in, + egestas eget quam. Morbi leo risus, porta ac consectetur ac, vestibulum at eros. Praesent commodo cursus magna, + vel scelerisque nisl consectetur et. Cras mattis consectetur purus sit amet fermentum. Cras justo odio, dapibus + ac facilisis in, egestas eget quam. Morbi leo risus, porta ac consectetur ac, vestibulum at eros. Praesent + commodo cursus magna, vel scelerisque nisl consectetur et. Cras mattis consectetur purus sit amet fermentum. + Cras justo odio, dapibus ac facilisis in, egestas eget quam. Morbi leo risus, porta ac consectetur ac, + vestibulum at eros. Praesent commodo cursus magna, vel scelerisque nisl consectetur et. Cras mattis consectetur + purus sit amet fermentum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Morbi leo risus, porta ac + consectetur ac, vestibulum at eros. Praesent commodo cursus magna, vel scelerisque nisl consectetur et. Cras + mattis consectetur purus sit amet fermentum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Morbi + leo risus, porta ac consectetur ac, vestibulum at eros. Praesent commodo cursus magna, vel scelerisque nisl + consectetur et. Cras mattis consectetur purus sit amet fermentum. Cras justo odio, dapibus ac facilisis in, + egestas eget quam. Morbi leo risus, porta ac consectetur ac, vestibulum at eros. Praesent commodo cursus magna, + vel scelerisque nisl consectetur et. Cras mattis consectetur purus sit amet fermentum. Cras justo odio, dapibus + ac facilisis in, egestas eget quam. Morbi leo risus, porta ac consectetur ac, vestibulum at eros. Praesent + commodo cursus magna, vel scelerisque nisl consectetur et. Cras mattis consectetur purus sit amet fermentum. + Cras justo odio, dapibus ac facilisis in, egestas eget quam. Morbi leo risus, porta ac consectetur ac, + vestibulum at eros. Praesent commodo cursus magna, vel scelerisque nisl consectetur et. Cras mattis consectetur + purus sit amet fermentum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Morbi leo risus, porta ac + consectetur ac, vestibulum at eros. Praesent commodo cursus magna, vel scelerisque nisl consectetur et. Cras + mattis consectetur purus sit amet fermentum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Morbi + leo risus, porta ac consectetur ac, vestibulum at eros. Praesent commodo cursus magna, vel scelerisque nisl + consectetur et. Cras mattis consectetur purus sit amet fermentum. Cras justo odio, dapibus ac facilisis in, + egestas eget quam. Morbi leo risus, porta ac consectetur ac, vestibulum at eros. Praesent commodo cursus magna, + vel scelerisque nisl consectetur et. Cras mattis consectetur purus sit amet fermentum. Cras justo odio, dapibus + ac facilisis in, egestas eget quam. Morbi leo risus, porta ac consectetur ac, vestibulum at eros. Praesent + commodo cursus magna, vel scelerisque nisl consectetur et. Cras mattis consectetur purus sit amet fermentum. + Cras justo odio, dapibus ac facilisis in, egestas eget quam. Morbi leo risus, porta ac consectetur ac, + vestibulum at eros. Praesent commodo cursus magna, vel scelerisque nisl consectetur et. Cras mattis consectetur + purus sit amet fermentum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Morbi leo risus, porta ac + consectetur ac, vestibulum at eros. Praesent commodo cursus magna, vel scelerisque nisl consectetur et. Cras + mattis consectetur purus sit amet fermentum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Morbi + leo risus, porta ac consectetur ac, vestibulum at eros. Praesent commodo cursus magna, vel scelerisque nisl + consectetur et. Cras mattis consectetur purus sit amet fermentum. Cras justo odio, dapibus ac facilisis in, + egestas eget quam. Morbi leo risus, porta ac consectetur ac, vestibulum at eros. Praesent commodo cursus magna, + vel scelerisque nisl consectetur et. Cras mattis consectetur purus sit amet fermentum. Cras justo odio, dapibus + ac facilisis in, egestas eget quam. Morbi leo risus, porta ac consectetur ac, vestibulum at eros. Praesent + commodo cursus magna, vel scelerisque nisl consectetur et. Cras mattis consectetur purus sit amet fermentum. + Cras justo odio, dapibus ac facilisis in, egestas eget quam. Morbi leo risus, porta ac consectetur ac, + vestibulum at eros. Praesent commodo cursus magna, vel scelerisque nisl consectetur et. Cras mattis consectetur + purus sit amet fermentum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Morbi leo risus, porta ac + consectetur ac, vestibulum at eros. Praesent commodo cursus magna, vel scelerisque nisl consectetur et. Cras + mattis consectetur purus sit amet fermentum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Morbi + leo risus, porta ac consectetur ac, vestibulum at eros. Praesent commodo cursus magna, vel scelerisque nisl + consectetur et. Cras mattis consectetur purus sit amet fermentum. Cras justo odio, dapibus ac facilisis in, + egestas eget quam. Morbi leo risus, porta ac consectetur ac, vestibulum at eros. Praesent commodo cursus magna, + vel scelerisque nisl consectetur et. Cras mattis consectetur purus sit amet fermentum. Cras justo odio, dapibus + ac facilisis in, egestas eget quam. Morbi leo risus, porta ac consectetur ac, vestibulum at eros. Praesent + commodo cursus magna, vel scelerisque nisl consectetur et. Cras mattis consectetur purus sit amet fermentum. + Cras justo odio, dapibus ac facilisis in, egestas eget quam. Morbi leo risus, porta ac consectetur ac, + vestibulum at eros. Praesent commodo cursus magna, vel scelerisque nisl consectetur et. Cras mattis consectetur + purus sit amet fermentum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Morbi leo risus, porta ac + consectetur ac, vestibulum at eros. Praesent commodo cursus magna, vel scelerisque nisl consectetur et. Cras + mattis consectetur purus sit amet fermentum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Morbi + leo risus, porta ac consectetur ac, vestibulum at eros. Praesent commodo cursus magna, vel scelerisque nisl + consectetur et. Cras mattis consectetur purus sit amet fermentum. Cras justo odio, dapibus ac facilisis in, + egestas eget quam. Morbi leo risus, porta ac consectetur ac, vestibulum at eros. Praesent commodo cursus magna, + vel scelerisque nisl consectetur et. Cras mattis consectetur purus sit amet fermentum. Cras justo odio, dapibus + ac facilisis in, egestas eget quam. Morbi leo risus, porta ac consectetur ac, vestibulum at eros. Praesent + commodo cursus magna, vel scelerisque nisl consectetur et. Cras mattis consectetur purus sit amet fermentum. + Cras justo odio, dapibus ac facilisis in, egestas eget quam. Morbi leo risus, porta ac consectetur ac, + vestibulum at eros. Praesent commodo cursus magna, vel scelerisque nisl consectetur et. Cras mattis consectetur + purus sit amet fermentum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Morbi leo risus, porta ac + consectetur ac, vestibulum at eros. Praesent commodo cursus magna, vel scelerisque nisl consectetur et. + + ) + } +}; + +export const MaxHeight: StoryObj = { + args: { + title: 'Title', + footer: true, + maxHeight: '400px', children: ( <> Cras mattis consectetur purus sit amet fermentum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. diff --git a/packages/components/src/Modal/Modal.style.tsx b/packages/components/src/Modal/Modal.style.tsx index 4ee89c6e3..86e658221 100644 --- a/packages/components/src/Modal/Modal.style.tsx +++ b/packages/components/src/Modal/Modal.style.tsx @@ -1,46 +1,44 @@ -import styled from 'styled-components'; +import styled, { CSSProperties } from 'styled-components'; +import { DialogSize } from '@interlay/theme'; -import { theme } from '../../../core/theme/src'; -import { Overflow } from '../../../core/theme/src'; import { overlayCSS } from '../utils/overlay'; import { Dialog, DialogBody } from '../Dialog'; +type StyledWrapperProps = { + $placement: 'top' | 'center'; +}; + type StyledModalProps = { $isOpen?: boolean; - $isCentered?: boolean; + $size: DialogSize; + $maxHeight?: CSSProperties['maxHeight']; }; type StyledDialogProps = { - $isCentered?: boolean; - $hasMaxHeight?: boolean; $isOpen?: boolean; }; type StyledModalBodyProps = { - $overflow?: Overflow; $noPadding?: boolean; }; -const StyledWrapper = styled.div` +const StyledWrapper = styled.div` position: fixed; top: 0; left: 0; - z-index: ${theme.modal.zIndex}; + z-index: 2; width: 100vw; - height: 100vh; + height: 100dvh; visibility: visible; display: flex; justify-content: center; - align-items: ${({ $isCentered }) => ($isCentered ? 'center' : 'flex-start')}; - overflow: ${({ $isCentered }) => !$isCentered && 'auto'}; + align-items: ${({ $placement }) => ($placement === 'center' ? 'center' : 'flex-start')}; `; +//FIXME: on very small screen (height) the modal could overflow when max-heigh is set +// might not need the max-heigh property const StyledModal = styled.div` - max-width: calc(100% - ${theme.spacing.spacing12}); - max-height: ${({ $isCentered }) => $isCentered && theme.modal.maxHeight}; - margin: ${({ $isCentered }) => ($isCentered ? 0 : theme.spacing.spacing16)} ${theme.spacing.spacing6}; - transform: ${({ $isOpen }) => ($isOpen ? 'translateY(0)' : `translateY(20px)`)}; ${({ $isOpen }) => overlayCSS(!!$isOpen)} // Overrides overlayCSS properties, because react-aria Overlay @@ -49,19 +47,25 @@ const StyledModal = styled.div` visibility: visible; // Allows scroll on the modal pointer-events: auto; - transition: ${({ $isOpen }) => ($isOpen ? theme.modal.transition.entering : theme.modal.transition.exiting)}; + transition: ${({ $isOpen }) => + $isOpen + ? 'transform .15s cubic-bezier(0,0,0.4,1) .1s, opacity .15s cubic-bezier(0,0,0.4,1)' + : 'opacity .1s cubic-bezier(0.5,0,1,1), visibility 0s linear, transform 0s linear .1s'}; outline: none; + margin: ${({ theme }) => `${theme.spacing('7xl')} ${theme.spacing('xl')}`}; + max-width: ${({ theme, $size }) => theme.dialog.size[$size].maxWidth}; + width: 100%; + max-height: ${({ theme, $maxHeight }) => $maxHeight || `calc(100dvh - ${theme.spacing('10xl')})`}; `; const StyledDialog = styled(Dialog)` - max-height: ${({ $hasMaxHeight }) => $hasMaxHeight && '560px'}; - overflow: ${({ $isCentered }) => $isCentered && 'hidden'}; pointer-events: ${({ $isOpen }) => !$isOpen && 'none'}; + max-height: inherit; `; const StyledDialogBody = styled(DialogBody)` - overflow-y: ${({ $overflow }) => $overflow}; + overflow-y: auto; position: relative; padding: ${({ $noPadding }) => $noPadding && 0}; `; diff --git a/packages/components/src/Modal/Modal.tsx b/packages/components/src/Modal/Modal.tsx index a38cc1f6f..375e1b77c 100644 --- a/packages/components/src/Modal/Modal.tsx +++ b/packages/components/src/Modal/Modal.tsx @@ -1,11 +1,12 @@ import { forwardRef, useRef } from 'react'; import { useDOMRef } from '@interlay/hooks'; +import { DialogSize } from '@interlay/theme'; +import { CSSProperties } from 'styled-components'; import { DialogProps } from '../Dialog'; import { Overlay } from '../Overlay'; import { StyledDialog } from './Modal.style'; -import { ModalContext } from './ModalContext'; import { ModalWrapper, ModalWrapperProps } from './ModalWrapper'; const isInteractingWithToasts = (element: Element) => { @@ -16,13 +17,16 @@ const isInteractingWithToasts = (element: Element) => { return toastsContainer.contains(element); }; +type ModalSizes = DialogSize; + type Props = { container?: Element; - hasMaxHeight?: boolean; - align?: 'top' | 'center'; + placement?: 'top' | 'center'; + size?: ModalSizes; + maxHeight?: CSSProperties['maxHeight']; }; -type InheritAttrs = Omit; +type InheritAttrs = Omit; type ModalProps = Props & InheritAttrs; @@ -31,13 +35,14 @@ const Modal = forwardRef( { children, isDismissable = true, - align = 'center', - hasMaxHeight, + placement = 'center', isKeyboardDismissDisabled, shouldCloseOnBlur, shouldCloseOnInteractOutside, container, isOpen, + size = 'md', + maxHeight, ...props }, ref @@ -46,8 +51,6 @@ const Modal = forwardRef( const { onClose } = props; const wrapperRef = useRef(null); - const isCentered = align === 'center'; - // Does not allow the modal to close when clicking on toasts const handleShouldCloseOnInteractOutside = (element: Element) => shouldCloseOnInteractOutside @@ -55,25 +58,25 @@ const Modal = forwardRef( : !isInteractingWithToasts(element); return ( - - - - - {children} - - - - + + + + {children} + + + ); } ); diff --git a/packages/components/src/Modal/ModalBody.tsx b/packages/components/src/Modal/ModalBody.tsx index 17ce166e8..895539df5 100644 --- a/packages/components/src/Modal/ModalBody.tsx +++ b/packages/components/src/Modal/ModalBody.tsx @@ -1,11 +1,8 @@ -import { Overflow } from '../../../core/theme/src'; import { DialogBodyProps } from '../Dialog'; import { StyledDialogBody } from './Modal.style'; -import { useModalContext } from './ModalContext'; type Props = { - overflow?: Overflow; noPadding?: boolean; }; @@ -13,11 +10,9 @@ type InheritAttrs = Omit; type ModalBodyProps = Props & InheritAttrs; -const ModalBody = ({ overflow, noPadding, ...props }: ModalBodyProps): JSX.Element => { - const { bodyProps } = useModalContext(); - - return ; -}; +const ModalBody = ({ noPadding, ...props }: ModalBodyProps): JSX.Element => ( + +); export { ModalBody }; export type { ModalBodyProps }; diff --git a/packages/components/src/Modal/ModalContext.tsx b/packages/components/src/Modal/ModalContext.tsx deleted file mode 100644 index 42353cbe0..000000000 --- a/packages/components/src/Modal/ModalContext.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import React from 'react'; - -import { ModalBodyProps } from './ModalBody'; - -interface ModalConfig { - bodyProps?: ModalBodyProps; -} - -const defaultContext = {}; - -const ModalContext = React.createContext(defaultContext); - -const useModalContext = (): ModalConfig => React.useContext(ModalContext); - -export { ModalContext, useModalContext }; -export type { ModalConfig }; diff --git a/packages/components/src/Modal/ModalDivider.tsx b/packages/components/src/Modal/ModalDivider.tsx deleted file mode 100644 index 1e9630a48..000000000 --- a/packages/components/src/Modal/ModalDivider.tsx +++ /dev/null @@ -1,8 +0,0 @@ -import { DialogDivider, DialogDividerProps } from '../Dialog'; - -type ModalDividerProps = DialogDividerProps; - -const ModalDivider = (props: ModalDividerProps): JSX.Element => ; - -export { ModalDivider }; -export type { ModalDividerProps }; diff --git a/packages/components/src/Modal/ModalFooter.tsx b/packages/components/src/Modal/ModalFooter.tsx index 655a8d5d2..0564102ad 100644 --- a/packages/components/src/Modal/ModalFooter.tsx +++ b/packages/components/src/Modal/ModalFooter.tsx @@ -2,7 +2,7 @@ import { DialogFooter, DialogFooterProps } from '../Dialog'; type ModalFooterProps = DialogFooterProps; -const ModalFooter = ({ direction = 'column', gap = 'spacing4', ...props }: ModalFooterProps): JSX.Element => ( +const ModalFooter = ({ direction = 'column', gap = 's', ...props }: ModalFooterProps): JSX.Element => ( ); diff --git a/packages/components/src/Modal/ModalHeader.tsx b/packages/components/src/Modal/ModalHeader.tsx index decf2059e..abb4bce5e 100644 --- a/packages/components/src/Modal/ModalHeader.tsx +++ b/packages/components/src/Modal/ModalHeader.tsx @@ -2,8 +2,8 @@ import { DialogHeader, DialogHeaderProps } from '../Dialog'; type ModalHeaderProps = DialogHeaderProps; -const ModalHeader = ({ align = 'center', children, ...props }: ModalHeaderProps): JSX.Element => ( - +const ModalHeader = ({ align = 'start', weight = 'semibold', children, ...props }: ModalHeaderProps): JSX.Element => ( + {children} ); diff --git a/packages/components/src/Modal/ModalWrapper.tsx b/packages/components/src/Modal/ModalWrapper.tsx index 578e93fc2..90a97c3fc 100644 --- a/packages/components/src/Modal/ModalWrapper.tsx +++ b/packages/components/src/Modal/ModalWrapper.tsx @@ -2,6 +2,8 @@ import { AriaModalOverlayProps, AriaOverlayProps, useModalOverlay } from '@react import { mergeProps } from '@react-aria/utils'; import { OverlayTriggerState } from '@react-stately/overlays'; import { forwardRef, ReactNode, RefObject } from 'react'; +import { DialogSize } from '@interlay/theme'; +import { CSSProperties } from 'styled-components'; import { Underlay } from '../Overlay/Underlay'; @@ -9,10 +11,12 @@ import { StyledModal, StyledWrapper } from './Modal.style'; type Props = { children: ReactNode; - align?: 'top' | 'center'; + placement?: 'top' | 'center'; isOpen?: boolean; onClose: () => void; wrapperRef: RefObject; + size: DialogSize; + maxHeight?: CSSProperties['maxHeight']; }; type InheritAttrs = Omit; @@ -24,13 +28,15 @@ const ModalWrapper = forwardRef( { children, isDismissable = true, - align = 'center', + placement = 'center', onClose, isKeyboardDismissDisabled, isOpen, shouldCloseOnInteractOutside, shouldCloseOnBlur, wrapperRef, + size, + maxHeight, ...props }, ref @@ -50,13 +56,17 @@ const ModalWrapper = forwardRef( ref as RefObject ); - const isCentered = align === 'center'; - return (
- - + + {children} diff --git a/packages/components/src/Modal/__tests__/Modal.test.tsx b/packages/components/src/Modal/__tests__/Modal.test.tsx index 0ddb069f4..e2e6d9cdd 100644 --- a/packages/components/src/Modal/__tests__/Modal.test.tsx +++ b/packages/components/src/Modal/__tests__/Modal.test.tsx @@ -1,15 +1,13 @@ -import { render } from '@testing-library/react'; import { createRef } from 'react'; -import { testA11y } from '@interlay/test-utils'; +import { testA11y, render } from '@interlay/test-utils'; -import { Modal, ModalBody, ModalDivider, ModalFooter, ModalHeader } from '..'; +import { Modal, ModalBody, ModalFooter, ModalHeader } from '..'; describe('Modal', () => { it('should render correctly', () => { const wrapper = render( title - body footer @@ -24,7 +22,6 @@ describe('Modal', () => { render( title - body footer @@ -37,7 +34,6 @@ describe('Modal', () => { await testA11y( title - body footer diff --git a/packages/components/src/Modal/index.tsx b/packages/components/src/Modal/index.tsx index d5534e741..f4212748f 100644 --- a/packages/components/src/Modal/index.tsx +++ b/packages/components/src/Modal/index.tsx @@ -2,8 +2,6 @@ export type { ModalProps } from './Modal'; export { Modal } from './Modal'; export type { ModalBodyProps } from './ModalBody'; export { ModalBody } from './ModalBody'; -export type { ModalDividerProps } from './ModalDivider'; -export { ModalDivider } from './ModalDivider'; export type { ModalFooterProps } from './ModalFooter'; export { ModalFooter } from './ModalFooter'; export type { ModalHeaderProps } from './ModalHeader'; diff --git a/packages/components/src/NumberInput/NumberInput.stories.tsx b/packages/components/src/NumberInput/NumberInput.stories.tsx index c98b9d15a..b8d549253 100644 --- a/packages/components/src/NumberInput/NumberInput.stories.tsx +++ b/packages/components/src/NumberInput/NumberInput.stories.tsx @@ -2,7 +2,7 @@ import { Meta, StoryFn, StoryObj } from '@storybook/react'; import { useState } from 'react'; import { InformationCircle } from '@interlay/icons'; -import { Flex, Span } from '..'; +import { Flex } from '..'; import { NumberInput, NumberInputProps } from '.'; @@ -67,11 +67,11 @@ export const Adornments: StoryFn = (args) => ( } label='End Adornment' /> - $0.00 - - } + // bottomAdornment={ + // + // $0.00 + // + // } label='Bottom Adornment' /> @@ -79,15 +79,15 @@ export const Adornments: StoryFn = (args) => ( export const Sizes: StoryFn = (args) => ( - + - + ); export const MaxWidth: StoryObj = { args: { - maxWidth: 'spacing12', + maxWidth: 'xl', labelPosition: 'side', justifyContent: 'space-between', style: { width: 150 }, diff --git a/packages/components/src/NumberInput/NumberInput.tsx b/packages/components/src/NumberInput/NumberInput.tsx index fcdcc664a..23585035e 100644 --- a/packages/components/src/NumberInput/NumberInput.tsx +++ b/packages/components/src/NumberInput/NumberInput.tsx @@ -26,7 +26,7 @@ type Props = { type InheritAttrs = Omit< BaseInputProps, - keyof Props | 'errorMessageProps' | 'descriptionProps' | 'inputProps' | 'elementType' + keyof Props | 'errorMessageProps' | 'descriptionProps' | 'inputProps' | 'elementType' | 'autoCapitalize' >; type AriaAttrs = Omit, keyof (Props & InheritAttrs)>; diff --git a/packages/components/src/NumberInput/__tests__/NumberInput.test.tsx b/packages/components/src/NumberInput/__tests__/NumberInput.test.tsx index a0cb21969..446f842a4 100644 --- a/packages/components/src/NumberInput/__tests__/NumberInput.test.tsx +++ b/packages/components/src/NumberInput/__tests__/NumberInput.test.tsx @@ -1,5 +1,5 @@ -import { blur, focus, testA11y } from '@interlay/test-utils'; -import { render, screen, waitFor } from '@testing-library/react'; +import { blur, focus, testA11y, render } from '@interlay/test-utils'; +import { screen, waitFor } from '@testing-library/react'; import { userEvent } from '@testing-library/user-event'; import { createRef, useState } from 'react'; diff --git a/packages/components/src/Overlay/__tests__/Overlay.test.tsx b/packages/components/src/Overlay/__tests__/Overlay.test.tsx index 1c55f1de3..1e189c39a 100644 --- a/packages/components/src/Overlay/__tests__/Overlay.test.tsx +++ b/packages/components/src/Overlay/__tests__/Overlay.test.tsx @@ -1,6 +1,5 @@ -import { render } from '@testing-library/react'; -import React, { createRef } from 'react'; -import { testA11y } from '@interlay/test-utils'; +import { render, testA11y } from '@interlay/test-utils'; +import { createRef } from 'react'; import { Overlay } from '..'; diff --git a/packages/components/src/Overlay/__tests__/Underlay.test.tsx b/packages/components/src/Overlay/__tests__/Underlay.test.tsx index ef9bf619b..5892484d1 100644 --- a/packages/components/src/Overlay/__tests__/Underlay.test.tsx +++ b/packages/components/src/Overlay/__tests__/Underlay.test.tsx @@ -1,5 +1,4 @@ -import { render } from '@testing-library/react'; -import { testA11y } from '@interlay/test-utils'; +import { render, testA11y } from '@interlay/test-utils'; import { Underlay } from '..'; diff --git a/packages/components/src/Popover/Popover.stories.tsx b/packages/components/src/Popover/Popover.stories.tsx index 1ddd4f07c..6c0f19a8a 100644 --- a/packages/components/src/Popover/Popover.stories.tsx +++ b/packages/components/src/Popover/Popover.stories.tsx @@ -1,6 +1,6 @@ import { Meta, StoryObj } from '@storybook/react'; -import { CTA } from '../CTA'; +import { Button } from '../Button'; import { Popover, PopoverBody, PopoverContent, PopoverFooter, PopoverHeader, PopoverProps, PopoverTrigger } from '.'; @@ -11,14 +11,14 @@ const Render = ({ title, footer, children, placement = 'left', ...args }: StoryP <> - Open Popover + {title && Popover Header} {children} {footer && ( - Confirm + )} diff --git a/packages/components/src/Popover/PopoverContentWrapper.tsx b/packages/components/src/Popover/PopoverContentWrapper.tsx index 4c81dc2b5..79ec89969 100644 --- a/packages/components/src/Popover/PopoverContentWrapper.tsx +++ b/packages/components/src/Popover/PopoverContentWrapper.tsx @@ -59,7 +59,7 @@ const PopoverContentWrapper = forwardRef {!isNonModal && } - + {children} diff --git a/packages/components/src/Popover/PopoverHeader.tsx b/packages/components/src/Popover/PopoverHeader.tsx index 04ea84f09..c83d9094e 100644 --- a/packages/components/src/Popover/PopoverHeader.tsx +++ b/packages/components/src/Popover/PopoverHeader.tsx @@ -2,7 +2,7 @@ import { DialogHeader, DialogHeaderProps } from '../Dialog'; type PopoverHeaderProps = DialogHeaderProps; -const PopoverHeader = ({ size = 'base', weight = 'semibold', children, ...props }: PopoverHeaderProps): JSX.Element => ( +const PopoverHeader = ({ size = 'md', weight = 'semibold', children, ...props }: PopoverHeaderProps): JSX.Element => ( {children} diff --git a/packages/components/src/Popover/__tests__/Popover.test.tsx b/packages/components/src/Popover/__tests__/Popover.test.tsx index de46fec41..8d9cac156 100644 --- a/packages/components/src/Popover/__tests__/Popover.test.tsx +++ b/packages/components/src/Popover/__tests__/Popover.test.tsx @@ -1,6 +1,5 @@ -import { render } from '@testing-library/react'; +import { render, testA11y } from '@interlay/test-utils'; import { createRef } from 'react'; -import { testA11y } from '@interlay/test-utils'; import { Popover, PopoverBody, PopoverContent, PopoverFooter, PopoverHeader, PopoverTrigger } from '..'; diff --git a/packages/components/src/ProgressBar/ProgressBar.stories.tsx b/packages/components/src/ProgressBar/ProgressBar.stories.tsx index c56cf215c..3c969a6d8 100644 --- a/packages/components/src/ProgressBar/ProgressBar.stories.tsx +++ b/packages/components/src/ProgressBar/ProgressBar.stories.tsx @@ -8,3 +8,5 @@ export default { } as Meta; export const Default: StoryObj = { args: { label: 'Loading...', value: 20 } }; + +export const ShowValue: StoryObj = { args: { label: 'Progress:', showValueLabel: true, value: 20 } }; diff --git a/packages/components/src/ProgressBar/ProgressBar.style.tsx b/packages/components/src/ProgressBar/ProgressBar.style.tsx index 52d7928de..070e54b60 100644 --- a/packages/components/src/ProgressBar/ProgressBar.style.tsx +++ b/packages/components/src/ProgressBar/ProgressBar.style.tsx @@ -1,26 +1,43 @@ -import styled from 'styled-components'; +import styled, { css } from 'styled-components'; import { theme } from '@interlay/theme'; -import { ProgressBarColors } from '@interlay/theme'; +import { Color, ProgressBarSize } from '@interlay/theme'; + +type StyledTrackProps = { + $size: ProgressBarSize; +}; type StyledFillProps = { - $color: ProgressBarColors; + $color?: Color; + $size: ProgressBarSize; }; -const StyledTrack = styled.div` +const StyledTrack = styled.div` overflow: hidden; z-index: 1; width: 100%; min-width: ${theme.spacing.spacing6}; - background-color: ${theme.progressBar.bg}; - height: 1px; + + ${({ theme, $size }) => css` + min-width: ${theme.spacing('2xl')}; + ${theme.progressBar.track} + ${theme.progressBar.size[$size].track} + `} `; const StyledFill = styled.div` - background-color: ${({ $color }) => ($color === 'red' ? theme.alert.status.error : theme.colors.textSecondary)}; - height: 1px; border: none; transition: width ${theme.transition.duration.duration100}ms; will-change: width; + + ${({ theme, $size, $color }) => { + const { backgroundColor, ...fillCss } = theme.progressBar.fill; + + return css` + background: ${($color && theme.color($color)) || backgroundColor}; + ${fillCss} + ${theme.progressBar.size[$size].fill} + `; + }} `; export { StyledFill, StyledTrack }; diff --git a/packages/components/src/ProgressBar/ProgressBar.tsx b/packages/components/src/ProgressBar/ProgressBar.tsx index 73d9017e9..5edc5f969 100644 --- a/packages/components/src/ProgressBar/ProgressBar.tsx +++ b/packages/components/src/ProgressBar/ProgressBar.tsx @@ -1,13 +1,13 @@ import { AriaProgressBarProps, useProgressBar } from '@react-aria/progress'; import { CSSProperties } from 'react'; -import { ProgressBarColors } from '@interlay/theme'; +import { Color, ProgressBarSize } from '@interlay/theme'; import { Flex, FlexProps } from '../Flex'; import { Span } from '../Text'; import { StyledFill, StyledTrack } from './ProgressBar.style'; -type Props = { color?: ProgressBarColors; showValueLabel?: boolean }; +type Props = { color?: Color; showValueLabel?: boolean; size?: ProgressBarSize }; type AriaAttrs = Omit; @@ -22,7 +22,8 @@ const ProgressBar = (props: ProgressBarProps): JSX.Element => { value = 0, minValue = 0, maxValue = 100, - color = 'default', + color, + size = 'md', showValueLabel, label, className, @@ -34,15 +35,15 @@ const ProgressBar = (props: ProgressBarProps): JSX.Element => { const barStyle: CSSProperties = { width: `${Math.round(percentage * 100)}%` }; return ( -