@wordpress/patterns 1.5.0 → 1.6.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.
- package/CHANGELOG.md +2 -0
- package/build/components/rename-pattern-category-modal.js +44 -5
- package/build/components/rename-pattern-category-modal.js.map +1 -1
- package/build-module/components/rename-pattern-category-modal.js +45 -6
- package/build-module/components/rename-pattern-category-modal.js.map +1 -1
- package/build-style/style-rtl.css +9 -0
- package/build-style/style.css +9 -0
- package/package.json +16 -15
- package/src/components/rename-pattern-category-modal.js +66 -12
- package/src/components/style.scss +9 -0
package/CHANGELOG.md
CHANGED
|
@@ -12,6 +12,7 @@ var _element = require("@wordpress/element");
|
|
|
12
12
|
var _htmlEntities = require("@wordpress/html-entities");
|
|
13
13
|
var _i18n = require("@wordpress/i18n");
|
|
14
14
|
var _notices = require("@wordpress/notices");
|
|
15
|
+
var _a11y = require("@wordpress/a11y");
|
|
15
16
|
var _categorySelector = require("./category-selector");
|
|
16
17
|
/**
|
|
17
18
|
* WordPress dependencies
|
|
@@ -23,13 +24,18 @@ var _categorySelector = require("./category-selector");
|
|
|
23
24
|
|
|
24
25
|
function RenamePatternCategoryModal({
|
|
25
26
|
category,
|
|
27
|
+
existingCategories,
|
|
26
28
|
onClose,
|
|
27
29
|
onError,
|
|
28
30
|
onSuccess,
|
|
29
31
|
...props
|
|
30
32
|
}) {
|
|
33
|
+
const id = (0, _element.useId)();
|
|
34
|
+
const textControlRef = (0, _element.useRef)();
|
|
31
35
|
const [name, setName] = (0, _element.useState)((0, _htmlEntities.decodeEntities)(category.name));
|
|
32
36
|
const [isSaving, setIsSaving] = (0, _element.useState)(false);
|
|
37
|
+
const [validationMessage, setValidationMessage] = (0, _element.useState)(false);
|
|
38
|
+
const validationMessageId = validationMessage ? `patterns-rename-pattern-category-modal__validation-message-${id}` : undefined;
|
|
33
39
|
const {
|
|
34
40
|
saveEntityRecord,
|
|
35
41
|
invalidateResolution
|
|
@@ -38,9 +44,35 @@ function RenamePatternCategoryModal({
|
|
|
38
44
|
createErrorNotice,
|
|
39
45
|
createSuccessNotice
|
|
40
46
|
} = (0, _data.useDispatch)(_notices.store);
|
|
41
|
-
const
|
|
47
|
+
const onChange = newName => {
|
|
48
|
+
if (validationMessage) {
|
|
49
|
+
setValidationMessage(undefined);
|
|
50
|
+
}
|
|
51
|
+
setName(newName);
|
|
52
|
+
};
|
|
53
|
+
const onSave = async event => {
|
|
42
54
|
event.preventDefault();
|
|
43
|
-
if (
|
|
55
|
+
if (isSaving) {
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
if (!name || name === category.name) {
|
|
59
|
+
const message = (0, _i18n.__)('Please enter a new name for this category.');
|
|
60
|
+
(0, _a11y.speak)(message, 'assertive');
|
|
61
|
+
setValidationMessage(message);
|
|
62
|
+
textControlRef.current?.focus();
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Check existing categories to avoid creating duplicates.
|
|
67
|
+
if (existingCategories.patternCategories.find(existingCategory => {
|
|
68
|
+
// Compare the id so that the we don't disallow the user changing the case of their current category
|
|
69
|
+
// (i.e. renaming 'test' to 'Test').
|
|
70
|
+
return existingCategory.id !== category.id && existingCategory.label.toLowerCase() === name.toLowerCase();
|
|
71
|
+
})) {
|
|
72
|
+
const message = (0, _i18n.__)('This category already exists. Please use a different name.');
|
|
73
|
+
(0, _a11y.speak)(message, 'assertive');
|
|
74
|
+
setValidationMessage(message);
|
|
75
|
+
textControlRef.current?.focus();
|
|
44
76
|
return;
|
|
45
77
|
}
|
|
46
78
|
try {
|
|
@@ -82,16 +114,23 @@ function RenamePatternCategoryModal({
|
|
|
82
114
|
onRequestClose: onRequestClose,
|
|
83
115
|
...props
|
|
84
116
|
}, (0, _react.createElement)("form", {
|
|
85
|
-
onSubmit:
|
|
117
|
+
onSubmit: onSave
|
|
86
118
|
}, (0, _react.createElement)(_components.__experimentalVStack, {
|
|
87
119
|
spacing: "5"
|
|
120
|
+
}, (0, _react.createElement)(_components.__experimentalVStack, {
|
|
121
|
+
spacing: "2"
|
|
88
122
|
}, (0, _react.createElement)(_components.TextControl, {
|
|
123
|
+
ref: textControlRef,
|
|
89
124
|
__nextHasNoMarginBottom: true,
|
|
90
125
|
label: (0, _i18n.__)('Name'),
|
|
91
126
|
value: name,
|
|
92
|
-
onChange:
|
|
127
|
+
onChange: onChange,
|
|
128
|
+
"aria-describedby": validationMessageId,
|
|
93
129
|
required: true
|
|
94
|
-
}), (0, _react.createElement)(
|
|
130
|
+
}), validationMessage && (0, _react.createElement)("span", {
|
|
131
|
+
className: "patterns-rename-pattern-category-modal__validation-message",
|
|
132
|
+
id: validationMessageId
|
|
133
|
+
}, validationMessage)), (0, _react.createElement)(_components.__experimentalHStack, {
|
|
95
134
|
justify: "right"
|
|
96
135
|
}, (0, _react.createElement)(_components.Button, {
|
|
97
136
|
variant: "tertiary",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["_components","require","_coreData","_data","_element","_htmlEntities","_i18n","_notices","_categorySelector","RenamePatternCategoryModal","category","onClose","onError","onSuccess","props","name","setName","useState","decodeEntities","isSaving","setIsSaving","saveEntityRecord","invalidateResolution","useDispatch","coreStore","createErrorNotice","createSuccessNotice","noticesStore","
|
|
1
|
+
{"version":3,"names":["_components","require","_coreData","_data","_element","_htmlEntities","_i18n","_notices","_a11y","_categorySelector","RenamePatternCategoryModal","category","existingCategories","onClose","onError","onSuccess","props","id","useId","textControlRef","useRef","name","setName","useState","decodeEntities","isSaving","setIsSaving","validationMessage","setValidationMessage","validationMessageId","undefined","saveEntityRecord","invalidateResolution","useDispatch","coreStore","createErrorNotice","createSuccessNotice","noticesStore","onChange","newName","onSave","event","preventDefault","message","__","speak","current","focus","patternCategories","find","existingCategory","label","toLowerCase","savedRecord","CATEGORY_SLUG","slug","type","error","onRequestClose","_react","createElement","Modal","title","onSubmit","__experimentalVStack","spacing","TextControl","ref","__nextHasNoMarginBottom","value","required","className","__experimentalHStack","justify","Button","variant","onClick","isBusy"],"sources":["@wordpress/patterns/src/components/rename-pattern-category-modal.js"],"sourcesContent":["/**\n * WordPress dependencies\n */\nimport {\n\tModal,\n\tButton,\n\tTextControl,\n\t__experimentalHStack as HStack,\n\t__experimentalVStack as VStack,\n} from '@wordpress/components';\nimport { store as coreStore } from '@wordpress/core-data';\nimport { useDispatch } from '@wordpress/data';\nimport { useId, useRef, useState } from '@wordpress/element';\nimport { decodeEntities } from '@wordpress/html-entities';\nimport { __ } from '@wordpress/i18n';\nimport { store as noticesStore } from '@wordpress/notices';\nimport { speak } from '@wordpress/a11y';\n\n/**\n * Internal dependencies\n */\nimport { CATEGORY_SLUG } from './category-selector';\n\nexport default function RenamePatternCategoryModal( {\n\tcategory,\n\texistingCategories,\n\tonClose,\n\tonError,\n\tonSuccess,\n\t...props\n} ) {\n\tconst id = useId();\n\tconst textControlRef = useRef();\n\tconst [ name, setName ] = useState( decodeEntities( category.name ) );\n\tconst [ isSaving, setIsSaving ] = useState( false );\n\tconst [ validationMessage, setValidationMessage ] = useState( false );\n\tconst validationMessageId = validationMessage\n\t\t? `patterns-rename-pattern-category-modal__validation-message-${ id }`\n\t\t: undefined;\n\n\tconst { saveEntityRecord, invalidateResolution } = useDispatch( coreStore );\n\tconst { createErrorNotice, createSuccessNotice } =\n\t\tuseDispatch( noticesStore );\n\n\tconst onChange = ( newName ) => {\n\t\tif ( validationMessage ) {\n\t\t\tsetValidationMessage( undefined );\n\t\t}\n\t\tsetName( newName );\n\t};\n\n\tconst onSave = async ( event ) => {\n\t\tevent.preventDefault();\n\n\t\tif ( isSaving ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( ! name || name === category.name ) {\n\t\t\tconst message = __( 'Please enter a new name for this category.' );\n\t\t\tspeak( message, 'assertive' );\n\t\t\tsetValidationMessage( message );\n\t\t\ttextControlRef.current?.focus();\n\t\t\treturn;\n\t\t}\n\n\t\t// Check existing categories to avoid creating duplicates.\n\t\tif (\n\t\t\texistingCategories.patternCategories.find( ( existingCategory ) => {\n\t\t\t\t// Compare the id so that the we don't disallow the user changing the case of their current category\n\t\t\t\t// (i.e. renaming 'test' to 'Test').\n\t\t\t\treturn (\n\t\t\t\t\texistingCategory.id !== category.id &&\n\t\t\t\t\texistingCategory.label.toLowerCase() === name.toLowerCase()\n\t\t\t\t);\n\t\t\t} )\n\t\t) {\n\t\t\tconst message = __(\n\t\t\t\t'This category already exists. Please use a different name.'\n\t\t\t);\n\t\t\tspeak( message, 'assertive' );\n\t\t\tsetValidationMessage( message );\n\t\t\ttextControlRef.current?.focus();\n\t\t\treturn;\n\t\t}\n\n\t\ttry {\n\t\t\tsetIsSaving( true );\n\n\t\t\t// User pattern category properties may differ as they can be\n\t\t\t// normalized for use alongside template part areas, core pattern\n\t\t\t// categories etc. As a result we won't just destructure the passed\n\t\t\t// category object.\n\t\t\tconst savedRecord = await saveEntityRecord(\n\t\t\t\t'taxonomy',\n\t\t\t\tCATEGORY_SLUG,\n\t\t\t\t{\n\t\t\t\t\tid: category.id,\n\t\t\t\t\tslug: category.slug,\n\t\t\t\t\tname,\n\t\t\t\t}\n\t\t\t);\n\n\t\t\tinvalidateResolution( 'getUserPatternCategories' );\n\t\t\tonSuccess?.( savedRecord );\n\t\t\tonClose();\n\n\t\t\tcreateSuccessNotice( __( 'Pattern category renamed.' ), {\n\t\t\t\ttype: 'snackbar',\n\t\t\t\tid: 'pattern-category-update',\n\t\t\t} );\n\t\t} catch ( error ) {\n\t\t\tonError?.();\n\t\t\tcreateErrorNotice( error.message, {\n\t\t\t\ttype: 'snackbar',\n\t\t\t\tid: 'pattern-category-update',\n\t\t\t} );\n\t\t} finally {\n\t\t\tsetIsSaving( false );\n\t\t\tsetName( '' );\n\t\t}\n\t};\n\n\tconst onRequestClose = () => {\n\t\tonClose();\n\t\tsetName( '' );\n\t};\n\n\treturn (\n\t\t<Modal\n\t\t\ttitle={ __( 'Rename' ) }\n\t\t\tonRequestClose={ onRequestClose }\n\t\t\t{ ...props }\n\t\t>\n\t\t\t<form onSubmit={ onSave }>\n\t\t\t\t<VStack spacing=\"5\">\n\t\t\t\t\t<VStack spacing=\"2\">\n\t\t\t\t\t\t<TextControl\n\t\t\t\t\t\t\tref={ textControlRef }\n\t\t\t\t\t\t\t__nextHasNoMarginBottom\n\t\t\t\t\t\t\tlabel={ __( 'Name' ) }\n\t\t\t\t\t\t\tvalue={ name }\n\t\t\t\t\t\t\tonChange={ onChange }\n\t\t\t\t\t\t\taria-describedby={ validationMessageId }\n\t\t\t\t\t\t\trequired\n\t\t\t\t\t\t/>\n\t\t\t\t\t\t{ validationMessage && (\n\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\tclassName=\"patterns-rename-pattern-category-modal__validation-message\"\n\t\t\t\t\t\t\t\tid={ validationMessageId }\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{ validationMessage }\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t) }\n\t\t\t\t\t</VStack>\n\t\t\t\t\t<HStack justify=\"right\">\n\t\t\t\t\t\t<Button variant=\"tertiary\" onClick={ onRequestClose }>\n\t\t\t\t\t\t\t{ __( 'Cancel' ) }\n\t\t\t\t\t\t</Button>\n\t\t\t\t\t\t<Button\n\t\t\t\t\t\t\tvariant=\"primary\"\n\t\t\t\t\t\t\ttype=\"submit\"\n\t\t\t\t\t\t\taria-disabled={\n\t\t\t\t\t\t\t\t! name || name === category.name || isSaving\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tisBusy={ isSaving }\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{ __( 'Save' ) }\n\t\t\t\t\t\t</Button>\n\t\t\t\t\t</HStack>\n\t\t\t\t</VStack>\n\t\t\t</form>\n\t\t</Modal>\n\t);\n}\n"],"mappings":";;;;;;;AAGA,IAAAA,WAAA,GAAAC,OAAA;AAOA,IAAAC,SAAA,GAAAD,OAAA;AACA,IAAAE,KAAA,GAAAF,OAAA;AACA,IAAAG,QAAA,GAAAH,OAAA;AACA,IAAAI,aAAA,GAAAJ,OAAA;AACA,IAAAK,KAAA,GAAAL,OAAA;AACA,IAAAM,QAAA,GAAAN,OAAA;AACA,IAAAO,KAAA,GAAAP,OAAA;AAKA,IAAAQ,iBAAA,GAAAR,OAAA;AArBA;AACA;AACA;;AAgBA;AACA;AACA;;AAGe,SAASS,0BAA0BA,CAAE;EACnDC,QAAQ;EACRC,kBAAkB;EAClBC,OAAO;EACPC,OAAO;EACPC,SAAS;EACT,GAAGC;AACJ,CAAC,EAAG;EACH,MAAMC,EAAE,GAAG,IAAAC,cAAK,EAAC,CAAC;EAClB,MAAMC,cAAc,GAAG,IAAAC,eAAM,EAAC,CAAC;EAC/B,MAAM,CAAEC,IAAI,EAAEC,OAAO,CAAE,GAAG,IAAAC,iBAAQ,EAAE,IAAAC,4BAAc,EAAEb,QAAQ,CAACU,IAAK,CAAE,CAAC;EACrE,MAAM,CAAEI,QAAQ,EAAEC,WAAW,CAAE,GAAG,IAAAH,iBAAQ,EAAE,KAAM,CAAC;EACnD,MAAM,CAAEI,iBAAiB,EAAEC,oBAAoB,CAAE,GAAG,IAAAL,iBAAQ,EAAE,KAAM,CAAC;EACrE,MAAMM,mBAAmB,GAAGF,iBAAiB,GACzC,8DAA8DV,EAAI,EAAC,GACpEa,SAAS;EAEZ,MAAM;IAAEC,gBAAgB;IAAEC;EAAqB,CAAC,GAAG,IAAAC,iBAAW,EAAEC,eAAU,CAAC;EAC3E,MAAM;IAAEC,iBAAiB;IAAEC;EAAoB,CAAC,GAC/C,IAAAH,iBAAW,EAAEI,cAAa,CAAC;EAE5B,MAAMC,QAAQ,GAAKC,OAAO,IAAM;IAC/B,IAAKZ,iBAAiB,EAAG;MACxBC,oBAAoB,CAAEE,SAAU,CAAC;IAClC;IACAR,OAAO,CAAEiB,OAAQ,CAAC;EACnB,CAAC;EAED,MAAMC,MAAM,GAAG,MAAQC,KAAK,IAAM;IACjCA,KAAK,CAACC,cAAc,CAAC,CAAC;IAEtB,IAAKjB,QAAQ,EAAG;MACf;IACD;IAEA,IAAK,CAAEJ,IAAI,IAAIA,IAAI,KAAKV,QAAQ,CAACU,IAAI,EAAG;MACvC,MAAMsB,OAAO,GAAG,IAAAC,QAAE,EAAE,4CAA6C,CAAC;MAClE,IAAAC,WAAK,EAAEF,OAAO,EAAE,WAAY,CAAC;MAC7Bf,oBAAoB,CAAEe,OAAQ,CAAC;MAC/BxB,cAAc,CAAC2B,OAAO,EAAEC,KAAK,CAAC,CAAC;MAC/B;IACD;;IAEA;IACA,IACCnC,kBAAkB,CAACoC,iBAAiB,CAACC,IAAI,CAAIC,gBAAgB,IAAM;MAClE;MACA;MACA,OACCA,gBAAgB,CAACjC,EAAE,KAAKN,QAAQ,CAACM,EAAE,IACnCiC,gBAAgB,CAACC,KAAK,CAACC,WAAW,CAAC,CAAC,KAAK/B,IAAI,CAAC+B,WAAW,CAAC,CAAC;IAE7D,CAAE,CAAC,EACF;MACD,MAAMT,OAAO,GAAG,IAAAC,QAAE,EACjB,4DACD,CAAC;MACD,IAAAC,WAAK,EAAEF,OAAO,EAAE,WAAY,CAAC;MAC7Bf,oBAAoB,CAAEe,OAAQ,CAAC;MAC/BxB,cAAc,CAAC2B,OAAO,EAAEC,KAAK,CAAC,CAAC;MAC/B;IACD;IAEA,IAAI;MACHrB,WAAW,CAAE,IAAK,CAAC;;MAEnB;MACA;MACA;MACA;MACA,MAAM2B,WAAW,GAAG,MAAMtB,gBAAgB,CACzC,UAAU,EACVuB,+BAAa,EACb;QACCrC,EAAE,EAAEN,QAAQ,CAACM,EAAE;QACfsC,IAAI,EAAE5C,QAAQ,CAAC4C,IAAI;QACnBlC;MACD,CACD,CAAC;MAEDW,oBAAoB,CAAE,0BAA2B,CAAC;MAClDjB,SAAS,GAAIsC,WAAY,CAAC;MAC1BxC,OAAO,CAAC,CAAC;MAETuB,mBAAmB,CAAE,IAAAQ,QAAE,EAAE,2BAA4B,CAAC,EAAE;QACvDY,IAAI,EAAE,UAAU;QAChBvC,EAAE,EAAE;MACL,CAAE,CAAC;IACJ,CAAC,CAAC,OAAQwC,KAAK,EAAG;MACjB3C,OAAO,GAAG,CAAC;MACXqB,iBAAiB,CAAEsB,KAAK,CAACd,OAAO,EAAE;QACjCa,IAAI,EAAE,UAAU;QAChBvC,EAAE,EAAE;MACL,CAAE,CAAC;IACJ,CAAC,SAAS;MACTS,WAAW,CAAE,KAAM,CAAC;MACpBJ,OAAO,CAAE,EAAG,CAAC;IACd;EACD,CAAC;EAED,MAAMoC,cAAc,GAAGA,CAAA,KAAM;IAC5B7C,OAAO,CAAC,CAAC;IACTS,OAAO,CAAE,EAAG,CAAC;EACd,CAAC;EAED,OACC,IAAAqC,MAAA,CAAAC,aAAA,EAAC5D,WAAA,CAAA6D,KAAK;IACLC,KAAK,EAAG,IAAAlB,QAAE,EAAE,QAAS,CAAG;IACxBc,cAAc,EAAGA,cAAgB;IAAA,GAC5B1C;EAAK,GAEV,IAAA2C,MAAA,CAAAC,aAAA;IAAMG,QAAQ,EAAGvB;EAAQ,GACxB,IAAAmB,MAAA,CAAAC,aAAA,EAAC5D,WAAA,CAAAgE,oBAAM;IAACC,OAAO,EAAC;EAAG,GAClB,IAAAN,MAAA,CAAAC,aAAA,EAAC5D,WAAA,CAAAgE,oBAAM;IAACC,OAAO,EAAC;EAAG,GAClB,IAAAN,MAAA,CAAAC,aAAA,EAAC5D,WAAA,CAAAkE,WAAW;IACXC,GAAG,EAAGhD,cAAgB;IACtBiD,uBAAuB;IACvBjB,KAAK,EAAG,IAAAP,QAAE,EAAE,MAAO,CAAG;IACtByB,KAAK,EAAGhD,IAAM;IACdiB,QAAQ,EAAGA,QAAU;IACrB,oBAAmBT,mBAAqB;IACxCyC,QAAQ;EAAA,CACR,CAAC,EACA3C,iBAAiB,IAClB,IAAAgC,MAAA,CAAAC,aAAA;IACCW,SAAS,EAAC,4DAA4D;IACtEtD,EAAE,EAAGY;EAAqB,GAExBF,iBACG,CAEA,CAAC,EACT,IAAAgC,MAAA,CAAAC,aAAA,EAAC5D,WAAA,CAAAwE,oBAAM;IAACC,OAAO,EAAC;EAAO,GACtB,IAAAd,MAAA,CAAAC,aAAA,EAAC5D,WAAA,CAAA0E,MAAM;IAACC,OAAO,EAAC,UAAU;IAACC,OAAO,EAAGlB;EAAgB,GAClD,IAAAd,QAAE,EAAE,QAAS,CACR,CAAC,EACT,IAAAe,MAAA,CAAAC,aAAA,EAAC5D,WAAA,CAAA0E,MAAM;IACNC,OAAO,EAAC,SAAS;IACjBnB,IAAI,EAAC,QAAQ;IACb,iBACC,CAAEnC,IAAI,IAAIA,IAAI,KAAKV,QAAQ,CAACU,IAAI,IAAII,QACpC;IACDoD,MAAM,EAAGpD;EAAU,GAEjB,IAAAmB,QAAE,EAAE,MAAO,CACN,CACD,CACD,CACH,CACA,CAAC;AAEV"}
|
|
@@ -5,10 +5,11 @@ import { createElement } from "react";
|
|
|
5
5
|
import { Modal, Button, TextControl, __experimentalHStack as HStack, __experimentalVStack as VStack } from '@wordpress/components';
|
|
6
6
|
import { store as coreStore } from '@wordpress/core-data';
|
|
7
7
|
import { useDispatch } from '@wordpress/data';
|
|
8
|
-
import { useState } from '@wordpress/element';
|
|
8
|
+
import { useId, useRef, useState } from '@wordpress/element';
|
|
9
9
|
import { decodeEntities } from '@wordpress/html-entities';
|
|
10
10
|
import { __ } from '@wordpress/i18n';
|
|
11
11
|
import { store as noticesStore } from '@wordpress/notices';
|
|
12
|
+
import { speak } from '@wordpress/a11y';
|
|
12
13
|
|
|
13
14
|
/**
|
|
14
15
|
* Internal dependencies
|
|
@@ -16,13 +17,18 @@ import { store as noticesStore } from '@wordpress/notices';
|
|
|
16
17
|
import { CATEGORY_SLUG } from './category-selector';
|
|
17
18
|
export default function RenamePatternCategoryModal({
|
|
18
19
|
category,
|
|
20
|
+
existingCategories,
|
|
19
21
|
onClose,
|
|
20
22
|
onError,
|
|
21
23
|
onSuccess,
|
|
22
24
|
...props
|
|
23
25
|
}) {
|
|
26
|
+
const id = useId();
|
|
27
|
+
const textControlRef = useRef();
|
|
24
28
|
const [name, setName] = useState(decodeEntities(category.name));
|
|
25
29
|
const [isSaving, setIsSaving] = useState(false);
|
|
30
|
+
const [validationMessage, setValidationMessage] = useState(false);
|
|
31
|
+
const validationMessageId = validationMessage ? `patterns-rename-pattern-category-modal__validation-message-${id}` : undefined;
|
|
26
32
|
const {
|
|
27
33
|
saveEntityRecord,
|
|
28
34
|
invalidateResolution
|
|
@@ -31,9 +37,35 @@ export default function RenamePatternCategoryModal({
|
|
|
31
37
|
createErrorNotice,
|
|
32
38
|
createSuccessNotice
|
|
33
39
|
} = useDispatch(noticesStore);
|
|
34
|
-
const
|
|
40
|
+
const onChange = newName => {
|
|
41
|
+
if (validationMessage) {
|
|
42
|
+
setValidationMessage(undefined);
|
|
43
|
+
}
|
|
44
|
+
setName(newName);
|
|
45
|
+
};
|
|
46
|
+
const onSave = async event => {
|
|
35
47
|
event.preventDefault();
|
|
36
|
-
if (
|
|
48
|
+
if (isSaving) {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
if (!name || name === category.name) {
|
|
52
|
+
const message = __('Please enter a new name for this category.');
|
|
53
|
+
speak(message, 'assertive');
|
|
54
|
+
setValidationMessage(message);
|
|
55
|
+
textControlRef.current?.focus();
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Check existing categories to avoid creating duplicates.
|
|
60
|
+
if (existingCategories.patternCategories.find(existingCategory => {
|
|
61
|
+
// Compare the id so that the we don't disallow the user changing the case of their current category
|
|
62
|
+
// (i.e. renaming 'test' to 'Test').
|
|
63
|
+
return existingCategory.id !== category.id && existingCategory.label.toLowerCase() === name.toLowerCase();
|
|
64
|
+
})) {
|
|
65
|
+
const message = __('This category already exists. Please use a different name.');
|
|
66
|
+
speak(message, 'assertive');
|
|
67
|
+
setValidationMessage(message);
|
|
68
|
+
textControlRef.current?.focus();
|
|
37
69
|
return;
|
|
38
70
|
}
|
|
39
71
|
try {
|
|
@@ -75,16 +107,23 @@ export default function RenamePatternCategoryModal({
|
|
|
75
107
|
onRequestClose: onRequestClose,
|
|
76
108
|
...props
|
|
77
109
|
}, createElement("form", {
|
|
78
|
-
onSubmit:
|
|
110
|
+
onSubmit: onSave
|
|
79
111
|
}, createElement(VStack, {
|
|
80
112
|
spacing: "5"
|
|
113
|
+
}, createElement(VStack, {
|
|
114
|
+
spacing: "2"
|
|
81
115
|
}, createElement(TextControl, {
|
|
116
|
+
ref: textControlRef,
|
|
82
117
|
__nextHasNoMarginBottom: true,
|
|
83
118
|
label: __('Name'),
|
|
84
119
|
value: name,
|
|
85
|
-
onChange:
|
|
120
|
+
onChange: onChange,
|
|
121
|
+
"aria-describedby": validationMessageId,
|
|
86
122
|
required: true
|
|
87
|
-
}), createElement(
|
|
123
|
+
}), validationMessage && createElement("span", {
|
|
124
|
+
className: "patterns-rename-pattern-category-modal__validation-message",
|
|
125
|
+
id: validationMessageId
|
|
126
|
+
}, validationMessage)), createElement(HStack, {
|
|
88
127
|
justify: "right"
|
|
89
128
|
}, createElement(Button, {
|
|
90
129
|
variant: "tertiary",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["Modal","Button","TextControl","__experimentalHStack","HStack","__experimentalVStack","VStack","store","coreStore","useDispatch","useState","decodeEntities","__","noticesStore","CATEGORY_SLUG","RenamePatternCategoryModal","category","onClose","onError","onSuccess","props","name","setName","isSaving","setIsSaving","saveEntityRecord","invalidateResolution","createErrorNotice","createSuccessNotice","
|
|
1
|
+
{"version":3,"names":["Modal","Button","TextControl","__experimentalHStack","HStack","__experimentalVStack","VStack","store","coreStore","useDispatch","useId","useRef","useState","decodeEntities","__","noticesStore","speak","CATEGORY_SLUG","RenamePatternCategoryModal","category","existingCategories","onClose","onError","onSuccess","props","id","textControlRef","name","setName","isSaving","setIsSaving","validationMessage","setValidationMessage","validationMessageId","undefined","saveEntityRecord","invalidateResolution","createErrorNotice","createSuccessNotice","onChange","newName","onSave","event","preventDefault","message","current","focus","patternCategories","find","existingCategory","label","toLowerCase","savedRecord","slug","type","error","onRequestClose","createElement","title","onSubmit","spacing","ref","__nextHasNoMarginBottom","value","required","className","justify","variant","onClick","isBusy"],"sources":["@wordpress/patterns/src/components/rename-pattern-category-modal.js"],"sourcesContent":["/**\n * WordPress dependencies\n */\nimport {\n\tModal,\n\tButton,\n\tTextControl,\n\t__experimentalHStack as HStack,\n\t__experimentalVStack as VStack,\n} from '@wordpress/components';\nimport { store as coreStore } from '@wordpress/core-data';\nimport { useDispatch } from '@wordpress/data';\nimport { useId, useRef, useState } from '@wordpress/element';\nimport { decodeEntities } from '@wordpress/html-entities';\nimport { __ } from '@wordpress/i18n';\nimport { store as noticesStore } from '@wordpress/notices';\nimport { speak } from '@wordpress/a11y';\n\n/**\n * Internal dependencies\n */\nimport { CATEGORY_SLUG } from './category-selector';\n\nexport default function RenamePatternCategoryModal( {\n\tcategory,\n\texistingCategories,\n\tonClose,\n\tonError,\n\tonSuccess,\n\t...props\n} ) {\n\tconst id = useId();\n\tconst textControlRef = useRef();\n\tconst [ name, setName ] = useState( decodeEntities( category.name ) );\n\tconst [ isSaving, setIsSaving ] = useState( false );\n\tconst [ validationMessage, setValidationMessage ] = useState( false );\n\tconst validationMessageId = validationMessage\n\t\t? `patterns-rename-pattern-category-modal__validation-message-${ id }`\n\t\t: undefined;\n\n\tconst { saveEntityRecord, invalidateResolution } = useDispatch( coreStore );\n\tconst { createErrorNotice, createSuccessNotice } =\n\t\tuseDispatch( noticesStore );\n\n\tconst onChange = ( newName ) => {\n\t\tif ( validationMessage ) {\n\t\t\tsetValidationMessage( undefined );\n\t\t}\n\t\tsetName( newName );\n\t};\n\n\tconst onSave = async ( event ) => {\n\t\tevent.preventDefault();\n\n\t\tif ( isSaving ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( ! name || name === category.name ) {\n\t\t\tconst message = __( 'Please enter a new name for this category.' );\n\t\t\tspeak( message, 'assertive' );\n\t\t\tsetValidationMessage( message );\n\t\t\ttextControlRef.current?.focus();\n\t\t\treturn;\n\t\t}\n\n\t\t// Check existing categories to avoid creating duplicates.\n\t\tif (\n\t\t\texistingCategories.patternCategories.find( ( existingCategory ) => {\n\t\t\t\t// Compare the id so that the we don't disallow the user changing the case of their current category\n\t\t\t\t// (i.e. renaming 'test' to 'Test').\n\t\t\t\treturn (\n\t\t\t\t\texistingCategory.id !== category.id &&\n\t\t\t\t\texistingCategory.label.toLowerCase() === name.toLowerCase()\n\t\t\t\t);\n\t\t\t} )\n\t\t) {\n\t\t\tconst message = __(\n\t\t\t\t'This category already exists. Please use a different name.'\n\t\t\t);\n\t\t\tspeak( message, 'assertive' );\n\t\t\tsetValidationMessage( message );\n\t\t\ttextControlRef.current?.focus();\n\t\t\treturn;\n\t\t}\n\n\t\ttry {\n\t\t\tsetIsSaving( true );\n\n\t\t\t// User pattern category properties may differ as they can be\n\t\t\t// normalized for use alongside template part areas, core pattern\n\t\t\t// categories etc. As a result we won't just destructure the passed\n\t\t\t// category object.\n\t\t\tconst savedRecord = await saveEntityRecord(\n\t\t\t\t'taxonomy',\n\t\t\t\tCATEGORY_SLUG,\n\t\t\t\t{\n\t\t\t\t\tid: category.id,\n\t\t\t\t\tslug: category.slug,\n\t\t\t\t\tname,\n\t\t\t\t}\n\t\t\t);\n\n\t\t\tinvalidateResolution( 'getUserPatternCategories' );\n\t\t\tonSuccess?.( savedRecord );\n\t\t\tonClose();\n\n\t\t\tcreateSuccessNotice( __( 'Pattern category renamed.' ), {\n\t\t\t\ttype: 'snackbar',\n\t\t\t\tid: 'pattern-category-update',\n\t\t\t} );\n\t\t} catch ( error ) {\n\t\t\tonError?.();\n\t\t\tcreateErrorNotice( error.message, {\n\t\t\t\ttype: 'snackbar',\n\t\t\t\tid: 'pattern-category-update',\n\t\t\t} );\n\t\t} finally {\n\t\t\tsetIsSaving( false );\n\t\t\tsetName( '' );\n\t\t}\n\t};\n\n\tconst onRequestClose = () => {\n\t\tonClose();\n\t\tsetName( '' );\n\t};\n\n\treturn (\n\t\t<Modal\n\t\t\ttitle={ __( 'Rename' ) }\n\t\t\tonRequestClose={ onRequestClose }\n\t\t\t{ ...props }\n\t\t>\n\t\t\t<form onSubmit={ onSave }>\n\t\t\t\t<VStack spacing=\"5\">\n\t\t\t\t\t<VStack spacing=\"2\">\n\t\t\t\t\t\t<TextControl\n\t\t\t\t\t\t\tref={ textControlRef }\n\t\t\t\t\t\t\t__nextHasNoMarginBottom\n\t\t\t\t\t\t\tlabel={ __( 'Name' ) }\n\t\t\t\t\t\t\tvalue={ name }\n\t\t\t\t\t\t\tonChange={ onChange }\n\t\t\t\t\t\t\taria-describedby={ validationMessageId }\n\t\t\t\t\t\t\trequired\n\t\t\t\t\t\t/>\n\t\t\t\t\t\t{ validationMessage && (\n\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\tclassName=\"patterns-rename-pattern-category-modal__validation-message\"\n\t\t\t\t\t\t\t\tid={ validationMessageId }\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{ validationMessage }\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t) }\n\t\t\t\t\t</VStack>\n\t\t\t\t\t<HStack justify=\"right\">\n\t\t\t\t\t\t<Button variant=\"tertiary\" onClick={ onRequestClose }>\n\t\t\t\t\t\t\t{ __( 'Cancel' ) }\n\t\t\t\t\t\t</Button>\n\t\t\t\t\t\t<Button\n\t\t\t\t\t\t\tvariant=\"primary\"\n\t\t\t\t\t\t\ttype=\"submit\"\n\t\t\t\t\t\t\taria-disabled={\n\t\t\t\t\t\t\t\t! name || name === category.name || isSaving\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tisBusy={ isSaving }\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{ __( 'Save' ) }\n\t\t\t\t\t\t</Button>\n\t\t\t\t\t</HStack>\n\t\t\t\t</VStack>\n\t\t\t</form>\n\t\t</Modal>\n\t);\n}\n"],"mappings":"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"}
|
|
@@ -132,4 +132,13 @@
|
|
|
132
132
|
.patterns-create-modal__name-input input[type=text] {
|
|
133
133
|
min-height: 40px;
|
|
134
134
|
margin: 0;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
.patterns-rename-pattern-category-modal__validation-message {
|
|
138
|
+
color: #cc1818;
|
|
139
|
+
}
|
|
140
|
+
@media (min-width: 782px) {
|
|
141
|
+
.patterns-rename-pattern-category-modal__validation-message {
|
|
142
|
+
width: 320px;
|
|
143
|
+
}
|
|
135
144
|
}
|
package/build-style/style.css
CHANGED
|
@@ -132,4 +132,13 @@
|
|
|
132
132
|
.patterns-create-modal__name-input input[type=text] {
|
|
133
133
|
min-height: 40px;
|
|
134
134
|
margin: 0;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
.patterns-rename-pattern-category-modal__validation-message {
|
|
138
|
+
color: #cc1818;
|
|
139
|
+
}
|
|
140
|
+
@media (min-width: 782px) {
|
|
141
|
+
.patterns-rename-pattern-category-modal__validation-message {
|
|
142
|
+
width: 320px;
|
|
143
|
+
}
|
|
135
144
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wordpress/patterns",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.6.0",
|
|
4
4
|
"description": "Management of user pattern editing.",
|
|
5
5
|
"author": "The WordPress Contributors",
|
|
6
6
|
"license": "GPL-2.0-or-later",
|
|
@@ -31,19 +31,20 @@
|
|
|
31
31
|
],
|
|
32
32
|
"dependencies": {
|
|
33
33
|
"@babel/runtime": "^7.16.0",
|
|
34
|
-
"@wordpress/
|
|
35
|
-
"@wordpress/
|
|
36
|
-
"@wordpress/
|
|
37
|
-
"@wordpress/
|
|
38
|
-
"@wordpress/
|
|
39
|
-
"@wordpress/data": "^
|
|
40
|
-
"@wordpress/
|
|
41
|
-
"@wordpress/
|
|
42
|
-
"@wordpress/
|
|
43
|
-
"@wordpress/
|
|
44
|
-
"@wordpress/
|
|
45
|
-
"@wordpress/
|
|
46
|
-
"@wordpress/
|
|
34
|
+
"@wordpress/a11y": "^3.45.0",
|
|
35
|
+
"@wordpress/block-editor": "^12.13.0",
|
|
36
|
+
"@wordpress/blocks": "^12.22.0",
|
|
37
|
+
"@wordpress/components": "^25.11.0",
|
|
38
|
+
"@wordpress/compose": "^6.22.0",
|
|
39
|
+
"@wordpress/core-data": "^6.22.0",
|
|
40
|
+
"@wordpress/data": "^9.15.0",
|
|
41
|
+
"@wordpress/element": "^5.22.0",
|
|
42
|
+
"@wordpress/html-entities": "^3.45.0",
|
|
43
|
+
"@wordpress/i18n": "^4.45.0",
|
|
44
|
+
"@wordpress/icons": "^9.36.0",
|
|
45
|
+
"@wordpress/notices": "^4.13.0",
|
|
46
|
+
"@wordpress/private-apis": "^0.27.0",
|
|
47
|
+
"@wordpress/url": "^3.46.0"
|
|
47
48
|
},
|
|
48
49
|
"peerDependencies": {
|
|
49
50
|
"react": "^18.0.0",
|
|
@@ -52,5 +53,5 @@
|
|
|
52
53
|
"publishConfig": {
|
|
53
54
|
"access": "public"
|
|
54
55
|
},
|
|
55
|
-
"gitHead": "
|
|
56
|
+
"gitHead": "2a00e87b57b9c27ed2b9b0fd8d423ef3cada72c1"
|
|
56
57
|
}
|
|
@@ -10,10 +10,11 @@ import {
|
|
|
10
10
|
} from '@wordpress/components';
|
|
11
11
|
import { store as coreStore } from '@wordpress/core-data';
|
|
12
12
|
import { useDispatch } from '@wordpress/data';
|
|
13
|
-
import { useState } from '@wordpress/element';
|
|
13
|
+
import { useId, useRef, useState } from '@wordpress/element';
|
|
14
14
|
import { decodeEntities } from '@wordpress/html-entities';
|
|
15
15
|
import { __ } from '@wordpress/i18n';
|
|
16
16
|
import { store as noticesStore } from '@wordpress/notices';
|
|
17
|
+
import { speak } from '@wordpress/a11y';
|
|
17
18
|
|
|
18
19
|
/**
|
|
19
20
|
* Internal dependencies
|
|
@@ -22,23 +23,64 @@ import { CATEGORY_SLUG } from './category-selector';
|
|
|
22
23
|
|
|
23
24
|
export default function RenamePatternCategoryModal( {
|
|
24
25
|
category,
|
|
26
|
+
existingCategories,
|
|
25
27
|
onClose,
|
|
26
28
|
onError,
|
|
27
29
|
onSuccess,
|
|
28
30
|
...props
|
|
29
31
|
} ) {
|
|
32
|
+
const id = useId();
|
|
33
|
+
const textControlRef = useRef();
|
|
30
34
|
const [ name, setName ] = useState( decodeEntities( category.name ) );
|
|
31
35
|
const [ isSaving, setIsSaving ] = useState( false );
|
|
36
|
+
const [ validationMessage, setValidationMessage ] = useState( false );
|
|
37
|
+
const validationMessageId = validationMessage
|
|
38
|
+
? `patterns-rename-pattern-category-modal__validation-message-${ id }`
|
|
39
|
+
: undefined;
|
|
32
40
|
|
|
33
41
|
const { saveEntityRecord, invalidateResolution } = useDispatch( coreStore );
|
|
34
|
-
|
|
35
42
|
const { createErrorNotice, createSuccessNotice } =
|
|
36
43
|
useDispatch( noticesStore );
|
|
37
44
|
|
|
38
|
-
const
|
|
45
|
+
const onChange = ( newName ) => {
|
|
46
|
+
if ( validationMessage ) {
|
|
47
|
+
setValidationMessage( undefined );
|
|
48
|
+
}
|
|
49
|
+
setName( newName );
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
const onSave = async ( event ) => {
|
|
39
53
|
event.preventDefault();
|
|
40
54
|
|
|
41
|
-
if (
|
|
55
|
+
if ( isSaving ) {
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if ( ! name || name === category.name ) {
|
|
60
|
+
const message = __( 'Please enter a new name for this category.' );
|
|
61
|
+
speak( message, 'assertive' );
|
|
62
|
+
setValidationMessage( message );
|
|
63
|
+
textControlRef.current?.focus();
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Check existing categories to avoid creating duplicates.
|
|
68
|
+
if (
|
|
69
|
+
existingCategories.patternCategories.find( ( existingCategory ) => {
|
|
70
|
+
// Compare the id so that the we don't disallow the user changing the case of their current category
|
|
71
|
+
// (i.e. renaming 'test' to 'Test').
|
|
72
|
+
return (
|
|
73
|
+
existingCategory.id !== category.id &&
|
|
74
|
+
existingCategory.label.toLowerCase() === name.toLowerCase()
|
|
75
|
+
);
|
|
76
|
+
} )
|
|
77
|
+
) {
|
|
78
|
+
const message = __(
|
|
79
|
+
'This category already exists. Please use a different name.'
|
|
80
|
+
);
|
|
81
|
+
speak( message, 'assertive' );
|
|
82
|
+
setValidationMessage( message );
|
|
83
|
+
textControlRef.current?.focus();
|
|
42
84
|
return;
|
|
43
85
|
}
|
|
44
86
|
|
|
@@ -90,15 +132,27 @@ export default function RenamePatternCategoryModal( {
|
|
|
90
132
|
onRequestClose={ onRequestClose }
|
|
91
133
|
{ ...props }
|
|
92
134
|
>
|
|
93
|
-
<form onSubmit={
|
|
135
|
+
<form onSubmit={ onSave }>
|
|
94
136
|
<VStack spacing="5">
|
|
95
|
-
<
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
137
|
+
<VStack spacing="2">
|
|
138
|
+
<TextControl
|
|
139
|
+
ref={ textControlRef }
|
|
140
|
+
__nextHasNoMarginBottom
|
|
141
|
+
label={ __( 'Name' ) }
|
|
142
|
+
value={ name }
|
|
143
|
+
onChange={ onChange }
|
|
144
|
+
aria-describedby={ validationMessageId }
|
|
145
|
+
required
|
|
146
|
+
/>
|
|
147
|
+
{ validationMessage && (
|
|
148
|
+
<span
|
|
149
|
+
className="patterns-rename-pattern-category-modal__validation-message"
|
|
150
|
+
id={ validationMessageId }
|
|
151
|
+
>
|
|
152
|
+
{ validationMessage }
|
|
153
|
+
</span>
|
|
154
|
+
) }
|
|
155
|
+
</VStack>
|
|
102
156
|
<HStack justify="right">
|
|
103
157
|
<Button variant="tertiary" onClick={ onRequestClose }>
|
|
104
158
|
{ __( 'Cancel' ) }
|