From 1a5465dc340aa007fa0b423420d2bf54b82278ad Mon Sep 17 00:00:00 2001 From: DaneEveritt <dane@daneeveritt.com> Date: Sun, 5 Jun 2022 14:56:42 -0400 Subject: [PATCH] Update react, add some V2 components for V1 usage --- package.json | 12 +- .../components/elements/button/Button.tsx | 36 ++++++ .../components/elements/button/index.ts | 2 + .../elements/button/style.module.css | 30 +++++ .../components/elements/dialog/Dialog.tsx | 112 ++++++++++++++++++ .../components/elements/dialog/index.ts | 2 + .../elements/dialog/style.module.css | 20 ++++ .../components/elements/dropdown/Dropdown.tsx | 62 ++++++++++ .../elements/dropdown/DropdownButton.tsx | 24 ++++ .../elements/dropdown/DropdownItem.tsx | 43 +++++++ .../components/elements/dropdown/index.ts | 2 + .../elements/dropdown/style.module.css | 58 +++++++++ .../components/elements/inputs/Checkbox.tsx | 11 ++ .../components/elements/inputs/InputField.tsx | 11 ++ .../components/elements/inputs/index.ts | 3 + .../elements/inputs/styles.module.css | 21 ++++ .../elements/transitions/FadeTransition.tsx | 31 +++++ .../components/elements/transitions/index.ts | 8 ++ resources/scripts/globals.d.ts | 1 + resources/scripts/macros.d.ts | 43 +++---- yarn.lock | 75 +++++++++--- 21 files changed, 564 insertions(+), 43 deletions(-) create mode 100644 resources/scripts/components/elements/button/Button.tsx create mode 100644 resources/scripts/components/elements/button/index.ts create mode 100644 resources/scripts/components/elements/button/style.module.css create mode 100644 resources/scripts/components/elements/dialog/Dialog.tsx create mode 100644 resources/scripts/components/elements/dialog/index.ts create mode 100644 resources/scripts/components/elements/dialog/style.module.css create mode 100644 resources/scripts/components/elements/dropdown/Dropdown.tsx create mode 100644 resources/scripts/components/elements/dropdown/DropdownButton.tsx create mode 100644 resources/scripts/components/elements/dropdown/DropdownItem.tsx create mode 100644 resources/scripts/components/elements/dropdown/index.ts create mode 100644 resources/scripts/components/elements/dropdown/style.module.css create mode 100644 resources/scripts/components/elements/inputs/Checkbox.tsx create mode 100644 resources/scripts/components/elements/inputs/InputField.tsx create mode 100644 resources/scripts/components/elements/inputs/index.ts create mode 100644 resources/scripts/components/elements/inputs/styles.module.css create mode 100644 resources/scripts/components/elements/transitions/FadeTransition.tsx create mode 100644 resources/scripts/components/elements/transitions/index.ts diff --git a/package.json b/package.json index 0d80e4a7..f4d8bf6d 100644 --- a/package.json +++ b/package.json @@ -4,9 +4,13 @@ "@fortawesome/fontawesome-svg-core": "^1.2.32", "@fortawesome/free-solid-svg-icons": "^5.15.1", "@fortawesome/react-fontawesome": "^0.1.11", + "@headlessui/react": "^1.6.4", + "@heroicons/react": "^1.0.6", + "@hot-loader/react-dom": "^16.14.0", "@tailwindcss/forms": "^0.5.2", "axios": "^0.21.1", "chart.js": "^2.8.0", + "classnames": "^2.3.1", "codemirror": "^5.57.0", "date-fns": "^2.16.1", "debounce": "^1.2.0", @@ -20,7 +24,7 @@ "i18next-xhr-backend": "^3.2.2", "qrcode.react": "^1.0.1", "query-string": "^6.7.0", - "react": "^16.13.1", + "react": "^16.14.0", "react-copy-to-clipboard": "^5.0.2", "react-dom": "npm:@hot-loader/react-dom", "react-fast-compare": "^3.2.0", @@ -64,9 +68,9 @@ "@types/node": "^14.11.10", "@types/qrcode.react": "^1.0.1", "@types/query-string": "^6.3.0", - "@types/react": "^16.9.41", + "@types/react": "^16.14.0", "@types/react-copy-to-clipboard": "^4.3.0", - "@types/react-dom": "^16.9.8", + "@types/react-dom": "^16.9.16", "@types/react-helmet": "^6.0.0", "@types/react-redux": "^7.1.1", "@types/react-router": "^5.1.3", @@ -103,7 +107,7 @@ "terser-webpack-plugin": "^4.2.3", "ts-essentials": "^9.1.2", "twin.macro": "^2.8.2", - "typescript": "^4.2.4", + "typescript": "^4.7.3", "webpack": "^4.43.0", "webpack-assets-manifest": "^3.1.1", "webpack-bundle-analyzer": "^3.8.0", diff --git a/resources/scripts/components/elements/button/Button.tsx b/resources/scripts/components/elements/button/Button.tsx new file mode 100644 index 00000000..55c8ca81 --- /dev/null +++ b/resources/scripts/components/elements/button/Button.tsx @@ -0,0 +1,36 @@ +import React, { forwardRef } from 'react'; +import classNames from 'classnames'; +import styles from './style.module.css'; + +export type ButtonProps = JSX.IntrinsicElements['button'] & { + square?: boolean; + small?: boolean; +} + +const Button = forwardRef<HTMLButtonElement, ButtonProps>( + ({ children, square, small, className, ...rest }, ref) => { + return ( + <button + ref={ref} + className={classNames(styles.button, { [styles.square]: square, [styles.small]: small }, className)} + {...rest} + > + {children} + </button> + ); + }, +); + +const TextButton = forwardRef<HTMLButtonElement, ButtonProps>(({ className, ...props }, ref) => ( + // @ts-expect-error + <Button ref={ref} className={classNames(styles.text, className)} {...props} /> +)); + +const DangerButton = forwardRef<HTMLButtonElement, ButtonProps>(({ className, ...props }, ref) => ( + // @ts-expect-error + <Button ref={ref} className={classNames(styles.danger, className)} {...props} /> +)); + +const _Button = Object.assign(Button, { Text: TextButton, Danger: DangerButton }); + +export default _Button; diff --git a/resources/scripts/components/elements/button/index.ts b/resources/scripts/components/elements/button/index.ts new file mode 100644 index 00000000..f40f42db --- /dev/null +++ b/resources/scripts/components/elements/button/index.ts @@ -0,0 +1,2 @@ +export { default as Button } from './Button'; +export { default as styles } from './style.module.css'; diff --git a/resources/scripts/components/elements/button/style.module.css b/resources/scripts/components/elements/button/style.module.css new file mode 100644 index 00000000..6956422a --- /dev/null +++ b/resources/scripts/components/elements/button/style.module.css @@ -0,0 +1,30 @@ +.button { + @apply px-4 py-2 inline-flex items-center justify-center; + @apply bg-blue-600 rounded text-base font-semibold text-blue-50 transition-all duration-100; + @apply hover:bg-blue-500 active:bg-blue-500; + + &.square { + @apply p-2; + } + + &:focus { + @apply ring-[3px] ring-blue-500 ring-offset-2 ring-offset-neutral-700; + } + + /* Sizing Controls */ + &.small { + @apply px-3 py-1 font-normal focus:ring-2; + + &.square { + @apply p-1; + } + } +} + +.text { + @apply bg-transparent focus:ring-neutral-300 focus:ring-opacity-50 hover:bg-neutral-500 active:bg-neutral-500; +} + +.danger { + @apply bg-red-600 hover:bg-red-500 active:bg-red-500 focus:ring-red-500 text-red-50; +} diff --git a/resources/scripts/components/elements/dialog/Dialog.tsx b/resources/scripts/components/elements/dialog/Dialog.tsx new file mode 100644 index 00000000..89180630 --- /dev/null +++ b/resources/scripts/components/elements/dialog/Dialog.tsx @@ -0,0 +1,112 @@ +import React, { Fragment } from 'react'; +import { Dialog as HeadlessDialog, Transition } from '@headlessui/react'; +import { Button } from '@/components/elements/button/index'; +import styles from './style.module.css'; +import { XIcon } from '@heroicons/react/solid'; +import { CheckIcon, ExclamationIcon, InformationCircleIcon, ShieldExclamationIcon } from '@heroicons/react/outline'; +import classNames from 'classnames'; + +interface Props { + visible: boolean; + onDismissed: () => void; + title?: string; + children?: React.ReactNode; +} + +interface DialogIconProps { + type: 'danger' | 'info' | 'success' | 'warning'; + className?: string; +} + +const DialogIcon = ({ type, className }: DialogIconProps) => { + const [ Component, styles ] = (function (): [(props: React.ComponentProps<'svg'>) => JSX.Element, string] { + switch (type) { + case 'danger': + return [ ShieldExclamationIcon, 'bg-red-500 text-red-50' ]; + case 'warning': + return [ ExclamationIcon, 'bg-yellow-600 text-yellow-50' ]; + case 'success': + return [ CheckIcon, 'bg-green-600 text-green-50' ]; + case 'info': + return [ InformationCircleIcon, 'bg-primary-500 text-primary-50' ]; + } + })(); + + return ( + <div className={classNames('flex items-center justify-center w-10 h-10 rounded-full', styles, className)}> + <Component className={'w-6 h-6'} /> + </div> + ); +}; + +const DialogButtons = ({ children }: { children: React.ReactNode }) => ( + <>{children}</> +); + +const Dialog = ({ visible, title, onDismissed, children }: Props) => { + const items = React.Children.toArray(children || []); + const [ buttons, icon, content ] = [ + // @ts-expect-error + items.find(child => child.type === DialogButtons), + // @ts-expect-error + items.find(child => child.type === DialogIcon), + // @ts-expect-error + items.filter(child => ![ DialogIcon, DialogButtons ].includes(child.type)), + ]; + + return ( + <Transition show={visible} as={Fragment}> + <HeadlessDialog onClose={() => onDismissed()} className={styles.wrapper}> + <div className={'flex items-center justify-center min-h-screen'}> + <Transition.Child + as={Fragment} + enter={'ease-out duration-200'} + enterFrom={'opacity-0'} + enterTo={'opacity-100'} + leave={'ease-in duration-100'} + leaveFrom={'opacity-100'} + leaveTo={'opacity-0'} + > + <HeadlessDialog.Overlay className={styles.overlay}/> + </Transition.Child> + <Transition.Child + as={Fragment} + enter={'ease-out duration-200'} + enterFrom={'opacity-0 scale-95'} + enterTo={'opacity-100 scale-100'} + leave={'ease-in duration-100'} + leaveFrom={'opacity-100 scale-100'} + leaveTo={'opacity-0 scale-95'} + > + <div className={styles.container}> + <div className={'flex p-6'}> + {icon && <div className={'mr-4'}>{icon}</div>} + <div className={'flex-1'}> + {title && + <HeadlessDialog.Title className={styles.title}> + {title} + </HeadlessDialog.Title> + } + <HeadlessDialog.Description className={'pr-4'}> + {content} + </HeadlessDialog.Description> + </div> + </div> + {buttons && <div className={styles.button_bar}>{buttons}</div>} + {/* Keep this below the other buttons so that it isn't the default focus if they're present. */} + <div className={'absolute right-0 top-0 m-4'}> + <Button.Text square small onClick={() => onDismissed()} className={'hover:rotate-90'}> + <XIcon className={'w-5 h-5'}/> + </Button.Text> + </div> + </div> + </Transition.Child> + </div> + </HeadlessDialog> + </Transition> + ); +}; + +const _Dialog = Object.assign(Dialog, { Buttons: DialogButtons, Icon: DialogIcon }); + +export default _Dialog; diff --git a/resources/scripts/components/elements/dialog/index.ts b/resources/scripts/components/elements/dialog/index.ts new file mode 100644 index 00000000..96085ec9 --- /dev/null +++ b/resources/scripts/components/elements/dialog/index.ts @@ -0,0 +1,2 @@ +export { default as Dialog } from './Dialog'; +export { default as styles } from './style.module.css'; diff --git a/resources/scripts/components/elements/dialog/style.module.css b/resources/scripts/components/elements/dialog/style.module.css new file mode 100644 index 00000000..94959ee7 --- /dev/null +++ b/resources/scripts/components/elements/dialog/style.module.css @@ -0,0 +1,20 @@ +.wrapper { + @apply fixed z-10 inset-0 overflow-y-auto; +} + +.overlay { + @apply fixed inset-0 bg-gray-900 opacity-50; +} + +.container { + @apply relative bg-gray-600 rounded max-w-xl w-full mx-auto shadow-lg; + @apply ring-4 ring-gray-800 ring-opacity-80; + + & .title { + @apply font-header text-xl font-medium mb-2 text-white pr-4; + } + + & > .button_bar { + @apply px-6 py-3 bg-gray-700 flex items-center justify-end space-x-3 rounded-b; + } +} diff --git a/resources/scripts/components/elements/dropdown/Dropdown.tsx b/resources/scripts/components/elements/dropdown/Dropdown.tsx new file mode 100644 index 00000000..e9378046 --- /dev/null +++ b/resources/scripts/components/elements/dropdown/Dropdown.tsx @@ -0,0 +1,62 @@ +import React, { ElementType, forwardRef, useMemo } from 'react'; +import { Menu, Transition } from '@headlessui/react'; +import styles from './style.module.css'; +import classNames from 'classnames'; +import DropdownItem from '@/components/elements/dropdown/DropdownItem'; +import DropdownButton from '@/components/elements/dropdown/DropdownButton'; + +interface Props { + as?: ElementType; + children: React.ReactNode; +} + +const DropdownGap = ({ invisible }: { invisible?: boolean }) => ( + <div className={classNames('border m-2', { 'border-neutral-700': !invisible, 'border-transparent': invisible })}/> +); + +type TypedChild = (React.ReactChild | React.ReactFragment | React.ReactPortal) & { + type?: JSX.Element; +} + +const Dropdown = forwardRef<typeof Menu, Props>(({ as, children }, ref) => { + const [ Button, items ] = useMemo(() => { + const list = React.Children.toArray(children) as unknown as TypedChild[]; + + return [ + list.filter(child => child.type === DropdownButton), + list.filter(child => child.type !== DropdownButton), + ]; + }, [ children ]); + + if (!Button) { + throw new Error('Cannot mount <Dropdown /> component without a child <Dropdown.Button />.'); + } + + return ( + <Menu as={as || 'div'} className={styles.menu} ref={ref}> + {Button} + <Transition + enter={'transition duration-100 ease-out'} + enterFrom={'transition scale-95 opacity-0'} + enterTo={'transform scale-100 opacity-100'} + leave={'transition duration-75 ease-out'} + leaveFrom={'transform scale-100 opacity-100'} + leaveTo={'transform scale-95 opacity-0'} + > + <Menu.Items className={classNames(styles.items_container, 'w-56')}> + <div className={'px-1 py-1'}> + {items} + </div> + </Menu.Items> + </Transition> + </Menu> + ); +}); + +const _Dropdown = Object.assign(Dropdown, { + Button: DropdownButton, + Item: DropdownItem, + Gap: DropdownGap, +}); + +export { _Dropdown as default }; diff --git a/resources/scripts/components/elements/dropdown/DropdownButton.tsx b/resources/scripts/components/elements/dropdown/DropdownButton.tsx new file mode 100644 index 00000000..32863d26 --- /dev/null +++ b/resources/scripts/components/elements/dropdown/DropdownButton.tsx @@ -0,0 +1,24 @@ +import classNames from 'classnames'; +import styles from '@/components/elements/dropdown/style.module.css'; +import { ChevronDownIcon } from '@heroicons/react/solid'; +import { Menu } from '@headlessui/react'; +import React from 'react'; + +interface Props { + className?: string; + animate?: boolean; + children: React.ReactNode; +} + +export default ({ className, animate = true, children }: Props) => ( + <Menu.Button className={classNames(styles.button, className || 'px-4')}> + {typeof children === 'string' ? + <> + <span className={'mr-2'}>{children}</span> + <ChevronDownIcon aria-hidden={'true'} data-animated={animate.toString()}/> + </> + : + children + } + </Menu.Button> +); diff --git a/resources/scripts/components/elements/dropdown/DropdownItem.tsx b/resources/scripts/components/elements/dropdown/DropdownItem.tsx new file mode 100644 index 00000000..86e5acb1 --- /dev/null +++ b/resources/scripts/components/elements/dropdown/DropdownItem.tsx @@ -0,0 +1,43 @@ +import React, { forwardRef } from 'react'; +import { Menu } from '@headlessui/react'; +import styles from './style.module.css'; +import classNames from 'classnames'; + +interface Props { + children: React.ReactNode | ((opts: { active: boolean; disabled: boolean }) => JSX.Element); + danger?: boolean; + disabled?: boolean; + className?: string; + icon?: JSX.Element; + onClick?: (e: React.MouseEvent) => void; +} + +const DropdownItem = forwardRef<HTMLAnchorElement, Props>(({ + disabled, + danger, + className, + onClick, + children, + icon: IconComponent, +}, ref) => { + return ( + <Menu.Item disabled={disabled}> + {({ disabled, active }) => ( + <a + ref={ref} + href={'#'} + className={classNames(styles.menu_item, { + [styles.danger]: danger, + [styles.disabled]: disabled, + }, className)} + onClick={onClick} + > + {IconComponent} + {typeof children === 'function' ? children({ disabled, active }) : children} + </a> + )} + </Menu.Item> + ); +}); + +export default DropdownItem; diff --git a/resources/scripts/components/elements/dropdown/index.ts b/resources/scripts/components/elements/dropdown/index.ts new file mode 100644 index 00000000..95a1a07d --- /dev/null +++ b/resources/scripts/components/elements/dropdown/index.ts @@ -0,0 +1,2 @@ +export { default as Dropdown } from './Dropdown'; +export * as styles from './style.module.css'; diff --git a/resources/scripts/components/elements/dropdown/style.module.css b/resources/scripts/components/elements/dropdown/style.module.css new file mode 100644 index 00000000..0b98e342 --- /dev/null +++ b/resources/scripts/components/elements/dropdown/style.module.css @@ -0,0 +1,58 @@ +.menu { + @apply relative inline-block text-left; + + & .button { + @apply inline-flex justify-center items-center w-full py-2 text-neutral-100 rounded-md; + @apply transition-all duration-100; + + &:hover, &[aria-expanded="true"] { + @apply bg-neutral-600 text-white; + } + + &:focus, &:focus-within, &:active { + @apply ring-2 ring-opacity-50 ring-neutral-300 text-white; + } + + & svg { + @apply w-5 h-5 transition-transform duration-75; + } + + &[aria-expanded="true"] svg[data-animated="true"] { + @apply rotate-180; + } + } + + & .items_container { + @apply absolute right-0 mt-2 origin-top-right bg-neutral-900 rounded z-10; + } +} + +.menu_item { + @apply flex items-center rounded w-full px-2 py-2; + + & svg { + @apply w-4 h-4 mr-4 text-neutral-300; + } + + &:hover, &:focus { + @apply bg-blue-500 text-blue-50; + + & svg { + @apply text-blue-50; + } + } + + &.danger { + &:hover, &:focus { + @apply bg-red-500 text-red-50; + + & svg { + @apply text-red-50; + } + } + } + + &.disabled { + @apply cursor-not-allowed hover:bg-neutral-800 opacity-30 focus:bg-transparent focus:hover:bg-neutral-800; + } +} diff --git a/resources/scripts/components/elements/inputs/Checkbox.tsx b/resources/scripts/components/elements/inputs/Checkbox.tsx new file mode 100644 index 00000000..da84d962 --- /dev/null +++ b/resources/scripts/components/elements/inputs/Checkbox.tsx @@ -0,0 +1,11 @@ +import React, { forwardRef } from 'react'; +import classNames from 'classnames'; +import styles from './styles.module.css'; + +export default forwardRef<HTMLInputElement, React.ComponentProps<'input'>>(({ className, ...props }, ref) => ( + <input + ref={ref} + className={classNames('form-input', styles.text_input, className)} + {...props} + /> +)); diff --git a/resources/scripts/components/elements/inputs/InputField.tsx b/resources/scripts/components/elements/inputs/InputField.tsx new file mode 100644 index 00000000..da84d962 --- /dev/null +++ b/resources/scripts/components/elements/inputs/InputField.tsx @@ -0,0 +1,11 @@ +import React, { forwardRef } from 'react'; +import classNames from 'classnames'; +import styles from './styles.module.css'; + +export default forwardRef<HTMLInputElement, React.ComponentProps<'input'>>(({ className, ...props }, ref) => ( + <input + ref={ref} + className={classNames('form-input', styles.text_input, className)} + {...props} + /> +)); diff --git a/resources/scripts/components/elements/inputs/index.ts b/resources/scripts/components/elements/inputs/index.ts new file mode 100644 index 00000000..e2e4443b --- /dev/null +++ b/resources/scripts/components/elements/inputs/index.ts @@ -0,0 +1,3 @@ +export { default as Checkbox } from './Checkbox'; +export { default as InputField } from './InputField'; +export { default as styles } from './styles.module.css'; diff --git a/resources/scripts/components/elements/inputs/styles.module.css b/resources/scripts/components/elements/inputs/styles.module.css new file mode 100644 index 00000000..c57cb0bb --- /dev/null +++ b/resources/scripts/components/elements/inputs/styles.module.css @@ -0,0 +1,21 @@ +.checkbox { + @apply w-4 h-4 rounded-sm border-neutral-500 bg-neutral-600 text-primary-500; + + &:focus, &:active { + @apply ring-2 ring-primary-500 ring-offset-2 ring-offset-neutral-700; + } + + &.indeterminate:checked { + @apply text-primary-500/50 border border-primary-500; + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' fill='white'%3E%3Cpath fill-rule='evenodd' d='M5 10a1 1 0 011-1h8a1 1 0 110 2H6a1 1 0 01-1-1z' clip-rule='evenodd' /%3E%3C/svg%3E"); + } +} + +.text_input { + @apply transition-all duration-75; + @apply bg-neutral-800 border-neutral-600 rounded px-4 py-2 outline-none; + + &:focus { + @apply border-blue-600 ring-2 ring-blue-500; + } +} diff --git a/resources/scripts/components/elements/transitions/FadeTransition.tsx b/resources/scripts/components/elements/transitions/FadeTransition.tsx new file mode 100644 index 00000000..d53acc47 --- /dev/null +++ b/resources/scripts/components/elements/transitions/FadeTransition.tsx @@ -0,0 +1,31 @@ +import React from 'react'; +import { Transition } from '@headlessui/react'; + +type Duration = `duration-${number}`; + +interface Props { + as?: React.ElementType; + duration?: Duration | [ Duration, Duration ]; + show: boolean; + children: React.ReactNode; +} + +export default ({ children, duration, ...props }: Props) => { + const [ enterDuration, exitDuration ] = Array.isArray(duration) + ? duration + : (!duration ? [ 'duration-200', 'duration-100' ] : [ duration, duration ]); + + return ( + <Transition + {...props} + enter={`ease-out ${enterDuration}`} + enterFrom={'opacity-0'} + enterTo={'opacity-100'} + leave={`ease-in ${exitDuration}`} + leaveFrom={'opacity-100'} + leaveTo={'opacity-0'} + > + {children} + </Transition> + ); +}; diff --git a/resources/scripts/components/elements/transitions/index.ts b/resources/scripts/components/elements/transitions/index.ts new file mode 100644 index 00000000..98060223 --- /dev/null +++ b/resources/scripts/components/elements/transitions/index.ts @@ -0,0 +1,8 @@ +import { Transition as TransitionComponent } from '@headlessui/react'; +import FadeTransition from '@/components/elements/transitions/FadeTransition'; + +const Transition = Object.assign(TransitionComponent, { + Fade: FadeTransition, +}); + +export { Transition }; diff --git a/resources/scripts/globals.d.ts b/resources/scripts/globals.d.ts index bb38b742..b08b7271 100644 --- a/resources/scripts/globals.d.ts +++ b/resources/scripts/globals.d.ts @@ -1,3 +1,4 @@ declare module '*.jpg'; declare module '*.png'; declare module '*.svg'; +declare module '*.css'; diff --git a/resources/scripts/macros.d.ts b/resources/scripts/macros.d.ts index 720aa9d2..2277519c 100644 --- a/resources/scripts/macros.d.ts +++ b/resources/scripts/macros.d.ts @@ -1,28 +1,29 @@ -// This allows the use of css={} on JSX elements. -// -// @see https://github.com/DefinitelyTyped/DefinitelyTyped/issues/31245 -// -// This is just the contents of the @types/styled-components/cssprop.d.ts file -// since using the other method of just importing the one file did not work -// correctly for some reason. -// noinspection ES6UnusedImports -import {} from 'react'; +import { ComponentType, ReactElement } from 'react'; // eslint-disable-next-line no-restricted-imports -import { CSSProp } from 'styled-components'; +import styledImport, { css as cssImport, CSSProp, StyledComponentProps } from 'styled-components'; declare module 'react' { interface Attributes { - // NOTE: unlike the plain javascript version, it is not possible to get access - // to the element's own attributes inside function interpolations. - // Only theme will be accessible, and only with the DefaultTheme due to the global - // nature of this declaration. - // If you are writing this inline you already have access to all the attributes anyway, - // no need for the extra indirection. - /** - * If present, this React element will be converted by - * `babel-plugin-styled-components` into a styled component - * with the given css as its styles. - */ css?: CSSProp; } } + +declare module 'styled-components' { + interface StyledComponentBase< + C extends string | ComponentType<any>, + // eslint-disable-next-line @typescript-eslint/ban-types + T extends object, + // eslint-disable-next-line @typescript-eslint/ban-types + O extends object = {}, + A extends keyof any = never + > extends ForwardRefExoticBase<StyledComponentProps<C, T, O, A>> { + (props: StyledComponentProps<C, T, O, A> & { as?: Element | string; forwardedAs?: never | undefined }): ReactElement< + StyledComponentProps<C, T, O, A> + >; + } +} + +declare module 'twin.macro' { + const css: typeof cssImport; + const styled: typeof styledImport; +} diff --git a/yarn.lock b/yarn.lock index 03d6e2f8..9b5b1c2a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1272,6 +1272,26 @@ resolved "https://registry.yarnpkg.com/@gar/promisify/-/promisify-1.1.3.tgz#555193ab2e3bb3b6adc3d551c9c030d9e860daf6" integrity sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw== +"@headlessui/react@^1.6.4": + version "1.6.4" + resolved "https://registry.yarnpkg.com/@headlessui/react/-/react-1.6.4.tgz#c73084e23386bef5fb86cd16da3352c3a844bb4c" + integrity sha512-0yqz1scwbFtwljmbbKjXsSGl5ABEYNICVHZnMCWo0UtOZodo2Tpu94uOVgCRjRZ77l2WcTi2S0uidINDvG7lsA== + +"@heroicons/react@^1.0.6": + version "1.0.6" + resolved "https://registry.yarnpkg.com/@heroicons/react/-/react-1.0.6.tgz#35dd26987228b39ef2316db3b1245c42eb19e324" + integrity sha512-JJCXydOFWMDpCP4q13iEplA503MQO3xLoZiKum+955ZCtHINWnx26CUxVxxFQu/uLb4LW3ge15ZpzIkXKkJ8oQ== + +"@hot-loader/react-dom@^16.14.0": + version "16.14.0" + resolved "https://registry.yarnpkg.com/@hot-loader/react-dom/-/react-dom-16.14.0.tgz#3cfc64e40bb78fa623e59b582b8f09dcdaad648a" + integrity sha512-EN9czvcLsMYmSDo5yRKZOAq3ZGRlDpad1gPtX0NdMMomJXcPE3yFSeFzE94X/NjOaiSVimB7LuqPYpkWVaIi4Q== + dependencies: + loose-envify "^1.1.0" + object-assign "^4.1.1" + prop-types "^15.6.2" + scheduler "^0.19.1" + "@jridgewell/gen-mapping@^0.3.0": version "0.3.1" resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.1.tgz#cf92a983c83466b8c0ce9124fadeaf09f7c66ea9" @@ -1471,12 +1491,12 @@ dependencies: "@types/react" "*" -"@types/react-dom@^16.9.8": - version "16.9.8" - resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-16.9.8.tgz#fe4c1e11dfc67155733dfa6aa65108b4971cb423" - integrity sha512-ykkPQ+5nFknnlU6lDd947WbQ6TE3NNzbQAkInC2EKY1qeYdTKp7onFusmYZb+ityzx2YviqT6BXSu+LyWWJwcA== +"@types/react-dom@^16.9.16": + version "16.9.16" + resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-16.9.16.tgz#c591f2ed1c6f32e9759dfa6eb4abfd8041f29e39" + integrity sha512-Oqc0RY4fggGA3ltEgyPLc3IV9T73IGoWjkONbsyJ3ZBn+UPPCYpU2ec0i3cEbJuEdZtkqcCF2l1zf2pBdgUGSg== dependencies: - "@types/react" "*" + "@types/react" "^16" "@types/react-helmet@^6.0.0": version "6.0.0" @@ -1523,13 +1543,19 @@ "@types/prop-types" "*" csstype "^2.2.0" -"@types/react@^16.9.41": - version "16.9.41" - resolved "https://registry.yarnpkg.com/@types/react/-/react-16.9.41.tgz#925137ee4d2ff406a0ecf29e8e9237390844002e" - integrity sha512-6cFei7F7L4wwuM+IND/Q2cV1koQUvJ8iSV+Gwn0c3kvABZ691g7sp3hfEQHOUBJtccl1gPi+EyNjMIl9nGA0ug== +"@types/react@^16", "@types/react@^16.14.0": + version "16.14.26" + resolved "https://registry.yarnpkg.com/@types/react/-/react-16.14.26.tgz#82540a240ba7207ebe87d9579051bc19c9ef7605" + integrity sha512-c/5CYyciOO4XdFcNhZW1O2woVx86k4T+DO2RorHZL7EhitkNQgSD/SgpdZJAUJa/qjVgOmTM44gHkAdZSXeQuQ== dependencies: "@types/prop-types" "*" - csstype "^2.2.0" + "@types/scheduler" "*" + csstype "^3.0.2" + +"@types/scheduler@*": + version "0.16.2" + resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.2.tgz#1a62f89525723dde24ba1b01b092bf5df8ad4d39" + integrity sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew== "@types/styled-components@^5.1.7": version "5.1.7" @@ -2657,6 +2683,11 @@ class-utils@^0.3.5: isobject "^3.0.0" static-extend "^0.1.1" +classnames@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.3.1.tgz#dfcfa3891e306ec1dad105d0e88f4417b8535e8e" + integrity sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA== + clean-set@^1.1.1: version "1.1.2" resolved "https://registry.yarnpkg.com/clean-set/-/clean-set-1.1.2.tgz#76d8bf238c3e27827bfa73073ecdfdc767187070" @@ -6994,10 +7025,10 @@ react-transition-group@^4.4.1: loose-envify "^1.4.0" prop-types "^15.6.2" -react@^16.13.1: - version "16.13.1" - resolved "https://registry.yarnpkg.com/react/-/react-16.13.1.tgz#2e818822f1a9743122c063d6410d85c1e3afe48e" - integrity sha512-YMZQQq32xHLX0bz5Mnibv1/LHb3Sqzngu7xstSM+vrkE5Kzr9xE0yMByK5kMoTK30YVJE61WfbxIFFvfeDKT1w== +react@^16.14.0: + version "16.14.0" + resolved "https://registry.yarnpkg.com/react/-/react-16.14.0.tgz#94d776ddd0aaa37da3eda8fc5b6b18a4c9a3114d" + integrity sha512-0X2CImDkJGApiAlcf0ODKIneSwBPhqJawOa5wCtKbu7ZECrmS26NvtSILynQ66cgkT/RJ4LidJOc3bUESwmU8g== dependencies: loose-envify "^1.1.0" object-assign "^4.1.1" @@ -7374,6 +7405,14 @@ scheduler@^0.17.0: loose-envify "^1.1.0" object-assign "^4.1.1" +scheduler@^0.19.1: + version "0.19.1" + resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.19.1.tgz#4f3e2ed2c1a7d65681f4c854fa8c5a1ccb40f196" + integrity sha512-n/zwRWRYSUj0/3g/otKDRPMh6qv2SYMWNq85IEa8iZyAv8od9zDYpGSnpBEjNgcMNq6Scbu5KfIPxNF72R/2EA== + dependencies: + loose-envify "^1.1.0" + object-assign "^4.1.1" + schema-utils@2.7.0, schema-utils@^2.6.5: version "2.7.0" resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-2.7.0.tgz#17151f76d8eae67fbbf77960c33c676ad9f4efc7" @@ -8369,10 +8408,10 @@ typedarray@^0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" -typescript@^4.2.4: - version "4.2.4" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.2.4.tgz#8610b59747de028fda898a8aef0e103f156d0961" - integrity sha512-V+evlYHZnQkaz8TRBuxTA92yZBPotr5H+WhQ7bD3hZUndx5tGOa1fuCgeSjxAzM1RiN5IzvadIXTVefuuwZCRg== +typescript@^4.7.3: + version "4.7.3" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.7.3.tgz#8364b502d5257b540f9de4c40be84c98e23a129d" + integrity sha512-WOkT3XYvrpXx4vMMqlD+8R8R37fZkjyLGlxavMc4iB8lrl8L0DeTcHbYgw/v0N/z9wAFsgBhcsF0ruoySS22mA== unbox-primitive@^1.0.1: version "1.0.1"