diff --git a/package.json b/package.json index 0fe2ae0b8..01f8ee098 100644 --- a/package.json +++ b/package.json @@ -139,6 +139,7 @@ "@docusaurus/preset-classic": "2.1.0", "@docusaurus/remark-plugin-npm2yarn": "2.1.0", "@docusaurus/theme-live-codeblock": "2.1.0", + "@emotion/css": "11.13.5", "@emotion/native": "11.9.3", "@emotion/react": "11.10.4", "@emotion/styled": "11.10.4", diff --git a/packages/vibrant-core/src/lib/Box/Box.tsx b/packages/vibrant-core/src/lib/Box/Box.tsx index b88326922..8f9e11bda 100644 --- a/packages/vibrant-core/src/lib/Box/Box.tsx +++ b/packages/vibrant-core/src/lib/Box/Box.tsx @@ -1,54 +1,58 @@ import type { ComponentType, FC, ReactElement } from 'react'; import { createElement, forwardRef, memo } from 'react'; -import styled from '@emotion/styled'; +import { css } from '@emotion/css'; import { useComposedRef, useLayoutEvent } from '@vibrant-ui/utils'; import { OnColorContainer } from '../OnColorContainer'; import type { BoxElements, BoxProps } from './BoxProps'; import { interpolation, shouldForwardProp } from './BoxProps'; export const Box = memo( - styled( - forwardRef( - ( - { - as, - base, - onLayout, - ariaLabel, - ariaChecked, - ariaLabelledBy, - ariaCurrent, - ariaSelected, - backgroundColor, - ...restProps - }, - ref - ) => { - const { ref: layoutEventRef } = useLayoutEvent(onLayout); - const composeRef = useComposedRef(ref, layoutEventRef); + forwardRef( + ( + { + as, + base, + onLayout, + ariaLabel, + ariaChecked, + ariaLabelledBy, + ariaCurrent, + ariaSelected, + backgroundColor, + ...restProps + }, + ref + ) => { + const { ref: layoutEventRef } = useLayoutEvent(onLayout); + const composeRef = useComposedRef(ref, layoutEventRef); - const element = createElement(base ?? as ?? 'div', { - ref: composeRef, - ...(base && as ? { as } : {}), - 'aria-label': ariaLabel, - 'aria-checked': ariaChecked, - 'aria-labelledby': ariaLabelledBy, - 'aria-current': ariaCurrent, - 'aria-selected': ariaSelected, - ...restProps, - }); + const className = Object.entries(interpolation({ ...restProps, backgroundColor } ?? {})) + .map(([key, value]) => css({ [key]: value })) + .join(' '); - if (backgroundColor) { - return {element}; - } + const domAttributeProps = Object.fromEntries( + Object.entries({ ...restProps }).filter(([key, _]) => shouldForwardProp(key)) + ); - return element; + const element = createElement(base ?? as ?? 'div', { + ref: composeRef, + ...(base && as ? { as } : {}), + 'aria-label': ariaLabel, + 'aria-checked': ariaChecked, + 'aria-labelledby': ariaLabelledBy, + 'aria-current': ariaCurrent, + 'aria-selected': ariaSelected, + ...domAttributeProps, + className, + }); + + if (backgroundColor) { + return {element}; } - ), - { - shouldForwardProp, + + return element; } - )(interpolation) + ) ) as < BaseComponent extends ComponentType | undefined = undefined, ElementName extends BoxElements | undefined = undefined diff --git a/packages/vibrant-core/src/lib/ScrollBox/ScrollBox.tsx b/packages/vibrant-core/src/lib/ScrollBox/ScrollBox.tsx index f7ca9106c..8033f01de 100644 --- a/packages/vibrant-core/src/lib/ScrollBox/ScrollBox.tsx +++ b/packages/vibrant-core/src/lib/ScrollBox/ScrollBox.tsx @@ -1,40 +1,53 @@ import { createElement, forwardRef } from 'react'; -import styled from '@emotion/styled'; +import { css } from '@emotion/css'; import { useComposedRef, useLayoutEvent } from '@vibrant-ui/utils'; import { transformResponsiveValue } from '../transformResponsiveValue'; import type { ScrollBoxProps } from './ScrollBoxProps'; import { interpolation, shouldForwardProp } from './ScrollBoxProps'; -const SystemScrollBox = styled( - forwardRef( - ({ as = 'div', ariaChecked, ariaCurrent, ariaLabel, ariaLabelledBy, ariaSelected, ...restProps }, ref) => - createElement(as, { - ref, - 'aria-label': ariaLabel, - 'aria-checked': ariaChecked, - 'aria-labelledby': ariaLabelledBy, - 'aria-current': ariaCurrent, - 'aria-selected': ariaSelected, - ...restProps, - }) - ), - { - shouldForwardProp, - } -)(interpolation); - -export const ScrollBox = forwardRef( - ({ keyboardShouldPersistTaps: _, scrollEnabled = true, onLayout, ...restProps }, ref) => { +export const ScrollBox = forwardRef( + ( + { + as = 'div', + ariaChecked, + ariaCurrent, + ariaLabel, + ariaLabelledBy, + ariaSelected, + scrollEnabled = true, + onLayout, + ...restProps + }, + ref + ) => { const { ref: layoutEventRef } = useLayoutEvent(onLayout); const composeRef = useComposedRef(ref, layoutEventRef); - return ( - (value ? 'auto' : 'hidden'))} - /> + const className = Object.entries( + interpolation({ + ...restProps, + overflow: transformResponsiveValue(scrollEnabled, value => (value ? 'auto' : 'hidden')), + }) + ) + .map(([key, value]) => css({ [key]: value })) + .join(' '); + + const domAttributeProps = Object.fromEntries( + Object.entries({ ...restProps }).filter(([key, _]) => shouldForwardProp(key)) ); + + const element = createElement(as, { + ref: composeRef, + 'aria-label': ariaLabel, + 'aria-checked': ariaChecked, + 'aria-labelledby': ariaLabelledBy, + 'aria-current': ariaCurrent, + 'aria-selected': ariaSelected, + ...domAttributeProps, + className, + }); + + return element; } ); diff --git a/packages/vibrant-core/src/lib/Text/Text.tsx b/packages/vibrant-core/src/lib/Text/Text.tsx index 5d0f0ccc6..4dd7a7da6 100644 --- a/packages/vibrant-core/src/lib/Text/Text.tsx +++ b/packages/vibrant-core/src/lib/Text/Text.tsx @@ -1,21 +1,24 @@ import type { FC } from 'react'; import { createElement, forwardRef } from 'react'; -import styled from '@emotion/styled'; +import { css } from '@emotion/css'; import { nl2br } from '../nl2br'; import type { TextProps } from './TextProps'; import { interpolation, shouldForwardProp } from './TextProps'; -export const Text: FC = styled( - forwardRef(({ as = 'span', children, ...restProps }, ref) => - createElement(as, { - ref, - children: typeof children === 'string' ? nl2br(children) : children, - ...restProps, - }) - ), - { - shouldForwardProp, - } -)(interpolation); +export const Text: FC = forwardRef(({ as = 'span', children, ...restProps }, ref) => { + const className = Object.entries(interpolation({ ...restProps } ?? {})) + .map(([key, value]) => css({ [key]: value })) + .join(' '); + const domAttributeProps = Object.fromEntries( + Object.entries({ ...restProps }).filter(([key, _]) => shouldForwardProp(key)) + ); + + return createElement(as, { + ref, + children: typeof children === 'string' ? nl2br(children) : children, + domAttributeProps, + className, + }); +}); (Text as FC).displayName = 'Text'; diff --git a/packages/vibrant-core/src/lib/TextInput/TextInput.tsx b/packages/vibrant-core/src/lib/TextInput/TextInput.tsx index 248b19d07..10aca29d9 100644 --- a/packages/vibrant-core/src/lib/TextInput/TextInput.tsx +++ b/packages/vibrant-core/src/lib/TextInput/TextInput.tsx @@ -1,6 +1,6 @@ -import { forwardRef, useEffect, useImperativeHandle, useMemo, useRef, useState } from 'react'; +import { createElement, forwardRef, useEffect, useImperativeHandle, useMemo, useRef, useState } from 'react'; import type { FormEvent, KeyboardEvent } from 'react'; -import styled from '@emotion/styled'; +import { css } from '@emotion/css'; import { createShouldForwardProp } from '../createShouldForwardProp'; import type { SystemProps, TextInputProps, TextInputRef } from './TextInputProps'; import { HTMLAutoCompleteOptions, interpolation, replaceValue, systemPropNames } from './TextInputProps'; @@ -9,10 +9,6 @@ type HTMLInputProps = Exclude(systemPropNames); -const SystemTextInput = styled<'input', HTMLInputProps>('input', { - shouldForwardProp, -})(interpolation); - export const TextInput = forwardRef( ( { @@ -74,74 +70,94 @@ export const TextInput = forwardRef( clear: () => { setValue(''); - onValueChange?.({ value: '', prevent: () => {}, target: innerRef.current }); + onValueChange?.({ + value: '', + prevent: () => {}, + target: innerRef.current, + }); }, isFocused: () => document.activeElement === innerRef.current, })); - return ( - { - setIsFocused(true); - - onFocus?.(); - }} - onBlur={() => { - setIsFocused(false); - - onBlur?.(); - }} - onKeyDown={(event: KeyboardEvent) => { - const { key } = event.nativeEvent; - - if (key === 'Enter') { - onSubmit?.(value); - - return; + const styleProps = interpolation({ + ...restProps, + ...(hidden + ? { + position: 'absolute', + height: 0, + opacity: 0, } + : {}), + ...(isFocused ? focusStyle : {}), + }); - onKeyPress?.({ key, prevent: () => event.preventDefault() }); - }} - onInput={(event: FormEvent) => { - const replacedValue = replaceValue({ - pattern: type === 'number' ? /\d/ : pattern, - value: event.currentTarget.value, - }); + const classNames = Object.entries(interpolation(styleProps)).map(([key, value]) => css({ [key]: value })); - let isPrevented = false; + const domAttributeProps = Object.fromEntries( + Object.entries(restProps).filter(([key, _]) => shouldForwardProp(key)) + ); - if (value === replacedValue) { - event.preventDefault(); + return createElement('input', { + ref: innerRef, + type: type === 'number' ? 'text' : type, + value, + enterKeyHint: enterKeyType, + inputMode, + autoCapitalize, + autoComplete: HTMLAutoCompleteOptions[autoComplete], + onFocus: () => { + setIsFocused(true); - return; - } + onFocus?.(); + }, + onBlur: () => { + setIsFocused(false); - onValueChange?.({ - value: replacedValue, - prevent: () => { - isPrevented = true; + onBlur?.(); + }, - event.preventDefault(); - }, - target: innerRef.current, - }); + onKeyDown: (event: KeyboardEvent) => { + const { key } = event.nativeEvent; - if (!isPrevented) { - setValue(replacedValue); - } - }} - {...restProps} - {...(isFocused ? focusStyle : {})} - {...(hidden ? { position: 'absolute', height: 0, opacity: 0 } : {})} - /> - ); + if (key === 'Enter') { + onSubmit?.(value); + + return; + } + + onKeyPress?.({ key, prevent: () => event.preventDefault() }); + }, + onInput: (event: FormEvent) => { + const replacedValue = replaceValue({ + pattern: type === 'number' ? /\d/ : pattern, + value: event.currentTarget.value, + }); + + let isPrevented = false; + + if (value === replacedValue) { + event.preventDefault(); + + return; + } + + onValueChange?.({ + value: replacedValue, + prevent: () => { + isPrevented = true; + + event.preventDefault(); + }, + target: innerRef.current, + }); + + if (!isPrevented) { + setValue(replacedValue); + } + }, + ...domAttributeProps, + className: classNames.join(' '), + }); } ); diff --git a/yarn.lock b/yarn.lock index 71a03de30..0fad02343 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4278,6 +4278,25 @@ __metadata: languageName: node linkType: hard +"@emotion/babel-plugin@npm:^11.13.5": + version: 11.13.5 + resolution: "@emotion/babel-plugin@npm:11.13.5" + dependencies: + "@babel/helper-module-imports": ^7.16.7 + "@babel/runtime": ^7.18.3 + "@emotion/hash": ^0.9.2 + "@emotion/memoize": ^0.9.0 + "@emotion/serialize": ^1.3.3 + babel-plugin-macros: ^3.1.0 + convert-source-map: ^1.5.0 + escape-string-regexp: ^4.0.0 + find-root: ^1.1.0 + source-map: ^0.5.7 + stylis: 4.2.0 + checksum: c41df7e6c19520e76d1939f884be878bf88b5ba00bd3de9d05c5b6c5baa5051686ab124d7317a0645de1b017b574d8139ae1d6390ec267fbe8e85a5252afb542 + languageName: node + linkType: hard + "@emotion/cache@npm:11.9.3": version: 11.9.3 resolution: "@emotion/cache@npm:11.9.3" @@ -4304,6 +4323,19 @@ __metadata: languageName: node linkType: hard +"@emotion/cache@npm:^11.13.5": + version: 11.14.0 + resolution: "@emotion/cache@npm:11.14.0" + dependencies: + "@emotion/memoize": ^0.9.0 + "@emotion/sheet": ^1.4.0 + "@emotion/utils": ^1.4.2 + "@emotion/weak-memoize": ^0.4.0 + stylis: 4.2.0 + checksum: 0a81591541ea43bc7851742e6444b7800d72e98006f94e775ae6ea0806662d14e0a86ff940f5f19d33b4bb2c427c882aa65d417e7322a6e0d5f20fe65ed920c9 + languageName: node + linkType: hard + "@emotion/css-prettifier@npm:^1.0.1": version: 1.1.3 resolution: "@emotion/css-prettifier@npm:1.1.3" @@ -4314,6 +4346,19 @@ __metadata: languageName: node linkType: hard +"@emotion/css@npm:11.13.5": + version: 11.13.5 + resolution: "@emotion/css@npm:11.13.5" + dependencies: + "@emotion/babel-plugin": ^11.13.5 + "@emotion/cache": ^11.13.5 + "@emotion/serialize": ^1.3.3 + "@emotion/sheet": ^1.4.0 + "@emotion/utils": ^1.4.2 + checksum: 1f96c612603f2a6ad3e288c6ec90ac457e75e09b8a0bd4fb6e9bc1cd552ed9edd4a1e40880060ed30a285e1141e354a3b41a815f22871d2178a882e3c1f79426 + languageName: node + linkType: hard + "@emotion/hash@npm:^0.9.1": version: 0.9.1 resolution: "@emotion/hash@npm:0.9.1" @@ -4321,6 +4366,13 @@ __metadata: languageName: node linkType: hard +"@emotion/hash@npm:^0.9.2": + version: 0.9.2 + resolution: "@emotion/hash@npm:0.9.2" + checksum: 379bde2830ccb0328c2617ec009642321c0e009a46aa383dfbe75b679c6aea977ca698c832d225a893901f29d7b3eef0e38cf341f560f6b2b56f1ff23c172387 + languageName: node + linkType: hard + "@emotion/is-prop-valid@npm:^1.2.0": version: 1.2.1 resolution: "@emotion/is-prop-valid@npm:1.2.1" @@ -4365,6 +4417,13 @@ __metadata: languageName: node linkType: hard +"@emotion/memoize@npm:^0.9.0": + version: 0.9.0 + resolution: "@emotion/memoize@npm:0.9.0" + checksum: 038132359397348e378c593a773b1148cd0cf0a2285ffd067a0f63447b945f5278860d9de718f906a74c7c940ba1783ac2ca18f1c06a307b01cc0e3944e783b1 + languageName: node + linkType: hard + "@emotion/native@npm:11.9.3": version: 11.9.3 resolution: "@emotion/native@npm:11.9.3" @@ -4429,6 +4488,19 @@ __metadata: languageName: node linkType: hard +"@emotion/serialize@npm:^1.3.3": + version: 1.3.3 + resolution: "@emotion/serialize@npm:1.3.3" + dependencies: + "@emotion/hash": ^0.9.2 + "@emotion/memoize": ^0.9.0 + "@emotion/unitless": ^0.10.0 + "@emotion/utils": ^1.4.2 + csstype: ^3.0.2 + checksum: 510331233767ae4e09e925287ca2c7269b320fa1d737ea86db5b3c861a734483ea832394c0c1fe5b21468fe335624a75e72818831d303ba38125f54f44ba02e7 + languageName: node + linkType: hard + "@emotion/sheet@npm:^1.1.1, @emotion/sheet@npm:^1.2.2": version: 1.2.2 resolution: "@emotion/sheet@npm:1.2.2" @@ -4436,6 +4508,13 @@ __metadata: languageName: node linkType: hard +"@emotion/sheet@npm:^1.4.0": + version: 1.4.0 + resolution: "@emotion/sheet@npm:1.4.0" + checksum: eeb1212e3289db8e083e72e7e401cd6d1a84deece87e9ce184f7b96b9b5dbd6f070a89057255a6ff14d9865c3ce31f27c39248a053e4cdd875540359042586b4 + languageName: node + linkType: hard + "@emotion/styled@npm:11.10.4": version: 11.10.4 resolution: "@emotion/styled@npm:11.10.4" @@ -4459,6 +4538,13 @@ __metadata: languageName: node linkType: hard +"@emotion/unitless@npm:^0.10.0": + version: 0.10.0 + resolution: "@emotion/unitless@npm:0.10.0" + checksum: d79346df31a933e6d33518e92636afeb603ce043f3857d0a39a2ac78a09ef0be8bedff40130930cb25df1beeee12d96ee38613963886fa377c681a89970b787c + languageName: node + linkType: hard + "@emotion/unitless@npm:^0.8.1": version: 0.8.1 resolution: "@emotion/unitless@npm:0.8.1" @@ -4482,6 +4568,13 @@ __metadata: languageName: node linkType: hard +"@emotion/utils@npm:^1.4.2": + version: 1.4.2 + resolution: "@emotion/utils@npm:1.4.2" + checksum: 04cf76849c6401205c058b82689fd0ec5bf501aed6974880fe9681a1d61543efb97e848f4c38664ac4a9068c7ad2d1cb84f73bde6cf95f1208aa3c28e0190321 + languageName: node + linkType: hard + "@emotion/weak-memoize@npm:^0.2.5": version: 0.2.5 resolution: "@emotion/weak-memoize@npm:0.2.5" @@ -4496,6 +4589,13 @@ __metadata: languageName: node linkType: hard +"@emotion/weak-memoize@npm:^0.4.0": + version: 0.4.0 + resolution: "@emotion/weak-memoize@npm:0.4.0" + checksum: db5da0e89bd752c78b6bd65a1e56231f0abebe2f71c0bd8fc47dff96408f7065b02e214080f99924f6a3bfe7ee15afc48dad999d76df86b39b16e513f7a94f52 + languageName: node + linkType: hard + "@esbuild/android-arm@npm:0.15.18": version: 0.15.18 resolution: "@esbuild/android-arm@npm:0.15.18" @@ -16543,6 +16643,7 @@ __metadata: "@docusaurus/theme-live-codeblock": 2.1.0 "@electron/remote": 2.0.8 "@emotion/cache": 11.9.3 + "@emotion/css": 11.13.5 "@emotion/jest": 11.9.3 "@emotion/native": 11.9.3 "@emotion/react": 11.10.4