@griddo/ax 1.49.42 → 1.51.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -0
- package/config/griddo-config.js +2 -2
- package/config/webpack.config.js +0 -3
- package/config/webpackSchemas.config.js +18 -0
- package/package.json +41 -24
- package/scripts/griddo-sync-schemas.js +28 -6
- package/scripts/griddo.js +0 -1
- package/src/api/sites.tsx +2 -2
- package/src/components/ConfigPanel/Form/ConnectedField/PageConnectedField/Field/index.tsx +2 -1
- package/src/components/ConfigPanel/GlobalPageForm/index.tsx +8 -2
- package/src/components/Fields/ArrayFieldGroup/ArrayFieldInline/index.tsx +43 -0
- package/src/components/Fields/ArrayFieldGroup/ArrayFieldInline/style.tsx +30 -0
- package/src/components/Fields/ArrayFieldGroup/ArrayFieldItem/index.tsx +55 -0
- package/src/components/Fields/ArrayFieldGroup/ArrayFieldItem/style.tsx +48 -0
- package/src/components/Fields/ArrayFieldGroup/index.tsx +91 -0
- package/src/components/Fields/ComponentArray/MixableComponentArray/index.tsx +12 -6
- package/src/components/Fields/ComponentArray/SameComponentArray/index.tsx +13 -5
- package/src/components/Fields/ComponentArray/helpers.tsx +13 -1
- package/src/components/Fields/ComponentContainer/index.tsx +5 -3
- package/src/components/Fields/FieldsDivider/index.tsx +21 -0
- package/src/components/Fields/FieldsDivider/style.tsx +19 -0
- package/src/components/Fields/RadioGroup/index.tsx +1 -1
- package/src/components/Fields/VisualUniqueSelection/ScrollableSelection/index.tsx +4 -11
- package/src/components/Fields/index.tsx +4 -0
- package/src/components/MainWrapper/AppBar/index.tsx +3 -1
- package/src/components/MainWrapper/index.tsx +1 -0
- package/src/components/index.tsx +4 -0
- package/src/containers/Navigation/Defaults/actions.tsx +32 -27
- package/src/containers/PageEditor/actions.tsx +44 -22
- package/src/containers/PageEditor/constants.tsx +1 -0
- package/src/containers/PageEditor/interfaces.tsx +6 -0
- package/src/containers/PageEditor/reducer.tsx +4 -0
- package/src/containers/Sites/actions.tsx +22 -0
- package/src/containers/Sites/constants.tsx +7 -7
- package/src/containers/Sites/interfaces.tsx +6 -0
- package/src/containers/Sites/reducer.tsx +4 -0
- package/src/forms/editor.tsx +17 -9
- package/src/forms/elements.tsx +8 -14
- package/src/forms/fields.tsx +1 -1
- package/src/forms/index.tsx +2 -0
- package/src/hooks/bulk.tsx +12 -3
- package/src/modules/Content/PageImporter/index.tsx +1 -0
- package/src/modules/Content/index.tsx +5 -1
- package/src/modules/GlobalEditor/Editor/index.tsx +6 -6
- package/src/modules/GlobalEditor/index.tsx +33 -0
- package/src/modules/Navigation/Defaults/DefaultsEditor/Editor/index.tsx +5 -5
- package/src/modules/PageEditor/Editor/index.tsx +11 -6
- package/src/modules/PageEditor/index.tsx +1 -0
- package/src/modules/StructuredData/Form/index.tsx +1 -0
- package/src/modules/StructuredData/StructuredDataList/index.tsx +9 -2
- package/src/types/index.tsx +1 -0
package/README.md
CHANGED
package/config/griddo-config.js
CHANGED
|
@@ -3,12 +3,12 @@ const findUp = require("find-up");
|
|
|
3
3
|
|
|
4
4
|
const pkgDir = require("pkg-dir");
|
|
5
5
|
|
|
6
|
-
const isComponentLibraryEnv =
|
|
6
|
+
const isComponentLibraryEnv = __dirname.includes("node_modules");
|
|
7
7
|
|
|
8
8
|
const resolveComponentsPath = (customPath = "") =>
|
|
9
9
|
isComponentLibraryEnv
|
|
10
10
|
? path.resolve(pkgDir.sync(process.cwd()), customPath)
|
|
11
|
-
: path.resolve(pkgDir.sync(__dirname), "
|
|
11
|
+
: path.resolve(pkgDir.sync(__dirname), "../griddo-components", customPath);
|
|
12
12
|
|
|
13
13
|
const getComponentsJSConfig = () => {
|
|
14
14
|
const jsConfigPath = findUp.sync("jsconfig.json", { cwd: resolveComponentsPath() });
|
package/config/webpack.config.js
CHANGED
|
@@ -39,9 +39,6 @@ const reactRefreshOverlayEntry = require.resolve("react-dev-utils/refreshOverlay
|
|
|
39
39
|
// makes for a smoother build process.
|
|
40
40
|
const shouldInlineRuntimeChunk = process.env.INLINE_RUNTIME_CHUNK !== "false";
|
|
41
41
|
|
|
42
|
-
const emitErrorsAsWarnings = process.env.ESLINT_NO_DEV_ERRORS === "true";
|
|
43
|
-
const disableESLintPlugin = process.env.DISABLE_ESLINT_PLUGIN === "true";
|
|
44
|
-
|
|
45
42
|
const imageInlineSizeLimit = parseInt(process.env.IMAGE_INLINE_SIZE_LIMIT || "10000");
|
|
46
43
|
|
|
47
44
|
// Check if TypeScript is setup
|
|
@@ -15,6 +15,20 @@ const createConfig = ({ input, output }) => ({
|
|
|
15
15
|
},
|
|
16
16
|
},
|
|
17
17
|
plugins: [new webpack.ProgressPlugin()],
|
|
18
|
+
module: {
|
|
19
|
+
rules: [
|
|
20
|
+
{
|
|
21
|
+
test: /\.m?js$/,
|
|
22
|
+
exclude: /(node_modules|bower_components)/,
|
|
23
|
+
use: {
|
|
24
|
+
loader: "babel-loader",
|
|
25
|
+
options: {
|
|
26
|
+
presets: ["@babel/preset-env"],
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
],
|
|
31
|
+
},
|
|
18
32
|
});
|
|
19
33
|
|
|
20
34
|
module.exports = (withExternalConfig) => {
|
|
@@ -29,6 +43,10 @@ module.exports = (withExternalConfig) => {
|
|
|
29
43
|
return reject(err);
|
|
30
44
|
}
|
|
31
45
|
|
|
46
|
+
if (stats.compilation.errors && stats.compilation.errors.length) {
|
|
47
|
+
return reject(stats.compilation.errors[0]);
|
|
48
|
+
}
|
|
49
|
+
|
|
32
50
|
return resolve({
|
|
33
51
|
stats,
|
|
34
52
|
});
|
package/package.json
CHANGED
|
@@ -1,14 +1,25 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@griddo/ax",
|
|
3
3
|
"description": "Griddo Author Experience",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.51.2",
|
|
5
|
+
"authors": [
|
|
6
|
+
"Álvaro Sánchez' <alvaro.sanches@secuoyas.com>",
|
|
7
|
+
"Carlos Torres <carlos.torres@secuoyas.com>",
|
|
8
|
+
"Diego Béjar <diego.bejar@secuoyas.com>",
|
|
9
|
+
"Francis Vega <francis.vega@secuoyas.com>",
|
|
10
|
+
"Gonzalo Hernández <gonzalo.hernandez@secuoyas.com>",
|
|
11
|
+
"Sergio Ródenas <sergio.rodenas@secuoyas.com>",
|
|
12
|
+
"Txema León <txema.leon@secuoyas.com>"
|
|
13
|
+
],
|
|
14
|
+
"homepage": "https://griddo.io",
|
|
15
|
+
"repository": {
|
|
16
|
+
"type": "git",
|
|
17
|
+
"url": "https://github.com/griddo/griddo"
|
|
18
|
+
},
|
|
5
19
|
"bin": {
|
|
6
20
|
"griddo": "./scripts/griddo.js",
|
|
7
21
|
"griddo-sync-schemas": "./scripts/griddo-sync-schemas.js"
|
|
8
22
|
},
|
|
9
|
-
"publishConfig": {
|
|
10
|
-
"access": "public"
|
|
11
|
-
},
|
|
12
23
|
"scripts": {
|
|
13
24
|
"start": "npm run start:dev",
|
|
14
25
|
"start:local": "env-cmd -f env/.env.local node scripts/start.js",
|
|
@@ -22,17 +33,10 @@
|
|
|
22
33
|
"format": "prettier -w .",
|
|
23
34
|
"start:test": "env-cmd -f env/.env.development node scripts/dev.js"
|
|
24
35
|
},
|
|
25
|
-
"files": [
|
|
26
|
-
"config",
|
|
27
|
-
"public",
|
|
28
|
-
"scripts",
|
|
29
|
-
"src",
|
|
30
|
-
"tsconfig.json",
|
|
31
|
-
"tsconfig.paths.json"
|
|
32
|
-
],
|
|
33
36
|
"dependencies": {
|
|
34
37
|
"@atlaskit/tree": "^8.2.0",
|
|
35
38
|
"@babel/core": "7.14.2",
|
|
39
|
+
"@babel/preset-env": "^7.14.5",
|
|
36
40
|
"@babel/preset-react": "^7.14.5",
|
|
37
41
|
"@pmmmwh/react-refresh-webpack-plugin": "0.5.0-rc.0",
|
|
38
42
|
"@styled-system/prop-types": "5.1.2",
|
|
@@ -54,6 +58,7 @@
|
|
|
54
58
|
"@types/react-test-renderer": "16.9.1",
|
|
55
59
|
"@types/react-textarea-autosize": "^4.3.5",
|
|
56
60
|
"@types/styled-components": "4.1.19",
|
|
61
|
+
"@types/uuid": "^8.3.1",
|
|
57
62
|
"@types/webpack-env": "^1.14.1",
|
|
58
63
|
"@typescript-eslint/eslint-plugin": "^4.25.0",
|
|
59
64
|
"@typescript-eslint/parser": "^4.25.0",
|
|
@@ -68,7 +73,7 @@
|
|
|
68
73
|
"case-sensitive-paths-webpack-plugin": "2.4.0",
|
|
69
74
|
"compress.js": "^1.1.2",
|
|
70
75
|
"connected-react-router": "6.5.2",
|
|
71
|
-
"css-loader": "4.3.0",
|
|
76
|
+
"css-loader": "^4.3.0",
|
|
72
77
|
"css-minimizer-webpack-plugin": "3.0.2",
|
|
73
78
|
"date-fns": "^2.21.3",
|
|
74
79
|
"dotenv": "6.2.0",
|
|
@@ -114,17 +119,18 @@
|
|
|
114
119
|
"reflect-metadata": "0.1.13",
|
|
115
120
|
"resolve": "^1.20.0",
|
|
116
121
|
"resolve-url-loader": "^4.0.0",
|
|
117
|
-
"sass-loader": "^
|
|
122
|
+
"sass-loader": "^8.0.2",
|
|
118
123
|
"semver": "^7.3.5",
|
|
119
124
|
"source-map-loader": "^1.1.2",
|
|
120
125
|
"string-replace-loader": "^3.0.1",
|
|
121
|
-
"style-loader": "1.
|
|
126
|
+
"style-loader": "^1.2.1",
|
|
122
127
|
"styled-components": "^4.4.1",
|
|
123
128
|
"styled-reset": "4.0.1",
|
|
124
129
|
"terser-webpack-plugin": "1.4.1",
|
|
125
130
|
"ts-pnp": "1.1.4",
|
|
126
131
|
"typescript": "~3.8",
|
|
127
132
|
"url-loader": "^4.1.1",
|
|
133
|
+
"uuid": "^8.3.2",
|
|
128
134
|
"webpack": "4.44.2",
|
|
129
135
|
"webpack-dev-server": "3.11.1",
|
|
130
136
|
"webpack-manifest-plugin": "2.2.0",
|
|
@@ -145,9 +151,11 @@
|
|
|
145
151
|
"prettier": "^2.3.0",
|
|
146
152
|
"react-test-render": "1.1.2"
|
|
147
153
|
},
|
|
148
|
-
"
|
|
149
|
-
"
|
|
150
|
-
|
|
154
|
+
"babel": {
|
|
155
|
+
"presets": [
|
|
156
|
+
"react-app",
|
|
157
|
+
"@babel/preset-react"
|
|
158
|
+
]
|
|
151
159
|
},
|
|
152
160
|
"browserslist": {
|
|
153
161
|
"production": [
|
|
@@ -161,6 +169,14 @@
|
|
|
161
169
|
"last 1 safari version"
|
|
162
170
|
]
|
|
163
171
|
},
|
|
172
|
+
"files": [
|
|
173
|
+
"config",
|
|
174
|
+
"public",
|
|
175
|
+
"scripts",
|
|
176
|
+
"src",
|
|
177
|
+
"tsconfig.json",
|
|
178
|
+
"tsconfig.paths.json"
|
|
179
|
+
],
|
|
164
180
|
"jest": {
|
|
165
181
|
"roots": [
|
|
166
182
|
"<rootDir>/src"
|
|
@@ -209,11 +225,12 @@
|
|
|
209
225
|
"jest-watch-typeahead/testname"
|
|
210
226
|
]
|
|
211
227
|
},
|
|
212
|
-
"
|
|
213
|
-
"
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
228
|
+
"peerDependencies": {
|
|
229
|
+
"react": "*",
|
|
230
|
+
"react-dom": "*"
|
|
231
|
+
},
|
|
232
|
+
"publishConfig": {
|
|
233
|
+
"access": "public"
|
|
217
234
|
},
|
|
218
|
-
"gitHead": "
|
|
235
|
+
"gitHead": "137fb5810ec6523db7745a43f77e47484611441b"
|
|
219
236
|
}
|
|
@@ -5,6 +5,7 @@ const axios = require("axios");
|
|
|
5
5
|
const chalk = require("chalk");
|
|
6
6
|
const dotenv = require("dotenv");
|
|
7
7
|
const path = require("path");
|
|
8
|
+
const fs = require("fs");
|
|
8
9
|
const compiler = require("../config/webpackSchemas.config");
|
|
9
10
|
|
|
10
11
|
const { resolveComponentsPath } = require("../config/griddo-config");
|
|
@@ -21,10 +22,30 @@ async function main() {
|
|
|
21
22
|
console.clear();
|
|
22
23
|
const tempFile = "__griddo_config_parsed__.js";
|
|
23
24
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
const inputFile = resolveComponentsPath("griddo.config.js");
|
|
26
|
+
const outputFile = `${__dirname}/${tempFile}`;
|
|
27
|
+
|
|
28
|
+
if (fs.existsSync(outputFile)) {
|
|
29
|
+
fs.unlinkSync(outputFile);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
try {
|
|
33
|
+
if (!fs.existsSync(inputFile)) {
|
|
34
|
+
throw new Error(`Source schemas config not found: ${inputFile}`);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
await compiler({
|
|
38
|
+
input: resolveComponentsPath("griddo.config.js"),
|
|
39
|
+
output: { filename: tempFile, path: __dirname },
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
if (!fs.existsSync(outputFile)) {
|
|
43
|
+
throw new Error(`Unknown error when parsing ${inputFile}`);
|
|
44
|
+
}
|
|
45
|
+
} catch (err) {
|
|
46
|
+
console.log(`\n${chalk.red("ERROR:")} ${err.message}\n`);
|
|
47
|
+
process.exit(1);
|
|
48
|
+
}
|
|
28
49
|
|
|
29
50
|
const _griddoConfig = require(path.resolve(__dirname, `./${tempFile}`));
|
|
30
51
|
const griddoConfig = _griddoConfig.default || _griddoConfig;
|
|
@@ -48,11 +69,12 @@ async function main() {
|
|
|
48
69
|
method: API_METHOD,
|
|
49
70
|
data: { version, ...emptySchemas, ...griddoConfig.schemas },
|
|
50
71
|
});
|
|
51
|
-
console.log(res);
|
|
72
|
+
// console.log(res);
|
|
52
73
|
const data = await res?.json?.();
|
|
53
|
-
console.log(data);
|
|
74
|
+
// console.log(data);
|
|
54
75
|
} catch (e) {
|
|
55
76
|
console.log(chalk.red("ERROR:"), e.response?.data?.message || e.response || e.message);
|
|
77
|
+
process.exit(1);
|
|
56
78
|
}
|
|
57
79
|
}
|
|
58
80
|
|
package/scripts/griddo.js
CHANGED
package/src/api/sites.tsx
CHANGED
|
@@ -156,9 +156,9 @@ const getGlobalPages = async (params: IGetGlobalPagesParams, filterQuery?: strin
|
|
|
156
156
|
const getGlobalPagesLight = async (params: IGetGlobalPagesParams): Promise<AxiosResponse> => {
|
|
157
157
|
const { host, endpoint } = SERVICES.GET_GLOBAL_PAGES_LIGHT;
|
|
158
158
|
|
|
159
|
-
const { deleted, page, itemsPerPage, query, filterStructuredData, excludeSite } = params;
|
|
159
|
+
const { deleted, page, itemsPerPage, query, filterStructuredData, excludeSite, liveStatus } = params;
|
|
160
160
|
|
|
161
|
-
SERVICES.GET_GLOBAL_PAGES_LIGHT.dynamicUrl = `${host}${endpoint}?deleted=${deleted}&page=${page}&itemsPerPage=${itemsPerPage}&excludeSite=${excludeSite}`;
|
|
161
|
+
SERVICES.GET_GLOBAL_PAGES_LIGHT.dynamicUrl = `${host}${endpoint}?deleted=${deleted}&page=${page}&itemsPerPage=${itemsPerPage}&excludeSite=${excludeSite}&liveStatus=${liveStatus}`;
|
|
162
162
|
|
|
163
163
|
if (query && query.trim() !== "") SERVICES.GET_GLOBAL_PAGES_LIGHT.dynamicUrl += `&query=${query}`;
|
|
164
164
|
if (filterStructuredData)
|
|
@@ -28,10 +28,11 @@ const Field = (props: IProps): JSX.Element => {
|
|
|
28
28
|
|
|
29
29
|
const isGroup = field.type === "FieldGroup";
|
|
30
30
|
const isConditional = field.type === "ConditionalField";
|
|
31
|
+
const isArrayGroup = field.type === "ArrayFieldGroup";
|
|
31
32
|
|
|
32
33
|
let innerFields: JSX.Element[] = [];
|
|
33
34
|
|
|
34
|
-
if (isGroup || isConditional) {
|
|
35
|
+
if (isGroup || isConditional || isArrayGroup) {
|
|
35
36
|
const innerActions = { ...actions, updateValue, goTo };
|
|
36
37
|
innerFields = getInnerFields(field.fields, innerActions, selectedContent, isTemplateActivated, errors, deleteError);
|
|
37
38
|
}
|
|
@@ -13,7 +13,10 @@ const GlobalPageForm = (props: IProps): JSX.Element => {
|
|
|
13
13
|
const { selectedTab, setSelectedTab, schema, pageTitle, setHistoryPush, actions } = props;
|
|
14
14
|
const tabs = ["content", "config"];
|
|
15
15
|
|
|
16
|
-
const handleGetGlobalPage = async () =>
|
|
16
|
+
const handleGetGlobalPage = async () => {
|
|
17
|
+
actions.saveCurrentSiteInfoAction();
|
|
18
|
+
await actions.getGlobalFromLocalPageAction();
|
|
19
|
+
};
|
|
17
20
|
|
|
18
21
|
const handleClick = async () => {
|
|
19
22
|
await handleGetGlobalPage();
|
|
@@ -67,7 +70,10 @@ interface IProps {
|
|
|
67
70
|
schema: ISchema;
|
|
68
71
|
pageTitle?: string;
|
|
69
72
|
setHistoryPush?: (path: string, isEditor: boolean) => void;
|
|
70
|
-
actions: {
|
|
73
|
+
actions: {
|
|
74
|
+
getGlobalFromLocalPageAction(): Promise<void>;
|
|
75
|
+
saveCurrentSiteInfoAction(): Promise<void>;
|
|
76
|
+
};
|
|
71
77
|
}
|
|
72
78
|
|
|
73
79
|
export default GlobalPageForm;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
|
|
3
|
+
import { IconAction } from "@ax/components";
|
|
4
|
+
|
|
5
|
+
import * as S from "./style";
|
|
6
|
+
|
|
7
|
+
const ArrayFieldInline = (props: IProps): JSX.Element => {
|
|
8
|
+
const { fields, item, index, onChange, handleDelete } = props;
|
|
9
|
+
|
|
10
|
+
const deleteItem = () => {
|
|
11
|
+
handleDelete(index);
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
return (
|
|
15
|
+
<S.Wrapper>
|
|
16
|
+
<S.Content>
|
|
17
|
+
<S.IconWrapper>
|
|
18
|
+
<IconAction icon="delete" onClick={deleteItem} size="s" />
|
|
19
|
+
</S.IconWrapper>
|
|
20
|
+
{fields.map((field: any) => {
|
|
21
|
+
const key = field.props.objKey;
|
|
22
|
+
const handleChange = (newValue: any) => onChange({ [key]: newValue });
|
|
23
|
+
|
|
24
|
+
return {
|
|
25
|
+
...field,
|
|
26
|
+
props: { ...field.props, value: item[key], objKey: key, onChange: handleChange },
|
|
27
|
+
key,
|
|
28
|
+
};
|
|
29
|
+
})}
|
|
30
|
+
</S.Content>
|
|
31
|
+
</S.Wrapper>
|
|
32
|
+
);
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
interface IProps {
|
|
36
|
+
fields: any[];
|
|
37
|
+
item: Record<string, unknown>;
|
|
38
|
+
index: number;
|
|
39
|
+
onChange: (value: Record<string, unknown>) => void;
|
|
40
|
+
handleDelete: (index: number) => void;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export default ArrayFieldInline;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import styled from "styled-components";
|
|
2
|
+
|
|
3
|
+
const Wrapper = styled.div`
|
|
4
|
+
margin-bottom: ${(p) => p.theme.spacing.xs};
|
|
5
|
+
`;
|
|
6
|
+
|
|
7
|
+
const Content = styled.div`
|
|
8
|
+
position: relative;
|
|
9
|
+
display: flex;
|
|
10
|
+
|
|
11
|
+
& > div {
|
|
12
|
+
margin-right: ${(p) => p.theme.spacing.m};
|
|
13
|
+
|
|
14
|
+
&:last-child,
|
|
15
|
+
&:first-child {
|
|
16
|
+
margin-right: 0;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
`;
|
|
20
|
+
|
|
21
|
+
const IconWrapper = styled.div`
|
|
22
|
+
position: absolute;
|
|
23
|
+
top: -2px;
|
|
24
|
+
right: 10px;
|
|
25
|
+
width: ${(p) => p.theme.spacing.s};
|
|
26
|
+
height: ${(p) => p.theme.spacing.s};
|
|
27
|
+
z-index: 99;
|
|
28
|
+
`;
|
|
29
|
+
|
|
30
|
+
export { Wrapper, Content, IconWrapper };
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import React, { useState } from "react";
|
|
2
|
+
|
|
3
|
+
import * as S from "./style";
|
|
4
|
+
|
|
5
|
+
const ArrayFieldItem = (props: IProps): JSX.Element => {
|
|
6
|
+
const { fields, item, name, index, onChange, handleDelete } = props;
|
|
7
|
+
|
|
8
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
9
|
+
|
|
10
|
+
const handleClick = () => setIsOpen(!isOpen);
|
|
11
|
+
|
|
12
|
+
const deleteItem = () => {
|
|
13
|
+
handleDelete(index);
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
const menuOptions = [
|
|
17
|
+
{
|
|
18
|
+
label: "Delete",
|
|
19
|
+
icon: "delete",
|
|
20
|
+
action: deleteItem,
|
|
21
|
+
},
|
|
22
|
+
];
|
|
23
|
+
|
|
24
|
+
return (
|
|
25
|
+
<S.Wrapper isOpen={isOpen}>
|
|
26
|
+
<S.Title onClick={handleClick} isOpen={isOpen}>
|
|
27
|
+
{`${name} ${index + 1}`}
|
|
28
|
+
<S.StyledActionMenu icon="more" options={menuOptions} />
|
|
29
|
+
</S.Title>
|
|
30
|
+
<S.Content isOpen={isOpen}>
|
|
31
|
+
{fields.map((field: any) => {
|
|
32
|
+
const key = field.props.objKey;
|
|
33
|
+
const handleChange = (newValue: any) => onChange({ [key]: newValue });
|
|
34
|
+
|
|
35
|
+
return {
|
|
36
|
+
...field,
|
|
37
|
+
props: { ...field.props, value: item[key], objKey: key, onChange: handleChange },
|
|
38
|
+
key,
|
|
39
|
+
};
|
|
40
|
+
})}
|
|
41
|
+
</S.Content>
|
|
42
|
+
</S.Wrapper>
|
|
43
|
+
);
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
interface IProps {
|
|
47
|
+
name: string;
|
|
48
|
+
fields: any[];
|
|
49
|
+
item: Record<string, unknown>;
|
|
50
|
+
index: number;
|
|
51
|
+
onChange: (value: Record<string, unknown>) => void;
|
|
52
|
+
handleDelete: (index: number) => void;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export default ArrayFieldItem;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import styled from "styled-components";
|
|
2
|
+
import ActionMenu from "@ax/components/ActionMenu";
|
|
3
|
+
|
|
4
|
+
const Wrapper = styled.div<{ isOpen: boolean }>`
|
|
5
|
+
background-color: ${(p) => p.theme.color.uiBarBackground};
|
|
6
|
+
margin-bottom: ${(p) => p.theme.spacing.xs};
|
|
7
|
+
border: 1px solid ${(p) => (p.isOpen ? p.theme.color.interactive01 : p.theme.color.uiLine)};
|
|
8
|
+
border-radius: ${(p) => p.theme.radii.s};
|
|
9
|
+
`;
|
|
10
|
+
|
|
11
|
+
const StyledActionMenu = styled(ActionMenu)`
|
|
12
|
+
width: ${(p) => p.theme.spacing.m};
|
|
13
|
+
height: ${(p) => p.theme.spacing.m};
|
|
14
|
+
display: flex;
|
|
15
|
+
margin-left: auto;
|
|
16
|
+
`;
|
|
17
|
+
|
|
18
|
+
const Title = styled.div<{ isOpen: boolean }>`
|
|
19
|
+
position: relative;
|
|
20
|
+
display: flex;
|
|
21
|
+
${(p) => p.theme.textStyle.fieldContent};
|
|
22
|
+
color: ${(p) => p.theme.colors.textHighEmphasis};
|
|
23
|
+
padding: ${(p) => p.theme.spacing.s};
|
|
24
|
+
cursor: pointer;
|
|
25
|
+
text-transform: capitalize;
|
|
26
|
+
align-items: center;
|
|
27
|
+
width: 100%;
|
|
28
|
+
:after {
|
|
29
|
+
position: absolute;
|
|
30
|
+
right: 55px;
|
|
31
|
+
top: ${(p) => (p.isOpen ? `28px` : `24px`)};
|
|
32
|
+
content: "";
|
|
33
|
+
border: solid ${(p) => p.theme.color.interactive01};
|
|
34
|
+
border-width: 0 2px 2px 0;
|
|
35
|
+
display: inline-block;
|
|
36
|
+
padding: 3px;
|
|
37
|
+
transform: ${(p) => (p.isOpen ? `rotate(-135deg)` : `rotate(45deg)`)};
|
|
38
|
+
}
|
|
39
|
+
`;
|
|
40
|
+
|
|
41
|
+
const Content = styled.div<{ isOpen: boolean }>`
|
|
42
|
+
overflow-y: hidden;
|
|
43
|
+
max-height: ${(p) => (p.isOpen ? `auto` : 0)};
|
|
44
|
+
transition: all 0.5s ease-in-out;
|
|
45
|
+
padding: ${(p) => `0 ${p.theme.spacing.s}`};
|
|
46
|
+
`;
|
|
47
|
+
|
|
48
|
+
export { Wrapper, Title, Content, StyledActionMenu };
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import React, { useState } from "react";
|
|
2
|
+
import { v4 as uuidv4 } from "uuid";
|
|
3
|
+
|
|
4
|
+
import { Button, FieldsDivider } from "@ax/components";
|
|
5
|
+
import ArrayFieldItem from "./ArrayFieldItem";
|
|
6
|
+
import ArrayFieldInline from "./ArrayFieldInline";
|
|
7
|
+
|
|
8
|
+
const ArrayFieldGroup = (props: IProps): JSX.Element => {
|
|
9
|
+
const { value, name, innerFields, onChange, divider, arrayType } = props;
|
|
10
|
+
|
|
11
|
+
const initialValue = value ? Object.values(value) : [];
|
|
12
|
+
const initialValueMapped = initialValue.map((val: any) => {
|
|
13
|
+
return val.id ? val : { id: uuidv4(), ...val };
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
const [items, setItems] = useState(initialValueMapped);
|
|
17
|
+
|
|
18
|
+
const handleClick = () => {
|
|
19
|
+
const newItems = [...items, { id: uuidv4() }];
|
|
20
|
+
setItems(newItems);
|
|
21
|
+
onChange(newItems);
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
const handleChange = (newValue: Record<string, unknown>, index: number) => {
|
|
25
|
+
const updatedItems = [...items];
|
|
26
|
+
updatedItems[index] = {
|
|
27
|
+
...updatedItems[index],
|
|
28
|
+
...newValue,
|
|
29
|
+
};
|
|
30
|
+
setItems(updatedItems);
|
|
31
|
+
onChange(updatedItems);
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const handleDelete = (index: number) => {
|
|
35
|
+
const updatedItems = [...items];
|
|
36
|
+
updatedItems.splice(index, 1);
|
|
37
|
+
setItems(updatedItems);
|
|
38
|
+
onChange(updatedItems);
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const DividerComponent = () => (divider ? <FieldsDivider data={divider} /> : null);
|
|
42
|
+
|
|
43
|
+
return (
|
|
44
|
+
<div>
|
|
45
|
+
<DividerComponent />
|
|
46
|
+
<div>
|
|
47
|
+
{items &&
|
|
48
|
+
items.map((item: any, index: number) => {
|
|
49
|
+
const handleFieldChange = (newValue: Record<string, unknown>) => handleChange(newValue, index);
|
|
50
|
+
|
|
51
|
+
return arrayType === "inline" ? (
|
|
52
|
+
<ArrayFieldInline
|
|
53
|
+
key={item.id}
|
|
54
|
+
fields={innerFields}
|
|
55
|
+
item={item}
|
|
56
|
+
index={index}
|
|
57
|
+
onChange={handleFieldChange}
|
|
58
|
+
handleDelete={handleDelete}
|
|
59
|
+
/>
|
|
60
|
+
) : (
|
|
61
|
+
<ArrayFieldItem
|
|
62
|
+
key={item.id}
|
|
63
|
+
name={name}
|
|
64
|
+
fields={innerFields}
|
|
65
|
+
item={item}
|
|
66
|
+
index={index}
|
|
67
|
+
onChange={handleFieldChange}
|
|
68
|
+
handleDelete={handleDelete}
|
|
69
|
+
/>
|
|
70
|
+
);
|
|
71
|
+
})}
|
|
72
|
+
</div>
|
|
73
|
+
<div>
|
|
74
|
+
<Button type="button" onClick={handleClick} buttonStyle="line">
|
|
75
|
+
{`Add ${name}`}
|
|
76
|
+
</Button>
|
|
77
|
+
</div>
|
|
78
|
+
</div>
|
|
79
|
+
);
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
interface IProps {
|
|
83
|
+
value: Record<string, unknown>[];
|
|
84
|
+
name: string;
|
|
85
|
+
onChange: (value: Record<string, unknown>[]) => void;
|
|
86
|
+
innerFields: any[];
|
|
87
|
+
divider: { title: string; text: string };
|
|
88
|
+
arrayType: string;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export default ArrayFieldGroup;
|
|
@@ -4,7 +4,7 @@ import { IModule } from "@ax/types";
|
|
|
4
4
|
import { ComponentContainer } from "@ax/components";
|
|
5
5
|
|
|
6
6
|
import AddItemButton from "./AddItemButton";
|
|
7
|
-
import { getComponentProps, containerToComponentArray } from "../helpers";
|
|
7
|
+
import { getComponentProps, containerToComponentArray, getTypefromKey } from "../helpers";
|
|
8
8
|
|
|
9
9
|
import * as S from "./style";
|
|
10
10
|
|
|
@@ -21,8 +21,13 @@ const MixableComponentArray = (props: IMixableComponentArrayProps): JSX.Element
|
|
|
21
21
|
maxItems,
|
|
22
22
|
disabled,
|
|
23
23
|
activatedModules,
|
|
24
|
+
objKey,
|
|
25
|
+
field,
|
|
24
26
|
} = props;
|
|
25
27
|
|
|
28
|
+
const type = getTypefromKey(objKey);
|
|
29
|
+
const { contentType = type } = field;
|
|
30
|
+
|
|
26
31
|
let addModuleAction: any;
|
|
27
32
|
let addComponentAction: any;
|
|
28
33
|
|
|
@@ -38,14 +43,12 @@ const MixableComponentArray = (props: IMixableComponentArrayProps): JSX.Element
|
|
|
38
43
|
return fixedValue.length > 1 ? `#${index + 1} ${name}` : name;
|
|
39
44
|
};
|
|
40
45
|
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
const isComponentModule = !!componentModules;
|
|
44
|
-
const isModuleArr = !elements && !isComponentModule;
|
|
46
|
+
const isComponentModule = contentType === "components";
|
|
47
|
+
const isModuleArr = contentType === "modules";
|
|
45
48
|
|
|
46
49
|
const handleAddModule = (moduleType: string) => addModuleAction(moduleType, editorID, isComponentModule);
|
|
47
50
|
|
|
48
|
-
const handleAddComponent = (componentType: string) => addComponentAction && addComponentAction(componentType);
|
|
51
|
+
const handleAddComponent = (componentType: string) => addComponentAction && addComponentAction(componentType, objKey);
|
|
49
52
|
|
|
50
53
|
const handleAdd = isModuleArr ? handleAddModule : handleAddComponent;
|
|
51
54
|
|
|
@@ -90,6 +93,7 @@ const MixableComponentArray = (props: IMixableComponentArrayProps): JSX.Element
|
|
|
90
93
|
selectedContent={selectedContent}
|
|
91
94
|
disabled={disabled}
|
|
92
95
|
canDuplicate={showAddItemButton && !isModuleDeactivated}
|
|
96
|
+
parentKey={objKey}
|
|
93
97
|
/>
|
|
94
98
|
);
|
|
95
99
|
})}
|
|
@@ -109,6 +113,8 @@ export interface IMixableComponentArrayProps {
|
|
|
109
113
|
categories?: any;
|
|
110
114
|
disabled?: boolean;
|
|
111
115
|
activatedModules: string[];
|
|
116
|
+
objKey: string;
|
|
117
|
+
field: any;
|
|
112
118
|
}
|
|
113
119
|
|
|
114
120
|
export default MixableComponentArray;
|