diff --git a/packages/css-in-js/src/sheet.ts b/packages/css-in-js/src/sheet.ts index d43bc95250..304a656559 100644 --- a/packages/css-in-js/src/sheet.ts +++ b/packages/css-in-js/src/sheet.ts @@ -4,8 +4,15 @@ const elementId = 'rcx-styles'; let element: HTMLStyleElement; const getStyleTag = (): HTMLStyleElement => { if (!element) { - element = (document.getElementById(elementId) || - document.createElement('style')) as HTMLStyleElement; + const el = document.getElementById(elementId) as HTMLStyleElement; + if (el) { + element = el; + return element; + } + } + + if (!element) { + element = document.createElement('style'); element.id = elementId; element.appendChild(document.createTextNode('')); if (document.head) { diff --git a/packages/fuselage-hooks/src/index.ts b/packages/fuselage-hooks/src/index.ts index f55877d1fb..648175530f 100644 --- a/packages/fuselage-hooks/src/index.ts +++ b/packages/fuselage-hooks/src/index.ts @@ -1,6 +1,7 @@ export * from './useAutoFocus'; export * from './useBreakpoints'; export * from './useClipboard'; +export * from './useDarkMode'; export * from './useDebouncedCallback'; export * from './useDebouncedReducer'; export * from './useDebouncedState'; diff --git a/packages/fuselage-hooks/src/useDarkMode.ts b/packages/fuselage-hooks/src/useDarkMode.ts new file mode 100644 index 0000000000..0175411976 --- /dev/null +++ b/packages/fuselage-hooks/src/useDarkMode.ts @@ -0,0 +1,11 @@ +import { usePrefersColorScheme } from './usePrefersColorScheme'; + +export const useDarkMode = (forced?: boolean): boolean => { + const systemDarkMode = usePrefersColorScheme('dark'); + + if (forced !== undefined) { + return forced; + } + + return systemDarkMode; +}; diff --git a/packages/fuselage/.loki/reference/chrome_iphone7_Data_Display_Tooltip_Arrow_Positioning.png b/packages/fuselage/.loki/reference/chrome_iphone7_Data_Display_Tooltip_Arrow_Positioning.png index d96e056961..6d19535e78 100644 Binary files a/packages/fuselage/.loki/reference/chrome_iphone7_Data_Display_Tooltip_Arrow_Positioning.png and b/packages/fuselage/.loki/reference/chrome_iphone7_Data_Display_Tooltip_Arrow_Positioning.png differ diff --git a/packages/fuselage/.loki/reference/chrome_laptop_Data_Display_Tooltip_Arrow_Positioning.png b/packages/fuselage/.loki/reference/chrome_laptop_Data_Display_Tooltip_Arrow_Positioning.png index a3e15fa825..0e786235ea 100644 Binary files a/packages/fuselage/.loki/reference/chrome_laptop_Data_Display_Tooltip_Arrow_Positioning.png and b/packages/fuselage/.loki/reference/chrome_laptop_Data_Display_Tooltip_Arrow_Positioning.png differ diff --git a/packages/fuselage/src/components/Box/AnimatedVisibility/AnimatedVisibility.d.ts b/packages/fuselage/src/components/Box/AnimatedVisibility/AnimatedVisibility.d.ts new file mode 100644 index 0000000000..b1043888d2 --- /dev/null +++ b/packages/fuselage/src/components/Box/AnimatedVisibility/AnimatedVisibility.d.ts @@ -0,0 +1,16 @@ +import { ReactElement, ReactNode } from 'react'; + +type AnimatedVisibilityProps = { + children: ReactNode; + visibility?: 'hidden' | 'visible' | 'hiding' | 'unhiding'; +}; + +const AnimatedVisibility: { + (props: AnimatedVisibilityProps): ReactElement; + HIDDEN: 'hidden'; + VISIBLE: 'visible'; + HIDING: 'hiding'; + UNHIDING: 'unhiding'; +}; + +export = AnimatedVisibility; diff --git a/packages/fuselage/src/components/Box/AnimatedVisibility/index.js b/packages/fuselage/src/components/Box/AnimatedVisibility/AnimatedVisibility.js similarity index 100% rename from packages/fuselage/src/components/Box/AnimatedVisibility/index.js rename to packages/fuselage/src/components/Box/AnimatedVisibility/AnimatedVisibility.js diff --git a/packages/fuselage/src/components/Box/AnimatedVisibility/index.ts b/packages/fuselage/src/components/Box/AnimatedVisibility/index.ts new file mode 100644 index 0000000000..a509d4a932 --- /dev/null +++ b/packages/fuselage/src/components/Box/AnimatedVisibility/index.ts @@ -0,0 +1 @@ +export { default } from './AnimatedVisibility'; diff --git a/packages/fuselage/src/components/Box/index.d.ts b/packages/fuselage/src/components/Box/index.d.ts index 34d16f2c07..e729414455 100644 --- a/packages/fuselage/src/components/Box/index.d.ts +++ b/packages/fuselage/src/components/Box/index.d.ts @@ -148,5 +148,6 @@ type BoxProps = PropsWithChildren<{ export const Box: ForwardRefExoticComponent; +export { default as AnimatedVisibility } from './AnimatedVisibility'; export { default as Position, PositionAnimated } from './Position'; export { default as Scrollable } from './Scrollable'; diff --git a/packages/fuselage/src/components/PasswordInput/PasswordInput.stories.tsx b/packages/fuselage/src/components/PasswordInput/PasswordInput.stories.tsx index db7e8c28f2..8e19d7903e 100644 --- a/packages/fuselage/src/components/PasswordInput/PasswordInput.stories.tsx +++ b/packages/fuselage/src/components/PasswordInput/PasswordInput.stories.tsx @@ -1,4 +1,3 @@ -import { Meta, Story } from '@storybook/react'; import React from 'react'; import { Icon, PasswordInput } from '../..'; @@ -8,25 +7,25 @@ export default { title: 'Forms/Inputs/PasswordInput', component: PasswordInput, parameters: { jest: ['PasswordInput.spec.tsx'] }, -} as Meta; +}; -export const Default: Story = () => ; +export const Default = () => ; -export const WithValue: Story = () => ; +export const WithValue = () => ; -export const WithIconAddon: Story = () => ( +export const WithIconAddon = () => ( } /> ); -export const Invalid: Story = () => ; +export const Invalid = () => ; -export const Disabled: Story = () => ; +export const Disabled = () => ; -export const WithPlaceholder: Story = () => ( +export const WithPlaceholder = () => ( ); -export const States: Story = () => ( +export const States = () => ( undefined }} diff --git a/packages/fuselage/src/components/Tooltip/Tooltip.styles.scss b/packages/fuselage/src/components/Tooltip/Tooltip.styles.scss index 5dd7ac08da..f9081b15d3 100644 --- a/packages/fuselage/src/components/Tooltip/Tooltip.styles.scss +++ b/packages/fuselage/src/components/Tooltip/Tooltip.styles.scss @@ -1,5 +1,4 @@ @use '../../styles/colors.scss'; -@use '../../styles/lengths.scss'; @use '../../styles/typography.scss'; @use '../../styles/functions.scss'; @@ -17,35 +16,37 @@ $tooltip-text-color: functions.theme('tooltip-text-color', colors.surface()); content: ' '; - border-width: lengths.border-width(4) + lengths.border-width(1); + border-width: 4px; border-color: transparent transparent $tooltip-background-color $tooltip-background-color; - border-radius: lengths.border-radius(none) lengths.border-radius(none) - lengths.border-radius(none) (lengths.border-radius(2) + to-rem(1)); + border-radius: 0 0 0 (2px); + + block-size: 0; + inline-size: 0; @if $direction == 'bottom' { - inset-block-start: lengths.inset(-4); + inset-block-start: -4px; transform: rotate(135deg); } @if $direction == 'top' { - inset-block-end: lengths.inset(-4); + inset-block-end: -4px; transform: rotate(-45deg); } @if $direction == 'right' { inset-block-start: 50%; - inset-inline-start: lengths.inset(-4); + inset-inline-start: -4px; - margin-block-start: lengths.margin(-4); + margin-block-start: -4px; transform: rotate(45deg); } @if $direction == 'left' { inset-block-start: 50%; - inset-inline-end: lengths.inset(-4); + inset-inline-end: -4px; - margin-block-start: lengths.margin(-4); + margin-block-start: -4px; transform: rotate(-135deg); } @@ -57,15 +58,19 @@ $tooltip-text-color: functions.theme('tooltip-text-color', colors.surface()); display: inline-block; - max-width: lengths.size(240); + max-width: 240px; + + padding: 8px 12px; - padding: lengths.padding(8) lengths.padding(12); + user-select: none; word-break: break-word; + pointer-events: none; + color: $tooltip-text-color; - border-radius: lengths.border-radius(4); + border-radius: 4px; background-color: $tooltip-background-color; @@ -92,22 +97,22 @@ $tooltip-text-color: functions.theme('tooltip-text-color', colors.surface()); &::after { inset-inline-start: 50%; - margin-inline-start: lengths.margin(-4); + margin-inline-start: -4px; } } &-start { &::after { - inset-inline-start: lengths.inset(8); + inset-inline-start: 8px; - margin: lengths.margin(none); + margin: 0; } } &-end { &::after { inset-inline-start: initial; - inset-inline-end: lengths.inset(8); + inset-inline-end: 8px; margin: 0; } diff --git a/packages/fuselage/src/components/Tooltip/Tooltip.tsx b/packages/fuselage/src/components/Tooltip/Tooltip.tsx index 2fb860b2b5..26b8927a80 100644 --- a/packages/fuselage/src/components/Tooltip/Tooltip.tsx +++ b/packages/fuselage/src/components/Tooltip/Tooltip.tsx @@ -4,6 +4,18 @@ import { useStyleSheet } from '../../hooks/useStyleSheet'; import { Box } from '../Box'; import tooltipStyleSheet from './Tooltip.styles.scss'; +const parsePlacement = (placement: string | null | undefined) => { + const [direction, position] = placement + ? placement.split('-') + : [false, false]; + + if (direction === 'right' || direction === 'left') { + return [direction, false]; + } + + return [direction, position]; +}; + type TooltipProps = ComponentProps & { placement?: | 'top-start' @@ -12,12 +24,6 @@ type TooltipProps = ComponentProps & { | 'bottom-start' | 'bottom-middle' | 'bottom-end' - | 'left-start' - | 'left-middle' - | 'left-end' - | 'right-start' - | 'right-middle' - | 'right-end' | 'top' | 'left' | 'bottom' @@ -32,9 +38,7 @@ const Tooltip = forwardRef(function Tooltip( useStyleSheet(); useStyleSheet(tooltipStyleSheet); - const [direction, position] = placement - ? placement.split('-') - : [false, false]; + const [direction, position] = parsePlacement(placement); return ( ({ { test: /\.tsx?$/, exclude: /node_modules/, - use: 'ts-loader', + use: { + loader: 'ts-loader', + options: { + configFile: path.resolve(__dirname, './tsconfig-bundle.json'), + }, + }, }, { test: /\.scss$/, diff --git a/packages/onboarding-ui/.eslintrc.js b/packages/onboarding-ui/.eslintrc.js index d11c05a965..e89a741370 100644 --- a/packages/onboarding-ui/.eslintrc.js +++ b/packages/onboarding-ui/.eslintrc.js @@ -1,6 +1,9 @@ module.exports = { - extends: '@rocket.chat/eslint-config-alt/typescript', + extends: '@rocket.chat/eslint-config-alt/react', env: { jest: true, }, + rules: { + 'react/react-in-jsx-scope': 'off', + }, }; diff --git a/packages/onboarding-ui/.lintstagedrc.json b/packages/onboarding-ui/.lintstagedrc.json new file mode 100644 index 0000000000..05ce703752 --- /dev/null +++ b/packages/onboarding-ui/.lintstagedrc.json @@ -0,0 +1,5 @@ +{ + "src/**/*.{js,ts,tsx}": [ + "yarn run eslint --fix --" + ] +} diff --git a/packages/onboarding-ui/.loki/.gitignore b/packages/onboarding-ui/.loki/.gitignore new file mode 100644 index 0000000000..a60a0897d2 --- /dev/null +++ b/packages/onboarding-ui/.loki/.gitignore @@ -0,0 +1,2 @@ +current +difference diff --git a/packages/onboarding-ui/.loki/reference/chrome_iphone7_MyComponent_My_Component.png b/packages/onboarding-ui/.loki/reference/chrome_iphone7_MyComponent_My_Component.png deleted file mode 100644 index 00fe269d5b..0000000000 Binary files a/packages/onboarding-ui/.loki/reference/chrome_iphone7_MyComponent_My_Component.png and /dev/null differ diff --git a/packages/onboarding-ui/.loki/reference/chrome_laptop_MyComponent_My_Component.png b/packages/onboarding-ui/.loki/reference/chrome_laptop_MyComponent_My_Component.png deleted file mode 100644 index 9e441c748f..0000000000 Binary files a/packages/onboarding-ui/.loki/reference/chrome_laptop_MyComponent_My_Component.png and /dev/null differ diff --git a/packages/onboarding-ui/.loki/reference/desktop_common_BackgroundLayer_Dark_Mode.png b/packages/onboarding-ui/.loki/reference/desktop_common_BackgroundLayer_Dark_Mode.png new file mode 100644 index 0000000000..28fd2f7157 Binary files /dev/null and b/packages/onboarding-ui/.loki/reference/desktop_common_BackgroundLayer_Dark_Mode.png differ diff --git a/packages/onboarding-ui/.loki/reference/desktop_common_BackgroundLayer_Light_Mode.png b/packages/onboarding-ui/.loki/reference/desktop_common_BackgroundLayer_Light_Mode.png new file mode 100644 index 0000000000..071299fcae Binary files /dev/null and b/packages/onboarding-ui/.loki/reference/desktop_common_BackgroundLayer_Light_Mode.png differ diff --git a/packages/onboarding-ui/.loki/reference/desktop_common_BackgroundLayer_System_Dark_Mode.png b/packages/onboarding-ui/.loki/reference/desktop_common_BackgroundLayer_System_Dark_Mode.png new file mode 100644 index 0000000000..071299fcae Binary files /dev/null and b/packages/onboarding-ui/.loki/reference/desktop_common_BackgroundLayer_System_Dark_Mode.png differ diff --git a/packages/onboarding-ui/.loki/reference/desktop_common_RocketChatLogo_RocketChatLogo.png b/packages/onboarding-ui/.loki/reference/desktop_common_RocketChatLogo_RocketChatLogo.png new file mode 100644 index 0000000000..1f17d2ec17 Binary files /dev/null and b/packages/onboarding-ui/.loki/reference/desktop_common_RocketChatLogo_RocketChatLogo.png differ diff --git a/packages/onboarding-ui/.loki/reference/mobile_common_BackgroundLayer_Dark_Mode.png b/packages/onboarding-ui/.loki/reference/mobile_common_BackgroundLayer_Dark_Mode.png new file mode 100644 index 0000000000..03797567fd Binary files /dev/null and b/packages/onboarding-ui/.loki/reference/mobile_common_BackgroundLayer_Dark_Mode.png differ diff --git a/packages/onboarding-ui/.loki/reference/mobile_common_BackgroundLayer_Light_Mode.png b/packages/onboarding-ui/.loki/reference/mobile_common_BackgroundLayer_Light_Mode.png new file mode 100644 index 0000000000..b3d468778f Binary files /dev/null and b/packages/onboarding-ui/.loki/reference/mobile_common_BackgroundLayer_Light_Mode.png differ diff --git a/packages/onboarding-ui/.loki/reference/mobile_common_BackgroundLayer_System_Dark_Mode.png b/packages/onboarding-ui/.loki/reference/mobile_common_BackgroundLayer_System_Dark_Mode.png new file mode 100644 index 0000000000..b3d468778f Binary files /dev/null and b/packages/onboarding-ui/.loki/reference/mobile_common_BackgroundLayer_System_Dark_Mode.png differ diff --git a/packages/onboarding-ui/.loki/reference/mobile_common_RocketChatLogo_RocketChatLogo.png b/packages/onboarding-ui/.loki/reference/mobile_common_RocketChatLogo_RocketChatLogo.png new file mode 100644 index 0000000000..e65320ff80 Binary files /dev/null and b/packages/onboarding-ui/.loki/reference/mobile_common_RocketChatLogo_RocketChatLogo.png differ diff --git a/packages/onboarding-ui/.loki/reference/tablet_common_BackgroundLayer_Dark_Mode.png b/packages/onboarding-ui/.loki/reference/tablet_common_BackgroundLayer_Dark_Mode.png new file mode 100644 index 0000000000..7bd64e5d41 Binary files /dev/null and b/packages/onboarding-ui/.loki/reference/tablet_common_BackgroundLayer_Dark_Mode.png differ diff --git a/packages/onboarding-ui/.loki/reference/tablet_common_BackgroundLayer_Light_Mode.png b/packages/onboarding-ui/.loki/reference/tablet_common_BackgroundLayer_Light_Mode.png new file mode 100644 index 0000000000..462beab6f1 Binary files /dev/null and b/packages/onboarding-ui/.loki/reference/tablet_common_BackgroundLayer_Light_Mode.png differ diff --git a/packages/onboarding-ui/.loki/reference/tablet_common_BackgroundLayer_System_Dark_Mode.png b/packages/onboarding-ui/.loki/reference/tablet_common_BackgroundLayer_System_Dark_Mode.png new file mode 100644 index 0000000000..462beab6f1 Binary files /dev/null and b/packages/onboarding-ui/.loki/reference/tablet_common_BackgroundLayer_System_Dark_Mode.png differ diff --git a/packages/onboarding-ui/.loki/reference/tablet_common_RocketChatLogo_RocketChatLogo.png b/packages/onboarding-ui/.loki/reference/tablet_common_RocketChatLogo_RocketChatLogo.png new file mode 100644 index 0000000000..74fa6b52b7 Binary files /dev/null and b/packages/onboarding-ui/.loki/reference/tablet_common_RocketChatLogo_RocketChatLogo.png differ diff --git a/packages/onboarding-ui/package.json b/packages/onboarding-ui/package.json index 22888a5e24..ff6de8e63b 100644 --- a/packages/onboarding-ui/package.json +++ b/packages/onboarding-ui/package.json @@ -48,6 +48,7 @@ }, "devDependencies": { "@rocket.chat/eslint-config-alt": "^0.27.0", + "@rocket.chat/fuselage-polyfills": "^0.27.0", "@rocket.chat/fuselage-tokens": "^0.27.0", "@rocket.chat/prettier-config": "^0.27.0", "@storybook/addon-essentials": "^6.3.1", @@ -75,25 +76,34 @@ "dependencies": { "@rocket.chat/fuselage": "^0.27.0", "@rocket.chat/fuselage-hooks": "^0.27.0", - "@rocket.chat/fuselage-polyfills": "^0.27.0", "@rocket.chat/icons": "^0.27.0", + "@rocket.chat/styled": "workspace:packages/styled", "tslib": "^2.3.0" }, "peerDependencies": { + "@rocket.chat/fuselage-polyfills": "^0.27.0", "react": "17.0.2", "react-dom": "17.0.2" }, "loki": { "configurations": { - "chrome.laptop": { + "desktop": { + "target": "chrome.docker", + "width": 1440, + "height": 896, + "deviceScaleFactor": 1, + "mobile": false, + "fitWindow": false + }, + "tablet": { "target": "chrome.docker", - "width": 1366, - "height": 768, + "width": 768, + "height": 970, "deviceScaleFactor": 1, "mobile": false, "fitWindow": false }, - "chrome.iphone7": { + "mobile": { "target": "chrome.docker", "preset": "iPhone 7" } diff --git a/packages/onboarding-ui/src/MyComponent.stories.tsx b/packages/onboarding-ui/src/MyComponent.stories.tsx deleted file mode 100644 index 3ed6c3f27b..0000000000 --- a/packages/onboarding-ui/src/MyComponent.stories.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import { ReactElement } from 'react'; - -import MyComponent from './MyComponent'; - -export default { - title: 'MyComponent', - component: MyComponent, -}; - -export const _MyComponent = (): ReactElement => ; diff --git a/packages/onboarding-ui/src/MyComponent.tsx b/packages/onboarding-ui/src/MyComponent.tsx deleted file mode 100644 index 5657043ec4..0000000000 --- a/packages/onboarding-ui/src/MyComponent.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ReactElement } from 'react'; - -const MyComponent = (): ReactElement =>
Hello, World!
; - -export default MyComponent; diff --git a/packages/onboarding-ui/src/common/.gitignore b/packages/onboarding-ui/src/common/.gitignore deleted file mode 100644 index d6b7ef32c8..0000000000 --- a/packages/onboarding-ui/src/common/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -* -!.gitignore diff --git a/packages/onboarding-ui/src/common/BackgroundLayer.spec.tsx b/packages/onboarding-ui/src/common/BackgroundLayer.spec.tsx new file mode 100644 index 0000000000..eb25bf850a --- /dev/null +++ b/packages/onboarding-ui/src/common/BackgroundLayer.spec.tsx @@ -0,0 +1,9 @@ +import ReactDOM from 'react-dom'; + +import BackgroundLayer from './BackgroundLayer'; + +it('renders without crashing', () => { + const div = document.createElement('div'); + ReactDOM.render(, div); + ReactDOM.unmountComponentAtNode(div); +}); diff --git a/packages/onboarding-ui/src/common/BackgroundLayer.stories.tsx b/packages/onboarding-ui/src/common/BackgroundLayer.stories.tsx new file mode 100644 index 0000000000..315f277c67 --- /dev/null +++ b/packages/onboarding-ui/src/common/BackgroundLayer.stories.tsx @@ -0,0 +1,38 @@ +import { Tile } from '@rocket.chat/fuselage'; +import type { Story, Meta } from '@storybook/react'; + +import BackgroundLayer from './BackgroundLayer'; + +export default { + title: 'common/BackgroundLayer', + component: BackgroundLayer, + parameters: { + layout: 'fullscreen', + }, + argTypes: { + forceDarkMode: { + options: [undefined, true, false], + control: { type: 'inline-radio' }, + }, + }, +} as Meta; + +export const SystemDarkMode: Story = (args) => ( + + An example tile + +); + +export const DarkMode: Story = (args) => ( + + An example tile + +); +DarkMode.args = { forceDarkMode: true }; + +export const LightMode: Story = (args) => ( + + An example tile + +); +LightMode.args = { forceDarkMode: false }; diff --git a/packages/onboarding-ui/src/common/BackgroundLayer.styles.tsx b/packages/onboarding-ui/src/common/BackgroundLayer.styles.tsx new file mode 100644 index 0000000000..21433a6cb8 --- /dev/null +++ b/packages/onboarding-ui/src/common/BackgroundLayer.styles.tsx @@ -0,0 +1,35 @@ +import styled from '@rocket.chat/styled'; + +const filterWrapperProps = ({ + backgroundColor, + lowerCorner, + upperCorner, + ...props +}: { + backgroundColor: string; + lowerCorner: string; + upperCorner: string; +}) => props; + +export const Wrapper = styled('div', filterWrapperProps)` + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + width: 100vw; + height: 100vh; + background-color: ${(p) => p.backgroundColor}; + background-image: url('data:image/svg+xml,${(p) => p.lowerCorner}'), + url('data:image/svg+xml,${(p) => p.upperCorner}'); + background-repeat: no-repeat; + background-position: left bottom, right top; + background-size: 87px auto, 73px auto; + + @media (min-width: 768px) { + background-size: 98px auto, 166px auto; + } + + @media (min-width: 1440px) { + background-size: auto, auto; + } +`; diff --git a/packages/onboarding-ui/src/common/BackgroundLayer.tsx b/packages/onboarding-ui/src/common/BackgroundLayer.tsx new file mode 100644 index 0000000000..a930944fd4 --- /dev/null +++ b/packages/onboarding-ui/src/common/BackgroundLayer.tsx @@ -0,0 +1,50 @@ +import { useDarkMode } from '@rocket.chat/fuselage-hooks'; +import colors from '@rocket.chat/fuselage-tokens/colors.json'; +import { ReactElement, ReactNode, useMemo } from 'react'; +import { renderToStaticMarkup } from 'react-dom/server'; + +import { Wrapper } from './BackgroundLayer.styles'; +import LowerCornerStripes from './BackgroundLayer/LowerCornerStripes'; +import UpperCornerStripes from './BackgroundLayer/UpperCornerStripes'; + +type BackgroundLayerProps = { + children?: ReactNode; + forceDarkMode?: boolean; +}; + +const BackgroundLayer = ({ + children, + forceDarkMode, +}: BackgroundLayerProps): ReactElement => { + const darkMode = useDarkMode(forceDarkMode); + + const upperCorner = useMemo( + () => + encodeURIComponent( + renderToStaticMarkup() + ), + [darkMode] + ); + + const lowerCorner = useMemo( + () => + encodeURIComponent( + renderToStaticMarkup() + ), + [darkMode] + ); + + const backgroundColor = darkMode ? colors.n800 : colors.n200; + + return ( + + {children} + + ); +}; + +export default BackgroundLayer; diff --git a/packages/onboarding-ui/src/common/BackgroundLayer/LowerCornerStripes.tsx b/packages/onboarding-ui/src/common/BackgroundLayer/LowerCornerStripes.tsx new file mode 100644 index 0000000000..e520c39967 --- /dev/null +++ b/packages/onboarding-ui/src/common/BackgroundLayer/LowerCornerStripes.tsx @@ -0,0 +1,31 @@ +import colors from '@rocket.chat/fuselage-tokens/colors.json'; +import { ReactElement } from 'react'; + +type LowerCornerStripesProps = { + darkMode: boolean; +}; + +const LowerCornerStripes = ({ + darkMode, +}: LowerCornerStripesProps): ReactElement => { + const fillColor = darkMode ? colors.r500 : colors.b500; + + return ( + + + + + + + + + ); +}; + +export default LowerCornerStripes; diff --git a/packages/onboarding-ui/src/common/BackgroundLayer/UpperCornerStripes.tsx b/packages/onboarding-ui/src/common/BackgroundLayer/UpperCornerStripes.tsx new file mode 100644 index 0000000000..c4b3c43a9a --- /dev/null +++ b/packages/onboarding-ui/src/common/BackgroundLayer/UpperCornerStripes.tsx @@ -0,0 +1,33 @@ +import colors from '@rocket.chat/fuselage-tokens/colors.json'; +import { ReactElement } from 'react'; + +type UpperCornerStripesProps = { + darkMode: boolean; +}; + +const UpperCornerStripes = ({ + darkMode, +}: UpperCornerStripesProps): ReactElement => { + const fillColor = darkMode ? colors.r500 : colors.b500; + + return ( + + + + + + + + + + + ); +}; + +export default UpperCornerStripes; diff --git a/packages/onboarding-ui/src/common/InformationTooltipTrigger.spec.tsx b/packages/onboarding-ui/src/common/InformationTooltipTrigger.spec.tsx new file mode 100644 index 0000000000..d4df641889 --- /dev/null +++ b/packages/onboarding-ui/src/common/InformationTooltipTrigger.spec.tsx @@ -0,0 +1,9 @@ +import ReactDOM from 'react-dom'; + +import InformationTooltipTrigger from './InformationTooltipTrigger'; + +it('renders without crashing', () => { + const div = document.createElement('div'); + ReactDOM.render(, div); + ReactDOM.unmountComponentAtNode(div); +}); diff --git a/packages/onboarding-ui/src/common/InformationTooltipTrigger.stories.tsx b/packages/onboarding-ui/src/common/InformationTooltipTrigger.stories.tsx new file mode 100644 index 0000000000..7998abecce --- /dev/null +++ b/packages/onboarding-ui/src/common/InformationTooltipTrigger.stories.tsx @@ -0,0 +1,25 @@ +import { Meta, Story } from '@storybook/react'; + +import InformationTooltipTrigger from './InformationTooltipTrigger'; + +export default { + title: 'common/InformationTooltipTrigger', + component: InformationTooltipTrigger, + argTypes: { + text: { + control: { type: 'text' }, + defaultValue: 'Some tooltip text', + }, + }, +} as Meta; + +export const _InformationTooltipTrigger: Story = (args) => ( + +); +_InformationTooltipTrigger.storyName = 'InformationTooltipTrigger'; +_InformationTooltipTrigger.parameters = { + layout: 'centered', + loki: { + skip: true, + }, +}; diff --git a/packages/onboarding-ui/src/common/InformationTooltipTrigger.tsx b/packages/onboarding-ui/src/common/InformationTooltipTrigger.tsx new file mode 100644 index 0000000000..3a59415125 --- /dev/null +++ b/packages/onboarding-ui/src/common/InformationTooltipTrigger.tsx @@ -0,0 +1,18 @@ +import { Icon } from '@rocket.chat/fuselage'; +import { ReactElement } from 'react'; + +import TooltipWrapper from './TooltipWrapper'; + +type InformationTooltipTriggerProps = { + text: string; +}; + +const InformationTooltipTrigger = ({ + text, +}: InformationTooltipTriggerProps): ReactElement => ( + + + +); + +export default InformationTooltipTrigger; diff --git a/packages/onboarding-ui/src/MyComponent.spec.tsx b/packages/onboarding-ui/src/common/RocketChatLogo.spec.tsx similarity index 64% rename from packages/onboarding-ui/src/MyComponent.spec.tsx rename to packages/onboarding-ui/src/common/RocketChatLogo.spec.tsx index 0ae56d0765..92662a0dc1 100644 --- a/packages/onboarding-ui/src/MyComponent.spec.tsx +++ b/packages/onboarding-ui/src/common/RocketChatLogo.spec.tsx @@ -1,9 +1,9 @@ import ReactDOM from 'react-dom'; -import MyComponent from './MyComponent'; +import RocketChatLogo from './RocketChatLogo'; it('renders without crashing', () => { const div = document.createElement('div'); - ReactDOM.render(, div); + ReactDOM.render(, div); ReactDOM.unmountComponentAtNode(div); }); diff --git a/packages/onboarding-ui/src/common/RocketChatLogo.stories.tsx b/packages/onboarding-ui/src/common/RocketChatLogo.stories.tsx new file mode 100644 index 0000000000..ed3a27188e --- /dev/null +++ b/packages/onboarding-ui/src/common/RocketChatLogo.stories.tsx @@ -0,0 +1,16 @@ +import type { Story, Meta } from '@storybook/react'; + +import RocketChatLogo from './RocketChatLogo'; + +export default { + title: 'common/RocketChatLogo', + component: RocketChatLogo, + argTypes: { + color: { + control: { type: 'color' }, + }, + }, +} as Meta; + +export const _RocketChatLogo: Story = (props) => ; +_RocketChatLogo.storyName = 'RocketChatLogo'; diff --git a/packages/onboarding-ui/src/common/RocketChatLogo.tsx b/packages/onboarding-ui/src/common/RocketChatLogo.tsx new file mode 100644 index 0000000000..6b3b81c054 --- /dev/null +++ b/packages/onboarding-ui/src/common/RocketChatLogo.tsx @@ -0,0 +1,42 @@ +import { useUniqueId } from '@rocket.chat/fuselage-hooks'; +import colors from '@rocket.chat/fuselage-tokens/colors.json'; +import { ReactElement, SVGAttributes } from 'react'; + +type RocketChatLogoProps = { + color?: SVGAttributes['fill']; +}; + +const RocketChatLogo = ({ + color = colors.r500, +}: RocketChatLogoProps): ReactElement => { + const titleId = useUniqueId(); + + return ( + + Rocket.Chat + + + + + + + + + + + + + + + + + ); +}; + +export default RocketChatLogo; diff --git a/packages/onboarding-ui/src/common/TooltipWrapper.spec.tsx b/packages/onboarding-ui/src/common/TooltipWrapper.spec.tsx new file mode 100644 index 0000000000..45a6455315 --- /dev/null +++ b/packages/onboarding-ui/src/common/TooltipWrapper.spec.tsx @@ -0,0 +1,15 @@ +import ReactDOM from 'react-dom'; + +import TooltipWrapper from './TooltipWrapper'; + +it('renders without crashing', () => { + const div = document.createElement('div'); + ReactDOM.render( null} text='' />, div); + ReactDOM.unmountComponentAtNode(div); +}); + +it('renders without crashing', () => { + const div = document.createElement('div'); + ReactDOM.render(} text='' />, div); + ReactDOM.unmountComponentAtNode(div); +}); diff --git a/packages/onboarding-ui/src/common/TooltipWrapper.stories.tsx b/packages/onboarding-ui/src/common/TooltipWrapper.stories.tsx new file mode 100644 index 0000000000..8bb2b6ec9a --- /dev/null +++ b/packages/onboarding-ui/src/common/TooltipWrapper.stories.tsx @@ -0,0 +1,45 @@ +import { Box } from '@rocket.chat/fuselage'; +import { Meta, Story } from '@storybook/react'; + +import TooltipWrapper from './TooltipWrapper'; + +export default { + title: 'common/TooltipWrapper', + component: TooltipWrapper, +} as Meta; + +export const WithRenderProp: Story = () => ( + + {({ ref, toggle, id }) => ( + toggle(true)} + onMouseLeave={() => toggle(false)} + onFocus={() => toggle(true)} + onBlur={() => toggle(false)} + tabIndex={0} + aria-describedby={id} + > + Text + + )} + +); +WithRenderProp.parameters = { + layout: 'centered', + loki: { + skip: true, + }, +}; + +export const WithElement: Story = () => ( + + Text + +); +WithElement.parameters = { + layout: 'centered', + loki: { + skip: true, + }, +}; diff --git a/packages/onboarding-ui/src/common/TooltipWrapper.tsx b/packages/onboarding-ui/src/common/TooltipWrapper.tsx new file mode 100644 index 0000000000..6a4a6c67d1 --- /dev/null +++ b/packages/onboarding-ui/src/common/TooltipWrapper.tsx @@ -0,0 +1,115 @@ +/* eslint-disable react/no-multi-comp */ + +import { + AnimatedVisibility, + PositionAnimated, + Tooltip, +} from '@rocket.chat/fuselage'; +import { useDebouncedState, useUniqueId } from '@rocket.chat/fuselage-hooks'; +import { + cloneElement, + ComponentProps, + Dispatch, + forwardRef, + MutableRefObject, + ReactElement, + ReactNode, + Ref, + SetStateAction, + useCallback, + useMemo, + useRef, +} from 'react'; + +type AnchorParams = { + ref: MutableRefObject; + toggle: Dispatch>; + id: string; +}; + +const getAnchor = ( + children: ReactElement | ((props: AnchorParams) => ReactNode), + params: AnchorParams +): ReactNode => { + if (typeof children === 'function') { + return children(params); + } + + return cloneElement(children, { + 'ref': params.ref, + 'onMouseEnter': () => params.toggle(true), + 'onMouseLeave': () => params.toggle(false), + 'onFocus': () => params.toggle(true), + 'onBlur': () => params.toggle(false), + 'aria-describedby': params.id, + }); +}; + +// Workaround to the c̶r̶a̶p̶p̶y̶ not-so-great API of PositionAnimated +const InnerTooltip = forwardRef(function InnerTooltip( + { style, ...props }: ComponentProps, + ref: Ref +): ReactElement { + return ( +
+ +
+ ); +}); + +type TooltipWrapperProps = { + children: ReactElement | ((props: AnchorParams) => ReactNode); + text: string; +}; + +const TooltipWrapper = ({ + children, + text, +}: TooltipWrapperProps): ReactElement => { + const anchorRef = useRef(null); + const [open, setOpen] = useDebouncedState(false, 460); + const toggle = useCallback( + (open) => { + setOpen(open); + + if (open) { + setOpen.flush(); + } + }, + [setOpen] + ); + + const id = useUniqueId(); + + const anchorParams = useMemo( + () => ({ ref: anchorRef, toggle, id }), + [id, toggle] + ); + const anchor = getAnchor(children, anchorParams); + + return ( + <> + {anchor} + + {open && ( + + setOpen(true)} + onMouseLeave={() => setOpen(false)} + > + {text} + + + )} + + ); +}; + +export default TooltipWrapper; diff --git a/packages/onboarding-ui/src/hooks/useStyle.ts b/packages/onboarding-ui/src/hooks/useStyle.ts new file mode 100644 index 0000000000..ab9b8b4a1f --- /dev/null +++ b/packages/onboarding-ui/src/hooks/useStyle.ts @@ -0,0 +1,41 @@ +import { + createClassName, + escapeName, + transpile, + attachRules, + css, +} from '@rocket.chat/css-in-js'; +import { useDebugValue, useLayoutEffect, useMemo } from 'react'; + +export const useStyle = ( + cssFn: ReturnType, + arg: unknown = undefined +): string | undefined => { + const content = useMemo(() => (cssFn ? cssFn(arg) : undefined), [arg, cssFn]); + + const className = useMemo(() => { + if (!content) { + return; + } + + return content ? createClassName(content) : undefined; + }, [content]); + + useDebugValue(className); + + useLayoutEffect(() => { + if (!content || !className) { + return; + } + + const escapedClassName = escapeName(className); + const transpiledContent = transpile(`.${escapedClassName}`, content); + const detach = attachRules(transpiledContent); + + return () => { + setTimeout(detach, 1000); + }; + }, [className, content]); + + return className; +}; diff --git a/packages/onboarding-ui/src/index.ts b/packages/onboarding-ui/src/index.ts index a68cfe323f..df48c13485 100644 --- a/packages/onboarding-ui/src/index.ts +++ b/packages/onboarding-ui/src/index.ts @@ -1 +1 @@ -export { default as MyComponent } from './MyComponent'; +export { default as RocketChatLogo } from './common/RocketChatLogo'; diff --git a/yarn.lock b/yarn.lock index 2268bfb607..6cddd355f0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5663,6 +5663,7 @@ __metadata: "@rocket.chat/fuselage-tokens": ^0.27.0 "@rocket.chat/icons": ^0.27.0 "@rocket.chat/prettier-config": ^0.27.0 + "@rocket.chat/styled": "workspace:packages/styled" "@storybook/addon-essentials": ^6.3.1 "@storybook/addons": ^6.3.1 "@storybook/react": ^6.3.1 @@ -5686,6 +5687,7 @@ __metadata: typedoc: ^0.21.2 typescript: ^4.3.4 peerDependencies: + "@rocket.chat/fuselage-polyfills": ^0.27.0 react: 17.0.2 react-dom: 17.0.2 languageName: unknown