@wordpress/components 25.8.0 → 25.8.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +11 -0
- package/build/date-time/time/index.js +6 -1
- package/build/date-time/time/index.js.map +1 -1
- package/build/modal/index.js +12 -3
- package/build/modal/index.js.map +1 -1
- package/build/modal/types.js.map +1 -1
- package/build/placeholder/index.js +10 -4
- package/build/placeholder/index.js.map +1 -1
- package/build-module/date-time/time/index.js +6 -1
- package/build-module/date-time/time/index.js.map +1 -1
- package/build-module/modal/index.js +12 -3
- package/build-module/modal/index.js.map +1 -1
- package/build-module/modal/types.js.map +1 -1
- package/build-module/placeholder/index.js +11 -4
- package/build-module/placeholder/index.js.map +1 -1
- package/build-style/style-rtl.css +0 -10
- package/build-style/style.css +0 -10
- package/build-types/date-time/time/index.d.ts.map +1 -1
- package/build-types/modal/index.d.ts.map +1 -1
- package/build-types/modal/stories/index.story.d.ts.map +1 -1
- package/build-types/modal/types.d.ts +1 -1
- package/build-types/modal/types.d.ts.map +1 -1
- package/build-types/placeholder/index.d.ts.map +1 -1
- package/package.json +20 -20
- package/src/date-time/time/index.tsx +8 -1
- package/src/modal/README.md +7 -1
- package/src/modal/index.tsx +27 -3
- package/src/modal/stories/index.story.tsx +2 -1
- package/src/modal/test/index.tsx +124 -0
- package/src/modal/types.ts +3 -1
- package/src/placeholder/index.tsx +15 -8
- package/src/placeholder/style.scss +0 -12
- package/src/placeholder/test/index.tsx +34 -15
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["classnames","createPortal","useCallback","useEffect","useRef","useState","forwardRef","useLayoutEffect","useInstanceId","useFocusReturn","useFocusOnMount","__experimentalUseFocusOutside","useFocusOutside","useConstrainedTabbing","useMergeRefs","__","close","getScrollContainer","ariaHelper","Button","StyleProvider","openModalCount","UnforwardedModal","props","forwardedRef","bodyOpenClassName","role","title","focusOnMount","shouldCloseOnEsc","shouldCloseOnClickOutside","isDismissible","aria","labelledby","undefined","describedby","onRequestClose","icon","closeButtonLabel","children","style","overlayClassName","className","contentLabel","onKeyDown","isFullScreen","headerActions","__experimentalHideHeader","ref","instanceId","Modal","headingId","focusOnMountRef","constrainedTabbingRef","focusReturnRef","focusOutsideProps","contentRef","childrenContainerRef","hasScrolledContent","setHasScrolledContent","hasScrollableContent","setHasScrollableContent","isContentScrollable","current","closestScrollContainer","hideApp","document","body","classList","add","remove","showApp","window","ResizeObserver","resizeObserver","observe","disconnect","handleEscapeKeyDown","event","nativeEvent","isComposing","keyCode","code","defaultPrevented","preventDefault","onContentContainerScroll","e","_e$currentTarget$scro","scrollY","currentTarget","scrollTop","pressTarget","overlayPressHandlers","onPointerDown","isPrimary","target","onPointerUp","button","isSameTarget","createElement","tabIndex","onScroll","id","onClick","label"],"sources":["@wordpress/components/src/modal/index.tsx"],"sourcesContent":["/**\n * External dependencies\n */\nimport classnames from 'classnames';\nimport type { ForwardedRef, KeyboardEvent, UIEvent } from 'react';\n\n/**\n * WordPress dependencies\n */\nimport {\n\tcreatePortal,\n\tuseCallback,\n\tuseEffect,\n\tuseRef,\n\tuseState,\n\tforwardRef,\n\tuseLayoutEffect,\n} from '@wordpress/element';\nimport {\n\tuseInstanceId,\n\tuseFocusReturn,\n\tuseFocusOnMount,\n\t__experimentalUseFocusOutside as useFocusOutside,\n\tuseConstrainedTabbing,\n\tuseMergeRefs,\n} from '@wordpress/compose';\nimport { __ } from '@wordpress/i18n';\nimport { close } from '@wordpress/icons';\nimport { getScrollContainer } from '@wordpress/dom';\n\n/**\n * Internal dependencies\n */\nimport * as ariaHelper from './aria-helper';\nimport Button from '../button';\nimport StyleProvider from '../style-provider';\nimport type { ModalProps } from './types';\n\n// Used to count the number of open modals.\nlet openModalCount = 0;\n\nfunction UnforwardedModal(\n\tprops: ModalProps,\n\tforwardedRef: ForwardedRef< HTMLDivElement >\n) {\n\tconst {\n\t\tbodyOpenClassName = 'modal-open',\n\t\trole = 'dialog',\n\t\ttitle = null,\n\t\tfocusOnMount = true,\n\t\tshouldCloseOnEsc = true,\n\t\tshouldCloseOnClickOutside = true,\n\t\tisDismissible = true,\n\t\t/* Accessibility. */\n\t\taria = {\n\t\t\tlabelledby: undefined,\n\t\t\tdescribedby: undefined,\n\t\t},\n\t\tonRequestClose,\n\t\ticon,\n\t\tcloseButtonLabel,\n\t\tchildren,\n\t\tstyle,\n\t\toverlayClassName,\n\t\tclassName,\n\t\tcontentLabel,\n\t\tonKeyDown,\n\t\tisFullScreen = false,\n\t\theaderActions = null,\n\t\t__experimentalHideHeader = false,\n\t} = props;\n\n\tconst ref = useRef< HTMLDivElement >();\n\tconst instanceId = useInstanceId( Modal );\n\tconst headingId = title\n\t\t? `components-modal-header-${ instanceId }`\n\t\t: aria.labelledby;\n\tconst focusOnMountRef = useFocusOnMount( focusOnMount );\n\tconst constrainedTabbingRef = useConstrainedTabbing();\n\tconst focusReturnRef = useFocusReturn();\n\tconst focusOutsideProps = useFocusOutside( onRequestClose );\n\tconst contentRef = useRef< HTMLDivElement >( null );\n\tconst childrenContainerRef = useRef< HTMLDivElement >( null );\n\n\tconst [ hasScrolledContent, setHasScrolledContent ] = useState( false );\n\tconst [ hasScrollableContent, setHasScrollableContent ] = useState( false );\n\n\t// Determines whether the Modal content is scrollable and updates the state.\n\tconst isContentScrollable = useCallback( () => {\n\t\tif ( ! contentRef.current ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst closestScrollContainer = getScrollContainer( contentRef.current );\n\n\t\tif ( contentRef.current === closestScrollContainer ) {\n\t\t\tsetHasScrollableContent( true );\n\t\t} else {\n\t\t\tsetHasScrollableContent( false );\n\t\t}\n\t}, [ contentRef ] );\n\n\tuseEffect( () => {\n\t\topenModalCount++;\n\n\t\tif ( openModalCount === 1 ) {\n\t\t\tariaHelper.hideApp( ref.current );\n\t\t\tdocument.body.classList.add( bodyOpenClassName );\n\t\t}\n\n\t\treturn () => {\n\t\t\topenModalCount--;\n\n\t\t\tif ( openModalCount === 0 ) {\n\t\t\t\tdocument.body.classList.remove( bodyOpenClassName );\n\t\t\t\tariaHelper.showApp();\n\t\t\t}\n\t\t};\n\t}, [ bodyOpenClassName ] );\n\n\t// Calls the isContentScrollable callback when the Modal children container resizes.\n\tuseLayoutEffect( () => {\n\t\tif ( ! window.ResizeObserver || ! childrenContainerRef.current ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst resizeObserver = new ResizeObserver( isContentScrollable );\n\t\tresizeObserver.observe( childrenContainerRef.current );\n\n\t\tisContentScrollable();\n\n\t\treturn () => {\n\t\t\tresizeObserver.disconnect();\n\t\t};\n\t}, [ isContentScrollable, childrenContainerRef ] );\n\n\tfunction handleEscapeKeyDown( event: KeyboardEvent< HTMLDivElement > ) {\n\t\tif (\n\t\t\t// Ignore keydowns from IMEs\n\t\t\tevent.nativeEvent.isComposing ||\n\t\t\t// Workaround for Mac Safari where the final Enter/Backspace of an IME composition\n\t\t\t// is `isComposing=false`, even though it's technically still part of the composition.\n\t\t\t// These can only be detected by keyCode.\n\t\t\tevent.keyCode === 229\n\t\t) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (\n\t\t\tshouldCloseOnEsc &&\n\t\t\tevent.code === 'Escape' &&\n\t\t\t! event.defaultPrevented\n\t\t) {\n\t\t\tevent.preventDefault();\n\t\t\tif ( onRequestClose ) {\n\t\t\t\tonRequestClose( event );\n\t\t\t}\n\t\t}\n\t}\n\n\tconst onContentContainerScroll = useCallback(\n\t\t( e: UIEvent< HTMLDivElement > ) => {\n\t\t\tconst scrollY = e?.currentTarget?.scrollTop ?? -1;\n\n\t\t\tif ( ! hasScrolledContent && scrollY > 0 ) {\n\t\t\t\tsetHasScrolledContent( true );\n\t\t\t} else if ( hasScrolledContent && scrollY <= 0 ) {\n\t\t\t\tsetHasScrolledContent( false );\n\t\t\t}\n\t\t},\n\t\t[ hasScrolledContent ]\n\t);\n\n\tlet pressTarget: EventTarget | null = null;\n\tconst overlayPressHandlers: {\n\t\tonPointerDown: React.PointerEventHandler< HTMLDivElement >;\n\t\tonPointerUp: React.PointerEventHandler< HTMLDivElement >;\n\t} = {\n\t\tonPointerDown: ( event ) => {\n\t\t\tif ( event.isPrimary && event.target === event.currentTarget ) {\n\t\t\t\tpressTarget = event.target;\n\t\t\t\t// Avoids loss of focus yet also leaves `useFocusOutside`\n\t\t\t\t// practically useless with its only potential trigger being\n\t\t\t\t// programmatic focus movement. TODO opt for either removing\n\t\t\t\t// the hook or enhancing it such that this isn't needed.\n\t\t\t\tevent.preventDefault();\n\t\t\t}\n\t\t},\n\t\t// Closes the modal with two exceptions. 1. Opening the context menu on\n\t\t// the overlay. 2. Pressing on the overlay then dragging the pointer\n\t\t// over the modal and releasing. Due to the modal being a child of the\n\t\t// overlay, such a gesture is a `click` on the overlay and cannot be\n\t\t// excepted by a `click` handler. Thus the tactic of handling\n\t\t// `pointerup` and comparing its target to that of the `pointerdown`.\n\t\tonPointerUp: ( { target, button } ) => {\n\t\t\tconst isSameTarget = target === pressTarget;\n\t\t\tpressTarget = null;\n\t\t\tif ( button === 0 && isSameTarget ) onRequestClose();\n\t\t},\n\t};\n\n\treturn createPortal(\n\t\t// eslint-disable-next-line jsx-a11y/no-static-element-interactions\n\t\t<div\n\t\t\tref={ useMergeRefs( [ ref, forwardedRef ] ) }\n\t\t\tclassName={ classnames(\n\t\t\t\t'components-modal__screen-overlay',\n\t\t\t\toverlayClassName\n\t\t\t) }\n\t\t\tonKeyDown={ handleEscapeKeyDown }\n\t\t\t{ ...( shouldCloseOnClickOutside ? overlayPressHandlers : {} ) }\n\t\t>\n\t\t\t<StyleProvider document={ document }>\n\t\t\t\t<div\n\t\t\t\t\tclassName={ classnames(\n\t\t\t\t\t\t'components-modal__frame',\n\t\t\t\t\t\tclassName,\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t'is-full-screen': isFullScreen,\n\t\t\t\t\t\t}\n\t\t\t\t\t) }\n\t\t\t\t\tstyle={ style }\n\t\t\t\t\tref={ useMergeRefs( [\n\t\t\t\t\t\tconstrainedTabbingRef,\n\t\t\t\t\t\tfocusReturnRef,\n\t\t\t\t\t\tfocusOnMountRef,\n\t\t\t\t\t] ) }\n\t\t\t\t\trole={ role }\n\t\t\t\t\taria-label={ contentLabel }\n\t\t\t\t\taria-labelledby={ contentLabel ? undefined : headingId }\n\t\t\t\t\taria-describedby={ aria.describedby }\n\t\t\t\t\ttabIndex={ -1 }\n\t\t\t\t\t{ ...( shouldCloseOnClickOutside\n\t\t\t\t\t\t? focusOutsideProps\n\t\t\t\t\t\t: {} ) }\n\t\t\t\t\tonKeyDown={ onKeyDown }\n\t\t\t\t>\n\t\t\t\t\t<div\n\t\t\t\t\t\tclassName={ classnames( 'components-modal__content', {\n\t\t\t\t\t\t\t'hide-header': __experimentalHideHeader,\n\t\t\t\t\t\t\t'is-scrollable': hasScrollableContent,\n\t\t\t\t\t\t\t'has-scrolled-content': hasScrolledContent,\n\t\t\t\t\t\t} ) }\n\t\t\t\t\t\trole=\"document\"\n\t\t\t\t\t\tonScroll={ onContentContainerScroll }\n\t\t\t\t\t\tref={ contentRef }\n\t\t\t\t\t\taria-label={\n\t\t\t\t\t\t\thasScrollableContent\n\t\t\t\t\t\t\t\t? __( 'Scrollable section' )\n\t\t\t\t\t\t\t\t: undefined\n\t\t\t\t\t\t}\n\t\t\t\t\t\ttabIndex={ hasScrollableContent ? 0 : undefined }\n\t\t\t\t\t>\n\t\t\t\t\t\t{ ! __experimentalHideHeader && (\n\t\t\t\t\t\t\t<div className=\"components-modal__header\">\n\t\t\t\t\t\t\t\t<div className=\"components-modal__header-heading-container\">\n\t\t\t\t\t\t\t\t\t{ icon && (\n\t\t\t\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\t\t\t\tclassName=\"components-modal__icon-container\"\n\t\t\t\t\t\t\t\t\t\t\taria-hidden\n\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t{ icon }\n\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t) }\n\t\t\t\t\t\t\t\t\t{ title && (\n\t\t\t\t\t\t\t\t\t\t<h1\n\t\t\t\t\t\t\t\t\t\t\tid={ headingId }\n\t\t\t\t\t\t\t\t\t\t\tclassName=\"components-modal__header-heading\"\n\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t{ title }\n\t\t\t\t\t\t\t\t\t\t</h1>\n\t\t\t\t\t\t\t\t\t) }\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t{ headerActions }\n\t\t\t\t\t\t\t\t{ isDismissible && (\n\t\t\t\t\t\t\t\t\t<Button\n\t\t\t\t\t\t\t\t\t\tonClick={ onRequestClose }\n\t\t\t\t\t\t\t\t\t\ticon={ close }\n\t\t\t\t\t\t\t\t\t\tlabel={\n\t\t\t\t\t\t\t\t\t\t\tcloseButtonLabel || __( 'Close' )\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t) }\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t) }\n\t\t\t\t\t\t<div ref={ childrenContainerRef }>{ children }</div>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</StyleProvider>\n\t\t</div>,\n\t\tdocument.body\n\t);\n}\n\n/**\n * Modals give users information and choices related to a task they’re trying to\n * accomplish. They can contain critical information, require decisions, or\n * involve multiple tasks.\n *\n * ```jsx\n * import { Button, Modal } from '@wordpress/components';\n * import { useState } from '@wordpress/element';\n *\n * const MyModal = () => {\n * const [ isOpen, setOpen ] = useState( false );\n * const openModal = () => setOpen( true );\n * const closeModal = () => setOpen( false );\n *\n * return (\n * <>\n * <Button variant=\"secondary\" onClick={ openModal }>\n * Open Modal\n * </Button>\n * { isOpen && (\n * <Modal title=\"This is my modal\" onRequestClose={ closeModal }>\n * <Button variant=\"secondary\" onClick={ closeModal }>\n * My custom close button\n * </Button>\n * </Modal>\n * ) }\n * </>\n * );\n * };\n * ```\n */\nexport const Modal = forwardRef( UnforwardedModal );\n\nexport default Modal;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"names":["classnames","createPortal","useCallback","useEffect","useRef","useState","forwardRef","useLayoutEffect","useInstanceId","useFocusReturn","useFocusOnMount","__experimentalUseFocusOutside","useFocusOutside","useConstrainedTabbing","useMergeRefs","__","close","getScrollContainer","ariaHelper","Button","StyleProvider","openModalCount","UnforwardedModal","props","forwardedRef","bodyOpenClassName","role","title","focusOnMount","shouldCloseOnEsc","shouldCloseOnClickOutside","isDismissible","aria","labelledby","undefined","describedby","onRequestClose","icon","closeButtonLabel","children","style","overlayClassName","className","contentLabel","onKeyDown","isFullScreen","headerActions","__experimentalHideHeader","ref","instanceId","Modal","headingId","focusOnMountRef","constrainedTabbingRef","focusReturnRef","focusOutsideProps","contentRef","childrenContainerRef","hasScrolledContent","setHasScrolledContent","hasScrollableContent","setHasScrollableContent","isContentScrollable","current","closestScrollContainer","hideApp","document","body","classList","add","remove","showApp","window","ResizeObserver","resizeObserver","observe","disconnect","handleEscapeKeyDown","event","nativeEvent","isComposing","keyCode","code","defaultPrevented","preventDefault","onContentContainerScroll","e","_e$currentTarget$scro","scrollY","currentTarget","scrollTop","pressTarget","overlayPressHandlers","onPointerDown","isPrimary","target","onPointerUp","button","isSameTarget","createElement","tabIndex","onScroll","id","onClick","label"],"sources":["@wordpress/components/src/modal/index.tsx"],"sourcesContent":["/**\n * External dependencies\n */\nimport classnames from 'classnames';\nimport type { ForwardedRef, KeyboardEvent, UIEvent } from 'react';\n\n/**\n * WordPress dependencies\n */\nimport {\n\tcreatePortal,\n\tuseCallback,\n\tuseEffect,\n\tuseRef,\n\tuseState,\n\tforwardRef,\n\tuseLayoutEffect,\n} from '@wordpress/element';\nimport {\n\tuseInstanceId,\n\tuseFocusReturn,\n\tuseFocusOnMount,\n\t__experimentalUseFocusOutside as useFocusOutside,\n\tuseConstrainedTabbing,\n\tuseMergeRefs,\n} from '@wordpress/compose';\nimport { __ } from '@wordpress/i18n';\nimport { close } from '@wordpress/icons';\nimport { getScrollContainer } from '@wordpress/dom';\n\n/**\n * Internal dependencies\n */\nimport * as ariaHelper from './aria-helper';\nimport Button from '../button';\nimport StyleProvider from '../style-provider';\nimport type { ModalProps } from './types';\n\n// Used to count the number of open modals.\nlet openModalCount = 0;\n\nfunction UnforwardedModal(\n\tprops: ModalProps,\n\tforwardedRef: ForwardedRef< HTMLDivElement >\n) {\n\tconst {\n\t\tbodyOpenClassName = 'modal-open',\n\t\trole = 'dialog',\n\t\ttitle = null,\n\t\tfocusOnMount = true,\n\t\tshouldCloseOnEsc = true,\n\t\tshouldCloseOnClickOutside = true,\n\t\tisDismissible = true,\n\t\t/* Accessibility. */\n\t\taria = {\n\t\t\tlabelledby: undefined,\n\t\t\tdescribedby: undefined,\n\t\t},\n\t\tonRequestClose,\n\t\ticon,\n\t\tcloseButtonLabel,\n\t\tchildren,\n\t\tstyle,\n\t\toverlayClassName,\n\t\tclassName,\n\t\tcontentLabel,\n\t\tonKeyDown,\n\t\tisFullScreen = false,\n\t\theaderActions = null,\n\t\t__experimentalHideHeader = false,\n\t} = props;\n\n\tconst ref = useRef< HTMLDivElement >();\n\n\tconst instanceId = useInstanceId( Modal );\n\tconst headingId = title\n\t\t? `components-modal-header-${ instanceId }`\n\t\t: aria.labelledby;\n\n\t// The focus hook does not support 'firstContentElement' but this is a valid\n\t// value for the Modal's focusOnMount prop. The following code ensures the focus\n\t// hook will focus the first focusable node within the element to which it is applied.\n\t// When `firstContentElement` is passed as the value of the focusOnMount prop,\n\t// the focus hook is applied to the Modal's content element.\n\t// Otherwise, the focus hook is applied to the Modal's ref. This ensures that the\n\t// focus hook will focus the first element in the Modal's **content** when\n\t// `firstContentElement` is passed.\n\tconst focusOnMountRef = useFocusOnMount(\n\t\tfocusOnMount === 'firstContentElement' ? 'firstElement' : focusOnMount\n\t);\n\tconst constrainedTabbingRef = useConstrainedTabbing();\n\tconst focusReturnRef = useFocusReturn();\n\tconst focusOutsideProps = useFocusOutside( onRequestClose );\n\tconst contentRef = useRef< HTMLDivElement >( null );\n\tconst childrenContainerRef = useRef< HTMLDivElement >( null );\n\n\tconst [ hasScrolledContent, setHasScrolledContent ] = useState( false );\n\tconst [ hasScrollableContent, setHasScrollableContent ] = useState( false );\n\n\t// Determines whether the Modal content is scrollable and updates the state.\n\tconst isContentScrollable = useCallback( () => {\n\t\tif ( ! contentRef.current ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst closestScrollContainer = getScrollContainer( contentRef.current );\n\n\t\tif ( contentRef.current === closestScrollContainer ) {\n\t\t\tsetHasScrollableContent( true );\n\t\t} else {\n\t\t\tsetHasScrollableContent( false );\n\t\t}\n\t}, [ contentRef ] );\n\n\tuseEffect( () => {\n\t\topenModalCount++;\n\n\t\tif ( openModalCount === 1 ) {\n\t\t\tariaHelper.hideApp( ref.current );\n\t\t\tdocument.body.classList.add( bodyOpenClassName );\n\t\t}\n\n\t\treturn () => {\n\t\t\topenModalCount--;\n\n\t\t\tif ( openModalCount === 0 ) {\n\t\t\t\tdocument.body.classList.remove( bodyOpenClassName );\n\t\t\t\tariaHelper.showApp();\n\t\t\t}\n\t\t};\n\t}, [ bodyOpenClassName ] );\n\n\t// Calls the isContentScrollable callback when the Modal children container resizes.\n\tuseLayoutEffect( () => {\n\t\tif ( ! window.ResizeObserver || ! childrenContainerRef.current ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst resizeObserver = new ResizeObserver( isContentScrollable );\n\t\tresizeObserver.observe( childrenContainerRef.current );\n\n\t\tisContentScrollable();\n\n\t\treturn () => {\n\t\t\tresizeObserver.disconnect();\n\t\t};\n\t}, [ isContentScrollable, childrenContainerRef ] );\n\n\tfunction handleEscapeKeyDown( event: KeyboardEvent< HTMLDivElement > ) {\n\t\tif (\n\t\t\t// Ignore keydowns from IMEs\n\t\t\tevent.nativeEvent.isComposing ||\n\t\t\t// Workaround for Mac Safari where the final Enter/Backspace of an IME composition\n\t\t\t// is `isComposing=false`, even though it's technically still part of the composition.\n\t\t\t// These can only be detected by keyCode.\n\t\t\tevent.keyCode === 229\n\t\t) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (\n\t\t\tshouldCloseOnEsc &&\n\t\t\tevent.code === 'Escape' &&\n\t\t\t! event.defaultPrevented\n\t\t) {\n\t\t\tevent.preventDefault();\n\t\t\tif ( onRequestClose ) {\n\t\t\t\tonRequestClose( event );\n\t\t\t}\n\t\t}\n\t}\n\n\tconst onContentContainerScroll = useCallback(\n\t\t( e: UIEvent< HTMLDivElement > ) => {\n\t\t\tconst scrollY = e?.currentTarget?.scrollTop ?? -1;\n\n\t\t\tif ( ! hasScrolledContent && scrollY > 0 ) {\n\t\t\t\tsetHasScrolledContent( true );\n\t\t\t} else if ( hasScrolledContent && scrollY <= 0 ) {\n\t\t\t\tsetHasScrolledContent( false );\n\t\t\t}\n\t\t},\n\t\t[ hasScrolledContent ]\n\t);\n\n\tlet pressTarget: EventTarget | null = null;\n\tconst overlayPressHandlers: {\n\t\tonPointerDown: React.PointerEventHandler< HTMLDivElement >;\n\t\tonPointerUp: React.PointerEventHandler< HTMLDivElement >;\n\t} = {\n\t\tonPointerDown: ( event ) => {\n\t\t\tif ( event.isPrimary && event.target === event.currentTarget ) {\n\t\t\t\tpressTarget = event.target;\n\t\t\t\t// Avoids loss of focus yet also leaves `useFocusOutside`\n\t\t\t\t// practically useless with its only potential trigger being\n\t\t\t\t// programmatic focus movement. TODO opt for either removing\n\t\t\t\t// the hook or enhancing it such that this isn't needed.\n\t\t\t\tevent.preventDefault();\n\t\t\t}\n\t\t},\n\t\t// Closes the modal with two exceptions. 1. Opening the context menu on\n\t\t// the overlay. 2. Pressing on the overlay then dragging the pointer\n\t\t// over the modal and releasing. Due to the modal being a child of the\n\t\t// overlay, such a gesture is a `click` on the overlay and cannot be\n\t\t// excepted by a `click` handler. Thus the tactic of handling\n\t\t// `pointerup` and comparing its target to that of the `pointerdown`.\n\t\tonPointerUp: ( { target, button } ) => {\n\t\t\tconst isSameTarget = target === pressTarget;\n\t\t\tpressTarget = null;\n\t\t\tif ( button === 0 && isSameTarget ) onRequestClose();\n\t\t},\n\t};\n\n\treturn createPortal(\n\t\t// eslint-disable-next-line jsx-a11y/no-static-element-interactions\n\t\t<div\n\t\t\tref={ useMergeRefs( [ ref, forwardedRef ] ) }\n\t\t\tclassName={ classnames(\n\t\t\t\t'components-modal__screen-overlay',\n\t\t\t\toverlayClassName\n\t\t\t) }\n\t\t\tonKeyDown={ handleEscapeKeyDown }\n\t\t\t{ ...( shouldCloseOnClickOutside ? overlayPressHandlers : {} ) }\n\t\t>\n\t\t\t<StyleProvider document={ document }>\n\t\t\t\t<div\n\t\t\t\t\tclassName={ classnames(\n\t\t\t\t\t\t'components-modal__frame',\n\t\t\t\t\t\tclassName,\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t'is-full-screen': isFullScreen,\n\t\t\t\t\t\t}\n\t\t\t\t\t) }\n\t\t\t\t\tstyle={ style }\n\t\t\t\t\tref={ useMergeRefs( [\n\t\t\t\t\t\tconstrainedTabbingRef,\n\t\t\t\t\t\tfocusReturnRef,\n\t\t\t\t\t\tfocusOnMount !== 'firstContentElement'\n\t\t\t\t\t\t\t? focusOnMountRef\n\t\t\t\t\t\t\t: null,\n\t\t\t\t\t] ) }\n\t\t\t\t\trole={ role }\n\t\t\t\t\taria-label={ contentLabel }\n\t\t\t\t\taria-labelledby={ contentLabel ? undefined : headingId }\n\t\t\t\t\taria-describedby={ aria.describedby }\n\t\t\t\t\ttabIndex={ -1 }\n\t\t\t\t\t{ ...( shouldCloseOnClickOutside\n\t\t\t\t\t\t? focusOutsideProps\n\t\t\t\t\t\t: {} ) }\n\t\t\t\t\tonKeyDown={ onKeyDown }\n\t\t\t\t>\n\t\t\t\t\t<div\n\t\t\t\t\t\tclassName={ classnames( 'components-modal__content', {\n\t\t\t\t\t\t\t'hide-header': __experimentalHideHeader,\n\t\t\t\t\t\t\t'is-scrollable': hasScrollableContent,\n\t\t\t\t\t\t\t'has-scrolled-content': hasScrolledContent,\n\t\t\t\t\t\t} ) }\n\t\t\t\t\t\trole=\"document\"\n\t\t\t\t\t\tonScroll={ onContentContainerScroll }\n\t\t\t\t\t\tref={ contentRef }\n\t\t\t\t\t\taria-label={\n\t\t\t\t\t\t\thasScrollableContent\n\t\t\t\t\t\t\t\t? __( 'Scrollable section' )\n\t\t\t\t\t\t\t\t: undefined\n\t\t\t\t\t\t}\n\t\t\t\t\t\ttabIndex={ hasScrollableContent ? 0 : undefined }\n\t\t\t\t\t>\n\t\t\t\t\t\t{ ! __experimentalHideHeader && (\n\t\t\t\t\t\t\t<div className=\"components-modal__header\">\n\t\t\t\t\t\t\t\t<div className=\"components-modal__header-heading-container\">\n\t\t\t\t\t\t\t\t\t{ icon && (\n\t\t\t\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\t\t\t\tclassName=\"components-modal__icon-container\"\n\t\t\t\t\t\t\t\t\t\t\taria-hidden\n\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t{ icon }\n\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t) }\n\t\t\t\t\t\t\t\t\t{ title && (\n\t\t\t\t\t\t\t\t\t\t<h1\n\t\t\t\t\t\t\t\t\t\t\tid={ headingId }\n\t\t\t\t\t\t\t\t\t\t\tclassName=\"components-modal__header-heading\"\n\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t{ title }\n\t\t\t\t\t\t\t\t\t\t</h1>\n\t\t\t\t\t\t\t\t\t) }\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t{ headerActions }\n\t\t\t\t\t\t\t\t{ isDismissible && (\n\t\t\t\t\t\t\t\t\t<Button\n\t\t\t\t\t\t\t\t\t\tonClick={ onRequestClose }\n\t\t\t\t\t\t\t\t\t\ticon={ close }\n\t\t\t\t\t\t\t\t\t\tlabel={\n\t\t\t\t\t\t\t\t\t\t\tcloseButtonLabel || __( 'Close' )\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t) }\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t) }\n\n\t\t\t\t\t\t<div\n\t\t\t\t\t\t\tref={ useMergeRefs( [\n\t\t\t\t\t\t\t\tchildrenContainerRef,\n\t\t\t\t\t\t\t\tfocusOnMount === 'firstContentElement'\n\t\t\t\t\t\t\t\t\t? focusOnMountRef\n\t\t\t\t\t\t\t\t\t: null,\n\t\t\t\t\t\t\t] ) }\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{ children }\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</StyleProvider>\n\t\t</div>,\n\t\tdocument.body\n\t);\n}\n\n/**\n * Modals give users information and choices related to a task they’re trying to\n * accomplish. They can contain critical information, require decisions, or\n * involve multiple tasks.\n *\n * ```jsx\n * import { Button, Modal } from '@wordpress/components';\n * import { useState } from '@wordpress/element';\n *\n * const MyModal = () => {\n * const [ isOpen, setOpen ] = useState( false );\n * const openModal = () => setOpen( true );\n * const closeModal = () => setOpen( false );\n *\n * return (\n * <>\n * <Button variant=\"secondary\" onClick={ openModal }>\n * Open Modal\n * </Button>\n * { isOpen && (\n * <Modal title=\"This is my modal\" onRequestClose={ closeModal }>\n * <Button variant=\"secondary\" onClick={ closeModal }>\n * My custom close button\n * </Button>\n * </Modal>\n * ) }\n * </>\n * );\n * };\n * ```\n */\nexport const Modal = forwardRef( UnforwardedModal );\n\nexport default Modal;\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":[],"sources":["@wordpress/components/src/modal/types.ts"],"sourcesContent":["/**\n * External dependencies\n */\nimport type {\n\tAriaRole,\n\tCSSProperties,\n\tReactNode,\n\tKeyboardEventHandler,\n\tKeyboardEvent,\n\tSyntheticEvent,\n} from 'react';\n\n/**\n * WordPress dependencies\n */\nimport type { useFocusOnMount } from '@wordpress/compose';\n\nexport type ModalProps = {\n\taria?: {\n\t\t/**\n\t\t * If this property is added, it will be added to the modal content\n\t\t * `div` as `aria-describedby`.\n\t\t */\n\t\tdescribedby?: string;\n\t\t/**\n\t\t * If this property is added, it will be added to the modal content\n\t\t * `div` as `aria-labelledby`. Use this when you are rendering the title\n\t\t * yourself within the modal's content area instead of using the `title`\n\t\t * prop. This ensures the title is usable by assistive technology.\n\t\t *\n\t\t * Titles are required for accessibility reasons, see `contentLabel` and\n\t\t * `title` for other ways to provide a title.\n\t\t */\n\t\tlabelledby?: string;\n\t};\n\t/**\n\t * Class name added to the body element when the modal is open.\n\t *\n\t * @default 'modal-open'\n\t */\n\tbodyOpenClassName?: string;\n\t/**\n\t * The children elements.\n\t */\n\tchildren: ReactNode;\n\t/**\n\t * If this property is added, it will an additional class name to the modal\n\t * content `div`.\n\t */\n\tclassName?: string;\n\t/**\n\t * Label on the close button.\n\t *\n\t * @default `__( 'Close' )`\n\t */\n\tcloseButtonLabel?: string;\n\t/**\n\t * If this property is added, it will be added to the modal content `div` as\n\t * `aria-label`.\n\t *\n\t * Titles are required for accessibility reasons, see `aria.labelledby` and\n\t * `title` for other ways to provide a title.\n\t */\n\tcontentLabel?: string;\n\t/**\n\t * If this property is true, it will focus the first tabbable element\n\t * rendered in the modal.\n\t *\n\t * @default true\n\t */\n\tfocusOnMount
|
|
1
|
+
{"version":3,"names":[],"sources":["@wordpress/components/src/modal/types.ts"],"sourcesContent":["/**\n * External dependencies\n */\nimport type {\n\tAriaRole,\n\tCSSProperties,\n\tReactNode,\n\tKeyboardEventHandler,\n\tKeyboardEvent,\n\tSyntheticEvent,\n} from 'react';\n\n/**\n * WordPress dependencies\n */\nimport type { useFocusOnMount } from '@wordpress/compose';\n\nexport type ModalProps = {\n\taria?: {\n\t\t/**\n\t\t * If this property is added, it will be added to the modal content\n\t\t * `div` as `aria-describedby`.\n\t\t */\n\t\tdescribedby?: string;\n\t\t/**\n\t\t * If this property is added, it will be added to the modal content\n\t\t * `div` as `aria-labelledby`. Use this when you are rendering the title\n\t\t * yourself within the modal's content area instead of using the `title`\n\t\t * prop. This ensures the title is usable by assistive technology.\n\t\t *\n\t\t * Titles are required for accessibility reasons, see `contentLabel` and\n\t\t * `title` for other ways to provide a title.\n\t\t */\n\t\tlabelledby?: string;\n\t};\n\t/**\n\t * Class name added to the body element when the modal is open.\n\t *\n\t * @default 'modal-open'\n\t */\n\tbodyOpenClassName?: string;\n\t/**\n\t * The children elements.\n\t */\n\tchildren: ReactNode;\n\t/**\n\t * If this property is added, it will an additional class name to the modal\n\t * content `div`.\n\t */\n\tclassName?: string;\n\t/**\n\t * Label on the close button.\n\t *\n\t * @default `__( 'Close' )`\n\t */\n\tcloseButtonLabel?: string;\n\t/**\n\t * If this property is added, it will be added to the modal content `div` as\n\t * `aria-label`.\n\t *\n\t * Titles are required for accessibility reasons, see `aria.labelledby` and\n\t * `title` for other ways to provide a title.\n\t */\n\tcontentLabel?: string;\n\t/**\n\t * If this property is true, it will focus the first tabbable element\n\t * rendered in the modal.\n\t *\n\t * @default true\n\t */\n\tfocusOnMount?:\n\t\t| Parameters< typeof useFocusOnMount >[ 0 ]\n\t\t| 'firstContentElement';\n\t/**\n\t * Elements that are injected into the modal header to the left of the close button (if rendered).\n\t * Hidden if `__experimentalHideHeader` is `true`.\n\t *\n\t * @default null\n\t */\n\theaderActions?: ReactNode;\n\n\t/**\n\t * If this property is added, an icon will be added before the title.\n\t */\n\ticon?: JSX.Element;\n\t/**\n\t * If this property is set to false, the modal will not display a close icon\n\t * and cannot be dismissed.\n\t *\n\t * @default true\n\t */\n\tisDismissible?: boolean;\n\t/**\n\t * This property when set to `true` will render a full screen modal.\n\t *\n\t * @default false\n\t */\n\tisFullScreen?: boolean;\n\t/**\n\t * Handle the key down on the modal frame `div`.\n\t */\n\tonKeyDown?: KeyboardEventHandler< HTMLDivElement >;\n\t/**\n\t * This function is called to indicate that the modal should be closed.\n\t */\n\tonRequestClose: (\n\t\tevent?: KeyboardEvent< HTMLDivElement > | SyntheticEvent\n\t) => void;\n\t/**\n\t * If this property is added, it will an additional class name to the modal\n\t * overlay `div`.\n\t */\n\toverlayClassName?: string;\n\t/**\n\t * If this property is added, it will override the default role of the\n\t * modal.\n\t *\n\t * @default 'dialog'\n\t */\n\trole?: AriaRole;\n\t/**\n\t * If this property is added, it will determine whether the modal requests\n\t * to close when a mouse click occurs outside of the modal content.\n\t *\n\t * @default true\n\t */\n\tshouldCloseOnClickOutside?: boolean;\n\t/**\n\t * If this property is added, it will determine whether the modal requests\n\t * to close when the escape key is pressed.\n\t *\n\t * @default true\n\t */\n\tshouldCloseOnEsc?: boolean;\n\t/**\n\t * If this property is added, it will be added to the modal frame `div`.\n\t */\n\tstyle?: CSSProperties;\n\t/**\n\t * This property is used as the modal header's title.\n\t *\n\t * Titles are required for accessibility reasons, see `aria.labelledby` and\n\t * `contentLabel` for other ways to provide a title.\n\t */\n\ttitle?: string;\n\t/**\n\t * When set to `true`, the Modal's header (including the icon, title and\n\t * close button) will not be rendered.\n\t *\n\t * _Warning_: This property is still experimental. “Experimental” means this\n\t * is an early implementation subject to drastic and breaking changes.\n\t *\n\t * @default false\n\t */\n\t__experimentalHideHeader?: boolean;\n};\n"],"mappings":""}
|
|
@@ -9,6 +9,8 @@ import classnames from 'classnames';
|
|
|
9
9
|
*/
|
|
10
10
|
import { useResizeObserver } from '@wordpress/compose';
|
|
11
11
|
import { SVG, Path } from '@wordpress/primitives';
|
|
12
|
+
import { useEffect } from '@wordpress/element';
|
|
13
|
+
import { speak } from '@wordpress/a11y';
|
|
12
14
|
|
|
13
15
|
/**
|
|
14
16
|
* Internal dependencies
|
|
@@ -66,6 +68,11 @@ export function Placeholder(props) {
|
|
|
66
68
|
const fieldsetClasses = classnames('components-placeholder__fieldset', {
|
|
67
69
|
'is-column-layout': isColumnLayout
|
|
68
70
|
});
|
|
71
|
+
useEffect(() => {
|
|
72
|
+
if (instructions) {
|
|
73
|
+
speak(instructions);
|
|
74
|
+
}
|
|
75
|
+
}, [instructions]);
|
|
69
76
|
return createElement("div", {
|
|
70
77
|
...additionalProps,
|
|
71
78
|
className: classes
|
|
@@ -75,11 +82,11 @@ export function Placeholder(props) {
|
|
|
75
82
|
className: "components-placeholder__label"
|
|
76
83
|
}, createElement(Icon, {
|
|
77
84
|
icon: icon
|
|
78
|
-
}), label), createElement("
|
|
79
|
-
className: fieldsetClasses
|
|
80
|
-
}, !!instructions && createElement("legend", {
|
|
85
|
+
}), label), !!instructions && createElement("div", {
|
|
81
86
|
className: "components-placeholder__instructions"
|
|
82
|
-
}, instructions),
|
|
87
|
+
}, instructions), createElement("div", {
|
|
88
|
+
className: fieldsetClasses
|
|
89
|
+
}, children));
|
|
83
90
|
}
|
|
84
91
|
export default Placeholder;
|
|
85
92
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["classnames","useResizeObserver","SVG","Path","Icon","PlaceholderIllustration","createElement","className","fill","xmlns","viewBox","preserveAspectRatio","vectorEffect","d","Placeholder","props","icon","children","label","instructions","notices","preview","isColumnLayout","withIllustration","additionalProps","resizeListener","width","modifierClassNames","classes","fieldsetClasses"],"sources":["@wordpress/components/src/placeholder/index.tsx"],"sourcesContent":["/**\n * External dependencies\n */\nimport classnames from 'classnames';\n\n/**\n * WordPress dependencies\n */\nimport { useResizeObserver } from '@wordpress/compose';\nimport { SVG, Path } from '@wordpress/primitives';\n\n/**\n * Internal dependencies\n */\nimport Icon from '../icon';\nimport type { PlaceholderProps } from './types';\nimport type { WordPressComponentProps } from '../ui/context';\n\nconst PlaceholderIllustration = (\n\t<SVG\n\t\tclassName=\"components-placeholder__illustration\"\n\t\tfill=\"none\"\n\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\tviewBox=\"0 0 60 60\"\n\t\tpreserveAspectRatio=\"none\"\n\t>\n\t\t<Path vectorEffect=\"non-scaling-stroke\" d=\"M60 60 0 0\" />\n\t</SVG>\n);\n\n/**\n * Renders a placeholder. Normally used by blocks to render their empty state.\n *\n * ```jsx\n * import { Placeholder } from '@wordpress/components';\n * import { more } from '@wordpress/icons';\n *\n * const MyPlaceholder = () => <Placeholder icon={ more } label=\"Placeholder\" />;\n * ```\n */\nexport function Placeholder(\n\tprops: WordPressComponentProps< PlaceholderProps, 'div', false >\n) {\n\tconst {\n\t\ticon,\n\t\tchildren,\n\t\tlabel,\n\t\tinstructions,\n\t\tclassName,\n\t\tnotices,\n\t\tpreview,\n\t\tisColumnLayout,\n\t\twithIllustration,\n\t\t...additionalProps\n\t} = props;\n\tconst [ resizeListener, { width } ] = useResizeObserver();\n\n\t// Since `useResizeObserver` will report a width of `null` until after the\n\t// first render, avoid applying any modifier classes until width is known.\n\tlet modifierClassNames;\n\tif ( typeof width === 'number' ) {\n\t\tmodifierClassNames = {\n\t\t\t'is-large': width >= 480,\n\t\t\t'is-medium': width >= 160 && width < 480,\n\t\t\t'is-small': width < 160,\n\t\t};\n\t}\n\n\tconst classes = classnames(\n\t\t'components-placeholder',\n\t\tclassName,\n\t\tmodifierClassNames,\n\t\twithIllustration ? 'has-illustration' : null\n\t);\n\tconst fieldsetClasses = classnames( 'components-placeholder__fieldset', {\n\t\t'is-column-layout': isColumnLayout,\n\t} );\n\n\treturn (\n\t\t<div { ...additionalProps } className={ classes }>\n\t\t\t{ withIllustration ? PlaceholderIllustration : null }\n\t\t\t{ resizeListener }\n\t\t\t{ notices }\n\t\t\t{ preview && (\n\t\t\t\t<div className=\"components-placeholder__preview\">\n\t\t\t\t\t{ preview }\n\t\t\t\t</div>\n\t\t\t) }\n\t\t\t<div className=\"components-placeholder__label\">\n\t\t\t\t<Icon icon={ icon } />\n\t\t\t\t{ label }\n\t\t\t</div>\n\t\t\t
|
|
1
|
+
{"version":3,"names":["classnames","useResizeObserver","SVG","Path","useEffect","speak","Icon","PlaceholderIllustration","createElement","className","fill","xmlns","viewBox","preserveAspectRatio","vectorEffect","d","Placeholder","props","icon","children","label","instructions","notices","preview","isColumnLayout","withIllustration","additionalProps","resizeListener","width","modifierClassNames","classes","fieldsetClasses"],"sources":["@wordpress/components/src/placeholder/index.tsx"],"sourcesContent":["/**\n * External dependencies\n */\nimport classnames from 'classnames';\n\n/**\n * WordPress dependencies\n */\nimport { useResizeObserver } from '@wordpress/compose';\nimport { SVG, Path } from '@wordpress/primitives';\nimport { useEffect } from '@wordpress/element';\nimport { speak } from '@wordpress/a11y';\n\n/**\n * Internal dependencies\n */\nimport Icon from '../icon';\nimport type { PlaceholderProps } from './types';\nimport type { WordPressComponentProps } from '../ui/context';\n\nconst PlaceholderIllustration = (\n\t<SVG\n\t\tclassName=\"components-placeholder__illustration\"\n\t\tfill=\"none\"\n\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\tviewBox=\"0 0 60 60\"\n\t\tpreserveAspectRatio=\"none\"\n\t>\n\t\t<Path vectorEffect=\"non-scaling-stroke\" d=\"M60 60 0 0\" />\n\t</SVG>\n);\n\n/**\n * Renders a placeholder. Normally used by blocks to render their empty state.\n *\n * ```jsx\n * import { Placeholder } from '@wordpress/components';\n * import { more } from '@wordpress/icons';\n *\n * const MyPlaceholder = () => <Placeholder icon={ more } label=\"Placeholder\" />;\n * ```\n */\nexport function Placeholder(\n\tprops: WordPressComponentProps< PlaceholderProps, 'div', false >\n) {\n\tconst {\n\t\ticon,\n\t\tchildren,\n\t\tlabel,\n\t\tinstructions,\n\t\tclassName,\n\t\tnotices,\n\t\tpreview,\n\t\tisColumnLayout,\n\t\twithIllustration,\n\t\t...additionalProps\n\t} = props;\n\tconst [ resizeListener, { width } ] = useResizeObserver();\n\n\t// Since `useResizeObserver` will report a width of `null` until after the\n\t// first render, avoid applying any modifier classes until width is known.\n\tlet modifierClassNames;\n\tif ( typeof width === 'number' ) {\n\t\tmodifierClassNames = {\n\t\t\t'is-large': width >= 480,\n\t\t\t'is-medium': width >= 160 && width < 480,\n\t\t\t'is-small': width < 160,\n\t\t};\n\t}\n\n\tconst classes = classnames(\n\t\t'components-placeholder',\n\t\tclassName,\n\t\tmodifierClassNames,\n\t\twithIllustration ? 'has-illustration' : null\n\t);\n\n\tconst fieldsetClasses = classnames( 'components-placeholder__fieldset', {\n\t\t'is-column-layout': isColumnLayout,\n\t} );\n\n\tuseEffect( () => {\n\t\tif ( instructions ) {\n\t\t\tspeak( instructions );\n\t\t}\n\t}, [ instructions ] );\n\n\treturn (\n\t\t<div { ...additionalProps } className={ classes }>\n\t\t\t{ withIllustration ? PlaceholderIllustration : null }\n\t\t\t{ resizeListener }\n\t\t\t{ notices }\n\t\t\t{ preview && (\n\t\t\t\t<div className=\"components-placeholder__preview\">\n\t\t\t\t\t{ preview }\n\t\t\t\t</div>\n\t\t\t) }\n\t\t\t<div className=\"components-placeholder__label\">\n\t\t\t\t<Icon icon={ icon } />\n\t\t\t\t{ label }\n\t\t\t</div>\n\t\t\t{ !! instructions && (\n\t\t\t\t<div className=\"components-placeholder__instructions\">\n\t\t\t\t\t{ instructions }\n\t\t\t\t</div>\n\t\t\t) }\n\t\t\t<div className={ fieldsetClasses }>{ children }</div>\n\t\t</div>\n\t);\n}\n\nexport default Placeholder;\n"],"mappings":";AAAA;AACA;AACA;AACA,OAAOA,UAAU,MAAM,YAAY;;AAEnC;AACA;AACA;AACA,SAASC,iBAAiB,QAAQ,oBAAoB;AACtD,SAASC,GAAG,EAAEC,IAAI,QAAQ,uBAAuB;AACjD,SAASC,SAAS,QAAQ,oBAAoB;AAC9C,SAASC,KAAK,QAAQ,iBAAiB;;AAEvC;AACA;AACA;AACA,OAAOC,IAAI,MAAM,SAAS;AAI1B,MAAMC,uBAAuB,GAC5BC,aAAA,CAACN,GAAG;EACHO,SAAS,EAAC,sCAAsC;EAChDC,IAAI,EAAC,MAAM;EACXC,KAAK,EAAC,4BAA4B;EAClCC,OAAO,EAAC,WAAW;EACnBC,mBAAmB,EAAC;AAAM,GAE1BL,aAAA,CAACL,IAAI;EAACW,YAAY,EAAC,oBAAoB;EAACC,CAAC,EAAC;AAAY,CAAE,CACpD,CACL;;AAED;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASC,WAAWA,CAC1BC,KAAgE,EAC/D;EACD,MAAM;IACLC,IAAI;IACJC,QAAQ;IACRC,KAAK;IACLC,YAAY;IACZZ,SAAS;IACTa,OAAO;IACPC,OAAO;IACPC,cAAc;IACdC,gBAAgB;IAChB,GAAGC;EACJ,CAAC,GAAGT,KAAK;EACT,MAAM,CAAEU,cAAc,EAAE;IAAEC;EAAM,CAAC,CAAE,GAAG3B,iBAAiB,CAAC,CAAC;;EAEzD;EACA;EACA,IAAI4B,kBAAkB;EACtB,IAAK,OAAOD,KAAK,KAAK,QAAQ,EAAG;IAChCC,kBAAkB,GAAG;MACpB,UAAU,EAAED,KAAK,IAAI,GAAG;MACxB,WAAW,EAAEA,KAAK,IAAI,GAAG,IAAIA,KAAK,GAAG,GAAG;MACxC,UAAU,EAAEA,KAAK,GAAG;IACrB,CAAC;EACF;EAEA,MAAME,OAAO,GAAG9B,UAAU,CACzB,wBAAwB,EACxBS,SAAS,EACToB,kBAAkB,EAClBJ,gBAAgB,GAAG,kBAAkB,GAAG,IACzC,CAAC;EAED,MAAMM,eAAe,GAAG/B,UAAU,CAAE,kCAAkC,EAAE;IACvE,kBAAkB,EAAEwB;EACrB,CAAE,CAAC;EAEHpB,SAAS,CAAE,MAAM;IAChB,IAAKiB,YAAY,EAAG;MACnBhB,KAAK,CAAEgB,YAAa,CAAC;IACtB;EACD,CAAC,EAAE,CAAEA,YAAY,CAAG,CAAC;EAErB,OACCb,aAAA;IAAA,GAAUkB,eAAe;IAAGjB,SAAS,EAAGqB;EAAS,GAC9CL,gBAAgB,GAAGlB,uBAAuB,GAAG,IAAI,EACjDoB,cAAc,EACdL,OAAO,EACPC,OAAO,IACRf,aAAA;IAAKC,SAAS,EAAC;EAAiC,GAC7Cc,OACE,CACL,EACDf,aAAA;IAAKC,SAAS,EAAC;EAA+B,GAC7CD,aAAA,CAACF,IAAI;IAACY,IAAI,EAAGA;EAAM,CAAE,CAAC,EACpBE,KACE,CAAC,EACJ,CAAC,CAAEC,YAAY,IAChBb,aAAA;IAAKC,SAAS,EAAC;EAAsC,GAClDY,YACE,CACL,EACDb,aAAA;IAAKC,SAAS,EAAGsB;EAAiB,GAAGZ,QAAe,CAChD,CAAC;AAER;AAEA,eAAeH,WAAW"}
|
|
@@ -2246,16 +2246,6 @@ body.rtl .components-panel__body-toggle.components-button .dashicons-arrow-right
|
|
|
2246
2246
|
font-size: 13px;
|
|
2247
2247
|
}
|
|
2248
2248
|
|
|
2249
|
-
.components-placeholder__fieldset.components-placeholder__fieldset {
|
|
2250
|
-
border: none;
|
|
2251
|
-
padding: 0;
|
|
2252
|
-
}
|
|
2253
|
-
.components-placeholder__fieldset.components-placeholder__fieldset .components-placeholder__instructions {
|
|
2254
|
-
padding: 0;
|
|
2255
|
-
font-weight: normal;
|
|
2256
|
-
font-size: 1em;
|
|
2257
|
-
}
|
|
2258
|
-
|
|
2259
2249
|
.components-placeholder__fieldset.is-column-layout,
|
|
2260
2250
|
.components-placeholder__fieldset.is-column-layout form {
|
|
2261
2251
|
flex-direction: column;
|
package/build-style/style.css
CHANGED
|
@@ -2253,16 +2253,6 @@ body.rtl .components-panel__body-toggle.components-button .dashicons-arrow-right
|
|
|
2253
2253
|
font-size: 13px;
|
|
2254
2254
|
}
|
|
2255
2255
|
|
|
2256
|
-
.components-placeholder__fieldset.components-placeholder__fieldset {
|
|
2257
|
-
border: none;
|
|
2258
|
-
padding: 0;
|
|
2259
|
-
}
|
|
2260
|
-
.components-placeholder__fieldset.components-placeholder__fieldset .components-placeholder__instructions {
|
|
2261
|
-
padding: 0;
|
|
2262
|
-
font-weight: normal;
|
|
2263
|
-
font-size: 1em;
|
|
2264
|
-
}
|
|
2265
|
-
|
|
2266
2256
|
.components-placeholder__fieldset.is-column-layout,
|
|
2267
2257
|
.components-placeholder__fieldset.is-column-layout form {
|
|
2268
2258
|
flex-direction: column;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/date-time/time/index.tsx"],"names":[],"mappings":";AAkBA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAuDhD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,UAAU,CAAE,EAC3B,QAAQ,EACR,WAAW,EACX,QAAQ,GACR,EAAE,eAAe,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/date-time/time/index.tsx"],"names":[],"mappings":";AAkBA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAuDhD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,UAAU,CAAE,EAC3B,QAAQ,EACR,WAAW,EACX,QAAQ,GACR,EAAE,eAAe,eA6QjB;AAED,eAAe,UAAU,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/modal/index.tsx"],"names":[],"mappings":";AAoCA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/modal/index.tsx"],"names":[],"mappings":";AAoCA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AA0R1C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,eAAO,MAAM,KAAK,uGAAiC,CAAC;AAEpD,eAAe,KAAK,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.story.d.ts","sourceRoot":"","sources":["../../../src/modal/stories/index.story.tsx"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAatD,OAAO,KAAK,MAAM,KAAK,CAAC;AAGxB,QAAA,MAAM,IAAI,EAAE,IAAI,CAAE,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"index.story.d.ts","sourceRoot":"","sources":["../../../src/modal/stories/index.story.tsx"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAatD,OAAO,KAAK,MAAM,KAAK,CAAC;AAGxB,QAAA,MAAM,IAAI,EAAE,IAAI,CAAE,OAAO,KAAK,CA2B7B,CAAC;AACF,eAAe,IAAI,CAAC;AA4CpB,eAAO,MAAM,OAAO,EAAE,OAAO,CAAE,OAAO,KAAK,CAAwB,CAAC;AAuBpE,eAAO,MAAM,iBAAiB,EAAE,OAAO,CAAE,OAAO,KAAK,CAAwB,CAAC"}
|
|
@@ -59,7 +59,7 @@ export type ModalProps = {
|
|
|
59
59
|
*
|
|
60
60
|
* @default true
|
|
61
61
|
*/
|
|
62
|
-
focusOnMount?: Parameters<typeof useFocusOnMount>[0];
|
|
62
|
+
focusOnMount?: Parameters<typeof useFocusOnMount>[0] | 'firstContentElement';
|
|
63
63
|
/**
|
|
64
64
|
* Elements that are injected into the modal header to the left of the close button (if rendered).
|
|
65
65
|
* Hidden if `__experimentalHideHeader` is `true`.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/modal/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,KAAK,EACX,QAAQ,EACR,aAAa,EACb,SAAS,EACT,oBAAoB,EACpB,aAAa,EACb,cAAc,EACd,MAAM,OAAO,CAAC;AAEf;;GAEG;AACH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAE1D,MAAM,MAAM,UAAU,GAAG;IACxB,IAAI,CAAC,EAAE;QACN;;;WAGG;QACH,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB;;;;;;;;WAQG;QACH,UAAU,CAAC,EAAE,MAAM,CAAC;KACpB,CAAC;IACF;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B;;OAEG;IACH,QAAQ,EAAE,SAAS,CAAC;IACpB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B;;;;;;OAMG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;;;OAKG;IACH,YAAY,CAAC,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/modal/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,KAAK,EACX,QAAQ,EACR,aAAa,EACb,SAAS,EACT,oBAAoB,EACpB,aAAa,EACb,cAAc,EACd,MAAM,OAAO,CAAC;AAEf;;GAEG;AACH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAE1D,MAAM,MAAM,UAAU,GAAG;IACxB,IAAI,CAAC,EAAE;QACN;;;WAGG;QACH,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB;;;;;;;;WAQG;QACH,UAAU,CAAC,EAAE,MAAM,CAAC;KACpB,CAAC;IACF;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B;;OAEG;IACH,QAAQ,EAAE,SAAS,CAAC;IACpB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B;;;;;;OAMG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;;;OAKG;IACH,YAAY,CAAC,EACV,UAAU,CAAE,OAAO,eAAe,CAAE,CAAE,CAAC,CAAE,GACzC,qBAAqB,CAAC;IACzB;;;;;OAKG;IACH,aAAa,CAAC,EAAE,SAAS,CAAC;IAE1B;;OAEG;IACH,IAAI,CAAC,EAAE,GAAG,CAAC,OAAO,CAAC;IACnB;;;;;OAKG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB;;;;OAIG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB;;OAEG;IACH,SAAS,CAAC,EAAE,oBAAoB,CAAE,cAAc,CAAE,CAAC;IACnD;;OAEG;IACH,cAAc,EAAE,CACf,KAAK,CAAC,EAAE,aAAa,CAAE,cAAc,CAAE,GAAG,cAAc,KACpD,IAAI,CAAC;IACV;;;OAGG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B;;;;;OAKG;IACH,IAAI,CAAC,EAAE,QAAQ,CAAC;IAChB;;;;;OAKG;IACH,yBAAyB,CAAC,EAAE,OAAO,CAAC;IACpC;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B;;OAEG;IACH,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB;;;;;OAKG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;;;;;OAQG;IACH,wBAAwB,CAAC,EAAE,OAAO,CAAC;CACnC,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/placeholder/index.tsx"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/placeholder/index.tsx"],"names":[],"mappings":";AAiBA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAChD,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,eAAe,CAAC;AAc7D;;;;;;;;;GASG;AACH,wBAAgB,WAAW,CAC1B,KAAK,EAAE,uBAAuB,CAAE,gBAAgB,EAAE,KAAK,EAAE,KAAK,CAAE,eAkEhE;AAED,eAAe,WAAW,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wordpress/components",
|
|
3
|
-
"version": "25.8.
|
|
3
|
+
"version": "25.8.2",
|
|
4
4
|
"description": "UI components for WordPress.",
|
|
5
5
|
"author": "The WordPress Contributors",
|
|
6
6
|
"license": "GPL-2.0-or-later",
|
|
@@ -41,23 +41,23 @@
|
|
|
41
41
|
"@floating-ui/react-dom": "^2.0.1",
|
|
42
42
|
"@radix-ui/react-dropdown-menu": "2.0.4",
|
|
43
43
|
"@use-gesture/react": "^10.2.24",
|
|
44
|
-
"@wordpress/a11y": "^3.42.
|
|
45
|
-
"@wordpress/compose": "^6.19.
|
|
46
|
-
"@wordpress/date": "^4.42.
|
|
47
|
-
"@wordpress/deprecated": "^3.42.
|
|
48
|
-
"@wordpress/dom": "^3.42.
|
|
49
|
-
"@wordpress/element": "^5.19.
|
|
50
|
-
"@wordpress/escape-html": "^2.42.
|
|
51
|
-
"@wordpress/hooks": "^3.42.
|
|
52
|
-
"@wordpress/html-entities": "^3.42.
|
|
53
|
-
"@wordpress/i18n": "^4.42.
|
|
54
|
-
"@wordpress/icons": "^9.33.
|
|
55
|
-
"@wordpress/is-shallow-equal": "^4.42.
|
|
56
|
-
"@wordpress/keycodes": "^3.42.
|
|
57
|
-
"@wordpress/primitives": "^3.40.
|
|
58
|
-
"@wordpress/private-apis": "^0.24.
|
|
59
|
-
"@wordpress/rich-text": "^6.19.
|
|
60
|
-
"@wordpress/warning": "^2.42.
|
|
44
|
+
"@wordpress/a11y": "^3.42.2",
|
|
45
|
+
"@wordpress/compose": "^6.19.2",
|
|
46
|
+
"@wordpress/date": "^4.42.2",
|
|
47
|
+
"@wordpress/deprecated": "^3.42.2",
|
|
48
|
+
"@wordpress/dom": "^3.42.2",
|
|
49
|
+
"@wordpress/element": "^5.19.2",
|
|
50
|
+
"@wordpress/escape-html": "^2.42.2",
|
|
51
|
+
"@wordpress/hooks": "^3.42.2",
|
|
52
|
+
"@wordpress/html-entities": "^3.42.2",
|
|
53
|
+
"@wordpress/i18n": "^4.42.2",
|
|
54
|
+
"@wordpress/icons": "^9.33.2",
|
|
55
|
+
"@wordpress/is-shallow-equal": "^4.42.2",
|
|
56
|
+
"@wordpress/keycodes": "^3.42.2",
|
|
57
|
+
"@wordpress/primitives": "^3.40.2",
|
|
58
|
+
"@wordpress/private-apis": "^0.24.2",
|
|
59
|
+
"@wordpress/rich-text": "^6.19.2",
|
|
60
|
+
"@wordpress/warning": "^2.42.2",
|
|
61
61
|
"change-case": "^4.1.2",
|
|
62
62
|
"classnames": "^2.3.1",
|
|
63
63
|
"colord": "^2.7.0",
|
|
@@ -77,7 +77,7 @@
|
|
|
77
77
|
"reakit": "^1.3.11",
|
|
78
78
|
"remove-accents": "^0.5.0",
|
|
79
79
|
"use-lilius": "^2.0.1",
|
|
80
|
-
"uuid": "^
|
|
80
|
+
"uuid": "^9.0.1",
|
|
81
81
|
"valtio": "1.7.0"
|
|
82
82
|
},
|
|
83
83
|
"peerDependencies": {
|
|
@@ -87,5 +87,5 @@
|
|
|
87
87
|
"publishConfig": {
|
|
88
88
|
"access": "public"
|
|
89
89
|
},
|
|
90
|
-
"gitHead": "
|
|
90
|
+
"gitHead": "5d2e3d07cc97af8090fc32c1e5d5013a2967e752"
|
|
91
91
|
}
|
|
@@ -127,7 +127,14 @@ export function TimePicker( {
|
|
|
127
127
|
method: 'hours' | 'minutes' | 'date' | 'year'
|
|
128
128
|
) => {
|
|
129
129
|
const callback: InputChangeCallback = ( value, { event } ) => {
|
|
130
|
-
|
|
130
|
+
// `instanceof` checks need to get the instance definition from the
|
|
131
|
+
// corresponding window object — therefore, the following logic makes
|
|
132
|
+
// the component work correctly even when rendered inside an iframe.
|
|
133
|
+
const HTMLInputElementInstance =
|
|
134
|
+
( event.target as HTMLInputElement )?.ownerDocument.defaultView
|
|
135
|
+
?.HTMLInputElement ?? HTMLInputElement;
|
|
136
|
+
|
|
137
|
+
if ( ! ( event.target instanceof HTMLInputElementInstance ) ) {
|
|
131
138
|
return;
|
|
132
139
|
}
|
|
133
140
|
|
package/src/modal/README.md
CHANGED
|
@@ -187,10 +187,16 @@ Titles are required for accessibility reasons, see `aria.labelledby` and `title`
|
|
|
187
187
|
|
|
188
188
|
- Required: No
|
|
189
189
|
|
|
190
|
-
#### `focusOnMount`: `boolean | 'firstElement'`
|
|
190
|
+
#### `focusOnMount`: `boolean | 'firstElement'` | 'firstContentElement'
|
|
191
191
|
|
|
192
192
|
If this property is true, it will focus the first tabbable element rendered in the modal.
|
|
193
193
|
|
|
194
|
+
If this property is false, focus will not be transferred and it is the responsibility of the consumer to ensure accessible focus management.
|
|
195
|
+
|
|
196
|
+
If set to `firstElement` focus will be placed on the first tabbable element anywhere within the Modal.
|
|
197
|
+
|
|
198
|
+
If set to `firstContentElement` focus will be placed on the first tabbable element within the Modal's **content** (i.e. children). Note that it is the responsibility of the consumer to ensure there is at least one tabbable element within the children **or the focus will be lost**.
|
|
199
|
+
|
|
194
200
|
- Required: No
|
|
195
201
|
- Default: `true`
|
|
196
202
|
|
package/src/modal/index.tsx
CHANGED
|
@@ -71,11 +71,23 @@ function UnforwardedModal(
|
|
|
71
71
|
} = props;
|
|
72
72
|
|
|
73
73
|
const ref = useRef< HTMLDivElement >();
|
|
74
|
+
|
|
74
75
|
const instanceId = useInstanceId( Modal );
|
|
75
76
|
const headingId = title
|
|
76
77
|
? `components-modal-header-${ instanceId }`
|
|
77
78
|
: aria.labelledby;
|
|
78
|
-
|
|
79
|
+
|
|
80
|
+
// The focus hook does not support 'firstContentElement' but this is a valid
|
|
81
|
+
// value for the Modal's focusOnMount prop. The following code ensures the focus
|
|
82
|
+
// hook will focus the first focusable node within the element to which it is applied.
|
|
83
|
+
// When `firstContentElement` is passed as the value of the focusOnMount prop,
|
|
84
|
+
// the focus hook is applied to the Modal's content element.
|
|
85
|
+
// Otherwise, the focus hook is applied to the Modal's ref. This ensures that the
|
|
86
|
+
// focus hook will focus the first element in the Modal's **content** when
|
|
87
|
+
// `firstContentElement` is passed.
|
|
88
|
+
const focusOnMountRef = useFocusOnMount(
|
|
89
|
+
focusOnMount === 'firstContentElement' ? 'firstElement' : focusOnMount
|
|
90
|
+
);
|
|
79
91
|
const constrainedTabbingRef = useConstrainedTabbing();
|
|
80
92
|
const focusReturnRef = useFocusReturn();
|
|
81
93
|
const focusOutsideProps = useFocusOutside( onRequestClose );
|
|
@@ -223,7 +235,9 @@ function UnforwardedModal(
|
|
|
223
235
|
ref={ useMergeRefs( [
|
|
224
236
|
constrainedTabbingRef,
|
|
225
237
|
focusReturnRef,
|
|
226
|
-
|
|
238
|
+
focusOnMount !== 'firstContentElement'
|
|
239
|
+
? focusOnMountRef
|
|
240
|
+
: null,
|
|
227
241
|
] ) }
|
|
228
242
|
role={ role }
|
|
229
243
|
aria-label={ contentLabel }
|
|
@@ -283,7 +297,17 @@ function UnforwardedModal(
|
|
|
283
297
|
) }
|
|
284
298
|
</div>
|
|
285
299
|
) }
|
|
286
|
-
|
|
300
|
+
|
|
301
|
+
<div
|
|
302
|
+
ref={ useMergeRefs( [
|
|
303
|
+
childrenContainerRef,
|
|
304
|
+
focusOnMount === 'firstContentElement'
|
|
305
|
+
? focusOnMountRef
|
|
306
|
+
: null,
|
|
307
|
+
] ) }
|
|
308
|
+
>
|
|
309
|
+
{ children }
|
|
310
|
+
</div>
|
|
287
311
|
</div>
|
|
288
312
|
</div>
|
|
289
313
|
</StyleProvider>
|
|
@@ -28,7 +28,8 @@ const meta: Meta< typeof Modal > = {
|
|
|
28
28
|
control: { type: null },
|
|
29
29
|
},
|
|
30
30
|
focusOnMount: {
|
|
31
|
-
|
|
31
|
+
options: [ true, false, 'firstElement', 'firstContentElement' ],
|
|
32
|
+
control: { type: 'select' },
|
|
32
33
|
},
|
|
33
34
|
role: {
|
|
34
35
|
control: { type: 'text' },
|
package/src/modal/test/index.tsx
CHANGED
|
@@ -13,6 +13,7 @@ import { useState } from '@wordpress/element';
|
|
|
13
13
|
* Internal dependencies
|
|
14
14
|
*/
|
|
15
15
|
import Modal from '../';
|
|
16
|
+
import type { ModalProps } from '../types';
|
|
16
17
|
|
|
17
18
|
const noop = () => {};
|
|
18
19
|
|
|
@@ -236,4 +237,127 @@ describe( 'Modal', () => {
|
|
|
236
237
|
screen.getByText( 'A sweet button', { selector: 'button' } )
|
|
237
238
|
).toBeInTheDocument();
|
|
238
239
|
} );
|
|
240
|
+
|
|
241
|
+
describe( 'Focus handling', () => {
|
|
242
|
+
let originalGetClientRects: () => DOMRectList;
|
|
243
|
+
|
|
244
|
+
const FocusMountDemo = ( {
|
|
245
|
+
focusOnMount,
|
|
246
|
+
}: Pick< ModalProps, 'focusOnMount' > ) => {
|
|
247
|
+
const [ isShown, setIsShown ] = useState( false );
|
|
248
|
+
return (
|
|
249
|
+
<>
|
|
250
|
+
<button onClick={ () => setIsShown( true ) }>
|
|
251
|
+
Toggle Modal
|
|
252
|
+
</button>
|
|
253
|
+
{ isShown && (
|
|
254
|
+
<Modal
|
|
255
|
+
focusOnMount={ focusOnMount }
|
|
256
|
+
onRequestClose={ () => setIsShown( false ) }
|
|
257
|
+
>
|
|
258
|
+
<p>Modal content</p>
|
|
259
|
+
<a href="https://wordpress.org">
|
|
260
|
+
First Focusable Content Element
|
|
261
|
+
</a>
|
|
262
|
+
|
|
263
|
+
<a href="https://wordpress.org">
|
|
264
|
+
Another Focusable Content Element
|
|
265
|
+
</a>
|
|
266
|
+
</Modal>
|
|
267
|
+
) }
|
|
268
|
+
</>
|
|
269
|
+
);
|
|
270
|
+
};
|
|
271
|
+
|
|
272
|
+
beforeEach( () => {
|
|
273
|
+
/**
|
|
274
|
+
* The test environment does not have a layout engine, so we need to mock
|
|
275
|
+
* the getClientRects method. This ensures that the focusable elements can be
|
|
276
|
+
* found by the `focusOnMount` logic which depends on layout information
|
|
277
|
+
* to determine if the element is visible or not.
|
|
278
|
+
* See https://github.com/WordPress/gutenberg/blob/trunk/packages/dom/src/focusable.js#L55-L61.
|
|
279
|
+
*/
|
|
280
|
+
// @ts-expect-error We're not trying to comply to the DOM spec, only mocking
|
|
281
|
+
window.HTMLElement.prototype.getClientRects = function () {
|
|
282
|
+
return [ 'trick-jsdom-into-having-size-for-element-rect' ];
|
|
283
|
+
};
|
|
284
|
+
} );
|
|
285
|
+
|
|
286
|
+
afterEach( () => {
|
|
287
|
+
// Restore original HTMLElement prototype.
|
|
288
|
+
// See beforeEach for details.
|
|
289
|
+
window.HTMLElement.prototype.getClientRects =
|
|
290
|
+
originalGetClientRects;
|
|
291
|
+
} );
|
|
292
|
+
|
|
293
|
+
it( 'should focus the Modal dialog by default when `focusOnMount` prop is not provided', async () => {
|
|
294
|
+
const user = userEvent.setup();
|
|
295
|
+
|
|
296
|
+
render( <FocusMountDemo /> );
|
|
297
|
+
|
|
298
|
+
const opener = screen.getByRole( 'button', {
|
|
299
|
+
name: 'Toggle Modal',
|
|
300
|
+
} );
|
|
301
|
+
|
|
302
|
+
await user.click( opener );
|
|
303
|
+
|
|
304
|
+
expect( screen.getByRole( 'dialog' ) ).toHaveFocus();
|
|
305
|
+
} );
|
|
306
|
+
|
|
307
|
+
it( 'should focus the Modal dialog when `true` passed as value for `focusOnMount` prop', async () => {
|
|
308
|
+
const user = userEvent.setup();
|
|
309
|
+
|
|
310
|
+
render( <FocusMountDemo focusOnMount={ true } /> );
|
|
311
|
+
|
|
312
|
+
const opener = screen.getByRole( 'button', {
|
|
313
|
+
name: 'Toggle Modal',
|
|
314
|
+
} );
|
|
315
|
+
|
|
316
|
+
await user.click( opener );
|
|
317
|
+
|
|
318
|
+
expect( screen.getByRole( 'dialog' ) ).toHaveFocus();
|
|
319
|
+
} );
|
|
320
|
+
|
|
321
|
+
it( 'should focus the first focusable element in the contents (if found) when `firstContentElement` passed as value for `focusOnMount` prop', async () => {
|
|
322
|
+
const user = userEvent.setup();
|
|
323
|
+
|
|
324
|
+
render( <FocusMountDemo focusOnMount="firstContentElement" /> );
|
|
325
|
+
|
|
326
|
+
const opener = screen.getByRole( 'button' );
|
|
327
|
+
|
|
328
|
+
await user.click( opener );
|
|
329
|
+
|
|
330
|
+
expect(
|
|
331
|
+
screen.getByText( 'First Focusable Content Element' )
|
|
332
|
+
).toHaveFocus();
|
|
333
|
+
} );
|
|
334
|
+
|
|
335
|
+
it( 'should focus the first element anywhere within the Modal when `firstElement` passed as value for `focusOnMount` prop', async () => {
|
|
336
|
+
const user = userEvent.setup();
|
|
337
|
+
|
|
338
|
+
render( <FocusMountDemo focusOnMount="firstElement" /> );
|
|
339
|
+
|
|
340
|
+
const opener = screen.getByRole( 'button' );
|
|
341
|
+
|
|
342
|
+
await user.click( opener );
|
|
343
|
+
|
|
344
|
+
expect(
|
|
345
|
+
screen.getByRole( 'button', { name: 'Close' } )
|
|
346
|
+
).toHaveFocus();
|
|
347
|
+
} );
|
|
348
|
+
|
|
349
|
+
it( 'should not move focus when `false` passed as value for `focusOnMount` prop', async () => {
|
|
350
|
+
const user = userEvent.setup();
|
|
351
|
+
|
|
352
|
+
render( <FocusMountDemo focusOnMount={ false } /> );
|
|
353
|
+
|
|
354
|
+
const opener = screen.getByRole( 'button', {
|
|
355
|
+
name: 'Toggle Modal',
|
|
356
|
+
} );
|
|
357
|
+
|
|
358
|
+
await user.click( opener );
|
|
359
|
+
|
|
360
|
+
expect( opener ).toHaveFocus();
|
|
361
|
+
} );
|
|
362
|
+
} );
|
|
239
363
|
} );
|
package/src/modal/types.ts
CHANGED
|
@@ -68,7 +68,9 @@ export type ModalProps = {
|
|
|
68
68
|
*
|
|
69
69
|
* @default true
|
|
70
70
|
*/
|
|
71
|
-
focusOnMount?:
|
|
71
|
+
focusOnMount?:
|
|
72
|
+
| Parameters< typeof useFocusOnMount >[ 0 ]
|
|
73
|
+
| 'firstContentElement';
|
|
72
74
|
/**
|
|
73
75
|
* Elements that are injected into the modal header to the left of the close button (if rendered).
|
|
74
76
|
* Hidden if `__experimentalHideHeader` is `true`.
|
|
@@ -8,6 +8,8 @@ import classnames from 'classnames';
|
|
|
8
8
|
*/
|
|
9
9
|
import { useResizeObserver } from '@wordpress/compose';
|
|
10
10
|
import { SVG, Path } from '@wordpress/primitives';
|
|
11
|
+
import { useEffect } from '@wordpress/element';
|
|
12
|
+
import { speak } from '@wordpress/a11y';
|
|
11
13
|
|
|
12
14
|
/**
|
|
13
15
|
* Internal dependencies
|
|
@@ -72,10 +74,17 @@ export function Placeholder(
|
|
|
72
74
|
modifierClassNames,
|
|
73
75
|
withIllustration ? 'has-illustration' : null
|
|
74
76
|
);
|
|
77
|
+
|
|
75
78
|
const fieldsetClasses = classnames( 'components-placeholder__fieldset', {
|
|
76
79
|
'is-column-layout': isColumnLayout,
|
|
77
80
|
} );
|
|
78
81
|
|
|
82
|
+
useEffect( () => {
|
|
83
|
+
if ( instructions ) {
|
|
84
|
+
speak( instructions );
|
|
85
|
+
}
|
|
86
|
+
}, [ instructions ] );
|
|
87
|
+
|
|
79
88
|
return (
|
|
80
89
|
<div { ...additionalProps } className={ classes }>
|
|
81
90
|
{ withIllustration ? PlaceholderIllustration : null }
|
|
@@ -90,14 +99,12 @@ export function Placeholder(
|
|
|
90
99
|
<Icon icon={ icon } />
|
|
91
100
|
{ label }
|
|
92
101
|
</div>
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
{ children }
|
|
100
|
-
</fieldset>
|
|
102
|
+
{ !! instructions && (
|
|
103
|
+
<div className="components-placeholder__instructions">
|
|
104
|
+
{ instructions }
|
|
105
|
+
</div>
|
|
106
|
+
) }
|
|
107
|
+
<div className={ fieldsetClasses }>{ children }</div>
|
|
101
108
|
</div>
|
|
102
109
|
);
|
|
103
110
|
}
|