@wordpress/patterns 1.8.0 → 1.9.1-next.79a6196f.0

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 (38) hide show
  1. package/CHANGELOG.md +2 -0
  2. package/LICENSE.md +1 -1
  3. package/build/components/create-pattern-modal.js +33 -20
  4. package/build/components/create-pattern-modal.js.map +1 -1
  5. package/build/components/duplicate-pattern-modal.js +29 -17
  6. package/build/components/duplicate-pattern-modal.js.map +1 -1
  7. package/build/components/partial-syncing-controls.js +101 -0
  8. package/build/components/partial-syncing-controls.js.map +1 -0
  9. package/build/components/rename-pattern-category-modal.js +3 -0
  10. package/build/components/rename-pattern-category-modal.js.map +1 -1
  11. package/build/components/rename-pattern-modal.js +3 -0
  12. package/build/components/rename-pattern-modal.js.map +1 -1
  13. package/build/constants.js +14 -1
  14. package/build/constants.js.map +1 -1
  15. package/build/private-apis.js +10 -3
  16. package/build/private-apis.js.map +1 -1
  17. package/build-module/components/create-pattern-modal.js +32 -20
  18. package/build-module/components/create-pattern-modal.js.map +1 -1
  19. package/build-module/components/duplicate-pattern-modal.js +28 -17
  20. package/build-module/components/duplicate-pattern-modal.js.map +1 -1
  21. package/build-module/components/partial-syncing-controls.js +93 -0
  22. package/build-module/components/partial-syncing-controls.js.map +1 -0
  23. package/build-module/components/rename-pattern-category-modal.js +3 -0
  24. package/build-module/components/rename-pattern-category-modal.js.map +1 -1
  25. package/build-module/components/rename-pattern-modal.js +3 -0
  26. package/build-module/components/rename-pattern-modal.js.map +1 -1
  27. package/build-module/constants.js +11 -0
  28. package/build-module/constants.js.map +1 -1
  29. package/build-module/private-apis.js +9 -4
  30. package/build-module/private-apis.js.map +1 -1
  31. package/package.json +17 -16
  32. package/src/components/create-pattern-modal.js +100 -89
  33. package/src/components/duplicate-pattern-modal.js +26 -24
  34. package/src/components/partial-syncing-controls.js +110 -0
  35. package/src/components/rename-pattern-category-modal.js +7 -1
  36. package/src/components/rename-pattern-modal.js +11 -2
  37. package/src/constants.js +10 -0
  38. package/src/private-apis.js +14 -2
@@ -2,23 +2,28 @@
2
2
  * Internal dependencies
3
3
  */
4
4
  import { lock } from './lock-unlock';
5
- import CreatePatternModal from './components/create-pattern-modal';
6
- import DuplicatePatternModal from './components/duplicate-pattern-modal';
5
+ import { default as CreatePatternModal, CreatePatternModalContents } from './components/create-pattern-modal';
6
+ import { default as DuplicatePatternModal, useDuplicatePatternProps } from './components/duplicate-pattern-modal';
7
7
  import RenamePatternModal from './components/rename-pattern-modal';
8
8
  import PatternsMenuItems from './components';
9
9
  import RenamePatternCategoryModal from './components/rename-pattern-category-modal';
10
- import { PATTERN_TYPES, PATTERN_DEFAULT_CATEGORY, PATTERN_USER_CATEGORY, EXCLUDED_PATTERN_SOURCES, PATTERN_SYNC_TYPES } from './constants';
10
+ import PartialSyncingControls from './components/partial-syncing-controls';
11
+ import { PATTERN_TYPES, PATTERN_DEFAULT_CATEGORY, PATTERN_USER_CATEGORY, EXCLUDED_PATTERN_SOURCES, PATTERN_SYNC_TYPES, PARTIAL_SYNCING_SUPPORTED_BLOCKS } from './constants';
11
12
  export const privateApis = {};
12
13
  lock(privateApis, {
13
14
  CreatePatternModal,
15
+ CreatePatternModalContents,
14
16
  DuplicatePatternModal,
17
+ useDuplicatePatternProps,
15
18
  RenamePatternModal,
16
19
  PatternsMenuItems,
17
20
  RenamePatternCategoryModal,
21
+ PartialSyncingControls,
18
22
  PATTERN_TYPES,
19
23
  PATTERN_DEFAULT_CATEGORY,
20
24
  PATTERN_USER_CATEGORY,
21
25
  EXCLUDED_PATTERN_SOURCES,
22
- PATTERN_SYNC_TYPES
26
+ PATTERN_SYNC_TYPES,
27
+ PARTIAL_SYNCING_SUPPORTED_BLOCKS
23
28
  });
24
29
  //# sourceMappingURL=private-apis.js.map
@@ -1 +1 @@
1
- {"version":3,"names":["lock","CreatePatternModal","DuplicatePatternModal","RenamePatternModal","PatternsMenuItems","RenamePatternCategoryModal","PATTERN_TYPES","PATTERN_DEFAULT_CATEGORY","PATTERN_USER_CATEGORY","EXCLUDED_PATTERN_SOURCES","PATTERN_SYNC_TYPES","privateApis"],"sources":["@wordpress/patterns/src/private-apis.js"],"sourcesContent":["/**\n * Internal dependencies\n */\nimport { lock } from './lock-unlock';\nimport CreatePatternModal from './components/create-pattern-modal';\nimport DuplicatePatternModal from './components/duplicate-pattern-modal';\nimport RenamePatternModal from './components/rename-pattern-modal';\nimport PatternsMenuItems from './components';\nimport RenamePatternCategoryModal from './components/rename-pattern-category-modal';\nimport {\n\tPATTERN_TYPES,\n\tPATTERN_DEFAULT_CATEGORY,\n\tPATTERN_USER_CATEGORY,\n\tEXCLUDED_PATTERN_SOURCES,\n\tPATTERN_SYNC_TYPES,\n} from './constants';\n\nexport const privateApis = {};\nlock( privateApis, {\n\tCreatePatternModal,\n\tDuplicatePatternModal,\n\tRenamePatternModal,\n\tPatternsMenuItems,\n\tRenamePatternCategoryModal,\n\tPATTERN_TYPES,\n\tPATTERN_DEFAULT_CATEGORY,\n\tPATTERN_USER_CATEGORY,\n\tEXCLUDED_PATTERN_SOURCES,\n\tPATTERN_SYNC_TYPES,\n} );\n"],"mappings":"AAAA;AACA;AACA;AACA,SAASA,IAAI,QAAQ,eAAe;AACpC,OAAOC,kBAAkB,MAAM,mCAAmC;AAClE,OAAOC,qBAAqB,MAAM,sCAAsC;AACxE,OAAOC,kBAAkB,MAAM,mCAAmC;AAClE,OAAOC,iBAAiB,MAAM,cAAc;AAC5C,OAAOC,0BAA0B,MAAM,4CAA4C;AACnF,SACCC,aAAa,EACbC,wBAAwB,EACxBC,qBAAqB,EACrBC,wBAAwB,EACxBC,kBAAkB,QACZ,aAAa;AAEpB,OAAO,MAAMC,WAAW,GAAG,CAAC,CAAC;AAC7BX,IAAI,CAAEW,WAAW,EAAE;EAClBV,kBAAkB;EAClBC,qBAAqB;EACrBC,kBAAkB;EAClBC,iBAAiB;EACjBC,0BAA0B;EAC1BC,aAAa;EACbC,wBAAwB;EACxBC,qBAAqB;EACrBC,wBAAwB;EACxBC;AACD,CAAE,CAAC"}
1
+ {"version":3,"names":["lock","default","CreatePatternModal","CreatePatternModalContents","DuplicatePatternModal","useDuplicatePatternProps","RenamePatternModal","PatternsMenuItems","RenamePatternCategoryModal","PartialSyncingControls","PATTERN_TYPES","PATTERN_DEFAULT_CATEGORY","PATTERN_USER_CATEGORY","EXCLUDED_PATTERN_SOURCES","PATTERN_SYNC_TYPES","PARTIAL_SYNCING_SUPPORTED_BLOCKS","privateApis"],"sources":["@wordpress/patterns/src/private-apis.js"],"sourcesContent":["/**\n * Internal dependencies\n */\nimport { lock } from './lock-unlock';\nimport {\n\tdefault as CreatePatternModal,\n\tCreatePatternModalContents,\n} from './components/create-pattern-modal';\nimport {\n\tdefault as DuplicatePatternModal,\n\tuseDuplicatePatternProps,\n} from './components/duplicate-pattern-modal';\nimport RenamePatternModal from './components/rename-pattern-modal';\nimport PatternsMenuItems from './components';\nimport RenamePatternCategoryModal from './components/rename-pattern-category-modal';\nimport PartialSyncingControls from './components/partial-syncing-controls';\nimport {\n\tPATTERN_TYPES,\n\tPATTERN_DEFAULT_CATEGORY,\n\tPATTERN_USER_CATEGORY,\n\tEXCLUDED_PATTERN_SOURCES,\n\tPATTERN_SYNC_TYPES,\n\tPARTIAL_SYNCING_SUPPORTED_BLOCKS,\n} from './constants';\n\nexport const privateApis = {};\nlock( privateApis, {\n\tCreatePatternModal,\n\tCreatePatternModalContents,\n\tDuplicatePatternModal,\n\tuseDuplicatePatternProps,\n\tRenamePatternModal,\n\tPatternsMenuItems,\n\tRenamePatternCategoryModal,\n\tPartialSyncingControls,\n\tPATTERN_TYPES,\n\tPATTERN_DEFAULT_CATEGORY,\n\tPATTERN_USER_CATEGORY,\n\tEXCLUDED_PATTERN_SOURCES,\n\tPATTERN_SYNC_TYPES,\n\tPARTIAL_SYNCING_SUPPORTED_BLOCKS,\n} );\n"],"mappings":"AAAA;AACA;AACA;AACA,SAASA,IAAI,QAAQ,eAAe;AACpC,SACCC,OAAO,IAAIC,kBAAkB,EAC7BC,0BAA0B,QACpB,mCAAmC;AAC1C,SACCF,OAAO,IAAIG,qBAAqB,EAChCC,wBAAwB,QAClB,sCAAsC;AAC7C,OAAOC,kBAAkB,MAAM,mCAAmC;AAClE,OAAOC,iBAAiB,MAAM,cAAc;AAC5C,OAAOC,0BAA0B,MAAM,4CAA4C;AACnF,OAAOC,sBAAsB,MAAM,uCAAuC;AAC1E,SACCC,aAAa,EACbC,wBAAwB,EACxBC,qBAAqB,EACrBC,wBAAwB,EACxBC,kBAAkB,EAClBC,gCAAgC,QAC1B,aAAa;AAEpB,OAAO,MAAMC,WAAW,GAAG,CAAC,CAAC;AAC7BhB,IAAI,CAAEgB,WAAW,EAAE;EAClBd,kBAAkB;EAClBC,0BAA0B;EAC1BC,qBAAqB;EACrBC,wBAAwB;EACxBC,kBAAkB;EAClBC,iBAAiB;EACjBC,0BAA0B;EAC1BC,sBAAsB;EACtBC,aAAa;EACbC,wBAAwB;EACxBC,qBAAqB;EACrBC,wBAAwB;EACxBC,kBAAkB;EAClBC;AACD,CAAE,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wordpress/patterns",
3
- "version": "1.8.0",
3
+ "version": "1.9.1-next.79a6196f.0",
4
4
  "description": "Management of user pattern editing.",
5
5
  "author": "The WordPress Contributors",
6
6
  "license": "GPL-2.0-or-later",
@@ -31,20 +31,21 @@
31
31
  ],
32
32
  "dependencies": {
33
33
  "@babel/runtime": "^7.16.0",
34
- "@wordpress/a11y": "^3.47.0",
35
- "@wordpress/block-editor": "^12.15.0",
36
- "@wordpress/blocks": "^12.24.0",
37
- "@wordpress/components": "^25.13.0",
38
- "@wordpress/compose": "^6.24.0",
39
- "@wordpress/core-data": "^6.24.0",
40
- "@wordpress/data": "^9.17.0",
41
- "@wordpress/element": "^5.24.0",
42
- "@wordpress/html-entities": "^3.47.0",
43
- "@wordpress/i18n": "^4.47.0",
44
- "@wordpress/icons": "^9.38.0",
45
- "@wordpress/notices": "^4.15.0",
46
- "@wordpress/private-apis": "^0.29.0",
47
- "@wordpress/url": "^3.48.0"
34
+ "@wordpress/a11y": "^3.48.1-next.79a6196f.0",
35
+ "@wordpress/block-editor": "^12.16.1-next.79a6196f.0",
36
+ "@wordpress/blocks": "^12.25.1-next.79a6196f.0",
37
+ "@wordpress/components": "^25.15.1-next.79a6196f.0",
38
+ "@wordpress/compose": "^6.25.1-next.79a6196f.0",
39
+ "@wordpress/core-data": "^6.25.1-next.79a6196f.0",
40
+ "@wordpress/data": "^9.18.1-next.79a6196f.0",
41
+ "@wordpress/element": "^5.25.1-next.79a6196f.0",
42
+ "@wordpress/html-entities": "^3.48.1-next.79a6196f.0",
43
+ "@wordpress/i18n": "^4.48.1-next.79a6196f.0",
44
+ "@wordpress/icons": "^9.39.1-next.79a6196f.0",
45
+ "@wordpress/notices": "^4.16.1-next.79a6196f.0",
46
+ "@wordpress/private-apis": "^0.30.1-next.79a6196f.0",
47
+ "@wordpress/url": "^3.49.1-next.79a6196f.0",
48
+ "nanoid": "^3.3.4"
48
49
  },
49
50
  "peerDependencies": {
50
51
  "react": "^18.0.0",
@@ -53,5 +54,5 @@
53
54
  "publishConfig": {
54
55
  "access": "public"
55
56
  },
56
- "gitHead": "d98dff8ea96f29cfea045bf964269f46f040d539"
57
+ "gitHead": "1e74b942ac0119a22ceaaf5c9594263f3ec516ab"
57
58
  }
@@ -28,11 +28,25 @@ import CategorySelector, { CATEGORY_SLUG } from './category-selector';
28
28
  import { unlock } from '../lock-unlock';
29
29
 
30
30
  export default function CreatePatternModal( {
31
+ className = 'patterns-menu-items__convert-modal',
32
+ modalTitle = __( 'Create pattern' ),
33
+ ...restProps
34
+ } ) {
35
+ return (
36
+ <Modal
37
+ title={ modalTitle }
38
+ onRequestClose={ restProps.onClose }
39
+ overlayClassName={ className }
40
+ >
41
+ <CreatePatternModalContents { ...restProps } />
42
+ </Modal>
43
+ );
44
+ }
45
+
46
+ export function CreatePatternModalContents( {
31
47
  confirmLabel = __( 'Create' ),
32
48
  defaultCategories = [],
33
- className = 'patterns-menu-items__convert-modal',
34
49
  content,
35
- modalTitle = __( 'Create pattern' ),
36
50
  onClose,
37
51
  onError,
38
52
  onSuccess,
@@ -63,24 +77,27 @@ export default function CreatePatternModal( {
63
77
  const categoryMap = useMemo( () => {
64
78
  // Merge the user and core pattern categories and remove any duplicates.
65
79
  const uniqueCategories = new Map();
66
- [ ...userPatternCategories, ...corePatternCategories ].forEach(
67
- ( category ) => {
68
- if (
69
- ! uniqueCategories.has( category.label ) &&
70
- // There are two core categories with `Post` label so explicitly remove the one with
71
- // the `query` slug to avoid any confusion.
72
- category.name !== 'query'
73
- ) {
74
- // We need to store the name separately as this is used as the slug in the
75
- // taxonomy and may vary from the label.
76
- uniqueCategories.set( category.label, {
77
- label: category.label,
78
- value: category.label,
79
- name: category.name,
80
- } );
81
- }
80
+ userPatternCategories.forEach( ( category ) => {
81
+ uniqueCategories.set( category.label.toLowerCase(), {
82
+ label: category.label,
83
+ name: category.name,
84
+ id: category.id,
85
+ } );
86
+ } );
87
+
88
+ corePatternCategories.forEach( ( category ) => {
89
+ if (
90
+ ! uniqueCategories.has( category.label.toLowerCase() ) &&
91
+ // There are two core categories with `Post` label so explicitly remove the one with
92
+ // the `query` slug to avoid any confusion.
93
+ category.name !== 'query'
94
+ ) {
95
+ uniqueCategories.set( category.label.toLowerCase(), {
96
+ label: category.label,
97
+ name: category.name,
98
+ } );
82
99
  }
83
- );
100
+ } );
84
101
  return uniqueCategories;
85
102
  }, [ userPatternCategories, corePatternCategories ] );
86
103
 
@@ -126,9 +143,13 @@ export default function CreatePatternModal( {
126
143
  */
127
144
  async function findOrCreateTerm( term ) {
128
145
  try {
129
- // We need to match any existing term to the correct slug to prevent duplicates, eg.
130
- // the core `Headers` category uses the singular `header` as the slug.
131
- const existingTerm = categoryMap.get( term );
146
+ const existingTerm = categoryMap.get( term.toLowerCase() );
147
+ if ( existingTerm && existingTerm.id ) {
148
+ return existingTerm.id;
149
+ }
150
+ // If we have an existing core category we need to match the new user category to the
151
+ // correct slug rather than autogenerating it to prevent duplicates, eg. the core `Headers`
152
+ // category uses the singular `header` as the slug.
132
153
  const termData = existingTerm
133
154
  ? { name: existingTerm.label, slug: existingTerm.name }
134
155
  : { name: term };
@@ -148,78 +169,68 @@ export default function CreatePatternModal( {
148
169
  return error.data.term_id;
149
170
  }
150
171
  }
151
-
152
172
  return (
153
- <Modal
154
- title={ modalTitle }
155
- onRequestClose={ () => {
156
- onClose();
157
- setTitle( '' );
173
+ <form
174
+ onSubmit={ ( event ) => {
175
+ event.preventDefault();
176
+ onCreate( title, syncType );
158
177
  } }
159
- overlayClassName={ className }
160
178
  >
161
- <form
162
- onSubmit={ ( event ) => {
163
- event.preventDefault();
164
- onCreate( title, syncType );
165
- } }
166
- >
167
- <VStack spacing="5">
168
- <TextControl
169
- label={ __( 'Name' ) }
170
- value={ title }
171
- onChange={ setTitle }
172
- placeholder={ __( 'My pattern' ) }
173
- className="patterns-create-modal__name-input"
174
- __nextHasNoMarginBottom
179
+ <VStack spacing="5">
180
+ <TextControl
181
+ label={ __( 'Name' ) }
182
+ value={ title }
183
+ onChange={ setTitle }
184
+ placeholder={ __( 'My pattern' ) }
185
+ className="patterns-create-modal__name-input"
186
+ __nextHasNoMarginBottom
187
+ __next40pxDefaultSize
188
+ />
189
+ <CategorySelector
190
+ categoryTerms={ categoryTerms }
191
+ onChange={ setCategoryTerms }
192
+ categoryMap={ categoryMap }
193
+ />
194
+ <ToggleControl
195
+ label={ _x(
196
+ 'Synced',
197
+ 'Option that makes an individual pattern synchronized'
198
+ ) }
199
+ help={ __(
200
+ 'Sync this pattern across multiple locations.'
201
+ ) }
202
+ checked={ syncType === PATTERN_SYNC_TYPES.full }
203
+ onChange={ () => {
204
+ setSyncType(
205
+ syncType === PATTERN_SYNC_TYPES.full
206
+ ? PATTERN_SYNC_TYPES.unsynced
207
+ : PATTERN_SYNC_TYPES.full
208
+ );
209
+ } }
210
+ />
211
+ <HStack justify="right">
212
+ <Button
175
213
  __next40pxDefaultSize
176
- />
177
- <CategorySelector
178
- categoryTerms={ categoryTerms }
179
- onChange={ setCategoryTerms }
180
- categoryMap={ categoryMap }
181
- />
182
- <ToggleControl
183
- label={ _x(
184
- 'Synced',
185
- 'Option that makes an individual pattern synchronized'
186
- ) }
187
- help={ __(
188
- 'Sync this pattern across multiple locations.'
189
- ) }
190
- checked={ syncType === PATTERN_SYNC_TYPES.full }
191
- onChange={ () => {
192
- setSyncType(
193
- syncType === PATTERN_SYNC_TYPES.full
194
- ? PATTERN_SYNC_TYPES.unsynced
195
- : PATTERN_SYNC_TYPES.full
196
- );
214
+ variant="tertiary"
215
+ onClick={ () => {
216
+ onClose();
217
+ setTitle( '' );
197
218
  } }
198
- />
199
- <HStack justify="right">
200
- <Button
201
- __next40pxDefaultSize
202
- variant="tertiary"
203
- onClick={ () => {
204
- onClose();
205
- setTitle( '' );
206
- } }
207
- >
208
- { __( 'Cancel' ) }
209
- </Button>
219
+ >
220
+ { __( 'Cancel' ) }
221
+ </Button>
210
222
 
211
- <Button
212
- __next40pxDefaultSize
213
- variant="primary"
214
- type="submit"
215
- aria-disabled={ ! title || isSaving }
216
- isBusy={ isSaving }
217
- >
218
- { confirmLabel }
219
- </Button>
220
- </HStack>
221
- </VStack>
222
- </form>
223
- </Modal>
223
+ <Button
224
+ __next40pxDefaultSize
225
+ variant="primary"
226
+ type="submit"
227
+ aria-disabled={ ! title || isSaving }
228
+ isBusy={ isSaving }
229
+ >
230
+ { confirmLabel }
231
+ </Button>
232
+ </HStack>
233
+ </VStack>
234
+ </form>
224
235
  );
225
236
  }
@@ -29,11 +29,7 @@ function getTermLabels( pattern, categories ) {
29
29
  .map( ( category ) => category.label );
30
30
  }
31
31
 
32
- export default function DuplicatePatternModal( {
33
- pattern,
34
- onClose,
35
- onSuccess,
36
- } ) {
32
+ export function useDuplicatePatternProps( { pattern, onSuccess } ) {
37
33
  const { createSuccessNotice } = useDispatch( noticesStore );
38
34
  const categories = useSelect( ( select ) => {
39
35
  const { getUserPatternCategories, getBlockPatternCategories } =
@@ -44,12 +40,10 @@ export default function DuplicatePatternModal( {
44
40
  user: getUserPatternCategories(),
45
41
  };
46
42
  } );
47
-
48
43
  if ( ! pattern ) {
49
44
  return null;
50
45
  }
51
-
52
- const duplicatedProps = {
46
+ return {
53
47
  content: pattern.content,
54
48
  defaultCategories: getTermLabels( pattern, categories ),
55
49
  defaultSyncType:
@@ -63,31 +57,39 @@ export default function DuplicatePatternModal( {
63
57
  ? pattern.title
64
58
  : pattern.title.raw
65
59
  ),
66
- };
60
+ onSuccess: ( { pattern: newPattern } ) => {
61
+ createSuccessNotice(
62
+ sprintf(
63
+ // translators: %s: The new pattern's title e.g. 'Call to action (copy)'.
64
+ __( '"%s" duplicated.' ),
65
+ newPattern.title.raw
66
+ ),
67
+ {
68
+ type: 'snackbar',
69
+ id: 'patterns-create',
70
+ }
71
+ );
67
72
 
68
- function handleOnSuccess( { pattern: newPattern } ) {
69
- createSuccessNotice(
70
- sprintf(
71
- // translators: %s: The new pattern's title e.g. 'Call to action (copy)'.
72
- __( '"%s" duplicated.' ),
73
- newPattern.title.raw
74
- ),
75
- {
76
- type: 'snackbar',
77
- id: 'patterns-create',
78
- }
79
- );
73
+ onSuccess?.( { pattern: newPattern } );
74
+ },
75
+ };
76
+ }
80
77
 
81
- onSuccess?.( { pattern: newPattern } );
78
+ export default function DuplicatePatternModal( {
79
+ pattern,
80
+ onClose,
81
+ onSuccess,
82
+ } ) {
83
+ const duplicatedProps = useDuplicatePatternProps( { pattern, onSuccess } );
84
+ if ( ! pattern ) {
85
+ return null;
82
86
  }
83
-
84
87
  return (
85
88
  <CreatePatternModal
86
89
  modalTitle={ __( 'Duplicate pattern' ) }
87
90
  confirmLabel={ __( 'Duplicate' ) }
88
91
  onClose={ onClose }
89
92
  onError={ onClose }
90
- onSuccess={ handleOnSuccess }
91
93
  { ...duplicatedProps }
92
94
  />
93
95
  );
@@ -0,0 +1,110 @@
1
+ /**
2
+ * External dependencies
3
+ */
4
+ import { nanoid } from 'nanoid';
5
+
6
+ /**
7
+ * WordPress dependencies
8
+ */
9
+ import { InspectorControls } from '@wordpress/block-editor';
10
+ import { BaseControl, CheckboxControl } from '@wordpress/components';
11
+ import { __ } from '@wordpress/i18n';
12
+
13
+ /**
14
+ * Internal dependencies
15
+ */
16
+ import { PARTIAL_SYNCING_SUPPORTED_BLOCKS } from '../constants';
17
+
18
+ function PartialSyncingControls( { name, attributes, setAttributes } ) {
19
+ const syncedAttributes = PARTIAL_SYNCING_SUPPORTED_BLOCKS[ name ];
20
+ const attributeSources = Object.keys( syncedAttributes ).map(
21
+ ( attributeName ) =>
22
+ attributes.metadata?.bindings?.[ attributeName ]?.source?.name
23
+ );
24
+ const isConnectedToOtherSources = attributeSources.every(
25
+ ( source ) => source && source !== 'pattern_attributes'
26
+ );
27
+
28
+ // Render nothing if all supported attributes are connected to other sources.
29
+ if ( isConnectedToOtherSources ) {
30
+ return null;
31
+ }
32
+
33
+ function updateBindings( isChecked ) {
34
+ let updatedBindings = {
35
+ ...attributes?.metadata?.bindings,
36
+ };
37
+
38
+ if ( ! isChecked ) {
39
+ for ( const attributeName of Object.keys( syncedAttributes ) ) {
40
+ if (
41
+ updatedBindings[ attributeName ]?.source?.name ===
42
+ 'pattern_attributes'
43
+ ) {
44
+ delete updatedBindings[ attributeName ];
45
+ }
46
+ }
47
+ if ( ! Object.keys( updatedBindings ).length ) {
48
+ updatedBindings = undefined;
49
+ }
50
+ setAttributes( {
51
+ metadata: {
52
+ ...attributes.metadata,
53
+ bindings: updatedBindings,
54
+ },
55
+ } );
56
+ return;
57
+ }
58
+
59
+ for ( const attributeName of Object.keys( syncedAttributes ) ) {
60
+ if ( ! updatedBindings[ attributeName ] ) {
61
+ updatedBindings[ attributeName ] = {
62
+ source: {
63
+ name: 'pattern_attributes',
64
+ },
65
+ };
66
+ }
67
+ }
68
+
69
+ if ( typeof attributes.metadata?.id === 'string' ) {
70
+ setAttributes( {
71
+ metadata: {
72
+ ...attributes.metadata,
73
+ bindings: updatedBindings,
74
+ },
75
+ } );
76
+ return;
77
+ }
78
+
79
+ const id = nanoid( 6 );
80
+ setAttributes( {
81
+ metadata: {
82
+ ...attributes.metadata,
83
+ id,
84
+ bindings: updatedBindings,
85
+ },
86
+ } );
87
+ }
88
+
89
+ return (
90
+ <InspectorControls group="advanced">
91
+ <BaseControl __nextHasNoMarginBottom>
92
+ <BaseControl.VisualLabel>
93
+ { __( 'Pattern overrides' ) }
94
+ </BaseControl.VisualLabel>
95
+ <CheckboxControl
96
+ __nextHasNoMarginBottom
97
+ label={ __( 'Allow instance overrides' ) }
98
+ checked={ attributeSources.some(
99
+ ( source ) => source === 'pattern_attributes'
100
+ ) }
101
+ onChange={ ( isChecked ) => {
102
+ updateBindings( isChecked );
103
+ } }
104
+ />
105
+ </BaseControl>
106
+ </InspectorControls>
107
+ );
108
+ }
109
+
110
+ export default PartialSyncingControls;
@@ -138,6 +138,7 @@ export default function RenamePatternCategoryModal( {
138
138
  <TextControl
139
139
  ref={ textControlRef }
140
140
  __nextHasNoMarginBottom
141
+ __next40pxDefaultSize
141
142
  label={ __( 'Name' ) }
142
143
  value={ name }
143
144
  onChange={ onChange }
@@ -154,10 +155,15 @@ export default function RenamePatternCategoryModal( {
154
155
  ) }
155
156
  </VStack>
156
157
  <HStack justify="right">
157
- <Button variant="tertiary" onClick={ onRequestClose }>
158
+ <Button
159
+ __next40pxDefaultSize
160
+ variant="tertiary"
161
+ onClick={ onRequestClose }
162
+ >
158
163
  { __( 'Cancel' ) }
159
164
  </Button>
160
165
  <Button
166
+ __next40pxDefaultSize
161
167
  variant="primary"
162
168
  type="submit"
163
169
  aria-disabled={
@@ -93,6 +93,7 @@ export default function RenamePatternModal( {
93
93
  <VStack spacing="5">
94
94
  <TextControl
95
95
  __nextHasNoMarginBottom
96
+ __next40pxDefaultSize
96
97
  label={ __( 'Name' ) }
97
98
  value={ name }
98
99
  onChange={ setName }
@@ -100,11 +101,19 @@ export default function RenamePatternModal( {
100
101
  />
101
102
 
102
103
  <HStack justify="right">
103
- <Button variant="tertiary" onClick={ onRequestClose }>
104
+ <Button
105
+ __next40pxDefaultSize
106
+ variant="tertiary"
107
+ onClick={ onRequestClose }
108
+ >
104
109
  { __( 'Cancel' ) }
105
110
  </Button>
106
111
 
107
- <Button variant="primary" type="submit">
112
+ <Button
113
+ __next40pxDefaultSize
114
+ variant="primary"
115
+ type="submit"
116
+ >
108
117
  { __( 'Save' ) }
109
118
  </Button>
110
119
  </HStack>
package/src/constants.js CHANGED
@@ -1,3 +1,8 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { __ } from '@wordpress/i18n';
5
+
1
6
  export const PATTERN_TYPES = {
2
7
  theme: 'pattern',
3
8
  user: 'wp_block',
@@ -14,3 +19,8 @@ export const PATTERN_SYNC_TYPES = {
14
19
  full: 'fully',
15
20
  unsynced: 'unsynced',
16
21
  };
22
+
23
+ // TODO: This should not be hardcoded. Maybe there should be a config and/or an UI.
24
+ export const PARTIAL_SYNCING_SUPPORTED_BLOCKS = {
25
+ 'core/paragraph': { content: __( 'Content' ) },
26
+ };
@@ -2,29 +2,41 @@
2
2
  * Internal dependencies
3
3
  */
4
4
  import { lock } from './lock-unlock';
5
- import CreatePatternModal from './components/create-pattern-modal';
6
- import DuplicatePatternModal from './components/duplicate-pattern-modal';
5
+ import {
6
+ default as CreatePatternModal,
7
+ CreatePatternModalContents,
8
+ } from './components/create-pattern-modal';
9
+ import {
10
+ default as DuplicatePatternModal,
11
+ useDuplicatePatternProps,
12
+ } from './components/duplicate-pattern-modal';
7
13
  import RenamePatternModal from './components/rename-pattern-modal';
8
14
  import PatternsMenuItems from './components';
9
15
  import RenamePatternCategoryModal from './components/rename-pattern-category-modal';
16
+ import PartialSyncingControls from './components/partial-syncing-controls';
10
17
  import {
11
18
  PATTERN_TYPES,
12
19
  PATTERN_DEFAULT_CATEGORY,
13
20
  PATTERN_USER_CATEGORY,
14
21
  EXCLUDED_PATTERN_SOURCES,
15
22
  PATTERN_SYNC_TYPES,
23
+ PARTIAL_SYNCING_SUPPORTED_BLOCKS,
16
24
  } from './constants';
17
25
 
18
26
  export const privateApis = {};
19
27
  lock( privateApis, {
20
28
  CreatePatternModal,
29
+ CreatePatternModalContents,
21
30
  DuplicatePatternModal,
31
+ useDuplicatePatternProps,
22
32
  RenamePatternModal,
23
33
  PatternsMenuItems,
24
34
  RenamePatternCategoryModal,
35
+ PartialSyncingControls,
25
36
  PATTERN_TYPES,
26
37
  PATTERN_DEFAULT_CATEGORY,
27
38
  PATTERN_USER_CATEGORY,
28
39
  EXCLUDED_PATTERN_SOURCES,
29
40
  PATTERN_SYNC_TYPES,
41
+ PARTIAL_SYNCING_SUPPORTED_BLOCKS,
30
42
  } );