@strapi/content-type-builder 5.54.0 → 5.55.1
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/dist/admin/components/AIChat/hooks/useAIFetch.js +6 -2
- package/dist/admin/components/AIChat/hooks/useAIFetch.js.map +1 -1
- package/dist/admin/components/AIChat/hooks/useAIFetch.mjs +7 -3
- package/dist/admin/components/AIChat/hooks/useAIFetch.mjs.map +1 -1
- package/dist/admin/components/AIChat/hooks/usePrefetchAIToken.js +20 -0
- package/dist/admin/components/AIChat/hooks/usePrefetchAIToken.js.map +1 -0
- package/dist/admin/components/AIChat/hooks/usePrefetchAIToken.mjs +18 -0
- package/dist/admin/components/AIChat/hooks/usePrefetchAIToken.mjs.map +1 -0
- package/dist/admin/components/ContentTypeBuilderNav/ContentTypeBuilderNav.js +83 -59
- package/dist/admin/components/ContentTypeBuilderNav/ContentTypeBuilderNav.js.map +1 -1
- package/dist/admin/components/ContentTypeBuilderNav/ContentTypeBuilderNav.mjs +86 -62
- package/dist/admin/components/ContentTypeBuilderNav/ContentTypeBuilderNav.mjs.map +1 -1
- package/dist/admin/components/ContentTypeBuilderNav/components/FolderNav/DeleteFolderDialog.js +112 -0
- package/dist/admin/components/ContentTypeBuilderNav/components/FolderNav/DeleteFolderDialog.js.map +1 -0
- package/dist/admin/components/ContentTypeBuilderNav/components/FolderNav/DeleteFolderDialog.mjs +110 -0
- package/dist/admin/components/ContentTypeBuilderNav/components/FolderNav/DeleteFolderDialog.mjs.map +1 -0
- package/dist/admin/components/ContentTypeBuilderNav/components/FolderNav/FolderNameField.js +159 -0
- package/dist/admin/components/ContentTypeBuilderNav/components/FolderNav/FolderNameField.js.map +1 -0
- package/dist/admin/components/ContentTypeBuilderNav/components/FolderNav/FolderNameField.mjs +157 -0
- package/dist/admin/components/ContentTypeBuilderNav/components/FolderNav/FolderNameField.mjs.map +1 -0
- package/dist/admin/components/ContentTypeBuilderNav/components/FolderNav/FolderNavSection.js +311 -0
- package/dist/admin/components/ContentTypeBuilderNav/components/FolderNav/FolderNavSection.js.map +1 -0
- package/dist/admin/components/ContentTypeBuilderNav/components/FolderNav/FolderNavSection.mjs +309 -0
- package/dist/admin/components/ContentTypeBuilderNav/components/FolderNav/FolderNavSection.mjs.map +1 -0
- package/dist/admin/components/ContentTypeBuilderNav/components/FolderNav/SortableTreeRow.js +379 -0
- package/dist/admin/components/ContentTypeBuilderNav/components/FolderNav/SortableTreeRow.js.map +1 -0
- package/dist/admin/components/ContentTypeBuilderNav/components/FolderNav/SortableTreeRow.mjs +376 -0
- package/dist/admin/components/ContentTypeBuilderNav/components/FolderNav/SortableTreeRow.mjs.map +1 -0
- package/dist/admin/components/ContentTypeBuilderNav/hooks/useContentTypeBuilderMenu.js +172 -0
- package/dist/admin/components/ContentTypeBuilderNav/hooks/useContentTypeBuilderMenu.js.map +1 -0
- package/dist/admin/components/ContentTypeBuilderNav/hooks/useContentTypeBuilderMenu.mjs +166 -0
- package/dist/admin/components/ContentTypeBuilderNav/hooks/useContentTypeBuilderMenu.mjs.map +1 -0
- package/dist/admin/components/ContentTypeBuilderNav/hooks/useFolderActions.js +62 -0
- package/dist/admin/components/ContentTypeBuilderNav/hooks/useFolderActions.js.map +1 -0
- package/dist/admin/components/ContentTypeBuilderNav/hooks/useFolderActions.mjs +60 -0
- package/dist/admin/components/ContentTypeBuilderNav/hooks/useFolderActions.mjs.map +1 -0
- package/dist/admin/components/ContentTypeBuilderNav/hooks/useSortableTree.js +145 -0
- package/dist/admin/components/ContentTypeBuilderNav/hooks/useSortableTree.js.map +1 -0
- package/dist/admin/components/ContentTypeBuilderNav/hooks/useSortableTree.mjs +143 -0
- package/dist/admin/components/ContentTypeBuilderNav/hooks/useSortableTree.mjs.map +1 -0
- package/dist/admin/components/ContentTypeBuilderNav/lib/buildFolderTree.js +176 -0
- package/dist/admin/components/ContentTypeBuilderNav/lib/buildFolderTree.js.map +1 -0
- package/dist/admin/components/ContentTypeBuilderNav/lib/buildFolderTree.mjs +169 -0
- package/dist/admin/components/ContentTypeBuilderNav/lib/buildFolderTree.mjs.map +1 -0
- package/dist/admin/components/ContentTypeBuilderNav/lib/dropProjection.js +277 -0
- package/dist/admin/components/ContentTypeBuilderNav/lib/dropProjection.js.map +1 -0
- package/dist/admin/components/ContentTypeBuilderNav/lib/dropProjection.mjs +273 -0
- package/dist/admin/components/ContentTypeBuilderNav/lib/dropProjection.mjs.map +1 -0
- package/dist/admin/components/ContentTypeBuilderNav/lib/flatModel.js +62 -0
- package/dist/admin/components/ContentTypeBuilderNav/lib/flatModel.js.map +1 -0
- package/dist/admin/components/ContentTypeBuilderNav/lib/flatModel.mjs +58 -0
- package/dist/admin/components/ContentTypeBuilderNav/lib/flatModel.mjs.map +1 -0
- package/dist/admin/components/DataManager/DataManagerContext.js.map +1 -1
- package/dist/admin/components/DataManager/DataManagerContext.mjs.map +1 -1
- package/dist/admin/components/DataManager/DataManagerProvider.js +70 -8
- package/dist/admin/components/DataManager/DataManagerProvider.js.map +1 -1
- package/dist/admin/components/DataManager/DataManagerProvider.mjs +70 -8
- package/dist/admin/components/DataManager/DataManagerProvider.mjs.map +1 -1
- package/dist/admin/components/DataManager/reducer.js +411 -33
- package/dist/admin/components/DataManager/reducer.js.map +1 -1
- package/dist/admin/components/DataManager/reducer.mjs +411 -33
- package/dist/admin/components/DataManager/reducer.mjs.map +1 -1
- package/dist/admin/components/DataManager/utils/cleanData.js +11 -2
- package/dist/admin/components/DataManager/utils/cleanData.js.map +1 -1
- package/dist/admin/components/DataManager/utils/cleanData.mjs +11 -2
- package/dist/admin/components/DataManager/utils/cleanData.mjs.map +1 -1
- package/dist/admin/components/DataManager/utils/contentStructure.js +150 -0
- package/dist/admin/components/DataManager/utils/contentStructure.js.map +1 -0
- package/dist/admin/components/DataManager/utils/contentStructure.mjs +133 -0
- package/dist/admin/components/DataManager/utils/contentStructure.mjs.map +1 -0
- package/dist/admin/components/FolderSelect.js +200 -0
- package/dist/admin/components/FolderSelect.js.map +1 -0
- package/dist/admin/components/FolderSelect.mjs +198 -0
- package/dist/admin/components/FolderSelect.mjs.map +1 -0
- package/dist/admin/components/FormModal/FormModal.js +23 -2
- package/dist/admin/components/FormModal/FormModal.js.map +1 -1
- package/dist/admin/components/FormModal/FormModal.mjs +23 -2
- package/dist/admin/components/FormModal/FormModal.mjs.map +1 -1
- package/dist/admin/components/FormModal/contentType/contentTypeForm.js +15 -18
- package/dist/admin/components/FormModal/contentType/contentTypeForm.js.map +1 -1
- package/dist/admin/components/FormModal/contentType/contentTypeForm.mjs +15 -18
- package/dist/admin/components/FormModal/contentType/contentTypeForm.mjs.map +1 -1
- package/dist/admin/components/FormModal/reducer.js +6 -0
- package/dist/admin/components/FormModal/reducer.js.map +1 -1
- package/dist/admin/components/FormModal/reducer.mjs +6 -0
- package/dist/admin/components/FormModal/reducer.mjs.map +1 -1
- package/dist/admin/pages/App/index.js +2 -5
- package/dist/admin/pages/App/index.js.map +1 -1
- package/dist/admin/pages/App/index.mjs +2 -5
- package/dist/admin/pages/App/index.mjs.map +1 -1
- package/dist/admin/src/components/AIChat/hooks/usePrefetchAIToken.d.ts +1 -0
- package/dist/admin/src/components/ContentTypeBuilderNav/components/FolderNav/DeleteFolderDialog.d.ts +16 -0
- package/dist/admin/src/components/ContentTypeBuilderNav/components/FolderNav/FolderNameField.d.ts +12 -0
- package/dist/admin/src/components/ContentTypeBuilderNav/components/FolderNav/FolderNavSection.d.ts +14 -0
- package/dist/admin/src/components/ContentTypeBuilderNav/components/FolderNav/SortableTreeRow.d.ts +38 -0
- package/dist/admin/src/components/ContentTypeBuilderNav/{useContentTypeBuilderMenu.d.ts → hooks/useContentTypeBuilderMenu.d.ts} +17 -7
- package/dist/admin/src/components/ContentTypeBuilderNav/hooks/useFolderActions.d.ts +42 -0
- package/dist/admin/src/components/ContentTypeBuilderNav/hooks/useSortableTree.d.ts +53 -0
- package/dist/admin/src/components/ContentTypeBuilderNav/lib/buildFolderTree.d.ts +42 -0
- package/dist/admin/src/components/ContentTypeBuilderNav/lib/dropProjection.d.ts +58 -0
- package/dist/admin/src/components/ContentTypeBuilderNav/lib/flatModel.d.ts +18 -0
- package/dist/admin/src/components/DataManager/DataManagerContext.d.ts +41 -0
- package/dist/admin/src/components/DataManager/reducer.d.ts +105 -1
- package/dist/admin/src/components/DataManager/utils/cleanData.d.ts +5 -1
- package/dist/admin/src/components/DataManager/utils/contentStructure.d.ts +68 -0
- package/dist/admin/src/components/FolderSelect.d.ts +18 -0
- package/dist/admin/src/components/FormModal/contentType/contentTypeForm.d.ts +0 -21
- package/dist/admin/src/components/FormModal/forms/forms.d.ts +0 -10
- package/dist/admin/src/components/FormModal/reducer.d.ts +7 -0
- package/dist/admin/src/utils/folderTelemetry.d.ts +5 -0
- package/dist/admin/translations/en.json.js +23 -0
- package/dist/admin/translations/en.json.js.map +1 -1
- package/dist/admin/translations/en.json.mjs +23 -0
- package/dist/admin/translations/en.json.mjs.map +1 -1
- package/dist/admin/utils/folderTelemetry.js +19 -0
- package/dist/admin/utils/folderTelemetry.js.map +1 -0
- package/dist/admin/utils/folderTelemetry.mjs +16 -0
- package/dist/admin/utils/folderTelemetry.mjs.map +1 -0
- package/dist/server/controllers/schema.js +1 -1
- package/dist/server/controllers/schema.js.map +1 -1
- package/dist/server/controllers/schema.mjs +1 -1
- package/dist/server/controllers/schema.mjs.map +1 -1
- package/dist/server/controllers/validation/common.js +3 -0
- package/dist/server/controllers/validation/common.js.map +1 -1
- package/dist/server/controllers/validation/common.mjs +3 -1
- package/dist/server/controllers/validation/common.mjs.map +1 -1
- package/dist/server/controllers/validation/content-structure.js +177 -0
- package/dist/server/controllers/validation/content-structure.js.map +1 -0
- package/dist/server/controllers/validation/content-structure.mjs +173 -0
- package/dist/server/controllers/validation/content-structure.mjs.map +1 -0
- package/dist/server/controllers/validation/schema.js +3 -1
- package/dist/server/controllers/validation/schema.js.map +1 -1
- package/dist/server/controllers/validation/schema.mjs +3 -1
- package/dist/server/controllers/validation/schema.mjs.map +1 -1
- package/dist/server/register.js +1 -1
- package/dist/server/register.js.map +1 -1
- package/dist/server/register.mjs +1 -1
- package/dist/server/register.mjs.map +1 -1
- package/dist/server/routes/content-api.js +4 -4
- package/dist/server/routes/content-api.js.map +1 -1
- package/dist/server/routes/content-api.mjs +4 -4
- package/dist/server/routes/content-api.mjs.map +1 -1
- package/dist/server/services/api-handler.js +37 -4
- package/dist/server/services/api-handler.js.map +1 -1
- package/dist/server/services/api-handler.mjs +36 -5
- package/dist/server/services/api-handler.mjs.map +1 -1
- package/dist/server/services/content-structure.js +174 -0
- package/dist/server/services/content-structure.js.map +1 -0
- package/dist/server/services/content-structure.mjs +172 -0
- package/dist/server/services/content-structure.mjs.map +1 -0
- package/dist/server/services/content-types.js +196 -44
- package/dist/server/services/content-types.js.map +1 -1
- package/dist/server/services/content-types.mjs +195 -45
- package/dist/server/services/content-types.mjs.map +1 -1
- package/dist/server/services/index.js +3 -1
- package/dist/server/services/index.js.map +1 -1
- package/dist/server/services/index.mjs +3 -1
- package/dist/server/services/index.mjs.map +1 -1
- package/dist/server/services/schema-builder/index.js +4 -2
- package/dist/server/services/schema-builder/index.js.map +1 -1
- package/dist/server/services/schema-builder/index.mjs +4 -2
- package/dist/server/services/schema-builder/index.mjs.map +1 -1
- package/dist/server/services/schema-builder/schema-handler.js +16 -16
- package/dist/server/services/schema-builder/schema-handler.js.map +1 -1
- package/dist/server/services/schema-builder/schema-handler.mjs +16 -16
- package/dist/server/services/schema-builder/schema-handler.mjs.map +1 -1
- package/dist/server/services/schema-mutation.js +46 -0
- package/dist/server/services/schema-mutation.js.map +1 -0
- package/dist/server/services/schema-mutation.mjs +43 -0
- package/dist/server/services/schema-mutation.mjs.map +1 -0
- package/dist/server/services/schema.js +134 -79
- package/dist/server/services/schema.js.map +1 -1
- package/dist/server/services/schema.mjs +135 -80
- package/dist/server/services/schema.mjs.map +1 -1
- package/dist/server/src/controllers/schema.d.ts.map +1 -1
- package/dist/server/src/controllers/validation/common.d.ts +1 -0
- package/dist/server/src/controllers/validation/common.d.ts.map +1 -1
- package/dist/server/src/controllers/validation/content-structure.d.ts +56 -0
- package/dist/server/src/controllers/validation/content-structure.d.ts.map +1 -0
- package/dist/server/src/controllers/validation/schema.d.ts +35 -0
- package/dist/server/src/controllers/validation/schema.d.ts.map +1 -1
- package/dist/server/src/index.d.ts +3 -0
- package/dist/server/src/index.d.ts.map +1 -1
- package/dist/server/src/routes/content-api.d.ts.map +1 -1
- package/dist/server/src/services/api-handler.d.ts +13 -1
- package/dist/server/src/services/api-handler.d.ts.map +1 -1
- package/dist/server/src/services/content-structure.d.ts +37 -0
- package/dist/server/src/services/content-structure.d.ts.map +1 -0
- package/dist/server/src/services/content-types.d.ts +4 -0
- package/dist/server/src/services/content-types.d.ts.map +1 -1
- package/dist/server/src/services/index.d.ts +4 -0
- package/dist/server/src/services/index.d.ts.map +1 -1
- package/dist/server/src/services/schema-builder/index.d.ts +3 -1
- package/dist/server/src/services/schema-builder/index.d.ts.map +1 -1
- package/dist/server/src/services/schema-builder/schema-handler.d.ts.map +1 -1
- package/dist/server/src/services/schema-mutation.d.ts +26 -0
- package/dist/server/src/services/schema-mutation.d.ts.map +1 -0
- package/dist/server/src/services/schema.d.ts +1 -0
- package/dist/server/src/services/schema.d.ts.map +1 -1
- package/dist/server/src/utils/index.d.ts +2 -0
- package/dist/server/src/utils/index.d.ts.map +1 -1
- package/dist/server/utils/index.js.map +1 -1
- package/dist/server/utils/index.mjs.map +1 -1
- package/package.json +6 -6
- package/dist/admin/components/ContentTypeBuilderNav/useContentTypeBuilderMenu.js +0 -157
- package/dist/admin/components/ContentTypeBuilderNav/useContentTypeBuilderMenu.js.map +0 -1
- package/dist/admin/components/ContentTypeBuilderNav/useContentTypeBuilderMenu.mjs +0 -151
- package/dist/admin/components/ContentTypeBuilderNav/useContentTypeBuilderMenu.mjs.map +0 -1
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
4
|
+
var React = require('react');
|
|
5
|
+
var designSystem = require('@strapi/design-system');
|
|
6
|
+
var Icons = require('@strapi/icons');
|
|
7
|
+
var reactIntl = require('react-intl');
|
|
8
|
+
var styledComponents = require('styled-components');
|
|
9
|
+
var getTrad = require('../../../../utils/getTrad.js');
|
|
10
|
+
|
|
11
|
+
const Row = styledComponents.styled(designSystem.Flex)`
|
|
12
|
+
padding-right: ${({ theme })=>theme.spaces[3]};
|
|
13
|
+
|
|
14
|
+
padding-block: ${({ theme })=>theme.spaces[1]};
|
|
15
|
+
|
|
16
|
+
padding-left: ${({ theme, $depth })=>`calc(${$depth} * ${theme.spaces[6]} + ${theme.spaces[3]})`};
|
|
17
|
+
|
|
18
|
+
gap: ${({ theme })=>theme.spaces[2]};
|
|
19
|
+
`;
|
|
20
|
+
const NameInput = styledComponents.styled.input`
|
|
21
|
+
flex: 1;
|
|
22
|
+
|
|
23
|
+
min-width: 0;
|
|
24
|
+
padding: 4px 8px;
|
|
25
|
+
|
|
26
|
+
background: ${({ theme })=>theme.colors.neutral0};
|
|
27
|
+
border: 1px solid
|
|
28
|
+
${({ $hasError, theme })=>$hasError ? theme.colors.danger600 : theme.colors.primary600};
|
|
29
|
+
border-radius: ${({ theme })=>theme.borderRadius};
|
|
30
|
+
|
|
31
|
+
font-weight: ${({ theme })=>theme.fontWeights.semiBold};
|
|
32
|
+
color: ${({ theme })=>theme.colors.neutral800};
|
|
33
|
+
font-size: ${({ theme })=>theme.fontSizes[1]};
|
|
34
|
+
|
|
35
|
+
&:focus {
|
|
36
|
+
outline: none;
|
|
37
|
+
}
|
|
38
|
+
`;
|
|
39
|
+
const ErrorBox = styledComponents.styled(designSystem.Box)`
|
|
40
|
+
padding-left: ${({ theme, $depth })=>`calc(${$depth} * ${theme.spaces[6]} + ${theme.spaces[3]} + ${theme.spaces[4]} + ${theme.spaces[2]})`};
|
|
41
|
+
`;
|
|
42
|
+
const FolderNameField = ({ defaultValue, onSubmit, onCancel, validate, depth })=>{
|
|
43
|
+
const { formatMessage } = reactIntl.useIntl();
|
|
44
|
+
const errorId = React.useId();
|
|
45
|
+
const [error, setError] = React.useState(undefined);
|
|
46
|
+
const [value, setValue] = React.useState(defaultValue);
|
|
47
|
+
const inputRef = React.useRef(null);
|
|
48
|
+
const settledRef = React.useRef(false); // Guards against Enter and the subsequent blur both firing.
|
|
49
|
+
React.useEffect(()=>{
|
|
50
|
+
inputRef.current?.select();
|
|
51
|
+
inputRef.current?.focus();
|
|
52
|
+
}, []);
|
|
53
|
+
const handleChange = (next)=>{
|
|
54
|
+
setValue(next);
|
|
55
|
+
const trimmed = next.trim();
|
|
56
|
+
setError(trimmed.length > 0 ? validate?.(trimmed) : undefined);
|
|
57
|
+
};
|
|
58
|
+
const commitFromEnter = ()=>{
|
|
59
|
+
if (settledRef.current) {
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
const trimmed = value.trim();
|
|
63
|
+
if (trimmed.length === 0) {
|
|
64
|
+
settledRef.current = true;
|
|
65
|
+
onCancel();
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
const validationError = validate?.(trimmed);
|
|
69
|
+
if (validationError) {
|
|
70
|
+
setError(validationError);
|
|
71
|
+
inputRef.current?.focus();
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
settledRef.current = true;
|
|
75
|
+
onSubmit(trimmed);
|
|
76
|
+
};
|
|
77
|
+
const commitFromBlur = ()=>{
|
|
78
|
+
if (settledRef.current) {
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
settledRef.current = true;
|
|
82
|
+
const trimmed = value.trim();
|
|
83
|
+
// On blur, an empty or invalid name cancels the edit rather than trapping focus.
|
|
84
|
+
if (trimmed.length === 0 || validate?.(trimmed)) {
|
|
85
|
+
onCancel();
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
onSubmit(trimmed);
|
|
89
|
+
};
|
|
90
|
+
const cancel = ()=>{
|
|
91
|
+
if (settledRef.current) {
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
settledRef.current = true;
|
|
95
|
+
onCancel();
|
|
96
|
+
};
|
|
97
|
+
const onNameInputChange = (event)=>{
|
|
98
|
+
handleChange(event.target.value);
|
|
99
|
+
};
|
|
100
|
+
const onNameInputKeyDown = (event)=>{
|
|
101
|
+
if (event.key === 'Enter') {
|
|
102
|
+
event.preventDefault();
|
|
103
|
+
commitFromEnter();
|
|
104
|
+
}
|
|
105
|
+
if (event.key === 'Escape') {
|
|
106
|
+
event.preventDefault();
|
|
107
|
+
cancel();
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
return /*#__PURE__*/ jsxRuntime.jsxs(designSystem.Box, {
|
|
111
|
+
children: [
|
|
112
|
+
/*#__PURE__*/ jsxRuntime.jsxs(Row, {
|
|
113
|
+
$depth: depth,
|
|
114
|
+
alignItems: "center",
|
|
115
|
+
children: [
|
|
116
|
+
/*#__PURE__*/ jsxRuntime.jsx(designSystem.Box, {
|
|
117
|
+
tag: "span",
|
|
118
|
+
width: "16px",
|
|
119
|
+
flex: "0 0 auto",
|
|
120
|
+
"aria-hidden": true,
|
|
121
|
+
children: /*#__PURE__*/ jsxRuntime.jsx(Icons.ChevronDown, {
|
|
122
|
+
fill: "neutral500",
|
|
123
|
+
style: {
|
|
124
|
+
transform: 'rotate(-90deg)'
|
|
125
|
+
}
|
|
126
|
+
})
|
|
127
|
+
}),
|
|
128
|
+
/*#__PURE__*/ jsxRuntime.jsx(NameInput, {
|
|
129
|
+
ref: inputRef,
|
|
130
|
+
value: value,
|
|
131
|
+
"aria-describedby": error ? errorId : undefined,
|
|
132
|
+
"aria-invalid": Boolean(error),
|
|
133
|
+
"aria-label": formatMessage({
|
|
134
|
+
id: getTrad.getTrad('nav.folder.name-label'),
|
|
135
|
+
defaultMessage: 'Folder name'
|
|
136
|
+
}),
|
|
137
|
+
onKeyDown: onNameInputKeyDown,
|
|
138
|
+
onChange: onNameInputChange,
|
|
139
|
+
onBlur: commitFromBlur,
|
|
140
|
+
$hasError: Boolean(error)
|
|
141
|
+
})
|
|
142
|
+
]
|
|
143
|
+
}),
|
|
144
|
+
error && /*#__PURE__*/ jsxRuntime.jsx(ErrorBox, {
|
|
145
|
+
$depth: depth,
|
|
146
|
+
paddingTop: 1,
|
|
147
|
+
children: /*#__PURE__*/ jsxRuntime.jsx(designSystem.Typography, {
|
|
148
|
+
id: errorId,
|
|
149
|
+
variant: "pi",
|
|
150
|
+
textColor: "danger600",
|
|
151
|
+
children: error
|
|
152
|
+
})
|
|
153
|
+
})
|
|
154
|
+
]
|
|
155
|
+
});
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
exports.FolderNameField = FolderNameField;
|
|
159
|
+
//# sourceMappingURL=FolderNameField.js.map
|
package/dist/admin/components/ContentTypeBuilderNav/components/FolderNav/FolderNameField.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FolderNameField.js","sources":["../../../../../../admin/src/components/ContentTypeBuilderNav/components/FolderNav/FolderNameField.tsx"],"sourcesContent":["import { useEffect, useId, useRef, useState } from 'react';\n\nimport { Box, Flex, Typography } from '@strapi/design-system';\nimport { ChevronDown } from '@strapi/icons';\nimport { useIntl } from 'react-intl';\nimport { styled } from 'styled-components';\n\nimport { getTrad } from '../../../../utils/getTrad';\n\nconst Row = styled(Flex)<{ $depth: number }>`\n padding-right: ${({ theme }) => theme.spaces[3]};\n\n padding-block: ${({ theme }) => theme.spaces[1]};\n\n padding-left: ${({ theme, $depth }) =>\n `calc(${$depth} * ${theme.spaces[6]} + ${theme.spaces[3]})`};\n\n gap: ${({ theme }) => theme.spaces[2]};\n`;\n\nconst NameInput = styled.input<{ $hasError: boolean }>`\n flex: 1;\n\n min-width: 0;\n padding: 4px 8px;\n\n background: ${({ theme }) => theme.colors.neutral0};\n border: 1px solid\n ${({ $hasError, theme }) => ($hasError ? theme.colors.danger600 : theme.colors.primary600)};\n border-radius: ${({ theme }) => theme.borderRadius};\n\n font-weight: ${({ theme }) => theme.fontWeights.semiBold};\n color: ${({ theme }) => theme.colors.neutral800};\n font-size: ${({ theme }) => theme.fontSizes[1]};\n\n &:focus {\n outline: none;\n }\n`;\n\nconst ErrorBox = styled(Box)<{ $depth: number }>`\n padding-left: ${({ theme, $depth }) =>\n `calc(${$depth} * ${theme.spaces[6]} + ${theme.spaces[3]} + ${theme.spaces[4]} + ${theme.spaces[2]})`};\n`;\n\ninterface FolderNameFieldProps {\n defaultValue: string;\n depth: number;\n\n /**\n * Function to validate a draft entry. Return an error message to block acceptance, or `undefined` if the draft is acceptable.\n */\n validate?: (name: string) => string | undefined;\n\n onSubmit: (name: string) => void;\n onCancel: () => void;\n}\n\nexport const FolderNameField = ({\n defaultValue,\n onSubmit,\n onCancel,\n validate,\n depth,\n}: FolderNameFieldProps) => {\n const { formatMessage } = useIntl();\n const errorId = useId();\n\n const [error, setError] = useState<string | undefined>(undefined);\n const [value, setValue] = useState(defaultValue);\n\n const inputRef = useRef<HTMLInputElement>(null);\n const settledRef = useRef(false); // Guards against Enter and the subsequent blur both firing.\n\n useEffect(() => {\n inputRef.current?.select();\n inputRef.current?.focus();\n }, []);\n\n const handleChange = (next: string) => {\n setValue(next);\n\n const trimmed = next.trim();\n setError(trimmed.length > 0 ? validate?.(trimmed) : undefined);\n };\n\n const commitFromEnter = () => {\n if (settledRef.current) {\n return;\n }\n\n const trimmed = value.trim();\n\n if (trimmed.length === 0) {\n settledRef.current = true;\n\n onCancel();\n return;\n }\n\n const validationError = validate?.(trimmed);\n\n if (validationError) {\n setError(validationError);\n inputRef.current?.focus();\n\n return;\n }\n\n settledRef.current = true;\n onSubmit(trimmed);\n };\n\n const commitFromBlur = () => {\n if (settledRef.current) {\n return;\n }\n\n settledRef.current = true;\n const trimmed = value.trim();\n\n // On blur, an empty or invalid name cancels the edit rather than trapping focus.\n if (trimmed.length === 0 || validate?.(trimmed)) {\n onCancel();\n return;\n }\n\n onSubmit(trimmed);\n };\n\n const cancel = () => {\n if (settledRef.current) {\n return;\n }\n\n settledRef.current = true;\n onCancel();\n };\n\n const onNameInputChange = (event: React.ChangeEvent<HTMLInputElement>) => {\n handleChange(event.target.value);\n };\n\n const onNameInputKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {\n if (event.key === 'Enter') {\n event.preventDefault();\n commitFromEnter();\n }\n\n if (event.key === 'Escape') {\n event.preventDefault();\n cancel();\n }\n };\n\n return (\n <Box>\n <Row $depth={depth} alignItems=\"center\">\n <Box tag=\"span\" width=\"16px\" flex=\"0 0 auto\" aria-hidden>\n <ChevronDown fill=\"neutral500\" style={{ transform: 'rotate(-90deg)' }} />\n </Box>\n <NameInput\n ref={inputRef}\n value={value}\n aria-describedby={error ? errorId : undefined}\n aria-invalid={Boolean(error)}\n aria-label={formatMessage({\n id: getTrad('nav.folder.name-label'),\n defaultMessage: 'Folder name',\n })}\n onKeyDown={onNameInputKeyDown}\n onChange={onNameInputChange}\n onBlur={commitFromBlur}\n $hasError={Boolean(error)}\n />\n </Row>\n {error && (\n <ErrorBox $depth={depth} paddingTop={1}>\n <Typography id={errorId} variant=\"pi\" textColor=\"danger600\">\n {error}\n </Typography>\n </ErrorBox>\n )}\n </Box>\n );\n};\n"],"names":["Row","styled","Flex","theme","spaces","$depth","NameInput","input","colors","neutral0","$hasError","danger600","primary600","borderRadius","fontWeights","semiBold","neutral800","fontSizes","ErrorBox","Box","FolderNameField","defaultValue","onSubmit","onCancel","validate","depth","formatMessage","useIntl","errorId","useId","error","setError","useState","undefined","value","setValue","inputRef","useRef","settledRef","useEffect","current","select","focus","handleChange","next","trimmed","trim","length","commitFromEnter","validationError","commitFromBlur","cancel","onNameInputChange","event","target","onNameInputKeyDown","key","preventDefault","_jsxs","alignItems","_jsx","tag","width","flex","aria-hidden","ChevronDown","fill","style","transform","ref","aria-describedby","aria-invalid","Boolean","aria-label","id","getTrad","defaultMessage","onKeyDown","onChange","onBlur","paddingTop","Typography","variant","textColor"],"mappings":"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"}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
2
|
+
import { useId, useState, useRef, useEffect } from 'react';
|
|
3
|
+
import { Box, Typography, Flex } from '@strapi/design-system';
|
|
4
|
+
import { ChevronDown } from '@strapi/icons';
|
|
5
|
+
import { useIntl } from 'react-intl';
|
|
6
|
+
import { styled } from 'styled-components';
|
|
7
|
+
import { getTrad } from '../../../../utils/getTrad.mjs';
|
|
8
|
+
|
|
9
|
+
const Row = styled(Flex)`
|
|
10
|
+
padding-right: ${({ theme })=>theme.spaces[3]};
|
|
11
|
+
|
|
12
|
+
padding-block: ${({ theme })=>theme.spaces[1]};
|
|
13
|
+
|
|
14
|
+
padding-left: ${({ theme, $depth })=>`calc(${$depth} * ${theme.spaces[6]} + ${theme.spaces[3]})`};
|
|
15
|
+
|
|
16
|
+
gap: ${({ theme })=>theme.spaces[2]};
|
|
17
|
+
`;
|
|
18
|
+
const NameInput = styled.input`
|
|
19
|
+
flex: 1;
|
|
20
|
+
|
|
21
|
+
min-width: 0;
|
|
22
|
+
padding: 4px 8px;
|
|
23
|
+
|
|
24
|
+
background: ${({ theme })=>theme.colors.neutral0};
|
|
25
|
+
border: 1px solid
|
|
26
|
+
${({ $hasError, theme })=>$hasError ? theme.colors.danger600 : theme.colors.primary600};
|
|
27
|
+
border-radius: ${({ theme })=>theme.borderRadius};
|
|
28
|
+
|
|
29
|
+
font-weight: ${({ theme })=>theme.fontWeights.semiBold};
|
|
30
|
+
color: ${({ theme })=>theme.colors.neutral800};
|
|
31
|
+
font-size: ${({ theme })=>theme.fontSizes[1]};
|
|
32
|
+
|
|
33
|
+
&:focus {
|
|
34
|
+
outline: none;
|
|
35
|
+
}
|
|
36
|
+
`;
|
|
37
|
+
const ErrorBox = styled(Box)`
|
|
38
|
+
padding-left: ${({ theme, $depth })=>`calc(${$depth} * ${theme.spaces[6]} + ${theme.spaces[3]} + ${theme.spaces[4]} + ${theme.spaces[2]})`};
|
|
39
|
+
`;
|
|
40
|
+
const FolderNameField = ({ defaultValue, onSubmit, onCancel, validate, depth })=>{
|
|
41
|
+
const { formatMessage } = useIntl();
|
|
42
|
+
const errorId = useId();
|
|
43
|
+
const [error, setError] = useState(undefined);
|
|
44
|
+
const [value, setValue] = useState(defaultValue);
|
|
45
|
+
const inputRef = useRef(null);
|
|
46
|
+
const settledRef = useRef(false); // Guards against Enter and the subsequent blur both firing.
|
|
47
|
+
useEffect(()=>{
|
|
48
|
+
inputRef.current?.select();
|
|
49
|
+
inputRef.current?.focus();
|
|
50
|
+
}, []);
|
|
51
|
+
const handleChange = (next)=>{
|
|
52
|
+
setValue(next);
|
|
53
|
+
const trimmed = next.trim();
|
|
54
|
+
setError(trimmed.length > 0 ? validate?.(trimmed) : undefined);
|
|
55
|
+
};
|
|
56
|
+
const commitFromEnter = ()=>{
|
|
57
|
+
if (settledRef.current) {
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
const trimmed = value.trim();
|
|
61
|
+
if (trimmed.length === 0) {
|
|
62
|
+
settledRef.current = true;
|
|
63
|
+
onCancel();
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
const validationError = validate?.(trimmed);
|
|
67
|
+
if (validationError) {
|
|
68
|
+
setError(validationError);
|
|
69
|
+
inputRef.current?.focus();
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
settledRef.current = true;
|
|
73
|
+
onSubmit(trimmed);
|
|
74
|
+
};
|
|
75
|
+
const commitFromBlur = ()=>{
|
|
76
|
+
if (settledRef.current) {
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
settledRef.current = true;
|
|
80
|
+
const trimmed = value.trim();
|
|
81
|
+
// On blur, an empty or invalid name cancels the edit rather than trapping focus.
|
|
82
|
+
if (trimmed.length === 0 || validate?.(trimmed)) {
|
|
83
|
+
onCancel();
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
onSubmit(trimmed);
|
|
87
|
+
};
|
|
88
|
+
const cancel = ()=>{
|
|
89
|
+
if (settledRef.current) {
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
settledRef.current = true;
|
|
93
|
+
onCancel();
|
|
94
|
+
};
|
|
95
|
+
const onNameInputChange = (event)=>{
|
|
96
|
+
handleChange(event.target.value);
|
|
97
|
+
};
|
|
98
|
+
const onNameInputKeyDown = (event)=>{
|
|
99
|
+
if (event.key === 'Enter') {
|
|
100
|
+
event.preventDefault();
|
|
101
|
+
commitFromEnter();
|
|
102
|
+
}
|
|
103
|
+
if (event.key === 'Escape') {
|
|
104
|
+
event.preventDefault();
|
|
105
|
+
cancel();
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
return /*#__PURE__*/ jsxs(Box, {
|
|
109
|
+
children: [
|
|
110
|
+
/*#__PURE__*/ jsxs(Row, {
|
|
111
|
+
$depth: depth,
|
|
112
|
+
alignItems: "center",
|
|
113
|
+
children: [
|
|
114
|
+
/*#__PURE__*/ jsx(Box, {
|
|
115
|
+
tag: "span",
|
|
116
|
+
width: "16px",
|
|
117
|
+
flex: "0 0 auto",
|
|
118
|
+
"aria-hidden": true,
|
|
119
|
+
children: /*#__PURE__*/ jsx(ChevronDown, {
|
|
120
|
+
fill: "neutral500",
|
|
121
|
+
style: {
|
|
122
|
+
transform: 'rotate(-90deg)'
|
|
123
|
+
}
|
|
124
|
+
})
|
|
125
|
+
}),
|
|
126
|
+
/*#__PURE__*/ jsx(NameInput, {
|
|
127
|
+
ref: inputRef,
|
|
128
|
+
value: value,
|
|
129
|
+
"aria-describedby": error ? errorId : undefined,
|
|
130
|
+
"aria-invalid": Boolean(error),
|
|
131
|
+
"aria-label": formatMessage({
|
|
132
|
+
id: getTrad('nav.folder.name-label'),
|
|
133
|
+
defaultMessage: 'Folder name'
|
|
134
|
+
}),
|
|
135
|
+
onKeyDown: onNameInputKeyDown,
|
|
136
|
+
onChange: onNameInputChange,
|
|
137
|
+
onBlur: commitFromBlur,
|
|
138
|
+
$hasError: Boolean(error)
|
|
139
|
+
})
|
|
140
|
+
]
|
|
141
|
+
}),
|
|
142
|
+
error && /*#__PURE__*/ jsx(ErrorBox, {
|
|
143
|
+
$depth: depth,
|
|
144
|
+
paddingTop: 1,
|
|
145
|
+
children: /*#__PURE__*/ jsx(Typography, {
|
|
146
|
+
id: errorId,
|
|
147
|
+
variant: "pi",
|
|
148
|
+
textColor: "danger600",
|
|
149
|
+
children: error
|
|
150
|
+
})
|
|
151
|
+
})
|
|
152
|
+
]
|
|
153
|
+
});
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
export { FolderNameField };
|
|
157
|
+
//# sourceMappingURL=FolderNameField.mjs.map
|
package/dist/admin/components/ContentTypeBuilderNav/components/FolderNav/FolderNameField.mjs.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FolderNameField.mjs","sources":["../../../../../../admin/src/components/ContentTypeBuilderNav/components/FolderNav/FolderNameField.tsx"],"sourcesContent":["import { useEffect, useId, useRef, useState } from 'react';\n\nimport { Box, Flex, Typography } from '@strapi/design-system';\nimport { ChevronDown } from '@strapi/icons';\nimport { useIntl } from 'react-intl';\nimport { styled } from 'styled-components';\n\nimport { getTrad } from '../../../../utils/getTrad';\n\nconst Row = styled(Flex)<{ $depth: number }>`\n padding-right: ${({ theme }) => theme.spaces[3]};\n\n padding-block: ${({ theme }) => theme.spaces[1]};\n\n padding-left: ${({ theme, $depth }) =>\n `calc(${$depth} * ${theme.spaces[6]} + ${theme.spaces[3]})`};\n\n gap: ${({ theme }) => theme.spaces[2]};\n`;\n\nconst NameInput = styled.input<{ $hasError: boolean }>`\n flex: 1;\n\n min-width: 0;\n padding: 4px 8px;\n\n background: ${({ theme }) => theme.colors.neutral0};\n border: 1px solid\n ${({ $hasError, theme }) => ($hasError ? theme.colors.danger600 : theme.colors.primary600)};\n border-radius: ${({ theme }) => theme.borderRadius};\n\n font-weight: ${({ theme }) => theme.fontWeights.semiBold};\n color: ${({ theme }) => theme.colors.neutral800};\n font-size: ${({ theme }) => theme.fontSizes[1]};\n\n &:focus {\n outline: none;\n }\n`;\n\nconst ErrorBox = styled(Box)<{ $depth: number }>`\n padding-left: ${({ theme, $depth }) =>\n `calc(${$depth} * ${theme.spaces[6]} + ${theme.spaces[3]} + ${theme.spaces[4]} + ${theme.spaces[2]})`};\n`;\n\ninterface FolderNameFieldProps {\n defaultValue: string;\n depth: number;\n\n /**\n * Function to validate a draft entry. Return an error message to block acceptance, or `undefined` if the draft is acceptable.\n */\n validate?: (name: string) => string | undefined;\n\n onSubmit: (name: string) => void;\n onCancel: () => void;\n}\n\nexport const FolderNameField = ({\n defaultValue,\n onSubmit,\n onCancel,\n validate,\n depth,\n}: FolderNameFieldProps) => {\n const { formatMessage } = useIntl();\n const errorId = useId();\n\n const [error, setError] = useState<string | undefined>(undefined);\n const [value, setValue] = useState(defaultValue);\n\n const inputRef = useRef<HTMLInputElement>(null);\n const settledRef = useRef(false); // Guards against Enter and the subsequent blur both firing.\n\n useEffect(() => {\n inputRef.current?.select();\n inputRef.current?.focus();\n }, []);\n\n const handleChange = (next: string) => {\n setValue(next);\n\n const trimmed = next.trim();\n setError(trimmed.length > 0 ? validate?.(trimmed) : undefined);\n };\n\n const commitFromEnter = () => {\n if (settledRef.current) {\n return;\n }\n\n const trimmed = value.trim();\n\n if (trimmed.length === 0) {\n settledRef.current = true;\n\n onCancel();\n return;\n }\n\n const validationError = validate?.(trimmed);\n\n if (validationError) {\n setError(validationError);\n inputRef.current?.focus();\n\n return;\n }\n\n settledRef.current = true;\n onSubmit(trimmed);\n };\n\n const commitFromBlur = () => {\n if (settledRef.current) {\n return;\n }\n\n settledRef.current = true;\n const trimmed = value.trim();\n\n // On blur, an empty or invalid name cancels the edit rather than trapping focus.\n if (trimmed.length === 0 || validate?.(trimmed)) {\n onCancel();\n return;\n }\n\n onSubmit(trimmed);\n };\n\n const cancel = () => {\n if (settledRef.current) {\n return;\n }\n\n settledRef.current = true;\n onCancel();\n };\n\n const onNameInputChange = (event: React.ChangeEvent<HTMLInputElement>) => {\n handleChange(event.target.value);\n };\n\n const onNameInputKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {\n if (event.key === 'Enter') {\n event.preventDefault();\n commitFromEnter();\n }\n\n if (event.key === 'Escape') {\n event.preventDefault();\n cancel();\n }\n };\n\n return (\n <Box>\n <Row $depth={depth} alignItems=\"center\">\n <Box tag=\"span\" width=\"16px\" flex=\"0 0 auto\" aria-hidden>\n <ChevronDown fill=\"neutral500\" style={{ transform: 'rotate(-90deg)' }} />\n </Box>\n <NameInput\n ref={inputRef}\n value={value}\n aria-describedby={error ? errorId : undefined}\n aria-invalid={Boolean(error)}\n aria-label={formatMessage({\n id: getTrad('nav.folder.name-label'),\n defaultMessage: 'Folder name',\n })}\n onKeyDown={onNameInputKeyDown}\n onChange={onNameInputChange}\n onBlur={commitFromBlur}\n $hasError={Boolean(error)}\n />\n </Row>\n {error && (\n <ErrorBox $depth={depth} paddingTop={1}>\n <Typography id={errorId} variant=\"pi\" textColor=\"danger600\">\n {error}\n </Typography>\n </ErrorBox>\n )}\n </Box>\n );\n};\n"],"names":["Row","styled","Flex","theme","spaces","$depth","NameInput","input","colors","neutral0","$hasError","danger600","primary600","borderRadius","fontWeights","semiBold","neutral800","fontSizes","ErrorBox","Box","FolderNameField","defaultValue","onSubmit","onCancel","validate","depth","formatMessage","useIntl","errorId","useId","error","setError","useState","undefined","value","setValue","inputRef","useRef","settledRef","useEffect","current","select","focus","handleChange","next","trimmed","trim","length","commitFromEnter","validationError","commitFromBlur","cancel","onNameInputChange","event","target","onNameInputKeyDown","key","preventDefault","_jsxs","alignItems","_jsx","tag","width","flex","aria-hidden","ChevronDown","fill","style","transform","ref","aria-describedby","aria-invalid","Boolean","aria-label","id","getTrad","defaultMessage","onKeyDown","onChange","onBlur","paddingTop","Typography","variant","textColor"],"mappings":"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"}
|
|
@@ -0,0 +1,311 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
4
|
+
var React = require('react');
|
|
5
|
+
var core = require('@dnd-kit/core');
|
|
6
|
+
var sortable = require('@dnd-kit/sortable');
|
|
7
|
+
var strapiAdmin = require('@strapi/admin/strapi-admin');
|
|
8
|
+
var designSystem = require('@strapi/design-system');
|
|
9
|
+
var Icons = require('@strapi/icons');
|
|
10
|
+
var reactIntl = require('react-intl');
|
|
11
|
+
var getTrad = require('../../../../utils/getTrad.js');
|
|
12
|
+
var useDataManager = require('../../../DataManager/useDataManager.js');
|
|
13
|
+
var contentStructure = require('../../../DataManager/utils/contentStructure.js');
|
|
14
|
+
var useFolderActions = require('../../hooks/useFolderActions.js');
|
|
15
|
+
var useSortableTree = require('../../hooks/useSortableTree.js');
|
|
16
|
+
var buildFolderTree = require('../../lib/buildFolderTree.js');
|
|
17
|
+
var flatModel = require('../../lib/flatModel.js');
|
|
18
|
+
var DeleteFolderDialog = require('./DeleteFolderDialog.js');
|
|
19
|
+
var FolderNameField = require('./FolderNameField.js');
|
|
20
|
+
var SortableTreeRow = require('./SortableTreeRow.js');
|
|
21
|
+
|
|
22
|
+
const countContentTypes = (nodes)=>{
|
|
23
|
+
return nodes.reduce((total, node)=>{
|
|
24
|
+
if (node.type === 'folder') {
|
|
25
|
+
return total + countContentTypes(node.children);
|
|
26
|
+
}
|
|
27
|
+
return total + 1;
|
|
28
|
+
}, 0);
|
|
29
|
+
};
|
|
30
|
+
const EMPTY_COLLAPSED = new Set(); // Empty set to uncollapse all items while searching
|
|
31
|
+
const FolderNavSection = ({ onCreateContentType, createTypeLabel, searchValue, sectionId, section, title, links })=>{
|
|
32
|
+
const { contentStructure: contentStructure$1, contentTypes, isInDevelopmentMode } = useDataManager.useDataManager();
|
|
33
|
+
const { formatMessage, locale } = reactIntl.useIntl();
|
|
34
|
+
const actions = useFolderActions.useFolderActions();
|
|
35
|
+
const [collapsed, setCollapsed] = React.useState(new Set());
|
|
36
|
+
const [editingId, setEditingId] = React.useState(null);
|
|
37
|
+
const [isDrafting, setIsDrafting] = React.useState(false);
|
|
38
|
+
const [deleteTarget, setDeleteTarget] = React.useState(null);
|
|
39
|
+
const { contains } = designSystem.useFilter(locale, {
|
|
40
|
+
sensitivity: 'base'
|
|
41
|
+
});
|
|
42
|
+
const formatter = designSystem.useCollator(locale, {
|
|
43
|
+
sensitivity: 'base'
|
|
44
|
+
});
|
|
45
|
+
const sectionData = contentStructure$1.sections[section];
|
|
46
|
+
const searchActive = searchValue.trim().length > 0;
|
|
47
|
+
const canEdit = Boolean(isInDevelopmentMode);
|
|
48
|
+
const deletableContentTypeUids = React.useMemo(()=>{
|
|
49
|
+
return new Set(Object.values(contentTypes).filter((contentType)=>contentType.uid.startsWith('api::') && !contentType.plugin).map((contentType)=>contentType.uid));
|
|
50
|
+
}, [
|
|
51
|
+
contentTypes
|
|
52
|
+
]);
|
|
53
|
+
const tree = React.useMemo(()=>{
|
|
54
|
+
return buildFolderTree.buildSectionTree(sectionData, links, (a, b)=>formatter.compare(a, b));
|
|
55
|
+
}, [
|
|
56
|
+
sectionData,
|
|
57
|
+
links,
|
|
58
|
+
formatter
|
|
59
|
+
]);
|
|
60
|
+
const effectiveCollapsed = searchActive ? EMPTY_COLLAPSED : collapsed;
|
|
61
|
+
const visibleTree = React.useMemo(()=>{
|
|
62
|
+
return searchActive ? buildFolderTree.filterTree(tree, (text)=>contains(text, searchValue)) : tree;
|
|
63
|
+
}, [
|
|
64
|
+
searchActive,
|
|
65
|
+
tree,
|
|
66
|
+
contains,
|
|
67
|
+
searchValue
|
|
68
|
+
]);
|
|
69
|
+
const flatItems = React.useMemo(()=>{
|
|
70
|
+
return flatModel.flattenSortableTree(visibleTree, effectiveCollapsed);
|
|
71
|
+
}, [
|
|
72
|
+
visibleTree,
|
|
73
|
+
effectiveCollapsed
|
|
74
|
+
]);
|
|
75
|
+
// This hook supplies the CTB contentStructure dnd engine.
|
|
76
|
+
const dnd = useSortableTree.useSortableTree({
|
|
77
|
+
disabled: !canEdit || searchActive,
|
|
78
|
+
collapsed: effectiveCollapsed,
|
|
79
|
+
items: flatItems,
|
|
80
|
+
canDrop: (activeNode, target)=>{
|
|
81
|
+
if (activeNode.type !== 'folder') {
|
|
82
|
+
return true;
|
|
83
|
+
}
|
|
84
|
+
const parentId = target.kind === 'nest' ? target.folderId : target.parentId;
|
|
85
|
+
if (contentStructure.isFolderNameTakenBySibling(sectionData.groups, parentId, activeNode.name, activeNode.id)) {
|
|
86
|
+
return false;
|
|
87
|
+
}
|
|
88
|
+
return true;
|
|
89
|
+
},
|
|
90
|
+
onDrop: (activeNode, target)=>{
|
|
91
|
+
const parentId = target.kind === 'nest' ? target.folderId : target.parentId;
|
|
92
|
+
const index = target.kind === 'nest' ? 0 : target.index;
|
|
93
|
+
if (activeNode.type === 'folder') {
|
|
94
|
+
actions.moveFolder({
|
|
95
|
+
newParentId: parentId,
|
|
96
|
+
id: activeNode.id,
|
|
97
|
+
section,
|
|
98
|
+
index
|
|
99
|
+
});
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
actions.assignContentTypeToFolder({
|
|
103
|
+
targetGroupId: parentId,
|
|
104
|
+
uid: activeNode.uid,
|
|
105
|
+
section,
|
|
106
|
+
index
|
|
107
|
+
});
|
|
108
|
+
},
|
|
109
|
+
onExpandFolder: (folderId)=>setCollapsed((prev)=>{
|
|
110
|
+
const next = new Set(prev);
|
|
111
|
+
next.delete(folderId);
|
|
112
|
+
return next;
|
|
113
|
+
})
|
|
114
|
+
});
|
|
115
|
+
const confirmDelete = ()=>{
|
|
116
|
+
if (!deleteTarget) {
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
if (deleteTarget.mode === 'withContent') {
|
|
120
|
+
actions.deleteFolderAndContent({
|
|
121
|
+
contentTypeUids: buildFolderTree.collectSubtreeContentTypeUids(sectionData, deleteTarget.node.id).filter((uid)=>deletableContentTypeUids.has(uid)),
|
|
122
|
+
id: deleteTarget.node.id,
|
|
123
|
+
section
|
|
124
|
+
});
|
|
125
|
+
} else {
|
|
126
|
+
if (contentStructure.getDeleteFolderOnlySiblingNameCollisions(sectionData.groups, deleteTarget.node.id).length > 0) {
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
actions.deleteFolderOnly({
|
|
130
|
+
section,
|
|
131
|
+
id: deleteTarget.node.id
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
setDeleteTarget(null);
|
|
135
|
+
};
|
|
136
|
+
const validateFolderName = ({ excludeId, parentId, name })=>{
|
|
137
|
+
const folderNameTaken = contentStructure.isFolderNameTakenBySibling(sectionData.groups, parentId, name, excludeId);
|
|
138
|
+
if (folderNameTaken) {
|
|
139
|
+
return formatMessage({
|
|
140
|
+
defaultMessage: 'A folder with this name already exists in this location',
|
|
141
|
+
id: getTrad.getTrad('nav.folder.name.duplicate')
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
return undefined;
|
|
145
|
+
};
|
|
146
|
+
const handlers = {
|
|
147
|
+
dropTargetId: dnd.dropTargetId,
|
|
148
|
+
dropLine: dnd.dropLine,
|
|
149
|
+
validateFolderName,
|
|
150
|
+
editingId,
|
|
151
|
+
section,
|
|
152
|
+
canEdit,
|
|
153
|
+
isCollapsed: (id)=>{
|
|
154
|
+
return effectiveCollapsed.has(id);
|
|
155
|
+
},
|
|
156
|
+
// Search forces the tree open; a collapse toggle then can't take effect, so don't present one.
|
|
157
|
+
canToggle: !searchActive,
|
|
158
|
+
onToggle: (id)=>{
|
|
159
|
+
setCollapsed((prev)=>{
|
|
160
|
+
const next = new Set(prev);
|
|
161
|
+
if (next.has(id)) {
|
|
162
|
+
next.delete(id);
|
|
163
|
+
} else {
|
|
164
|
+
next.add(id);
|
|
165
|
+
}
|
|
166
|
+
return next;
|
|
167
|
+
});
|
|
168
|
+
},
|
|
169
|
+
// Deferred past the closing menu's focus restoration so the inline input isn't blurred (and consequently auto-committed) the instant it mounts.
|
|
170
|
+
onBeginRename: (id)=>{
|
|
171
|
+
setTimeout(()=>{
|
|
172
|
+
setIsDrafting(false);
|
|
173
|
+
setEditingId(id);
|
|
174
|
+
}, 0);
|
|
175
|
+
},
|
|
176
|
+
onSubmitRename: (id, name)=>{
|
|
177
|
+
actions.renameFolder({
|
|
178
|
+
section,
|
|
179
|
+
id,
|
|
180
|
+
name
|
|
181
|
+
});
|
|
182
|
+
setEditingId(null);
|
|
183
|
+
},
|
|
184
|
+
onCancelRename: ()=>{
|
|
185
|
+
setEditingId(null);
|
|
186
|
+
},
|
|
187
|
+
onDeleteFolder: (node)=>{
|
|
188
|
+
setDeleteTarget({
|
|
189
|
+
node,
|
|
190
|
+
mode: 'only'
|
|
191
|
+
});
|
|
192
|
+
},
|
|
193
|
+
onDeleteFolderAndContent: (node)=>{
|
|
194
|
+
setDeleteTarget({
|
|
195
|
+
node,
|
|
196
|
+
mode: 'withContent'
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
};
|
|
200
|
+
const sectionLink = {
|
|
201
|
+
label: createTypeLabel,
|
|
202
|
+
// The "New folder" option mounts the folder name input input and focuses it. Without this flag enabled, closing the menu would restore focus to the menu icon trigger.
|
|
203
|
+
suppressFocusCaptureOnMenuClose: true,
|
|
204
|
+
menu: [
|
|
205
|
+
{
|
|
206
|
+
label: createTypeLabel,
|
|
207
|
+
onSelect: onCreateContentType,
|
|
208
|
+
startIcon: /*#__PURE__*/ jsxRuntime.jsx(Icons.File, {})
|
|
209
|
+
},
|
|
210
|
+
{
|
|
211
|
+
label: formatMessage({
|
|
212
|
+
id: getTrad.getTrad('nav.action.new-folder'),
|
|
213
|
+
defaultMessage: 'New folder'
|
|
214
|
+
}),
|
|
215
|
+
onSelect: ()=>{
|
|
216
|
+
setEditingId(null);
|
|
217
|
+
setTimeout(()=>setIsDrafting(true), 0);
|
|
218
|
+
},
|
|
219
|
+
startIcon: /*#__PURE__*/ jsxRuntime.jsx(Icons.Folder, {})
|
|
220
|
+
}
|
|
221
|
+
]
|
|
222
|
+
};
|
|
223
|
+
const rows = // No extra horizontal padding here — the rows sit directly in the section's
|
|
224
|
+
// list so their left edge lines up with the components SubSections.
|
|
225
|
+
/*#__PURE__*/ jsxRuntime.jsxs(designSystem.Box, {
|
|
226
|
+
children: [
|
|
227
|
+
canEdit && isDrafting && /*#__PURE__*/ jsxRuntime.jsx(FolderNameField.FolderNameField, {
|
|
228
|
+
depth: 0,
|
|
229
|
+
defaultValue: formatMessage({
|
|
230
|
+
id: getTrad.getTrad('nav.folder.default-name'),
|
|
231
|
+
defaultMessage: 'New folder'
|
|
232
|
+
}),
|
|
233
|
+
validate: (name)=>{
|
|
234
|
+
return validateFolderName({
|
|
235
|
+
name,
|
|
236
|
+
parentId: null
|
|
237
|
+
});
|
|
238
|
+
},
|
|
239
|
+
onSubmit: (name)=>{
|
|
240
|
+
actions.createFolder({
|
|
241
|
+
section,
|
|
242
|
+
name,
|
|
243
|
+
parentId: null
|
|
244
|
+
});
|
|
245
|
+
setIsDrafting(false);
|
|
246
|
+
},
|
|
247
|
+
onCancel: ()=>{
|
|
248
|
+
setIsDrafting(false);
|
|
249
|
+
}
|
|
250
|
+
}),
|
|
251
|
+
/*#__PURE__*/ jsxRuntime.jsxs(core.DndContext, {
|
|
252
|
+
collisionDetection: dnd.collisionDetection,
|
|
253
|
+
onDragCancel: dnd.onDragCancel,
|
|
254
|
+
onDragStart: dnd.onDragStart,
|
|
255
|
+
onDragMove: dnd.onDragMove,
|
|
256
|
+
onDragEnd: dnd.onDragEnd,
|
|
257
|
+
sensors: dnd.sensors,
|
|
258
|
+
children: [
|
|
259
|
+
/*#__PURE__*/ jsxRuntime.jsx(sortable.SortableContext, {
|
|
260
|
+
items: dnd.renderedItems.map((item)=>item.id),
|
|
261
|
+
strategy: dnd.sortingStrategy,
|
|
262
|
+
children: dnd.renderedItems.map((item)=>{
|
|
263
|
+
return /*#__PURE__*/ jsxRuntime.jsx(SortableTreeRow.SortableTreeRow, {
|
|
264
|
+
item: item,
|
|
265
|
+
handlers: handlers
|
|
266
|
+
}, item.id);
|
|
267
|
+
})
|
|
268
|
+
}),
|
|
269
|
+
/*#__PURE__*/ jsxRuntime.jsx(core.DragOverlay, {
|
|
270
|
+
dropAnimation: null,
|
|
271
|
+
children: dnd.activeItem ? /*#__PURE__*/ jsxRuntime.jsx(SortableTreeRow.RowOverlay, {
|
|
272
|
+
item: dnd.activeItem
|
|
273
|
+
}) : null
|
|
274
|
+
})
|
|
275
|
+
]
|
|
276
|
+
})
|
|
277
|
+
]
|
|
278
|
+
}, "section-rows");
|
|
279
|
+
return /*#__PURE__*/ jsxRuntime.jsxs(jsxRuntime.Fragment, {
|
|
280
|
+
children: [
|
|
281
|
+
/*#__PURE__*/ jsxRuntime.jsx(strapiAdmin.SubNav.Section, {
|
|
282
|
+
badgeLabel: countContentTypes(visibleTree).toString(),
|
|
283
|
+
link: canEdit ? sectionLink : undefined,
|
|
284
|
+
sectionId: sectionId,
|
|
285
|
+
label: title,
|
|
286
|
+
children: [
|
|
287
|
+
rows
|
|
288
|
+
]
|
|
289
|
+
}),
|
|
290
|
+
deleteTarget && /*#__PURE__*/ jsxRuntime.jsx(DeleteFolderDialog.DeleteFolderDialog, {
|
|
291
|
+
counts: {
|
|
292
|
+
...buildFolderTree.countSubtree(sectionData, deleteTarget.node.id, deletableContentTypeUids),
|
|
293
|
+
preservedContentTypes: buildFolderTree.collectSubtreeContentTypeUids(sectionData, deleteTarget.node.id).filter((uid)=>!deletableContentTypeUids.has(uid)).length
|
|
294
|
+
},
|
|
295
|
+
conflictingFolderNames: deleteTarget.mode === 'only' ? contentStructure.getDeleteFolderOnlySiblingNameCollisions(sectionData.groups, deleteTarget.node.id) : [],
|
|
296
|
+
folderName: deleteTarget.node.name,
|
|
297
|
+
onConfirm: confirmDelete,
|
|
298
|
+
mode: deleteTarget.mode,
|
|
299
|
+
open: true,
|
|
300
|
+
onOpenChange: (open)=>{
|
|
301
|
+
if (!open) {
|
|
302
|
+
setDeleteTarget(null);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
})
|
|
306
|
+
]
|
|
307
|
+
});
|
|
308
|
+
};
|
|
309
|
+
|
|
310
|
+
exports.FolderNavSection = FolderNavSection;
|
|
311
|
+
//# sourceMappingURL=FolderNavSection.js.map
|