From 72cd96b1856c1e5e5f04fc2443fa18f97a5ced0d Mon Sep 17 00:00:00 2001 From: Marcelo Serpa <81248+fullofcaffeine@users.noreply.github.com> Date: Wed, 18 Aug 2021 21:42:43 -0500 Subject: [PATCH 01/85] Proof of Concept --- docs/manifest.json | 6 ++ package-lock.json | 6 ++ packages/components/package.json | 1 + packages/components/src/confirm/README.md | 3 + packages/components/src/confirm/component.tsx | 63 +++++++++++++++++++ packages/components/src/confirm/hook.ts | 32 ++++++++++ packages/components/src/confirm/index.ts | 15 +++++ .../components/src/confirm/stories/index.js | 18 ++++++ packages/components/src/confirm/styles.ts | 24 +++++++ packages/components/src/confirm/test/index.js | 1 + packages/components/src/confirm/types.ts | 10 +++ packages/components/src/index.js | 1 + packages/components/tsconfig.json | 1 + .../src/components/post-visibility/index.js | 12 ++-- 14 files changed, 188 insertions(+), 5 deletions(-) create mode 100644 packages/components/src/confirm/README.md create mode 100644 packages/components/src/confirm/component.tsx create mode 100644 packages/components/src/confirm/hook.ts create mode 100644 packages/components/src/confirm/index.ts create mode 100644 packages/components/src/confirm/stories/index.js create mode 100644 packages/components/src/confirm/styles.ts create mode 100644 packages/components/src/confirm/test/index.js create mode 100644 packages/components/src/confirm/types.ts diff --git a/docs/manifest.json b/docs/manifest.json index 3fa9280108d4f..e424b1381a3c6 100644 --- a/docs/manifest.json +++ b/docs/manifest.json @@ -785,6 +785,12 @@ "markdown_source": "../packages/components/src/combobox-control/README.md", "parent": "components" }, + { + "title": "Confirm", + "slug": "confirm", + "markdown_source": "../packages/components/src/confirm/README.md", + "parent": "components" + }, { "title": "CustomSelectControl", "slug": "custom-select-control", diff --git a/package-lock.json b/package-lock.json index 629b31cb939cb..ac5226529cc7b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18162,6 +18162,7 @@ "moment": "^2.22.1", "re-resizable": "^6.4.0", "react-colorful": "^5.3.0", + "react-confirm": "0.1.24", "react-dates": "^17.1.1", "react-resize-aware": "^3.1.0", "react-use-gesture": "^9.0.0", @@ -52416,6 +52417,11 @@ "integrity": "sha512-lAge4syxosZg9SX8fJiwOLd9ZJSW3poPBtypnz1aMiFoHsRnK5G3+INGGx9DGtsrso4h5uFYbiFpjAfWyK3Kag==", "dev": true }, + "react-confirm": { + "version": "0.1.24", + "resolved": "https://registry.npmjs.org/react-confirm/-/react-confirm-0.1.24.tgz", + "integrity": "sha512-96qA+mbZyBRmh/3Y5aDgrYLwLndbaRjkP3GlXQtPEQbIH0P66xGcHJ7ui6y/MN85AZWq/V3drA1fJOiEcVkAVA==" + }, "react-dates": { "version": "17.2.0", "resolved": "https://registry.npmjs.org/react-dates/-/react-dates-17.2.0.tgz", diff --git a/packages/components/package.json b/packages/components/package.json index 8af8b32f533b1..640e4d739f8e6 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -60,6 +60,7 @@ "moment": "^2.22.1", "re-resizable": "^6.4.0", "react-colorful": "^5.3.0", + "react-confirm": "0.1.24", "react-dates": "^17.1.1", "react-resize-aware": "^3.1.0", "react-use-gesture": "^9.0.0", diff --git a/packages/components/src/confirm/README.md b/packages/components/src/confirm/README.md new file mode 100644 index 0000000000000..3586c12eeb86e --- /dev/null +++ b/packages/components/src/confirm/README.md @@ -0,0 +1,3 @@ +# `Confirm` + +TBD diff --git a/packages/components/src/confirm/component.tsx b/packages/components/src/confirm/component.tsx new file mode 100644 index 0000000000000..5f58b88ea5f02 --- /dev/null +++ b/packages/components/src/confirm/component.tsx @@ -0,0 +1,63 @@ +// @ts-nocheck (for now) + +/** + * External dependencies + */ +// eslint-disable-next-line no-restricted-imports +import type { Ref } from 'react'; +import { confirmable } from 'react-confirm'; + +/** + * Internal dependencies + */ +import Button from '../button'; +import type { OwnProps } from './types'; +import { Card, CardHeader, CardFooter } from '../card'; +import { Heading } from '../heading'; +import { contextConnect, PolymorphicComponentProps } from '../ui/context'; +import { useConfirm } from './hook'; + +// @todo deal with overlay click event, close dialog +// @todo add type declarations for the react-confirm functions +function Confirm( + props: PolymorphicComponentProps< OwnProps, 'div', false >, + forwardedRef: Ref< any > +) { + const { + role, + wrapperClassName, + show, + proceed, + confirmation, + ...otherProps + } = useConfirm( props ); + + return ( +
+ + + { confirmation } + + + + + + +
+ ); +} + +export default confirmable( contextConnect( Confirm, 'Confirm' ) ); diff --git a/packages/components/src/confirm/hook.ts b/packages/components/src/confirm/hook.ts new file mode 100644 index 0000000000000..5ed593f402091 --- /dev/null +++ b/packages/components/src/confirm/hook.ts @@ -0,0 +1,32 @@ +/** + * Internal dependencies + */ +import { useContextSystem, PolymorphicComponentProps } from '../ui/context'; + +/** + * Internal dependencies + */ +import * as styles from './styles'; +import { useCx } from '../utils/hooks/use-cx'; +import type { OwnProps } from './types'; + +export function useConfirm( + props: PolymorphicComponentProps< OwnProps, 'div' > +) { + const { className, ...otherProps } = useContextSystem( props, 'Confirm' ); + + const cx = useCx(); + + const classes = cx( className ); + const wrapperClassName = cx( styles.overlayWrapper ); + const dialogWrapperClassName = cx( styles.dialogWrapper ); + + console.log( otherProps ); + + return { + className: classes, + wrapperClassName, + dialogWrapperClassName, + ...otherProps, + }; +} diff --git a/packages/components/src/confirm/index.ts b/packages/components/src/confirm/index.ts new file mode 100644 index 0000000000000..51bfc98fc1b4d --- /dev/null +++ b/packages/components/src/confirm/index.ts @@ -0,0 +1,15 @@ +//@ts-nocheck + +/** + * External dependencies + */ +import { createConfirmation } from 'react-confirm'; + +/** + * Internal dependencies + */ +import Confirm from './component'; + +const confirm = createConfirmation( Confirm ); + +export { Confirm, confirm }; diff --git a/packages/components/src/confirm/stories/index.js b/packages/components/src/confirm/stories/index.js new file mode 100644 index 0000000000000..29c336e215f6f --- /dev/null +++ b/packages/components/src/confirm/stories/index.js @@ -0,0 +1,18 @@ +/** + * External dependencies + */ +import React from 'react'; + +/** + * Internal dependencies + */ +import { Confirm } from '..'; + +export default { + component: Confirm, + title: 'Components (Experimental)/Confirm', +}; + +export const _default = () => { + return ; +}; diff --git a/packages/components/src/confirm/styles.ts b/packages/components/src/confirm/styles.ts new file mode 100644 index 0000000000000..ba5fbfe8a515b --- /dev/null +++ b/packages/components/src/confirm/styles.ts @@ -0,0 +1,24 @@ +/** + * External dependencies + */ +import { css } from '@emotion/react'; + +export const overlayWrapper = css` + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + z-index: 99; + background: rgba( 0, 0, 0, 0.5 ); + display: -webkit-flex; + display: -moz-flex; + display: -ms-flex; + display: -o-flex; + display: flex; + justify-content: center; + -ms-align-items: center; + align-items: center; +`; + +export const dialogWrapper = css``; diff --git a/packages/components/src/confirm/test/index.js b/packages/components/src/confirm/test/index.js new file mode 100644 index 0000000000000..954ddd236b585 --- /dev/null +++ b/packages/components/src/confirm/test/index.js @@ -0,0 +1 @@ +// TBD diff --git a/packages/components/src/confirm/types.ts b/packages/components/src/confirm/types.ts new file mode 100644 index 0000000000000..f917d36434c55 --- /dev/null +++ b/packages/components/src/confirm/types.ts @@ -0,0 +1,10 @@ +/** + * Internal dependencies + */ + +// TBD +export interface OwnProps { + show: boolean; + proceed: Function; + confirmation: string; +} diff --git a/packages/components/src/index.js b/packages/components/src/index.js index 04146b32a2fb1..827e12c73d459 100644 --- a/packages/components/src/index.js +++ b/packages/components/src/index.js @@ -184,3 +184,4 @@ export { } from './higher-order/with-focus-return'; export { default as withNotices } from './higher-order/with-notices'; export { default as withSpokenMessages } from './higher-order/with-spoken-messages'; +export { confirm } from './confirm'; // @todo make it experimental diff --git a/packages/components/tsconfig.json b/packages/components/tsconfig.json index 77809950efbdd..e479cda0ce936 100644 --- a/packages/components/tsconfig.json +++ b/packages/components/tsconfig.json @@ -24,6 +24,7 @@ "src/base-field/**/*", "src/button/**/*", "src/card/**/*", + "src/confirm/**/*", "src/dashicon/**/*", "src/disabled/**/*", "src/divider/**/*", diff --git a/packages/editor/src/components/post-visibility/index.js b/packages/editor/src/components/post-visibility/index.js index 7d86880def97d..52d71dae6a9c1 100644 --- a/packages/editor/src/components/post-visibility/index.js +++ b/packages/editor/src/components/post-visibility/index.js @@ -3,7 +3,7 @@ */ import { __ } from '@wordpress/i18n'; import { Component } from '@wordpress/element'; -import { VisuallyHidden } from '@wordpress/components'; +import { VisuallyHidden, confirm } from '@wordpress/components'; import { withInstanceId, compose } from '@wordpress/compose'; import { withSelect, withDispatch } from '@wordpress/data'; @@ -34,12 +34,14 @@ export class PostVisibility extends Component { this.setState( { hasPassword: false } ); } - setPrivate() { + async setPrivate() { if ( // eslint-disable-next-line no-alert - ! window.confirm( - __( 'Would you like to privately publish this post now?' ) - ) + ! ( await confirm( { + confirmation: __( + 'Would you like to privately publish this post now?' + ), + } ) ) ) { return; } From 335053aa6c8248a46af3564eaf979dfc3c17501c Mon Sep 17 00:00:00 2001 From: Marcelo Serpa <81248+fullofcaffeine@users.noreply.github.com> Date: Fri, 20 Aug 2021 17:59:08 -0500 Subject: [PATCH 02/85] Improve UX to more closely resembles a native confirm --- packages/components/src/confirm/component.tsx | 26 ++++++++++++++++--- packages/components/src/confirm/hook.ts | 6 ++--- packages/components/src/confirm/styles.ts | 19 +++++++++----- 3 files changed, 38 insertions(+), 13 deletions(-) diff --git a/packages/components/src/confirm/component.tsx b/packages/components/src/confirm/component.tsx index 5f58b88ea5f02..8d1bf5eac15e9 100644 --- a/packages/components/src/confirm/component.tsx +++ b/packages/components/src/confirm/component.tsx @@ -4,7 +4,7 @@ * External dependencies */ // eslint-disable-next-line no-restricted-imports -import type { Ref } from 'react'; +import { Ref, useEffect } from 'react'; import { confirmable } from 'react-confirm'; /** @@ -16,6 +16,8 @@ import { Card, CardHeader, CardFooter } from '../card'; import { Heading } from '../heading'; import { contextConnect, PolymorphicComponentProps } from '../ui/context'; import { useConfirm } from './hook'; +import type { KeyboardEvent } from 'react'; +import { ESCAPE } from '@wordpress/keycodes'; // @todo deal with overlay click event, close dialog // @todo add type declarations for the react-confirm functions @@ -26,21 +28,35 @@ function Confirm( const { role, wrapperClassName, + overlayClassName, show, proceed, confirmation, ...otherProps } = useConfirm( props ); + function handleEscapePress( event: KeyboardEvent< HTMLDivElement > ) { + // `keyCode` is depreacted, so let's use `key` + if ( event.key === 'Escape' ) { + proceed( false ); + } + } + + useEffect( () => { + document.addEventListener( 'keydown', handleEscapePress ); + return () => + document.removeEventListener( 'keydown', handleEscapePress ); + } ); + return (
- + event.preventDefault() }> { confirmation } @@ -56,6 +72,10 @@ function Confirm( +
proceed( false ) } + >
); } diff --git a/packages/components/src/confirm/hook.ts b/packages/components/src/confirm/hook.ts index 5ed593f402091..69a2eb9ddfb44 100644 --- a/packages/components/src/confirm/hook.ts +++ b/packages/components/src/confirm/hook.ts @@ -18,15 +18,15 @@ export function useConfirm( const cx = useCx(); const classes = cx( className ); - const wrapperClassName = cx( styles.overlayWrapper ); - const dialogWrapperClassName = cx( styles.dialogWrapper ); + const wrapperClassName = cx( styles.wrapper ); + const overlayClassName = cx( styles.overlay ); console.log( otherProps ); return { className: classes, wrapperClassName, - dialogWrapperClassName, + overlayClassName, ...otherProps, }; } diff --git a/packages/components/src/confirm/styles.ts b/packages/components/src/confirm/styles.ts index ba5fbfe8a515b..b7a389abefa65 100644 --- a/packages/components/src/confirm/styles.ts +++ b/packages/components/src/confirm/styles.ts @@ -3,22 +3,27 @@ */ import { css } from '@emotion/react'; -export const overlayWrapper = css` +export const wrapper = css` position: fixed; top: 0; left: 0; right: 0; bottom: 0; - z-index: 99; - background: rgba( 0, 0, 0, 0.5 ); - display: -webkit-flex; - display: -moz-flex; - display: -ms-flex; - display: -o-flex; + z-index: 9999999; display: flex; justify-content: center; -ms-align-items: center; align-items: center; `; +export const overlay = css` + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + z-index: -1; + background: rgba( 0, 0, 0, 0.5 ); +`; + export const dialogWrapper = css``; From f4a3396b36201f5bc05363463c8d1920ba381d8d Mon Sep 17 00:00:00 2001 From: Marcelo Serpa <81248+fullofcaffeine@users.noreply.github.com> Date: Fri, 20 Aug 2021 18:01:22 -0500 Subject: [PATCH 03/85] Remove unused import and outdated comment --- packages/components/src/confirm/component.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/components/src/confirm/component.tsx b/packages/components/src/confirm/component.tsx index 8d1bf5eac15e9..e486469214cb4 100644 --- a/packages/components/src/confirm/component.tsx +++ b/packages/components/src/confirm/component.tsx @@ -17,9 +17,7 @@ import { Heading } from '../heading'; import { contextConnect, PolymorphicComponentProps } from '../ui/context'; import { useConfirm } from './hook'; import type { KeyboardEvent } from 'react'; -import { ESCAPE } from '@wordpress/keycodes'; -// @todo deal with overlay click event, close dialog // @todo add type declarations for the react-confirm functions function Confirm( props: PolymorphicComponentProps< OwnProps, 'div', false >, From 1b2f104967f7e155e58694d9590d0a76123ea66e Mon Sep 17 00:00:00 2001 From: Marcelo Serpa <81248+fullofcaffeine@users.noreply.github.com> Date: Fri, 20 Aug 2021 18:41:12 -0500 Subject: [PATCH 04/85] Improve the story --- .../components/src/confirm/stories/index.js | 25 ++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/packages/components/src/confirm/stories/index.js b/packages/components/src/confirm/stories/index.js index 29c336e215f6f..0ecee6007cf4e 100644 --- a/packages/components/src/confirm/stories/index.js +++ b/packages/components/src/confirm/stories/index.js @@ -1,18 +1,37 @@ /** * External dependencies */ -import React from 'react'; +import React, { useState } from 'react'; /** * Internal dependencies */ -import { Confirm } from '..'; +import Button from '../../button'; +import { Confirm, confirm } from '..'; export default { component: Confirm, title: 'Components (Experimental)/Confirm', + argTypes: { proceed: { action: 'proceed' } }, }; export const _default = () => { - return ; + const [ confirmVal, setConfirmVal ] = useState(); + + async function triggerConfirm() { + if ( await confirm( { confirmation: 'Are you sure?' } ) ) { + setConfirmVal( 'You are sure!' ); + } else { + setConfirmVal( 'Ok, take more time to decide!' ); + } + } + + return ( + <> + + { confirmVal &&

{ confirmVal }

} + + ); }; From d5e8d73c506742da5924155f8d8e6c8be074d413 Mon Sep 17 00:00:00 2001 From: Marcelo Serpa <81248+fullofcaffeine@users.noreply.github.com> Date: Fri, 20 Aug 2021 18:42:25 -0500 Subject: [PATCH 05/85] Spelling fix --- packages/components/src/confirm/component.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/components/src/confirm/component.tsx b/packages/components/src/confirm/component.tsx index e486469214cb4..5a12b12ba3d85 100644 --- a/packages/components/src/confirm/component.tsx +++ b/packages/components/src/confirm/component.tsx @@ -34,7 +34,7 @@ function Confirm( } = useConfirm( props ); function handleEscapePress( event: KeyboardEvent< HTMLDivElement > ) { - // `keyCode` is depreacted, so let's use `key` + // `keyCode` is deprecated, so let's use `key` if ( event.key === 'Escape' ) { proceed( false ); } From f7250b67dd57cfaf3cb6e70d797d447c0dfc2dac Mon Sep 17 00:00:00 2001 From: Marcelo Serpa <81248+fullofcaffeine@users.noreply.github.com> Date: Fri, 20 Aug 2021 18:52:35 -0500 Subject: [PATCH 06/85] Remove debug code --- packages/components/src/confirm/hook.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/components/src/confirm/hook.ts b/packages/components/src/confirm/hook.ts index 69a2eb9ddfb44..05bb1004b4f81 100644 --- a/packages/components/src/confirm/hook.ts +++ b/packages/components/src/confirm/hook.ts @@ -21,8 +21,6 @@ export function useConfirm( const wrapperClassName = cx( styles.wrapper ); const overlayClassName = cx( styles.overlay ); - console.log( otherProps ); - return { className: classes, wrapperClassName, From 6062648ed8ef42f19b152ec5db1178f44848e715 Mon Sep 17 00:00:00 2001 From: Marcelo Serpa <81248+fullofcaffeine@users.noreply.github.com> Date: Fri, 20 Aug 2021 19:22:02 -0500 Subject: [PATCH 07/85] Fix invalid props warning --- packages/components/src/confirm/component.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/components/src/confirm/component.tsx b/packages/components/src/confirm/component.tsx index 5a12b12ba3d85..ebb4a801bde97 100644 --- a/packages/components/src/confirm/component.tsx +++ b/packages/components/src/confirm/component.tsx @@ -48,7 +48,6 @@ function Confirm( return (
Date: Tue, 24 Aug 2021 17:06:33 -0500 Subject: [PATCH 08/85] Empty dependency array to avoid listener from being re-added at each render --- packages/components/src/confirm/component.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/components/src/confirm/component.tsx b/packages/components/src/confirm/component.tsx index ebb4a801bde97..49bde17e74436 100644 --- a/packages/components/src/confirm/component.tsx +++ b/packages/components/src/confirm/component.tsx @@ -44,7 +44,7 @@ function Confirm( document.addEventListener( 'keydown', handleEscapePress ); return () => document.removeEventListener( 'keydown', handleEscapePress ); - } ); + }, [] ); return (
Date: Tue, 24 Aug 2021 17:06:59 -0500 Subject: [PATCH 09/85] Remove unused style --- packages/components/src/confirm/styles.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/components/src/confirm/styles.ts b/packages/components/src/confirm/styles.ts index b7a389abefa65..c1ad06057e598 100644 --- a/packages/components/src/confirm/styles.ts +++ b/packages/components/src/confirm/styles.ts @@ -25,5 +25,3 @@ export const overlay = css` z-index: -1; background: rgba( 0, 0, 0, 0.5 ); `; - -export const dialogWrapper = css``; From 18e0231d6b22d2b8dde1dfffb0b3e7cda2a33674 Mon Sep 17 00:00:00 2001 From: Marcelo Serpa <81248+fullofcaffeine@users.noreply.github.com> Date: Tue, 24 Aug 2021 19:29:03 -0500 Subject: [PATCH 10/85] wip --- packages/components/src/confirm/component.tsx | 76 +++++++------------ packages/components/src/confirm/hook.ts | 30 -------- packages/components/src/confirm/styles.ts | 23 +----- .../higher-order/with-focus-outside/index.js | 2 + packages/components/src/modal/aria-helper.js | 2 + packages/components/src/modal/frame.js | 2 + packages/components/src/modal/header.js | 2 + packages/components/src/modal/index.js | 2 + packages/components/tsconfig.json | 6 +- 9 files changed, 44 insertions(+), 101 deletions(-) delete mode 100644 packages/components/src/confirm/hook.ts diff --git a/packages/components/src/confirm/component.tsx b/packages/components/src/confirm/component.tsx index 49bde17e74436..9520a37809f11 100644 --- a/packages/components/src/confirm/component.tsx +++ b/packages/components/src/confirm/component.tsx @@ -1,78 +1,58 @@ -// @ts-nocheck (for now) +//@ts-nocheck (while we're using react-confirm) /** * External dependencies */ // eslint-disable-next-line no-restricted-imports -import { Ref, useEffect } from 'react'; import { confirmable } from 'react-confirm'; +import { __ } from '@wordpress/i18n'; +import { useMemo } from 'react'; /** * Internal dependencies */ +import * as styles from './styles'; import Button from '../button'; +import Modal from '../modal'; import type { OwnProps } from './types'; -import { Card, CardHeader, CardFooter } from '../card'; -import { Heading } from '../heading'; -import { contextConnect, PolymorphicComponentProps } from '../ui/context'; +import { + useContextSystem, + contextConnect, + PolymorphicComponentProps, +} from '../ui/context'; import { useConfirm } from './hook'; -import type { KeyboardEvent } from 'react'; +import { useCx } from '../utils/hooks/use-cx'; // @todo add type declarations for the react-confirm functions function Confirm( props: PolymorphicComponentProps< OwnProps, 'div', false >, forwardedRef: Ref< any > ) { - const { - role, - wrapperClassName, - overlayClassName, - show, - proceed, - confirmation, - ...otherProps - } = useConfirm( props ); + const { show, proceed, role, ...otherProps } = useContextSystem( + props, + 'Confirm' + ); + const cx = useCx(); - function handleEscapePress( event: KeyboardEvent< HTMLDivElement > ) { - // `keyCode` is deprecated, so let's use `key` - if ( event.key === 'Escape' ) { - proceed( false ); - } - } + const invisibleClassName = cx( ! show && styles.wrapperHidden ); - useEffect( () => { - document.addEventListener( 'keydown', handleEscapePress ); - return () => - document.removeEventListener( 'keydown', handleEscapePress ); - }, [] ); + console.log( show ); + console.log( isVisible ); return (
- event.preventDefault() }> - - { confirmation } - - - - - - -
proceed( false ) } - >
+ + + +
); } diff --git a/packages/components/src/confirm/hook.ts b/packages/components/src/confirm/hook.ts deleted file mode 100644 index 05bb1004b4f81..0000000000000 --- a/packages/components/src/confirm/hook.ts +++ /dev/null @@ -1,30 +0,0 @@ -/** - * Internal dependencies - */ -import { useContextSystem, PolymorphicComponentProps } from '../ui/context'; - -/** - * Internal dependencies - */ -import * as styles from './styles'; -import { useCx } from '../utils/hooks/use-cx'; -import type { OwnProps } from './types'; - -export function useConfirm( - props: PolymorphicComponentProps< OwnProps, 'div' > -) { - const { className, ...otherProps } = useContextSystem( props, 'Confirm' ); - - const cx = useCx(); - - const classes = cx( className ); - const wrapperClassName = cx( styles.wrapper ); - const overlayClassName = cx( styles.overlay ); - - return { - className: classes, - wrapperClassName, - overlayClassName, - ...otherProps, - }; -} diff --git a/packages/components/src/confirm/styles.ts b/packages/components/src/confirm/styles.ts index c1ad06057e598..b34d4ea936013 100644 --- a/packages/components/src/confirm/styles.ts +++ b/packages/components/src/confirm/styles.ts @@ -3,25 +3,6 @@ */ import { css } from '@emotion/react'; -export const wrapper = css` - position: fixed; - top: 0; - left: 0; - right: 0; - bottom: 0; - z-index: 9999999; - display: flex; - justify-content: center; - -ms-align-items: center; - align-items: center; -`; - -export const overlay = css` - position: fixed; - top: 0; - left: 0; - right: 0; - bottom: 0; - z-index: -1; - background: rgba( 0, 0, 0, 0.5 ); +export const wrapperHidden = css` + visibility: hidden; `; diff --git a/packages/components/src/higher-order/with-focus-outside/index.js b/packages/components/src/higher-order/with-focus-outside/index.js index c83de77f00906..41a7d9c9c3ea4 100644 --- a/packages/components/src/higher-order/with-focus-outside/index.js +++ b/packages/components/src/higher-order/with-focus-outside/index.js @@ -1,3 +1,5 @@ +//@ts-nocheck + /** * WordPress dependencies */ diff --git a/packages/components/src/modal/aria-helper.js b/packages/components/src/modal/aria-helper.js index 277293b337f46..aa6ecd01064ee 100644 --- a/packages/components/src/modal/aria-helper.js +++ b/packages/components/src/modal/aria-helper.js @@ -1,3 +1,5 @@ +//@ts-nocheck + /** * External dependencies */ diff --git a/packages/components/src/modal/frame.js b/packages/components/src/modal/frame.js index b563dff76c255..c38d776864e9a 100644 --- a/packages/components/src/modal/frame.js +++ b/packages/components/src/modal/frame.js @@ -1,3 +1,5 @@ +//@ts-nocheck + /** * External dependencies */ diff --git a/packages/components/src/modal/header.js b/packages/components/src/modal/header.js index 7fcc145b05484..ef05861a08ad1 100644 --- a/packages/components/src/modal/header.js +++ b/packages/components/src/modal/header.js @@ -1,3 +1,5 @@ +//@ts-nocheck + /** * WordPress dependencies */ diff --git a/packages/components/src/modal/index.js b/packages/components/src/modal/index.js index 2144972d42f18..e689b77171486 100644 --- a/packages/components/src/modal/index.js +++ b/packages/components/src/modal/index.js @@ -1,3 +1,5 @@ +//@ts-nocheck + /** * WordPress dependencies */ diff --git a/packages/components/tsconfig.json b/packages/components/tsconfig.json index e479cda0ce936..3c8f146acaff8 100644 --- a/packages/components/tsconfig.json +++ b/packages/components/tsconfig.json @@ -36,9 +36,11 @@ "src/grid/**/*", "src/h-stack/**/*", "src/heading/**/*", - "src/item-group/**/*", - "src/input-control/**/*", + "src/higher-order/with-focus-outside/**/*", "src/icon/**/*", + "src/input-control/**/*", + "src/item-group/**/*", + "src/modal/**/*", "src/number-control/**/*", "src/popover/**/*", "src/range-control/**/*", From 2391e35044b6b542661c5cd83cce4dccdbf8ace1 Mon Sep 17 00:00:00 2001 From: Marcelo Serpa <81248+fullofcaffeine@users.noreply.github.com> Date: Tue, 24 Aug 2021 20:22:36 -0500 Subject: [PATCH 11/85] Address code review suggestions partially, and refactor to use the existing component --- packages/components/src/confirm/component.tsx | 64 +++++++++++-------- .../components/src/confirm/stories/index.js | 6 +- packages/components/src/confirm/styles.ts | 8 --- packages/components/src/confirm/types.ts | 5 +- .../src/components/post-visibility/index.js | 2 +- 5 files changed, 42 insertions(+), 43 deletions(-) delete mode 100644 packages/components/src/confirm/styles.ts diff --git a/packages/components/src/confirm/component.tsx b/packages/components/src/confirm/component.tsx index 9520a37809f11..5872d2e33e1f6 100644 --- a/packages/components/src/confirm/component.tsx +++ b/packages/components/src/confirm/component.tsx @@ -5,13 +5,14 @@ */ // eslint-disable-next-line no-restricted-imports import { confirmable } from 'react-confirm'; +/** + * WordPress dependencies + */ import { __ } from '@wordpress/i18n'; -import { useMemo } from 'react'; /** * Internal dependencies */ -import * as styles from './styles'; import Button from '../button'; import Modal from '../modal'; import type { OwnProps } from './types'; @@ -20,40 +21,47 @@ import { contextConnect, PolymorphicComponentProps, } from '../ui/context'; -import { useConfirm } from './hook'; -import { useCx } from '../utils/hooks/use-cx'; +import { Flex } from '../flex'; // @todo add type declarations for the react-confirm functions function Confirm( props: PolymorphicComponentProps< OwnProps, 'div', false >, forwardedRef: Ref< any > ) { - const { show, proceed, role, ...otherProps } = useContextSystem( - props, - 'Confirm' - ); - const cx = useCx(); - - const invisibleClassName = cx( ! show && styles.wrapperHidden ); - - console.log( show ); - console.log( isVisible ); + const { + show: isOpen = true, + proceed, + role, + message, + ...otherProps + } = useContextSystem( props, 'Confirm' ); return ( -
- - - - -
+ <> + { isOpen && ( + proceed( false ) } + { ...otherProps } + ref={ forwardedRef } + > + + + + + + ) } + ); } diff --git a/packages/components/src/confirm/stories/index.js b/packages/components/src/confirm/stories/index.js index 0ecee6007cf4e..e0d63ffbaa431 100644 --- a/packages/components/src/confirm/stories/index.js +++ b/packages/components/src/confirm/stories/index.js @@ -19,10 +19,10 @@ export const _default = () => { const [ confirmVal, setConfirmVal ] = useState(); async function triggerConfirm() { - if ( await confirm( { confirmation: 'Are you sure?' } ) ) { - setConfirmVal( 'You are sure!' ); + if ( await confirm( { message: 'Are you sure?' } ) ) { + setConfirmVal( "Let's do it!" ); } else { - setConfirmVal( 'Ok, take more time to decide!' ); + setConfirmVal( 'Ok, take your time!' ); } } diff --git a/packages/components/src/confirm/styles.ts b/packages/components/src/confirm/styles.ts deleted file mode 100644 index b34d4ea936013..0000000000000 --- a/packages/components/src/confirm/styles.ts +++ /dev/null @@ -1,8 +0,0 @@ -/** - * External dependencies - */ -import { css } from '@emotion/react'; - -export const wrapperHidden = css` - visibility: hidden; -`; diff --git a/packages/components/src/confirm/types.ts b/packages/components/src/confirm/types.ts index f917d36434c55..69b0e9b283bee 100644 --- a/packages/components/src/confirm/types.ts +++ b/packages/components/src/confirm/types.ts @@ -2,9 +2,8 @@ * Internal dependencies */ -// TBD export interface OwnProps { show: boolean; - proceed: Function; - confirmation: string; + proceed: ( flag: boolean ) => void; + confirmation: React.ReactNode; } diff --git a/packages/editor/src/components/post-visibility/index.js b/packages/editor/src/components/post-visibility/index.js index 52d71dae6a9c1..ac3fb2cfc9e4a 100644 --- a/packages/editor/src/components/post-visibility/index.js +++ b/packages/editor/src/components/post-visibility/index.js @@ -38,7 +38,7 @@ export class PostVisibility extends Component { if ( // eslint-disable-next-line no-alert ! ( await confirm( { - confirmation: __( + message: __( 'Would you like to privately publish this post now?' ), } ) ) From a8788021ebd8a14f00316c841c42bcace818fdbd Mon Sep 17 00:00:00 2001 From: Marcelo Serpa <81248+fullofcaffeine@users.noreply.github.com> Date: Wed, 25 Aug 2021 18:47:37 -0500 Subject: [PATCH 12/85] Improve component by allowing it to be used without the `confirm` helper, remove dependency on `react-confirm` --- packages/components/package.json | 2 +- packages/components/src/confirm/component.tsx | 29 +++++---- packages/components/src/confirm/index.ts | 15 ----- packages/components/src/confirm/index.tsx | 59 +++++++++++++++++++ .../components/src/confirm/stories/index.js | 3 +- packages/components/src/confirm/types.ts | 10 ++-- 6 files changed, 87 insertions(+), 31 deletions(-) delete mode 100644 packages/components/src/confirm/index.ts create mode 100644 packages/components/src/confirm/index.tsx diff --git a/packages/components/package.json b/packages/components/package.json index 640e4d739f8e6..d37128ced84e0 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -60,8 +60,8 @@ "moment": "^2.22.1", "re-resizable": "^6.4.0", "react-colorful": "^5.3.0", - "react-confirm": "0.1.24", "react-dates": "^17.1.1", + "react-dom": "^16.14.0", "react-resize-aware": "^3.1.0", "react-use-gesture": "^9.0.0", "reakit": "^1.3.8", diff --git a/packages/components/src/confirm/component.tsx b/packages/components/src/confirm/component.tsx index 5872d2e33e1f6..ea81a6444ad14 100644 --- a/packages/components/src/confirm/component.tsx +++ b/packages/components/src/confirm/component.tsx @@ -1,10 +1,10 @@ -//@ts-nocheck (while we're using react-confirm) - /** * External dependencies */ // eslint-disable-next-line no-restricted-imports -import { confirmable } from 'react-confirm'; +import { useState } from 'react'; +// eslint-disable-next-line no-restricted-imports +import type { Ref, MouseEvent } from 'react'; /** * WordPress dependencies */ @@ -29,32 +29,41 @@ function Confirm( forwardedRef: Ref< any > ) { const { - show: isOpen = true, - proceed, - role, message, + onConfirm, + onCancel, + role, ...otherProps } = useContextSystem( props, 'Confirm' ); + const [ isOpen, setIsOpen ] = useState( true ); + + const closeAndHandle = ( + callback: ( event: MouseEvent< HTMLButtonElement > ) => void + ) => ( event: MouseEvent< HTMLButtonElement > ) => { + setIsOpen( false ); + callback( event ); + }; + return ( <> { isOpen && ( proceed( false ) } + onRequestClose={ closeAndHandle( onCancel ) } { ...otherProps } ref={ forwardedRef } > @@ -65,4 +74,4 @@ function Confirm( ); } -export default confirmable( contextConnect( Confirm, 'Confirm' ) ); +export default contextConnect( Confirm, 'Confirm' ); diff --git a/packages/components/src/confirm/index.ts b/packages/components/src/confirm/index.ts deleted file mode 100644 index 51bfc98fc1b4d..0000000000000 --- a/packages/components/src/confirm/index.ts +++ /dev/null @@ -1,15 +0,0 @@ -//@ts-nocheck - -/** - * External dependencies - */ -import { createConfirmation } from 'react-confirm'; - -/** - * Internal dependencies - */ -import Confirm from './component'; - -const confirm = createConfirmation( Confirm ); - -export { Confirm, confirm }; diff --git a/packages/components/src/confirm/index.tsx b/packages/components/src/confirm/index.tsx new file mode 100644 index 0000000000000..3a9ea16d81e0d --- /dev/null +++ b/packages/components/src/confirm/index.tsx @@ -0,0 +1,59 @@ +//@ts-nocheck + +/** + * External dependencies + */ +import ReactDOM from 'react-dom'; + +/** + * Internal dependencies + */ +import Confirm from './component'; + +/** + * Helper function that turns the Confirm component into a self-contained + * confirm dialog, callable from outside an existing React tree, mimicking + * the native `confirm` API. + * + * @param message the confirm message + * @return Promise + */ +const confirm = ( message: string ) => { + const wrapper = document.body.appendChild( + document.createElement( 'div' ) + ); + + const dispose = () => { + setTimeout( () => { + ReactDOM.unmountComponentAtNode( wrapper ); + setTimeout( () => { + if ( document.body.contains( wrapper ) ) { + document.body.removeChild( wrapper ); + } + } ); + }, 1000 ); + }; + + return new Promise( ( resolve ) => { + const confirmHandler = ( _ ) => resolve( true ); + const cancelHandler = ( _ ) => resolve( false ); + + try { + ReactDOM.render( + , + wrapper + ); + } catch ( e ) { + throw e; + } + } ).then( ( result: boolean ) => { + dispose(); + return result; + } ); +}; + +export { Confirm, confirm }; diff --git a/packages/components/src/confirm/stories/index.js b/packages/components/src/confirm/stories/index.js index e0d63ffbaa431..a091814daa29a 100644 --- a/packages/components/src/confirm/stories/index.js +++ b/packages/components/src/confirm/stories/index.js @@ -1,6 +1,7 @@ /** * External dependencies */ +// eslint-disable-next-line no-restricted-imports import React, { useState } from 'react'; /** @@ -19,7 +20,7 @@ export const _default = () => { const [ confirmVal, setConfirmVal ] = useState(); async function triggerConfirm() { - if ( await confirm( { message: 'Are you sure?' } ) ) { + if ( await confirm( 'Are you sure?' ) ) { setConfirmVal( "Let's do it!" ); } else { setConfirmVal( 'Ok, take your time!' ); diff --git a/packages/components/src/confirm/types.ts b/packages/components/src/confirm/types.ts index 69b0e9b283bee..41048d633818f 100644 --- a/packages/components/src/confirm/types.ts +++ b/packages/components/src/confirm/types.ts @@ -1,9 +1,11 @@ /** - * Internal dependencies + * External dependencies */ +// eslint-disable-next-line no-restricted-imports +import type { MouseEvent } from 'react'; export interface OwnProps { - show: boolean; - proceed: ( flag: boolean ) => void; - confirmation: React.ReactNode; + message: string; + onConfirm: ( event: MouseEvent< HTMLButtonElement > ) => void; + onCancel: ( event: MouseEvent< HTMLButtonElement > ) => void; } From b09651b5e4f1d7747bc4fa1af18230b0df8674e6 Mon Sep 17 00:00:00 2001 From: Marcelo Serpa <81248+fullofcaffeine@users.noreply.github.com> Date: Wed, 25 Aug 2021 19:54:20 -0500 Subject: [PATCH 13/85] Update README --- packages/components/src/confirm/README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/components/src/confirm/README.md b/packages/components/src/confirm/README.md index 3586c12eeb86e..07fe55bc119f6 100644 --- a/packages/components/src/confirm/README.md +++ b/packages/components/src/confirm/README.md @@ -1,3 +1,7 @@ # `Confirm` +
+This feature is still experimental. “Experimental” means this is an early implementation subject to drastic and breaking changes. +
+ TBD From c221e9d91823ee102f527a9e6d352f7227837663 Mon Sep 17 00:00:00 2001 From: Marcelo Serpa <81248+fullofcaffeine@users.noreply.github.com> Date: Wed, 25 Aug 2021 20:14:46 -0500 Subject: [PATCH 14/85] Update confirm call in post-visibility --- packages/editor/src/components/post-visibility/index.js | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/packages/editor/src/components/post-visibility/index.js b/packages/editor/src/components/post-visibility/index.js index ac3fb2cfc9e4a..a12cfeb0b40cb 100644 --- a/packages/editor/src/components/post-visibility/index.js +++ b/packages/editor/src/components/post-visibility/index.js @@ -37,11 +37,9 @@ export class PostVisibility extends Component { async setPrivate() { if ( // eslint-disable-next-line no-alert - ! ( await confirm( { - message: __( - 'Would you like to privately publish this post now?' - ), - } ) ) + ! ( await confirm( + __( 'Would you like to privately publish this post now?' ) + ) ) ) { return; } From cac2732fde5a25c97e5234ff9fe900fdf4c746fd Mon Sep 17 00:00:00 2001 From: Marcelo Serpa <81248+fullofcaffeine@users.noreply.github.com> Date: Wed, 25 Aug 2021 20:19:25 -0500 Subject: [PATCH 15/85] Remove role prop as it is not explicitely used at the moment --- packages/components/src/confirm/component.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/components/src/confirm/component.tsx b/packages/components/src/confirm/component.tsx index ea81a6444ad14..49b579eda3ce0 100644 --- a/packages/components/src/confirm/component.tsx +++ b/packages/components/src/confirm/component.tsx @@ -32,7 +32,6 @@ function Confirm( message, onConfirm, onCancel, - role, ...otherProps } = useContextSystem( props, 'Confirm' ); From 09427074bd0cd2c76373383c4ad6a0649288a7a8 Mon Sep 17 00:00:00 2001 From: Marcelo Serpa <81248+fullofcaffeine@users.noreply.github.com> Date: Wed, 25 Aug 2021 21:29:23 -0500 Subject: [PATCH 16/85] Add basic tests --- .../confirm/test/__snapshots__/index.js.snap | 441 ++++++++++++++++++ packages/components/src/confirm/test/index.js | 84 ++++ 2 files changed, 525 insertions(+) create mode 100644 packages/components/src/confirm/test/__snapshots__/index.js.snap diff --git a/packages/components/src/confirm/test/__snapshots__/index.js.snap b/packages/components/src/confirm/test/__snapshots__/index.js.snap new file mode 100644 index 0000000000000..d565e49fbe79e --- /dev/null +++ b/packages/components/src/confirm/test/__snapshots__/index.js.snap @@ -0,0 +1,441 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Confirm Confirm component should not render if closed by clicking OK 1`] = ` +Object { + "asFragment": [Function], + "baseElement": +
+
+ , + "container":
, + "debug": [Function], + "findAllByAltText": [Function], + "findAllByDisplayValue": [Function], + "findAllByLabelText": [Function], + "findAllByPlaceholderText": [Function], + "findAllByRole": [Function], + "findAllByTestId": [Function], + "findAllByText": [Function], + "findAllByTitle": [Function], + "findByAltText": [Function], + "findByDisplayValue": [Function], + "findByLabelText": [Function], + "findByPlaceholderText": [Function], + "findByRole": [Function], + "findByTestId": [Function], + "findByText": [Function], + "findByTitle": [Function], + "getAllByAltText": [Function], + "getAllByDisplayValue": [Function], + "getAllByLabelText": [Function], + "getAllByPlaceholderText": [Function], + "getAllByRole": [Function], + "getAllByTestId": [Function], + "getAllByText": [Function], + "getAllByTitle": [Function], + "getByAltText": [Function], + "getByDisplayValue": [Function], + "getByLabelText": [Function], + "getByPlaceholderText": [Function], + "getByRole": [Function], + "getByTestId": [Function], + "getByText": [Function], + "getByTitle": [Function], + "queryAllByAltText": [Function], + "queryAllByDisplayValue": [Function], + "queryAllByLabelText": [Function], + "queryAllByPlaceholderText": [Function], + "queryAllByRole": [Function], + "queryAllByTestId": [Function], + "queryAllByText": [Function], + "queryAllByTitle": [Function], + "queryByAltText": [Function], + "queryByDisplayValue": [Function], + "queryByLabelText": [Function], + "queryByPlaceholderText": [Function], + "queryByRole": [Function], + "queryByTestId": [Function], + "queryByText": [Function], + "queryByTitle": [Function], + "rerender": [Function], + "unmount": [Function], +} +`; + +exports[`Confirm Confirm component should not render if closed by clicking cancel 1`] = ` +Object { + "asFragment": [Function], + "baseElement": +
+
+ , + "container":
, + "debug": [Function], + "findAllByAltText": [Function], + "findAllByDisplayValue": [Function], + "findAllByLabelText": [Function], + "findAllByPlaceholderText": [Function], + "findAllByRole": [Function], + "findAllByTestId": [Function], + "findAllByText": [Function], + "findAllByTitle": [Function], + "findByAltText": [Function], + "findByDisplayValue": [Function], + "findByLabelText": [Function], + "findByPlaceholderText": [Function], + "findByRole": [Function], + "findByTestId": [Function], + "findByText": [Function], + "findByTitle": [Function], + "getAllByAltText": [Function], + "getAllByDisplayValue": [Function], + "getAllByLabelText": [Function], + "getAllByPlaceholderText": [Function], + "getAllByRole": [Function], + "getAllByTestId": [Function], + "getAllByText": [Function], + "getAllByTitle": [Function], + "getByAltText": [Function], + "getByDisplayValue": [Function], + "getByLabelText": [Function], + "getByPlaceholderText": [Function], + "getByRole": [Function], + "getByTestId": [Function], + "getByText": [Function], + "getByTitle": [Function], + "queryAllByAltText": [Function], + "queryAllByDisplayValue": [Function], + "queryAllByLabelText": [Function], + "queryAllByPlaceholderText": [Function], + "queryAllByRole": [Function], + "queryAllByTestId": [Function], + "queryAllByText": [Function], + "queryAllByTitle": [Function], + "queryByAltText": [Function], + "queryByDisplayValue": [Function], + "queryByLabelText": [Function], + "queryByPlaceholderText": [Function], + "queryByRole": [Function], + "queryByTestId": [Function], + "queryByText": [Function], + "queryByTitle": [Function], + "rerender": [Function], + "unmount": [Function], +} +`; + +exports[`Confirm Confirm component should not render if dialog is closed by clicking the \`x\` button 1`] = ` +Object { + "asFragment": [Function], + "baseElement": +
+
+ , + "container":
, + "debug": [Function], + "findAllByAltText": [Function], + "findAllByDisplayValue": [Function], + "findAllByLabelText": [Function], + "findAllByPlaceholderText": [Function], + "findAllByRole": [Function], + "findAllByTestId": [Function], + "findAllByText": [Function], + "findAllByTitle": [Function], + "findByAltText": [Function], + "findByDisplayValue": [Function], + "findByLabelText": [Function], + "findByPlaceholderText": [Function], + "findByRole": [Function], + "findByTestId": [Function], + "findByText": [Function], + "findByTitle": [Function], + "getAllByAltText": [Function], + "getAllByDisplayValue": [Function], + "getAllByLabelText": [Function], + "getAllByPlaceholderText": [Function], + "getAllByRole": [Function], + "getAllByTestId": [Function], + "getAllByText": [Function], + "getAllByTitle": [Function], + "getByAltText": [Function], + "getByDisplayValue": [Function], + "getByLabelText": [Function], + "getByPlaceholderText": [Function], + "getByRole": [Function], + "getByTestId": [Function], + "getByText": [Function], + "getByTitle": [Function], + "queryAllByAltText": [Function], + "queryAllByDisplayValue": [Function], + "queryAllByLabelText": [Function], + "queryAllByPlaceholderText": [Function], + "queryAllByRole": [Function], + "queryAllByTestId": [Function], + "queryAllByText": [Function], + "queryAllByTitle": [Function], + "queryByAltText": [Function], + "queryByDisplayValue": [Function], + "queryByLabelText": [Function], + "queryByPlaceholderText": [Function], + "queryByRole": [Function], + "queryByTestId": [Function], + "queryByText": [Function], + "queryByTitle": [Function], + "rerender": [Function], + "unmount": [Function], +} +`; + +exports[`Confirm Confirm component should not render if dialog is closed by clicking the overlay 1`] = ` +.emotion-0 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; + -webkit-box-pack: end; + -ms-flex-pack: end; + -webkit-justify-content: flex-end; + justify-content: flex-end; + width: 100%; +} + +.emotion-0>*+*:not( marquee ) { + margin-left: calc(4px * 2); +} + +.emotion-0>* { + min-width: 0; +} + +
+ +`; + +exports[`Confirm Confirm component should render correctly 1`] = ` +Object { + "asFragment": [Function], + "baseElement": .emotion-0 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; + -webkit-box-pack: end; + -ms-flex-pack: end; + -webkit-justify-content: flex-end; + justify-content: flex-end; + width: 100%; +} + +.emotion-0>*+*:not( marquee ) { + margin-left: calc(4px * 2); +} + +.emotion-0>* { + min-width: 0; +} + + +