@wordpress/edit-site 5.12.7 → 5.12.9

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.
Files changed (166) hide show
  1. package/build/components/block-editor/editor-canvas.js +1 -1
  2. package/build/components/block-editor/editor-canvas.js.map +1 -1
  3. package/build/components/block-editor/index.js +0 -4
  4. package/build/components/block-editor/index.js.map +1 -1
  5. package/build/components/block-editor/use-site-editor-settings.js +12 -6
  6. package/build/components/block-editor/use-site-editor-settings.js.map +1 -1
  7. package/build/components/create-pattern-modal/index.js +7 -3
  8. package/build/components/create-pattern-modal/index.js.map +1 -1
  9. package/build/components/page-patterns/duplicate-menu-item.js +163 -0
  10. package/build/components/page-patterns/duplicate-menu-item.js.map +1 -0
  11. package/build/components/page-patterns/grid-item.js +83 -59
  12. package/build/components/page-patterns/grid-item.js.map +1 -1
  13. package/build/components/page-patterns/grid.js +81 -13
  14. package/build/components/page-patterns/grid.js.map +1 -1
  15. package/build/components/page-patterns/header.js +69 -0
  16. package/build/components/page-patterns/header.js.map +1 -0
  17. package/build/components/page-patterns/index.js +3 -1
  18. package/build/components/page-patterns/index.js.map +1 -1
  19. package/build/components/page-patterns/patterns-list.js +66 -27
  20. package/build/components/page-patterns/patterns-list.js.map +1 -1
  21. package/build/components/page-patterns/rename-menu-item.js +109 -0
  22. package/build/components/page-patterns/rename-menu-item.js.map +1 -0
  23. package/build/components/page-patterns/use-patterns.js +99 -118
  24. package/build/components/page-patterns/use-patterns.js.map +1 -1
  25. package/build/components/page-template-parts/add-new-template-part.js +74 -0
  26. package/build/components/page-template-parts/add-new-template-part.js.map +1 -0
  27. package/build/components/page-template-parts/index.js +2 -23
  28. package/build/components/page-template-parts/index.js.map +1 -1
  29. package/build/components/resizable-frame/index.js +75 -32
  30. package/build/components/resizable-frame/index.js.map +1 -1
  31. package/build/components/sidebar-navigation-screen/index.js +14 -8
  32. package/build/components/sidebar-navigation-screen/index.js.map +1 -1
  33. package/build/components/sidebar-navigation-screen-main/template-part-hint.js +1 -1
  34. package/build/components/sidebar-navigation-screen-main/template-part-hint.js.map +1 -1
  35. package/build/components/sidebar-navigation-screen-navigation-menu/more-menu.js +1 -0
  36. package/build/components/sidebar-navigation-screen-navigation-menu/more-menu.js.map +1 -1
  37. package/build/components/sidebar-navigation-screen-navigation-menu/single-navigation-menu.js +3 -3
  38. package/build/components/sidebar-navigation-screen-navigation-menu/single-navigation-menu.js.map +1 -1
  39. package/build/components/sidebar-navigation-screen-page/status-label.js +1 -34
  40. package/build/components/sidebar-navigation-screen-page/status-label.js.map +1 -1
  41. package/build/components/sidebar-navigation-screen-pages/index.js +33 -25
  42. package/build/components/sidebar-navigation-screen-pages/index.js.map +1 -1
  43. package/build/components/sidebar-navigation-screen-pattern/template-part-navigation-menu.js +3 -2
  44. package/build/components/sidebar-navigation-screen-pattern/template-part-navigation-menu.js.map +1 -1
  45. package/build/components/sidebar-navigation-screen-pattern/template-part-navigation-menus.js +3 -2
  46. package/build/components/sidebar-navigation-screen-pattern/template-part-navigation-menus.js.map +1 -1
  47. package/build/components/sidebar-navigation-screen-patterns/index.js +5 -6
  48. package/build/components/sidebar-navigation-screen-patterns/index.js.map +1 -1
  49. package/build/components/sidebar-navigation-screen-patterns/use-my-patterns.js +9 -5
  50. package/build/components/sidebar-navigation-screen-patterns/use-my-patterns.js.map +1 -1
  51. package/build/components/site-hub/index.js +4 -2
  52. package/build/components/site-hub/index.js.map +1 -1
  53. package/build/components/sync-state-with-url/use-sync-path-with-url.js +15 -12
  54. package/build/components/sync-state-with-url/use-sync-path-with-url.js.map +1 -1
  55. package/build/components/template-actions/index.js +3 -1
  56. package/build/components/template-actions/index.js.map +1 -1
  57. package/build/components/template-actions/rename-menu-item.js +9 -6
  58. package/build/components/template-actions/rename-menu-item.js.map +1 -1
  59. package/build/hooks/push-changes-to-global-styles/index.js +3 -1
  60. package/build/hooks/push-changes-to-global-styles/index.js.map +1 -1
  61. package/build/utils/use-activate-theme.js +1 -1
  62. package/build/utils/use-activate-theme.js.map +1 -1
  63. package/build-module/components/block-editor/editor-canvas.js +1 -1
  64. package/build-module/components/block-editor/editor-canvas.js.map +1 -1
  65. package/build-module/components/block-editor/index.js +0 -4
  66. package/build-module/components/block-editor/index.js.map +1 -1
  67. package/build-module/components/block-editor/use-site-editor-settings.js +13 -7
  68. package/build-module/components/block-editor/use-site-editor-settings.js.map +1 -1
  69. package/build-module/components/create-pattern-modal/index.js +6 -3
  70. package/build-module/components/create-pattern-modal/index.js.map +1 -1
  71. package/build-module/components/page-patterns/duplicate-menu-item.js +147 -0
  72. package/build-module/components/page-patterns/duplicate-menu-item.js.map +1 -0
  73. package/build-module/components/page-patterns/grid-item.js +84 -65
  74. package/build-module/components/page-patterns/grid-item.js.map +1 -1
  75. package/build-module/components/page-patterns/grid.js +82 -15
  76. package/build-module/components/page-patterns/grid.js.map +1 -1
  77. package/build-module/components/page-patterns/header.js +54 -0
  78. package/build-module/components/page-patterns/header.js.map +1 -0
  79. package/build-module/components/page-patterns/index.js +3 -1
  80. package/build-module/components/page-patterns/index.js.map +1 -1
  81. package/build-module/components/page-patterns/patterns-list.js +68 -30
  82. package/build-module/components/page-patterns/patterns-list.js.map +1 -1
  83. package/build-module/components/page-patterns/rename-menu-item.js +97 -0
  84. package/build-module/components/page-patterns/rename-menu-item.js.map +1 -0
  85. package/build-module/components/page-patterns/use-patterns.js +100 -119
  86. package/build-module/components/page-patterns/use-patterns.js.map +1 -1
  87. package/build-module/components/page-template-parts/add-new-template-part.js +58 -0
  88. package/build-module/components/page-template-parts/add-new-template-part.js.map +1 -0
  89. package/build-module/components/page-template-parts/index.js +3 -22
  90. package/build-module/components/page-template-parts/index.js.map +1 -1
  91. package/build-module/components/resizable-frame/index.js +76 -35
  92. package/build-module/components/resizable-frame/index.js.map +1 -1
  93. package/build-module/components/sidebar-navigation-screen/index.js +15 -9
  94. package/build-module/components/sidebar-navigation-screen/index.js.map +1 -1
  95. package/build-module/components/sidebar-navigation-screen-main/template-part-hint.js +1 -1
  96. package/build-module/components/sidebar-navigation-screen-main/template-part-hint.js.map +1 -1
  97. package/build-module/components/sidebar-navigation-screen-navigation-menu/more-menu.js +1 -0
  98. package/build-module/components/sidebar-navigation-screen-navigation-menu/more-menu.js.map +1 -1
  99. package/build-module/components/sidebar-navigation-screen-navigation-menu/single-navigation-menu.js +3 -3
  100. package/build-module/components/sidebar-navigation-screen-navigation-menu/single-navigation-menu.js.map +1 -1
  101. package/build-module/components/sidebar-navigation-screen-page/status-label.js +1 -32
  102. package/build-module/components/sidebar-navigation-screen-page/status-label.js.map +1 -1
  103. package/build-module/components/sidebar-navigation-screen-pages/index.js +33 -25
  104. package/build-module/components/sidebar-navigation-screen-pages/index.js.map +1 -1
  105. package/build-module/components/sidebar-navigation-screen-pattern/template-part-navigation-menu.js +3 -2
  106. package/build-module/components/sidebar-navigation-screen-pattern/template-part-navigation-menu.js.map +1 -1
  107. package/build-module/components/sidebar-navigation-screen-pattern/template-part-navigation-menus.js +3 -2
  108. package/build-module/components/sidebar-navigation-screen-pattern/template-part-navigation-menus.js.map +1 -1
  109. package/build-module/components/sidebar-navigation-screen-patterns/index.js +5 -6
  110. package/build-module/components/sidebar-navigation-screen-patterns/index.js.map +1 -1
  111. package/build-module/components/sidebar-navigation-screen-patterns/use-my-patterns.js +9 -5
  112. package/build-module/components/sidebar-navigation-screen-patterns/use-my-patterns.js.map +1 -1
  113. package/build-module/components/site-hub/index.js +4 -2
  114. package/build-module/components/site-hub/index.js.map +1 -1
  115. package/build-module/components/sync-state-with-url/use-sync-path-with-url.js +16 -12
  116. package/build-module/components/sync-state-with-url/use-sync-path-with-url.js.map +1 -1
  117. package/build-module/components/template-actions/index.js +2 -1
  118. package/build-module/components/template-actions/index.js.map +1 -1
  119. package/build-module/components/template-actions/rename-menu-item.js +8 -6
  120. package/build-module/components/template-actions/rename-menu-item.js.map +1 -1
  121. package/build-module/hooks/push-changes-to-global-styles/index.js +4 -2
  122. package/build-module/hooks/push-changes-to-global-styles/index.js.map +1 -1
  123. package/build-module/utils/use-activate-theme.js +1 -1
  124. package/build-module/utils/use-activate-theme.js.map +1 -1
  125. package/build-style/style-rtl.css +150 -54
  126. package/build-style/style.css +150 -54
  127. package/package.json +14 -14
  128. package/src/components/block-editor/editor-canvas.js +1 -1
  129. package/src/components/block-editor/index.js +0 -4
  130. package/src/components/block-editor/use-site-editor-settings.js +16 -11
  131. package/src/components/create-pattern-modal/index.js +5 -2
  132. package/src/components/header-edit-mode/document-actions/style.scss +4 -0
  133. package/src/components/layout/style.scss +1 -0
  134. package/src/components/page-patterns/duplicate-menu-item.js +196 -0
  135. package/src/components/page-patterns/grid-item.js +187 -137
  136. package/src/components/page-patterns/grid.js +118 -20
  137. package/src/components/page-patterns/header.js +69 -0
  138. package/src/components/page-patterns/index.js +6 -1
  139. package/src/components/page-patterns/patterns-list.js +87 -46
  140. package/src/components/page-patterns/rename-menu-item.js +115 -0
  141. package/src/components/page-patterns/style.scss +106 -26
  142. package/src/components/page-patterns/use-patterns.js +96 -167
  143. package/src/components/page-template-parts/add-new-template-part.js +57 -0
  144. package/src/components/page-template-parts/index.js +3 -22
  145. package/src/components/resizable-frame/index.js +100 -31
  146. package/src/components/resizable-frame/style.scss +26 -9
  147. package/src/components/sidebar-navigation-item/style.scss +10 -1
  148. package/src/components/sidebar-navigation-screen/index.js +14 -7
  149. package/src/components/sidebar-navigation-screen-main/template-part-hint.js +1 -3
  150. package/src/components/sidebar-navigation-screen-navigation-menu/more-menu.js +1 -0
  151. package/src/components/sidebar-navigation-screen-navigation-menu/single-navigation-menu.js +1 -1
  152. package/src/components/sidebar-navigation-screen-page/status-label.js +1 -35
  153. package/src/components/sidebar-navigation-screen-pages/index.js +39 -29
  154. package/src/components/sidebar-navigation-screen-pattern/template-part-navigation-menu.js +2 -1
  155. package/src/components/sidebar-navigation-screen-pattern/template-part-navigation-menus.js +2 -1
  156. package/src/components/sidebar-navigation-screen-patterns/index.js +20 -24
  157. package/src/components/sidebar-navigation-screen-patterns/style.scss +0 -3
  158. package/src/components/sidebar-navigation-screen-patterns/use-my-patterns.js +7 -6
  159. package/src/components/site-hub/index.js +6 -2
  160. package/src/components/site-hub/style.scss +5 -0
  161. package/src/components/sync-state-with-url/use-sync-path-with-url.js +73 -66
  162. package/src/components/template-actions/index.js +2 -1
  163. package/src/components/template-actions/rename-menu-item.js +8 -6
  164. package/src/hooks/push-changes-to-global-styles/index.js +8 -1
  165. package/src/style.scss +10 -12
  166. package/src/utils/use-activate-theme.js +1 -1
@@ -2,38 +2,136 @@
2
2
  * WordPress dependencies
3
3
  */
4
4
  import {
5
- __unstableComposite as Composite,
6
- __unstableUseCompositeState as useCompositeState,
5
+ __experimentalHStack as HStack,
6
+ __experimentalText as Text,
7
+ Button,
7
8
  } from '@wordpress/components';
9
+ import { useRef, useState, useMemo } from '@wordpress/element';
10
+ import { __, _x, _n, sprintf } from '@wordpress/i18n';
11
+ import { useAsyncList } from '@wordpress/compose';
8
12
 
9
13
  /**
10
14
  * Internal dependencies
11
15
  */
12
16
  import GridItem from './grid-item';
13
17
 
14
- export default function Grid( { categoryId, label, icon, items } ) {
15
- const composite = useCompositeState( { orientation: 'vertical' } );
18
+ const PAGE_SIZE = 20;
16
19
 
17
- if ( ! items?.length ) {
20
+ function Pagination( { currentPage, numPages, changePage, totalItems } ) {
21
+ return (
22
+ <HStack
23
+ expanded={ false }
24
+ spacing={ 3 }
25
+ className="edit-site-patterns__grid-pagination"
26
+ >
27
+ <Text variant="muted">
28
+ {
29
+ // translators: %s: Total number of patterns.
30
+ sprintf(
31
+ // translators: %s: Total number of patterns.
32
+ _n( '%s item', '%s items', totalItems ),
33
+ totalItems
34
+ )
35
+ }
36
+ </Text>
37
+ <HStack expanded={ false } spacing={ 1 }>
38
+ <Button
39
+ variant="tertiary"
40
+ onClick={ () => changePage( 1 ) }
41
+ disabled={ currentPage === 1 }
42
+ aria-label={ __( 'First page' ) }
43
+ >
44
+ «
45
+ </Button>
46
+ <Button
47
+ variant="tertiary"
48
+ onClick={ () => changePage( currentPage - 1 ) }
49
+ disabled={ currentPage === 1 }
50
+ aria-label={ __( 'Previous page' ) }
51
+ >
52
+
53
+ </Button>
54
+ </HStack>
55
+ <Text variant="muted">
56
+ { sprintf(
57
+ // translators: %1$s: Current page number, %2$s: Total number of pages.
58
+ _x( '%1$s of %2$s', 'paging' ),
59
+ currentPage,
60
+ numPages
61
+ ) }
62
+ </Text>
63
+ <HStack expanded={ false } spacing={ 1 }>
64
+ <Button
65
+ variant="tertiary"
66
+ onClick={ () => changePage( currentPage + 1 ) }
67
+ disabled={ currentPage === numPages }
68
+ aria-label={ __( 'Next page' ) }
69
+ >
70
+
71
+ </Button>
72
+ <Button
73
+ variant="tertiary"
74
+ onClick={ () => changePage( numPages ) }
75
+ disabled={ currentPage === numPages }
76
+ aria-label={ __( 'Last page' ) }
77
+ >
78
+ »
79
+ </Button>
80
+ </HStack>
81
+ </HStack>
82
+ );
83
+ }
84
+
85
+ export default function Grid( { categoryId, items, ...props } ) {
86
+ const [ currentPage, setCurrentPage ] = useState( 1 );
87
+ const gridRef = useRef();
88
+ const totalItems = items.length;
89
+ const pageIndex = currentPage - 1;
90
+
91
+ const list = useMemo(
92
+ () =>
93
+ items.slice(
94
+ pageIndex * PAGE_SIZE,
95
+ pageIndex * PAGE_SIZE + PAGE_SIZE
96
+ ),
97
+ [ pageIndex, items ]
98
+ );
99
+
100
+ const asyncList = useAsyncList( list, { step: 10 } );
101
+
102
+ if ( ! list?.length ) {
18
103
  return null;
19
104
  }
20
105
 
106
+ const numPages = Math.ceil( items.length / PAGE_SIZE );
107
+ const changePage = ( page ) => {
108
+ const scrollContainer = document.querySelector( '.edit-site-patterns' );
109
+ scrollContainer?.scrollTo( 0, 0 );
110
+
111
+ setCurrentPage( page );
112
+ };
113
+
21
114
  return (
22
- <Composite
23
- { ...composite }
24
- role="listbox"
25
- className="edit-site-patterns__grid"
26
- aria-label={ label }
27
- >
28
- { items.map( ( item ) => (
29
- <GridItem
30
- key={ item.name }
31
- icon={ icon }
32
- item={ item }
33
- categoryId={ categoryId }
34
- composite={ composite }
115
+ <>
116
+ <ul
117
+ role="listbox"
118
+ className="edit-site-patterns__grid"
119
+ { ...props }
120
+ ref={ gridRef }
121
+ >
122
+ { asyncList.map( ( item ) => (
123
+ <GridItem
124
+ key={ item.name }
125
+ item={ item }
126
+ categoryId={ categoryId }
127
+ />
128
+ ) ) }
129
+ </ul>
130
+ { numPages > 1 && (
131
+ <Pagination
132
+ { ...{ currentPage, numPages, changePage, totalItems } }
35
133
  />
36
- ) ) }
37
- </Composite>
134
+ ) }
135
+ </>
38
136
  );
39
137
  }
@@ -0,0 +1,69 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import {
5
+ __experimentalVStack as VStack,
6
+ __experimentalHeading as Heading,
7
+ __experimentalText as Text,
8
+ } from '@wordpress/components';
9
+ import { __ } from '@wordpress/i18n';
10
+ import { store as editorStore } from '@wordpress/editor';
11
+ import { useSelect } from '@wordpress/data';
12
+
13
+ /**
14
+ * Internal dependencies
15
+ */
16
+ import usePatternCategories from '../sidebar-navigation-screen-patterns/use-pattern-categories';
17
+ import {
18
+ USER_PATTERN_CATEGORY,
19
+ USER_PATTERNS,
20
+ TEMPLATE_PARTS,
21
+ PATTERNS,
22
+ } from './utils';
23
+
24
+ export default function PatternsHeader( {
25
+ categoryId,
26
+ type,
27
+ titleId,
28
+ descriptionId,
29
+ } ) {
30
+ const { patternCategories } = usePatternCategories();
31
+ const templatePartAreas = useSelect(
32
+ ( select ) =>
33
+ select( editorStore ).__experimentalGetDefaultTemplatePartAreas(),
34
+ []
35
+ );
36
+
37
+ let title, description;
38
+ if ( categoryId === USER_PATTERN_CATEGORY && type === USER_PATTERNS ) {
39
+ title = __( 'My Patterns' );
40
+ description = '';
41
+ } else if ( type === TEMPLATE_PARTS ) {
42
+ const templatePartArea = templatePartAreas.find(
43
+ ( area ) => area.area === categoryId
44
+ );
45
+ title = templatePartArea?.label;
46
+ description = templatePartArea?.description;
47
+ } else if ( type === PATTERNS ) {
48
+ const patternCategory = patternCategories.find(
49
+ ( category ) => category.name === categoryId
50
+ );
51
+ title = patternCategory?.label;
52
+ description = patternCategory?.description;
53
+ }
54
+
55
+ if ( ! title ) return null;
56
+
57
+ return (
58
+ <VStack className="edit-site-patterns__section-header">
59
+ <Heading as="h2" level={ 4 } id={ titleId }>
60
+ { title }
61
+ </Heading>
62
+ { description ? (
63
+ <Text variant="muted" as="p" id={ descriptionId }>
64
+ { description }
65
+ </Text>
66
+ ) : null }
67
+ </VStack>
68
+ );
69
+ }
@@ -32,7 +32,12 @@ export default function PagePatterns() {
32
32
  title={ __( 'Patterns content' ) }
33
33
  hideTitleFromUI
34
34
  >
35
- <PatternsList type={ type } categoryId={ category } />
35
+ <PatternsList
36
+ // Reset the states when switching between categories and types.
37
+ key={ `${ type }-${ category }` }
38
+ type={ type }
39
+ categoryId={ category }
40
+ />
36
41
  </Page>
37
42
  </ExperimentalBlockEditorProvider>
38
43
  );
@@ -1,51 +1,86 @@
1
1
  /**
2
2
  * WordPress dependencies
3
3
  */
4
-
4
+ import { useState, useDeferredValue, useId } from '@wordpress/element';
5
5
  import {
6
6
  SearchControl,
7
- __experimentalHeading as Heading,
8
- __experimentalText as Text,
9
7
  __experimentalVStack as VStack,
10
8
  Flex,
11
9
  FlexBlock,
10
+ __experimentalToggleGroupControl as ToggleGroupControl,
11
+ __experimentalToggleGroupControlOption as ToggleGroupControlOption,
12
+ __experimentalHeading as Heading,
13
+ __experimentalText as Text,
12
14
  } from '@wordpress/components';
13
15
  import { __, isRTL } from '@wordpress/i18n';
14
- import { symbol, chevronLeft, chevronRight } from '@wordpress/icons';
16
+ import { chevronLeft, chevronRight } from '@wordpress/icons';
15
17
  import { privateApis as routerPrivateApis } from '@wordpress/router';
16
18
  import { useViewportMatch } from '@wordpress/compose';
17
19
 
18
20
  /**
19
21
  * Internal dependencies
20
22
  */
23
+ import PatternsHeader from './header';
21
24
  import Grid from './grid';
22
25
  import NoPatterns from './no-patterns';
23
26
  import usePatterns from './use-patterns';
24
27
  import SidebarButton from '../sidebar-button';
25
28
  import useDebouncedInput from '../../utils/use-debounced-input';
26
29
  import { unlock } from '../../lock-unlock';
30
+ import { SYNC_TYPES, USER_PATTERN_CATEGORY } from './utils';
27
31
 
28
32
  const { useLocation, useHistory } = unlock( routerPrivateApis );
29
33
 
34
+ const SYNC_FILTERS = {
35
+ all: __( 'All' ),
36
+ [ SYNC_TYPES.full ]: __( 'Synced' ),
37
+ [ SYNC_TYPES.unsynced ]: __( 'Standard' ),
38
+ };
39
+
40
+ const SYNC_DESCRIPTIONS = {
41
+ all: '',
42
+ [ SYNC_TYPES.full ]: __(
43
+ 'Patterns that are kept in sync across the site.'
44
+ ),
45
+ [ SYNC_TYPES.unsynced ]: __(
46
+ 'Patterns that can be changed freely without affecting the site.'
47
+ ),
48
+ };
49
+
30
50
  export default function PatternsList( { categoryId, type } ) {
31
51
  const location = useLocation();
32
52
  const history = useHistory();
33
53
  const isMobileViewport = useViewportMatch( 'medium', '<' );
34
54
  const [ filterValue, setFilterValue, delayedFilterValue ] =
35
55
  useDebouncedInput( '' );
56
+ const deferredFilterValue = useDeferredValue( delayedFilterValue );
36
57
 
37
- const [ patterns, isResolving ] = usePatterns(
38
- type,
39
- categoryId,
40
- delayedFilterValue
41
- );
58
+ const [ syncFilter, setSyncFilter ] = useState( 'all' );
59
+ const deferredSyncedFilter = useDeferredValue( syncFilter );
60
+ const { patterns, isResolving } = usePatterns( type, categoryId, {
61
+ search: deferredFilterValue,
62
+ syncStatus:
63
+ deferredSyncedFilter === 'all' ? undefined : deferredSyncedFilter,
64
+ } );
42
65
 
43
- const { syncedPatterns, unsyncedPatterns } = patterns;
44
- const hasPatterns = !! syncedPatterns.length || !! unsyncedPatterns.length;
66
+ const id = useId();
67
+ const titleId = `${ id }-title`;
68
+ const descriptionId = `${ id }-description`;
69
+
70
+ const hasPatterns = patterns.length;
71
+ const title = SYNC_FILTERS[ syncFilter ];
72
+ const description = SYNC_DESCRIPTIONS[ syncFilter ];
45
73
 
46
74
  return (
47
75
  <VStack spacing={ 6 }>
48
- <Flex>
76
+ <PatternsHeader
77
+ categoryId={ categoryId }
78
+ type={ type }
79
+ titleId={ titleId }
80
+ descriptionId={ descriptionId }
81
+ />
82
+
83
+ <Flex alignment="stretch" wrap>
49
84
  { isMobileViewport && (
50
85
  <SidebarButton
51
86
  icon={ isRTL() ? chevronRight : chevronLeft }
@@ -61,7 +96,7 @@ export default function PatternsList( { categoryId, type } ) {
61
96
  } }
62
97
  />
63
98
  ) }
64
- <FlexBlock>
99
+ <FlexBlock className="edit-site-patterns__search-block">
65
100
  <SearchControl
66
101
  className="edit-site-patterns__search"
67
102
  onChange={ ( value ) => setFilterValue( value ) }
@@ -71,42 +106,48 @@ export default function PatternsList( { categoryId, type } ) {
71
106
  __nextHasNoMarginBottom
72
107
  />
73
108
  </FlexBlock>
109
+ { categoryId === USER_PATTERN_CATEGORY && (
110
+ <ToggleGroupControl
111
+ className="edit-site-patterns__sync-status-filter"
112
+ hideLabelFromVision
113
+ label={ __( 'Filter by sync status' ) }
114
+ value={ syncFilter }
115
+ isBlock
116
+ onChange={ ( value ) => setSyncFilter( value ) }
117
+ __nextHasNoMarginBottom
118
+ >
119
+ { Object.entries( SYNC_FILTERS ).map(
120
+ ( [ key, label ] ) => (
121
+ <ToggleGroupControlOption
122
+ className="edit-site-patterns__sync-status-filter-option"
123
+ key={ key }
124
+ value={ key }
125
+ label={ label }
126
+ />
127
+ )
128
+ ) }
129
+ </ToggleGroupControl>
130
+ ) }
74
131
  </Flex>
75
- { isResolving && __( 'Loading' ) }
76
- { ! isResolving && !! syncedPatterns.length && (
77
- <>
78
- <VStack className="edit-site-patterns__section-header">
79
- <Heading level={ 4 }>{ __( 'Synced' ) }</Heading>
80
- <Text variant="muted" as="p">
81
- { __(
82
- 'Patterns that are kept in sync across the site'
83
- ) }
132
+ { syncFilter !== 'all' && (
133
+ <VStack className="edit-site-patterns__section-header">
134
+ <Heading as="h3" level={ 5 } id={ titleId }>
135
+ { title }
136
+ </Heading>
137
+ { description ? (
138
+ <Text variant="muted" as="p" id={ descriptionId }>
139
+ { description }
84
140
  </Text>
85
- </VStack>
86
- <Grid
87
- icon={ symbol }
88
- categoryId={ categoryId }
89
- label={ __( 'Synced' ) }
90
- items={ syncedPatterns }
91
- />
92
- </>
141
+ ) : null }
142
+ </VStack>
93
143
  ) }
94
- { ! isResolving && !! unsyncedPatterns.length && (
95
- <>
96
- <VStack className="edit-site-patterns__section-header">
97
- <Heading level={ 4 }>{ __( 'Standard' ) }</Heading>
98
- <Text variant="muted" as="p">
99
- { __(
100
- 'Patterns that can be changed freely without affecting the site'
101
- ) }
102
- </Text>
103
- </VStack>
104
- <Grid
105
- categoryId={ categoryId }
106
- label={ __( 'Standard patterns' ) }
107
- items={ unsyncedPatterns }
108
- />
109
- </>
144
+ { hasPatterns && (
145
+ <Grid
146
+ categoryId={ categoryId }
147
+ items={ patterns }
148
+ aria-labelledby={ titleId }
149
+ aria-describedby={ descriptionId }
150
+ />
110
151
  ) }
111
152
  { ! isResolving && ! hasPatterns && <NoPatterns /> }
112
153
  </VStack>
@@ -0,0 +1,115 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import {
5
+ Button,
6
+ MenuItem,
7
+ Modal,
8
+ TextControl,
9
+ __experimentalHStack as HStack,
10
+ __experimentalVStack as VStack,
11
+ } from '@wordpress/components';
12
+ import { store as coreStore } from '@wordpress/core-data';
13
+ import { useDispatch } from '@wordpress/data';
14
+ import { useState } from '@wordpress/element';
15
+ import { __ } from '@wordpress/i18n';
16
+ import { store as noticesStore } from '@wordpress/notices';
17
+
18
+ /**
19
+ * Internal dependencies
20
+ */
21
+ import { TEMPLATE_PARTS } from './utils';
22
+
23
+ export default function RenameMenuItem( { item, onClose } ) {
24
+ const [ title, setTitle ] = useState( () => item.title );
25
+ const [ isModalOpen, setIsModalOpen ] = useState( false );
26
+
27
+ const { editEntityRecord, saveEditedEntityRecord } =
28
+ useDispatch( coreStore );
29
+ const { createSuccessNotice, createErrorNotice } =
30
+ useDispatch( noticesStore );
31
+
32
+ if ( item.type === TEMPLATE_PARTS && ! item.isCustom ) {
33
+ return null;
34
+ }
35
+
36
+ async function onRename( event ) {
37
+ event.preventDefault();
38
+
39
+ try {
40
+ await editEntityRecord( 'postType', item.type, item.id, { title } );
41
+
42
+ // Update state before saving rerenders the list.
43
+ setTitle( '' );
44
+ setIsModalOpen( false );
45
+ onClose();
46
+
47
+ // Persist edited entity.
48
+ await saveEditedEntityRecord( 'postType', item.type, item.id, {
49
+ throwOnError: true,
50
+ } );
51
+
52
+ createSuccessNotice( __( 'Entity renamed.' ), {
53
+ type: 'snackbar',
54
+ } );
55
+ } catch ( error ) {
56
+ const errorMessage =
57
+ error.message && error.code !== 'unknown_error'
58
+ ? error.message
59
+ : __( 'An error occurred while renaming the entity.' );
60
+
61
+ createErrorNotice( errorMessage, { type: 'snackbar' } );
62
+ }
63
+ }
64
+
65
+ return (
66
+ <>
67
+ <MenuItem
68
+ onClick={ () => {
69
+ setIsModalOpen( true );
70
+ setTitle( item.title );
71
+ } }
72
+ >
73
+ { __( 'Rename' ) }
74
+ </MenuItem>
75
+ { isModalOpen && (
76
+ <Modal
77
+ title={ __( 'Rename' ) }
78
+ onRequestClose={ () => {
79
+ setIsModalOpen( false );
80
+ onClose();
81
+ } }
82
+ overlayClassName="edit-site-list__rename_modal"
83
+ >
84
+ <form onSubmit={ onRename }>
85
+ <VStack spacing="5">
86
+ <TextControl
87
+ __nextHasNoMarginBottom
88
+ label={ __( 'Name' ) }
89
+ value={ title }
90
+ onChange={ setTitle }
91
+ required
92
+ />
93
+
94
+ <HStack justify="right">
95
+ <Button
96
+ variant="tertiary"
97
+ onClick={ () => {
98
+ setIsModalOpen( false );
99
+ onClose();
100
+ } }
101
+ >
102
+ { __( 'Cancel' ) }
103
+ </Button>
104
+
105
+ <Button variant="primary" type="submit">
106
+ { __( 'Save' ) }
107
+ </Button>
108
+ </HStack>
109
+ </VStack>
110
+ </form>
111
+ </Modal>
112
+ ) }
113
+ </>
114
+ );
115
+ }