openyida 2026.9.19 → 2026.9.20
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 +3 -3
- package/lib/app/application-style.js +67 -0
- package/lib/app/create-form/args.js +37 -12
- package/lib/app/create-form/batch.js +32 -5
- package/lib/app/create-form.js +94 -57
- package/lib/app/form-field-validator.js +0 -36
- package/lib/app/services/form-compiler.js +0 -2
- package/lib/app/theme-from-design.js +2 -1
- package/lib/core/command-manifest.js +51 -7
- package/lib/core/locales/en.js +3 -3
- package/lib/core/locales/zh.js +3 -3
- package/lib/core/sample.js +20 -1
- package/lib/design/document.js +1 -0
- package/lib/design-plan/init.js +5 -2
- package/lib/design-plan/materialize.js +23 -2
- package/lib/design-plan/validate.js +10 -0
- package/lib/design-plan/visual-policy.js +11 -0
- package/package.json +1 -1
- package/yida-skills/references/official-example-schema-patterns.md +1 -1
- package/yida-skills/skills/yida-app/SKILL.md +3 -0
- package/yida-skills/skills/yida-create-form-page/SKILL.md +34 -43
- package/yida-skills/skills/yida-create-form-page/references/advanced-form-modes.md +5 -5
- package/yida-skills/skills/yida-create-form-page/references/association-form-field.md +4 -4
- package/yida-skills/skills/yida-create-form-page/references/batch-forms.md +2 -2
- package/yida-skills/skills/yida-create-form-page/references/field-definition-guide.md +4 -16
- package/yida-skills/skills/yida-create-form-page/references/form-field-properties.md +14 -37
- package/yida-skills/skills/yida-design/SKILL.md +3 -3
- package/yida-skills/skills/yida-design/references/application-style-library.md +78 -0
- package/yida-skills/skills/yida-design/references/application-theme-consistency.md +3 -2
- package/yida-skills/skills/yida-design/references/native-form-styles.md +208 -0
- package/yida-skills/skills/yida-design/references/theme/app-custom-theme-template.css +48 -1
- package/yida-skills/skills/yida-design/references/theme/application-style-recipes.css +58 -0
- package/yida-skills/skills/yida-design/references/theme-selection.md +5 -5
- package/yida-skills/skills/yida-design/scripts/validate_design_themes.py +23 -6
- package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/SKILL.md +1 -1
- package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/references/build-plan-compact-schema.md +2 -0
- package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/references/build-plan-schema.md +1 -1
- package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/references/visual-theme-selection.md +12 -11
- package/yida-skills/skills/yida-design/templates/application-styles.json +398 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-amber/app_theme.css +607 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-amber/design.md +219 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-amber/form-layout.json +15 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-editorial/app_theme.css +607 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-editorial/design.md +219 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-editorial/form-layout.json +14 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-executive/app_theme.css +607 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-executive/design.md +219 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-executive/form-layout.json +13 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-finance/app_theme.css +607 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-finance/design.md +219 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-finance/form-layout.json +14 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-glass/app_theme.css +607 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-glass/design.md +219 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-glass/form-layout.json +14 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-graphite/app_theme.css +607 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-graphite/design.md +219 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-graphite/form-layout.json +14 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-line/app_theme.css +607 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-line/design.md +219 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-line/form-layout.json +13 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-neon/app_theme.css +607 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-neon/design.md +219 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-neon/form-layout.json +14 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-nordic/app_theme.css +607 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-nordic/design.md +219 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-nordic/form-layout.json +13 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-paper/app_theme.css +607 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-paper/design.md +219 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-paper/form-layout.json +13 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-platinum/app_theme.css +607 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-platinum/design.md +219 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-platinum/form-layout.json +14 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-plum/app_theme.css +607 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-plum/design.md +219 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-plum/form-layout.json +14 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-pop/app_theme.css +607 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-pop/design.md +219 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-pop/form-layout.json +14 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-sage/app_theme.css +607 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-sage/design.md +219 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-sage/form-layout.json +14 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-teal/app_theme.css +607 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-teal/design.md +219 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-teal/form-layout.json +14 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-terminal/app_theme.css +607 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-terminal/design.md +219 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-terminal/form-layout.json +14 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-ticket/app_theme.css +607 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-ticket/design.md +219 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-ticket/form-layout.json +13 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-wire/app_theme.css +607 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-wire/design.md +219 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-wire/form-layout.json +14 -0
- package/yida-skills/skills/yida-design/templates/design-themes/dark-inset-hairline.md +4 -0
- package/yida-skills/skills/yida-design/templates/design-themes/dark-rail-fine-lines.md +4 -0
- package/yida-skills/skills/yida-design/templates/design-themes/dark-rail-signal-panels.md +4 -0
- package/yida-skills/skills/yida-design/templates/design-themes/free-creative/app_theme.css +526 -0
- package/yida-skills/skills/yida-design/templates/design-themes/free-creative/design.md +191 -0
- package/yida-skills/skills/yida-design/templates/design-themes/free-creative/form-layout.json +13 -0
- package/yida-skills/skills/yida-design/templates/design-themes/graphite-bevel-grid.md +4 -0
- package/yida-skills/skills/yida-design/templates/design-themes/hairline-shared-bands.md +4 -0
- package/yida-skills/skills/yida-design/templates/design-themes/hairline-soft-blocks.md +4 -0
- package/yida-skills/skills/yida-design/templates/design-themes/index.json +276 -1
- package/yida-skills/skills/yida-design/templates/design-themes/ink-glow-soft-panels.md +4 -0
- package/yida-skills/skills/yida-design/templates/design-themes/inset-frame-pixel-rhythm.md +4 -0
- package/yida-skills/skills/yida-design/templates/design-themes/outlined-texture-duotone.md +4 -0
- package/yida-skills/skills/yida-design/templates/design-themes/soft-inset-surfaces.md +4 -0
- package/yida-skills/skills/yida-design/templates/design-themes/soft-outline-rhythm.md +4 -0
- package/yida-skills/skills/yida-design/templates/design-themes/soft-rail-bold-band.md +4 -0
- package/yida-skills/skills/yida-design/templates/design-themes/soft-spectral-panels.md +4 -0
- package/yida-skills/skills/yida-design/templates/design-themes/warm-canvas-contrast-panels.md +4 -0
- package/yida-skills/skills/yida-design/templates/design-themes/warm-rail-muted-panels.md +4 -0
- package/yida-skills/skills/yida-design/workflow/output-design.md +5 -2
- package/yida-skills/skills/yida-design/workflow/step-2-theme-system.md +9 -3
package/README.md
CHANGED
|
@@ -183,7 +183,7 @@ openyida get-schema APP_XXX FORM_XXX --compact --resolve-fields "Customer Name,S
|
|
|
183
183
|
openyida get-schema APP_XXX --all --output-dir .cache/schemas
|
|
184
184
|
```
|
|
185
185
|
|
|
186
|
-
|
|
186
|
+
Native forms use a component tree: business fields capture data, tabs switch content, action groups trigger business actions, images establish visual focus, status areas provide feedback, and `Divider` plus `ColumnContainer` organize hierarchy and columns. `create-form` field definitions create 19 business field types plus `Divider` and `ColumnContainer` (mapped to `ColumnsLayout` + `Column`), while updates retain other existing components.
|
|
187
187
|
|
|
188
188
|
### Custom Page Development
|
|
189
189
|
|
|
@@ -415,7 +415,7 @@ Run `openyida --help` or `openyida <command> --help` for detailed usage.
|
|
|
415
415
|
| Command | Description |
|
|
416
416
|
|---------|-------------|
|
|
417
417
|
| `openyida create-form batch <appType> <plan.json> [--concurrency 1..4] [--check] [--json]` | Create forms concurrently by dependency |
|
|
418
|
-
| `openyida create-form create <appType> "<formTitle>" <fieldsJsonFile> [--icon auto\|<iconName>] [--locale zh_CN\|en_US\|ja_JP] [--open\|--no-open]` | Create a form page |
|
|
418
|
+
| `openyida create-form create <appType> "<formTitle>" <fieldsJsonFile> [--layout single\|double\|card\|section] [--theme default\|compact\|comfortable] [--label-align top\|left\|right] [--icon auto\|<iconName>] [--locale zh_CN\|en_US\|ja_JP] [--open\|--no-open]` | Create a form page |
|
|
419
419
|
| `openyida create-form icons [--json]` | List available form navigation icons |
|
|
420
420
|
| `openyida create-form validate-fields <fieldsJsonOrFile> [--json]` | Validate form field JSON locally |
|
|
421
421
|
| `openyida create-form update <appType> <formUuid> (<changesJsonOrFile> \| --data-file <changesJsonOrFile>) [--locale zh_CN\|en_US\|ja_JP] [--open\|--no-open]` | Update a form page |
|
|
@@ -523,7 +523,7 @@ Run `openyida --help` or `openyida <command> --help` for detailed usage.
|
|
|
523
523
|
| `openyida a2a <serve\|agent-card> [options]` | Start local read-only A2A adapter or print Agent Card |
|
|
524
524
|
| `openyida bridge start [--token <pair-token>] [--port 6736] [--origin https://demo.aliwork.com] [--open\|--no-open]` | Start OpenYida local web bridge service |
|
|
525
525
|
| `openyida copy [--force]` | Copy project working directory |
|
|
526
|
-
| `openyida sample [--list] [<skill> <name>] [--output <file>] [--var KEY=VALUE ...] [--design-file <design.md>]` | Output code samples/templates |
|
|
526
|
+
| `openyida sample [--list] [<skill> <name>] [--output <file-or-directory>] [--var KEY=VALUE ...] [--design-file <design.md>] [--style-id <themeId\|free-creative>]` | Output code samples/templates |
|
|
527
527
|
| `openyida doctor [--fix]` | Environment diagnostics & auto-fix |
|
|
528
528
|
| `openyida db-seq-fix [--fix]` | Detect and repair PostgreSQL sequence drift |
|
|
529
529
|
| `openyida formula evaluate <formula\|file> [--schema file]` | Static-check Yida formula syntax and field refs |
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const { CliError } = require('../core/cli-error');
|
|
6
|
+
const { t } = require('../core/i18n');
|
|
7
|
+
const { DESIGN_SKILL_ROOT, loadThemeIndex } = require('../design-plan/themes');
|
|
8
|
+
const START = '/* OPENYIDA APPLICATION STYLE RECIPES START';
|
|
9
|
+
const END = '/* OPENYIDA APPLICATION STYLE RECIPES END */';
|
|
10
|
+
const CREATIVE_TOKENS = [
|
|
11
|
+
'--pod-page-bg-color', '--pod-card-bg-color', '--color-text1-4',
|
|
12
|
+
'--form-element-medium-corner', '--form-element-medium-height',
|
|
13
|
+
'--pod-page-footer-bg-color', '--pod-sticky-footer-box-shadow',
|
|
14
|
+
'--oyd-content-width', '--oyd-content-padding', '--oyd-field-gap',
|
|
15
|
+
'--oyd-heading-font', '--oyd-heading-size', '--oyd-rule-style',
|
|
16
|
+
];
|
|
17
|
+
|
|
18
|
+
function validateCreativeDirection(direction, tokens) {
|
|
19
|
+
const missing = ['businessRationale', 'composition', 'typography', 'material', 'formLayout']
|
|
20
|
+
.filter(key => typeof direction?.[key] !== 'string' || !direction[key].trim());
|
|
21
|
+
missing.push(...CREATIVE_TOKENS.filter(key => typeof tokens?.[key] !== 'string' || !tokens[key].trim()));
|
|
22
|
+
if (missing.length) {
|
|
23
|
+
throw new CliError(t('design_document.invalid', 'creativeDirection', missing.join(', ')), {
|
|
24
|
+
code: 'APPLICATION_STYLE_CREATIVE_INCOMPLETE', details: { missing },
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function applyApplicationStyle(css, metadata, tokens) {
|
|
30
|
+
const style = metadata.applicationStyle;
|
|
31
|
+
if (style && (style.recipe !== 'application-style-v1' || !['template', 'creative'].includes(style.mode))) {
|
|
32
|
+
throw new CliError(t('design_document.invalid', 'applicationStyle', 'APPLICATION_STYLE_INVALID'), { code: 'APPLICATION_STYLE_INVALID' });
|
|
33
|
+
}
|
|
34
|
+
if (style?.mode === 'creative') {validateCreativeDirection(metadata.creativeDirection, tokens);}
|
|
35
|
+
const first = css.indexOf(START);
|
|
36
|
+
const last = css.indexOf(END);
|
|
37
|
+
if (first >= 0 && last < first) {
|
|
38
|
+
throw new CliError(t('design_document.invalid', 'app_theme.css', 'APPLICATION_STYLE_CSS_INVALID'), { code: 'APPLICATION_STYLE_CSS_INVALID' });
|
|
39
|
+
}
|
|
40
|
+
const recipe = style
|
|
41
|
+
? fs.readFileSync(path.join(DESIGN_SKILL_ROOT, 'references/theme/application-style-recipes.css'), 'utf8').trim()
|
|
42
|
+
: '';
|
|
43
|
+
// Only the managed recipe block is replaced. User-authored rules stay intact.
|
|
44
|
+
if (first >= 0) {return css.slice(0, first) + recipe + css.slice(last + END.length);}
|
|
45
|
+
return recipe ? `${css.trimEnd()}\n\n${recipe}\n` : css;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function exportApplicationStyle(id, outputDirectory) {
|
|
49
|
+
const theme = loadThemeIndex().themes.find(item => item.themeId === id && item.collection === 'application-styles');
|
|
50
|
+
if (!theme) {throw new CliError(t('design_document.invalid', id || '--style-id', 'APPLICATION_STYLE_UNKNOWN'), { code: 'APPLICATION_STYLE_UNKNOWN' });}
|
|
51
|
+
const directory = path.resolve(outputDirectory);
|
|
52
|
+
const assets = [['design.md', theme.templatePath], ['app_theme.css', theme.cssTemplatePath], ['form-layout.json', theme.formLayoutPath]];
|
|
53
|
+
const outputs = assets.map(([name, relative]) => {
|
|
54
|
+
const source = path.resolve(DESIGN_SKILL_ROOT, relative);
|
|
55
|
+
const target = path.join(directory, name);
|
|
56
|
+
const root = path.resolve(DESIGN_SKILL_ROOT, 'templates/design-themes') + path.sep;
|
|
57
|
+
if (!source.startsWith(root) || fs.existsSync(target)) {
|
|
58
|
+
throw new CliError(t('design_document.invalid', target, 'APPLICATION_STYLE_OUTPUT_CONFLICT'), { code: 'APPLICATION_STYLE_OUTPUT_CONFLICT' });
|
|
59
|
+
}
|
|
60
|
+
return { source, target, content: fs.readFileSync(source, 'utf8') };
|
|
61
|
+
});
|
|
62
|
+
fs.mkdirSync(directory, { recursive: true });
|
|
63
|
+
for (const item of outputs) {fs.writeFileSync(item.target, item.content, { flag: 'wx' });}
|
|
64
|
+
return { success: true, mode: theme.mode, themeId: id, authoringRequired: true, outputs: outputs.map(item => item.target) };
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
module.exports = { applyApplicationStyle, validateCreativeDirection, CREATIVE_TOKENS, exportApplicationStyle };
|
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
const { detectDeprecatedCreateFormInvocation } = require('../../core/command-contract');
|
|
4
4
|
|
|
5
|
+
const CREATE_FORM_LAYOUTS = new Set(['single', '1', 'double', '2', 'card', 'section']);
|
|
6
|
+
const CREATE_FORM_THEMES = new Set(['default', 'compact', 'comfortable']);
|
|
7
|
+
const CREATE_FORM_LABEL_ALIGNS = new Set(['top', 'left', 'right']);
|
|
8
|
+
|
|
5
9
|
function parseMaybeJsonValue(value) {
|
|
6
10
|
if (typeof value !== 'string') {
|
|
7
11
|
return value;
|
|
@@ -94,24 +98,38 @@ function createParseArgs(dependencies) {
|
|
|
94
98
|
const args = [...rawArgs];
|
|
95
99
|
|
|
96
100
|
for (let i = 0; i < args.length; i++) {
|
|
97
|
-
if (args[i] === '--layout'
|
|
98
|
-
|
|
101
|
+
if (args[i] === '--layout') {
|
|
102
|
+
const value = args[i + 1];
|
|
103
|
+
if (!value || value.startsWith('--') || !CREATE_FORM_LAYOUTS.has(value)) {
|
|
104
|
+
throwCreateFormError('--layout must be one of: single, double, card, section', 'CREATE_FORM_INVALID_ARGUMENTS');
|
|
105
|
+
}
|
|
106
|
+
options.layout = value;
|
|
99
107
|
args.splice(i, 2);
|
|
100
108
|
i--;
|
|
101
|
-
} else if (args[i] === '--theme'
|
|
102
|
-
|
|
109
|
+
} else if (args[i] === '--theme') {
|
|
110
|
+
const value = args[i + 1];
|
|
111
|
+
if (!value || value.startsWith('--') || !CREATE_FORM_THEMES.has(value)) {
|
|
112
|
+
throwCreateFormError('--theme must be one of: default, compact, comfortable', 'CREATE_FORM_INVALID_ARGUMENTS');
|
|
113
|
+
}
|
|
114
|
+
options.theme = value;
|
|
103
115
|
args.splice(i, 2);
|
|
104
116
|
i--;
|
|
105
|
-
} else if (args[i] === '--label-align'
|
|
106
|
-
|
|
117
|
+
} else if (args[i] === '--label-align') {
|
|
118
|
+
const value = args[i + 1];
|
|
119
|
+
if (!value || value.startsWith('--') || !CREATE_FORM_LABEL_ALIGNS.has(value)) {
|
|
120
|
+
throwCreateFormError('--label-align must be one of: top, left, right', 'CREATE_FORM_INVALID_ARGUMENTS');
|
|
121
|
+
}
|
|
122
|
+
options.labelAlign = value;
|
|
107
123
|
args.splice(i, 2);
|
|
108
124
|
i--;
|
|
109
|
-
} else if (args[i] === '--icon'
|
|
110
|
-
|
|
125
|
+
} else if (args[i] === '--icon') {
|
|
126
|
+
const value = args[i + 1];
|
|
127
|
+
if (!value || value.startsWith('--')) {
|
|
128
|
+
throwCreateFormError('--icon requires a value', 'CREATE_FORM_INVALID_ARGUMENTS');
|
|
129
|
+
}
|
|
130
|
+
options.icon = value;
|
|
111
131
|
args.splice(i, 2);
|
|
112
132
|
i--;
|
|
113
|
-
} else if (args[i] === '--icon') {
|
|
114
|
-
throwCreateFormError('--icon requires a value', 'CREATE_FORM_INVALID_ARGUMENTS');
|
|
115
133
|
} else if (args[i] === '--data-file') {
|
|
116
134
|
const next = args[i + 1];
|
|
117
135
|
if (dataFileInput !== undefined || !next || next.startsWith('--')) {
|
|
@@ -120,8 +138,12 @@ function createParseArgs(dependencies) {
|
|
|
120
138
|
dataFileInput = next;
|
|
121
139
|
args.splice(i, 2);
|
|
122
140
|
i--;
|
|
123
|
-
} else if (
|
|
124
|
-
|
|
141
|
+
} else if (args[i] === '--locale' || args[i] === '--content-locale' || args[i] === '--lang') {
|
|
142
|
+
const value = args[i + 1];
|
|
143
|
+
if (!value || value.startsWith('--')) {
|
|
144
|
+
throwCreateFormError(`${args[i]} requires a value`, 'CREATE_FORM_INVALID_ARGUMENTS');
|
|
145
|
+
}
|
|
146
|
+
options.contentLocale = value;
|
|
125
147
|
if (!normalizeYidaLocale(options.contentLocale)) {
|
|
126
148
|
error(`Unsupported locale: ${options.contentLocale}`);
|
|
127
149
|
throwCreateFormError(`Unsupported locale: ${options.contentLocale}`, 'CREATE_FORM_INVALID_ARGUMENTS');
|
|
@@ -361,4 +383,7 @@ module.exports = {
|
|
|
361
383
|
createParseArgs,
|
|
362
384
|
parseInlineValidationOptions,
|
|
363
385
|
parseMaybeJsonValue,
|
|
386
|
+
CREATE_FORM_LAYOUTS,
|
|
387
|
+
CREATE_FORM_THEMES,
|
|
388
|
+
CREATE_FORM_LABEL_ALIGNS,
|
|
364
389
|
};
|
|
@@ -9,10 +9,15 @@ const { t } = require('../../core/i18n');
|
|
|
9
9
|
const { usage, hint } = require('../../core/chalk');
|
|
10
10
|
const { assertNoEmojiInText, assertNoEmojiInValue } = require('../../core/no-emoji-guard');
|
|
11
11
|
const { normalizeYidaLocale } = require('../../core/yida-i18n');
|
|
12
|
+
const {
|
|
13
|
+
CREATE_FORM_LAYOUTS,
|
|
14
|
+
CREATE_FORM_THEMES,
|
|
15
|
+
CREATE_FORM_LABEL_ALIGNS,
|
|
16
|
+
} = require('./args');
|
|
12
17
|
const { FORM_NAV_ICONS, resolveFormNavIcon } = require('./nav-icon');
|
|
13
18
|
|
|
14
19
|
const BATCH_USAGE = 'openyida create-form batch <appType> <plan.json> [--concurrency 1..4] [--check] [--json]';
|
|
15
|
-
const BATCH_PLAN_EXAMPLE = '{"forms":[{"key":"customer","title":"客户","fieldsFile":"customer-fields.json"},{"key":"order","title":"订单","fieldsFile":"order-fields.json","dependsOn":["customer"]}]}';
|
|
20
|
+
const BATCH_PLAN_EXAMPLE = '{"forms":[{"key":"customer","title":"客户","fieldsFile":"customer-fields.json","layout":"section","theme":"comfortable","labelAlign":"left"},{"key":"order","title":"订单","fieldsFile":"order-fields.json","dependsOn":["customer"]}]}';
|
|
16
21
|
|
|
17
22
|
function invalid(reason) {
|
|
18
23
|
throw new CliError(t('create_form.batch_invalid'), { code: 'FORM_BATCH_INVALID', details: { reason } });
|
|
@@ -46,6 +51,20 @@ function validateStaticDefinition(form, fields) {
|
|
|
46
51
|
locale: form.locale,
|
|
47
52
|
});
|
|
48
53
|
}
|
|
54
|
+
for (const [key, values] of [
|
|
55
|
+
['layout', CREATE_FORM_LAYOUTS],
|
|
56
|
+
['theme', CREATE_FORM_THEMES],
|
|
57
|
+
['labelAlign', CREATE_FORM_LABEL_ALIGNS],
|
|
58
|
+
]) {
|
|
59
|
+
if (form[key] !== undefined && !values.has(form[key])) {
|
|
60
|
+
invalid({
|
|
61
|
+
formKey: form.key,
|
|
62
|
+
errorCode: 'CREATE_FORM_INVALID_ARGUMENTS',
|
|
63
|
+
errorMsg: `Unsupported ${key}: ${form[key]}`,
|
|
64
|
+
[key]: form[key],
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
}
|
|
49
68
|
}
|
|
50
69
|
|
|
51
70
|
function parseArgs(args) {
|
|
@@ -126,9 +145,9 @@ function loadPlan(file, options = {}) {
|
|
|
126
145
|
if (!form || !/^[a-zA-Z][\w-]*$/.test(form.key || '') || typeof form.title !== 'string' || !form.title.trim() ||
|
|
127
146
|
(form.fields === undefined) === (form.fieldsFile === undefined) ||
|
|
128
147
|
(form.dependsOn !== undefined && (!Array.isArray(form.dependsOn) || form.dependsOn.some(key => typeof key !== 'string')))) { invalid('form'); }
|
|
129
|
-
if (Object.keys(form).some(key => !['key', 'title', 'fields', 'fieldsFile', 'dependsOn', 'formUuid', 'icon', 'locale'].includes(key))) { invalid(form.key); }
|
|
148
|
+
if (Object.keys(form).some(key => !['key', 'title', 'fields', 'fieldsFile', 'dependsOn', 'formUuid', 'layout', 'theme', 'labelAlign', 'icon', 'locale'].includes(key))) { invalid(form.key); }
|
|
130
149
|
if (form.formUuid !== undefined && (typeof form.formUuid !== 'string' || !form.formUuid.startsWith('FORM'))) { invalid(form.key); }
|
|
131
|
-
for (const key of ['icon', 'locale']) { if (form[key] !== undefined && typeof form[key] !== 'string') { invalid(key); } }
|
|
150
|
+
for (const key of ['layout', 'theme', 'labelAlign', 'icon', 'locale']) { if (form[key] !== undefined && typeof form[key] !== 'string') { invalid(key); } }
|
|
132
151
|
const rawFields = form.fieldsFile === undefined ? form.fields : JSON.parse(fs.readFileSync(path.resolve(path.dirname(file), form.fieldsFile), 'utf8'));
|
|
133
152
|
const fields = normalizeAssociationReferences(rawFields, options.appType);
|
|
134
153
|
validateStaticDefinition(form, fields);
|
|
@@ -192,7 +211,7 @@ function expectedReadbackFields(fields) {
|
|
|
192
211
|
expected.push(...expectedReadbackFields(field.children));
|
|
193
212
|
continue;
|
|
194
213
|
}
|
|
195
|
-
if (['Divider', 'RichText'
|
|
214
|
+
if (['Divider', 'RichText'].includes(field.type)) { continue; }
|
|
196
215
|
if (typeof field.label === 'string' && field.label.trim()) {
|
|
197
216
|
expected.push({ label: field.label.trim(), componentName: field.type });
|
|
198
217
|
}
|
|
@@ -361,7 +380,15 @@ async function run(args, dependencies = {}) {
|
|
|
361
380
|
const resolvedFields = mapReferences(form.fields, resolve);
|
|
362
381
|
if (!formUuid) {
|
|
363
382
|
const argv = ['create-form', 'create', options.appType, form.title, JSON.stringify(resolvedFields), '--no-open'];
|
|
364
|
-
for (const key
|
|
383
|
+
for (const [key, option] of Object.entries({
|
|
384
|
+
layout: '--layout',
|
|
385
|
+
theme: '--theme',
|
|
386
|
+
labelAlign: '--label-align',
|
|
387
|
+
icon: '--icon',
|
|
388
|
+
locale: '--locale',
|
|
389
|
+
})) {
|
|
390
|
+
if (form[key]) { argv.push(option, form[key]); }
|
|
391
|
+
}
|
|
365
392
|
try {
|
|
366
393
|
const created = await call(argv);
|
|
367
394
|
if (typeof created.formUuid !== 'string' || !created.formUuid.startsWith('FORM')) { invalid(`create result: ${form.key}`); }
|
package/lib/app/create-form.js
CHANGED
|
@@ -288,13 +288,9 @@ const FORM_PRESENTATION_TYPE_ALIAS = {
|
|
|
288
288
|
columnContainer: 'ColumnsLayout',
|
|
289
289
|
Column: 'Column',
|
|
290
290
|
column: 'Column',
|
|
291
|
-
GroupContainer: 'PageSection',
|
|
292
|
-
groupContainer: 'PageSection',
|
|
293
|
-
PageSection: 'PageSection',
|
|
294
|
-
pageSection: 'PageSection',
|
|
295
291
|
};
|
|
296
292
|
|
|
297
|
-
const FORM_PRESENTATION_COMPONENTS = ['Divider', 'ColumnsLayout', 'Column'
|
|
293
|
+
const FORM_PRESENTATION_COMPONENTS = ['Divider', 'ColumnsLayout', 'Column'];
|
|
298
294
|
|
|
299
295
|
const COMPONENT_ALIAS_META = Symbol('openyida.componentAlias');
|
|
300
296
|
|
|
@@ -521,13 +517,6 @@ function normalizeI18nValue(value, fallback) {
|
|
|
521
517
|
return i18n(text, text, text);
|
|
522
518
|
}
|
|
523
519
|
|
|
524
|
-
function normalizeStyleChoice(value, fallback) {
|
|
525
|
-
if (value && typeof value === 'object') {
|
|
526
|
-
return value;
|
|
527
|
-
}
|
|
528
|
-
return { value: value || fallback };
|
|
529
|
-
}
|
|
530
|
-
|
|
531
520
|
function buildSchemaNode(componentName, props, children, options) {
|
|
532
521
|
const node = {
|
|
533
522
|
componentName: componentName,
|
|
@@ -596,41 +585,6 @@ function buildDividerComponent(field) {
|
|
|
596
585
|
return buildSchemaNode('Divider', props, undefined, { fieldId: props.fieldId || fieldId });
|
|
597
586
|
}
|
|
598
587
|
|
|
599
|
-
function buildPageSectionComponent(field) {
|
|
600
|
-
const fieldId = field.fieldId || field.id || generateFieldId('PageSection');
|
|
601
|
-
const props = mergeExtraProps({
|
|
602
|
-
fieldId,
|
|
603
|
-
behavior: field.behavior || 'NORMAL',
|
|
604
|
-
visibility: field.visibility || ['PC', 'MOBILE'],
|
|
605
|
-
showHeader: field.showHeader !== undefined ? !!field.showHeader : true,
|
|
606
|
-
title: normalizeI18nValue(field.title !== undefined ? field.title : field.label, '分组'),
|
|
607
|
-
tooltip: normalizeI18nValue(field.tooltip || field.tips, ''),
|
|
608
|
-
showHeadDivider: field.showHeadDivider !== undefined ? !!field.showHeadDivider : true,
|
|
609
|
-
sectionHeaderStyle: field.sectionHeaderStyle || 'origin',
|
|
610
|
-
sectionHeaderBgColor: field.sectionHeaderBgColor || '#0089ff',
|
|
611
|
-
sectionHeaderTitleColor: field.sectionHeaderTitleColor || '#171A1D',
|
|
612
|
-
pcStyle: normalizeStyleChoice(field.pcStyle, 'origin'),
|
|
613
|
-
showBorder: !!field.showBorder,
|
|
614
|
-
withMargin: !!field.withMargin,
|
|
615
|
-
withPadding: field.withPadding !== undefined ? !!field.withPadding : true,
|
|
616
|
-
mobileStyle: normalizeStyleChoice(field.mobileStyle, 'origin'),
|
|
617
|
-
showBorderMobile: !!field.showBorderMobile,
|
|
618
|
-
withMarginMobile: !!field.withMarginMobile,
|
|
619
|
-
withPaddingMobile: !!field.withPaddingMobile,
|
|
620
|
-
}, field);
|
|
621
|
-
|
|
622
|
-
if (field.newIcon !== undefined) {
|
|
623
|
-
props.newIcon = field.newIcon;
|
|
624
|
-
}
|
|
625
|
-
|
|
626
|
-
return buildSchemaNode(
|
|
627
|
-
'PageSection',
|
|
628
|
-
props,
|
|
629
|
-
buildFormNodeComponents(field.children || []),
|
|
630
|
-
{ fieldId: props.fieldId || fieldId }
|
|
631
|
-
);
|
|
632
|
-
}
|
|
633
|
-
|
|
634
588
|
function countLayoutColumns(layout) {
|
|
635
589
|
const parts = String(layout || '12').split(':').filter(Boolean);
|
|
636
590
|
return parts.length || 1;
|
|
@@ -684,9 +638,6 @@ function buildFormNodeComponent(field) {
|
|
|
684
638
|
if (componentName === 'Divider') {
|
|
685
639
|
return buildDividerComponent(field);
|
|
686
640
|
}
|
|
687
|
-
if (componentName === 'PageSection') {
|
|
688
|
-
return buildPageSectionComponent(field);
|
|
689
|
-
}
|
|
690
641
|
if (componentName === 'ColumnsLayout') {
|
|
691
642
|
return buildColumnsLayoutComponent(field);
|
|
692
643
|
}
|
|
@@ -1734,7 +1685,6 @@ function buildFormSchema(formTitle, fields, formUuid, corpId, appType, layout, t
|
|
|
1734
1685
|
labelWeightMobile: 'normal',
|
|
1735
1686
|
},
|
|
1736
1687
|
condition: true,
|
|
1737
|
-
css: 'body{background-color:transparent}',
|
|
1738
1688
|
methods: {
|
|
1739
1689
|
__initMethods__: {
|
|
1740
1690
|
type: 'js',
|
|
@@ -1944,7 +1894,6 @@ function buildEmptyFormSchema() {
|
|
|
1944
1894
|
contentBgColorMobile: 'white',
|
|
1945
1895
|
},
|
|
1946
1896
|
condition: true,
|
|
1947
|
-
css: 'body{background-color:transparent}',
|
|
1948
1897
|
methods: {
|
|
1949
1898
|
__initMethods__: {
|
|
1950
1899
|
type: 'js',
|
|
@@ -2609,6 +2558,84 @@ function findFieldByIdOrLabelDeep(fields, identifier) {
|
|
|
2609
2558
|
return null;
|
|
2610
2559
|
}
|
|
2611
2560
|
|
|
2561
|
+
function normalizeFormInjectionKey(key) {
|
|
2562
|
+
return String(key || '').replace(/[^a-z0-9]/gi, '').toLowerCase();
|
|
2563
|
+
}
|
|
2564
|
+
|
|
2565
|
+
function isRawFormInjectionKey(key) {
|
|
2566
|
+
const normalized = normalizeFormInjectionKey(key);
|
|
2567
|
+
return normalized === 'srcdoc'
|
|
2568
|
+
|| normalized === 'stylesheet'
|
|
2569
|
+
|| normalized === 'stylesheets'
|
|
2570
|
+
|| normalized === 'styletext'
|
|
2571
|
+
|| normalized === 'styletag'
|
|
2572
|
+
|| normalized.includes('innerhtml')
|
|
2573
|
+
|| normalized.includes('outerhtml')
|
|
2574
|
+
|| normalized.includes('dangerouslysetinnerhtml')
|
|
2575
|
+
|| normalized.startsWith('css')
|
|
2576
|
+
|| normalized.endsWith('css')
|
|
2577
|
+
|| normalized.startsWith('html')
|
|
2578
|
+
|| normalized.endsWith('html');
|
|
2579
|
+
}
|
|
2580
|
+
|
|
2581
|
+
function isRawMarkupComponent(componentName) {
|
|
2582
|
+
return ['html', 'iframe'].includes(String(componentName || '').toLowerCase());
|
|
2583
|
+
}
|
|
2584
|
+
|
|
2585
|
+
function assertNoFormInjectionValue(value, location) {
|
|
2586
|
+
if (Array.isArray(value)) {
|
|
2587
|
+
value.forEach(function (item, index) {
|
|
2588
|
+
assertNoFormInjectionValue(item, location + '[' + index + ']');
|
|
2589
|
+
});
|
|
2590
|
+
return;
|
|
2591
|
+
}
|
|
2592
|
+
if (!value || typeof value !== 'object') {
|
|
2593
|
+
return;
|
|
2594
|
+
}
|
|
2595
|
+
Object.keys(value).forEach(function (key) {
|
|
2596
|
+
if (isRawFormInjectionKey(key)) {
|
|
2597
|
+
throw new Error('表单补丁不支持 CSS/HTML 注入: ' + location + '.' + key);
|
|
2598
|
+
}
|
|
2599
|
+
if (normalizeFormInjectionKey(key) === 'componentname' && isRawMarkupComponent(value[key])) {
|
|
2600
|
+
throw new Error('表单补丁不支持 CSS/HTML 注入组件: ' + value[key]);
|
|
2601
|
+
}
|
|
2602
|
+
assertNoFormInjectionValue(value[key], location + '.' + key);
|
|
2603
|
+
});
|
|
2604
|
+
}
|
|
2605
|
+
|
|
2606
|
+
function assertNoFormInjectionPath(pointer, value) {
|
|
2607
|
+
if (!pointer) {
|
|
2608
|
+
return;
|
|
2609
|
+
}
|
|
2610
|
+
const segments = splitJsonPointer(pointer);
|
|
2611
|
+
const blockedSegment = segments.find(isRawFormInjectionKey);
|
|
2612
|
+
if (blockedSegment) {
|
|
2613
|
+
throw new Error('表单补丁不支持 CSS/HTML 注入路径: ' + pointer);
|
|
2614
|
+
}
|
|
2615
|
+
const lastSegment = normalizeFormInjectionKey(segments[segments.length - 1]);
|
|
2616
|
+
if (lastSegment === 'componentname' && isRawMarkupComponent(value)) {
|
|
2617
|
+
throw new Error('表单补丁不支持 CSS/HTML 注入组件: ' + value);
|
|
2618
|
+
}
|
|
2619
|
+
}
|
|
2620
|
+
|
|
2621
|
+
function assertNoFormInjectionSource(source, location) {
|
|
2622
|
+
if (typeof source !== 'string' || source.length === 0) {
|
|
2623
|
+
return;
|
|
2624
|
+
}
|
|
2625
|
+
const forbiddenPatterns = [
|
|
2626
|
+
/\b(?:innerHTML|outerHTML|insertAdjacentHTML|dangerouslySetInnerHTML|srcdoc|cssText|insertRule|adoptedStyleSheets)\b/i,
|
|
2627
|
+
/\bdocument\s*\.\s*(?:write|writeln)\s*\(/i,
|
|
2628
|
+
/\bcreateElement\s*\(\s*['"`](?:style|script|iframe|link)['"`]\s*\)/i,
|
|
2629
|
+
/\bsetAttribute\s*\(\s*['"`](?:style|srcdoc)['"`]/i,
|
|
2630
|
+
/\.\s*style\s*(?:\.|\[)/i,
|
|
2631
|
+
/<\s*(?:style|script|iframe|html|body)\b/i,
|
|
2632
|
+
/openyida:theme|yida-global-theme/i,
|
|
2633
|
+
];
|
|
2634
|
+
if (forbiddenPatterns.some(function (pattern) { return pattern.test(source); })) {
|
|
2635
|
+
throw new Error('表单动作不支持 CSS/HTML 注入: ' + location);
|
|
2636
|
+
}
|
|
2637
|
+
}
|
|
2638
|
+
|
|
2612
2639
|
function resolveJsonPointerParent(target, pointer) {
|
|
2613
2640
|
const segments = splitJsonPointer(pointer);
|
|
2614
2641
|
if (segments.length === 0) {
|
|
@@ -2764,6 +2791,7 @@ function applyAtomicFieldAction(schema, formContainer, operation) {
|
|
|
2764
2791
|
const actions = ensureActionModule(schema);
|
|
2765
2792
|
const source = readOptionalSource(operation, 'source', 'sourceFile');
|
|
2766
2793
|
if (source !== undefined) {
|
|
2794
|
+
assertNoFormInjectionSource(source, 'field-action ' + actionName);
|
|
2767
2795
|
if (!extractExportedActionFunctionNames(source).includes(actionName)) {
|
|
2768
2796
|
throw createCreateFormError(
|
|
2769
2797
|
t('create_form.action_source_export_missing', actionName),
|
|
@@ -2779,12 +2807,14 @@ function applyAtomicFieldAction(schema, formContainer, operation) {
|
|
|
2779
2807
|
}
|
|
2780
2808
|
const blockStart = '/* openyida:field-action:start:' + actionName + ' */';
|
|
2781
2809
|
const blockEnd = '/* openyida:field-action:end:' + actionName + ' */';
|
|
2782
|
-
|
|
2810
|
+
const nextActionSource = upsertGeneratedSourceBlockWithBounds(
|
|
2783
2811
|
actions.module.source || '',
|
|
2784
2812
|
source,
|
|
2785
2813
|
blockStart,
|
|
2786
2814
|
blockEnd
|
|
2787
2815
|
);
|
|
2816
|
+
assertNoFormInjectionSource(nextActionSource, 'field-action module');
|
|
2817
|
+
actions.module.source = nextActionSource;
|
|
2788
2818
|
actions.module.compiled = compileActionSource(actions.module.source);
|
|
2789
2819
|
actions.type = actions.type || 'FUNCTION';
|
|
2790
2820
|
} else if (!extractExportedActionFunctionNames(actions.module.source || '').includes(actionName)) {
|
|
@@ -2829,6 +2859,14 @@ function applySchemaPatchOperations(schema, operations) {
|
|
|
2829
2859
|
throw new Error('补丁[' + index + '] 缺少 action/op');
|
|
2830
2860
|
}
|
|
2831
2861
|
|
|
2862
|
+
assertNoFormInjectionPath(operation.path, operation.value);
|
|
2863
|
+
if (Object.prototype.hasOwnProperty.call(operation, 'value')) {
|
|
2864
|
+
assertNoFormInjectionValue(operation.value, '补丁[' + index + '].value');
|
|
2865
|
+
}
|
|
2866
|
+
if (operation.props !== undefined) {
|
|
2867
|
+
assertNoFormInjectionValue(operation.props, '补丁[' + index + '].props');
|
|
2868
|
+
}
|
|
2869
|
+
|
|
2832
2870
|
if (['add', 'replace', 'remove'].includes(action)) {
|
|
2833
2871
|
applyJsonPointerOperation(schema, operation);
|
|
2834
2872
|
applied.push({ action, path: operation.path });
|
|
@@ -2888,6 +2926,8 @@ function applySchemaPatchOperations(schema, operations) {
|
|
|
2888
2926
|
const source = readOptionalSource(operation, 'source', 'sourceFile');
|
|
2889
2927
|
const compiled = readOptionalSource(operation, 'compiled', 'compiledFile')
|
|
2890
2928
|
|| (source ? compileActionSource(source) : undefined);
|
|
2929
|
+
assertNoFormInjectionSource(source, 'actions-module source');
|
|
2930
|
+
assertNoFormInjectionSource(compiled, 'actions-module compiled');
|
|
2891
2931
|
if (source !== undefined) {
|
|
2892
2932
|
actions.module.source = source;
|
|
2893
2933
|
}
|
|
@@ -4351,10 +4391,6 @@ function applyFieldChanges(component, changes) {
|
|
|
4351
4391
|
props.tips = i18n(changes.tips);
|
|
4352
4392
|
}
|
|
4353
4393
|
|
|
4354
|
-
if (changes.tooltip !== undefined && component.componentName === 'PageSection') {
|
|
4355
|
-
props.tooltip = i18n(changes.tooltip);
|
|
4356
|
-
}
|
|
4357
|
-
|
|
4358
4394
|
// ── 特殊处理:required(操作 validation 数组)
|
|
4359
4395
|
if (changes.required !== undefined && !isFormPresentationComponent(component.componentName)) {
|
|
4360
4396
|
if (changes.required) {
|
|
@@ -6518,6 +6554,7 @@ module.exports = {
|
|
|
6518
6554
|
parseArgs,
|
|
6519
6555
|
_private: {
|
|
6520
6556
|
buildFormSchema,
|
|
6557
|
+
buildEmptyFormSchema,
|
|
6521
6558
|
buildFormNodeComponent,
|
|
6522
6559
|
countDataFieldDefinitions,
|
|
6523
6560
|
collectComponentNames,
|
|
@@ -58,10 +58,6 @@ const PRESENTATION_TYPE_ALIAS = Object.freeze({
|
|
|
58
58
|
columnContainer: 'ColumnContainer',
|
|
59
59
|
Column: 'Column',
|
|
60
60
|
column: 'Column',
|
|
61
|
-
GroupContainer: 'GroupContainer',
|
|
62
|
-
groupContainer: 'GroupContainer',
|
|
63
|
-
PageSection: 'PageSection',
|
|
64
|
-
pageSection: 'PageSection',
|
|
65
61
|
});
|
|
66
62
|
|
|
67
63
|
const BUSINESS_FIELD_TYPES = Object.freeze([
|
|
@@ -90,8 +86,6 @@ const PRESENTATION_FIELD_TYPES = Object.freeze([
|
|
|
90
86
|
'Divider',
|
|
91
87
|
'ColumnContainer',
|
|
92
88
|
'Column',
|
|
93
|
-
'GroupContainer',
|
|
94
|
-
'PageSection',
|
|
95
89
|
]);
|
|
96
90
|
|
|
97
91
|
const OPTION_FIELD_TYPES = Object.freeze([
|
|
@@ -372,11 +366,6 @@ function validateFieldDefinition(field, path, diagnostics, options) {
|
|
|
372
366
|
return;
|
|
373
367
|
}
|
|
374
368
|
|
|
375
|
-
if (type === 'GroupContainer' || type === 'PageSection') {
|
|
376
|
-
validateOneDimensionalChildren(field, path, diagnostics, type);
|
|
377
|
-
return;
|
|
378
|
-
}
|
|
379
|
-
|
|
380
369
|
if (type === 'TableField') {
|
|
381
370
|
validateTableField(field, path, diagnostics);
|
|
382
371
|
}
|
|
@@ -496,31 +485,6 @@ function validateColumnContainer(field, path, diagnostics) {
|
|
|
496
485
|
});
|
|
497
486
|
}
|
|
498
487
|
|
|
499
|
-
function validateOneDimensionalChildren(field, path, diagnostics, type) {
|
|
500
|
-
if (!validateChildrenPropertyShape(field, path, diagnostics, 'FieldDefinition[]')) {
|
|
501
|
-
return;
|
|
502
|
-
}
|
|
503
|
-
if (field.children === undefined || field.children === null) {
|
|
504
|
-
return;
|
|
505
|
-
}
|
|
506
|
-
field.children.forEach(function (child, childIndex) {
|
|
507
|
-
const childPath = path + '.children[' + childIndex + ']';
|
|
508
|
-
if (Array.isArray(child)) {
|
|
509
|
-
pushDiagnostic(
|
|
510
|
-
diagnostics,
|
|
511
|
-
'INVALID_' + type.toUpperCase() + '_CHILDREN_DEPTH',
|
|
512
|
-
childPath,
|
|
513
|
-
'FieldDefinition object',
|
|
514
|
-
'array',
|
|
515
|
-
type + '.children must be a one-dimensional field array.',
|
|
516
|
-
'Remove extra array nesting from ' + type + '.children.'
|
|
517
|
-
);
|
|
518
|
-
return;
|
|
519
|
-
}
|
|
520
|
-
validateFieldDefinition(child, childPath, diagnostics);
|
|
521
|
-
});
|
|
522
|
-
}
|
|
523
|
-
|
|
524
488
|
function validateTableField(field, path, diagnostics) {
|
|
525
489
|
if (!validateChildrenPropertyShape(field, path, diagnostics, 'FieldDefinition[]')) {
|
|
526
490
|
return;
|
|
@@ -1638,7 +1638,6 @@ function buildFormSchema(formTitle, fields, formUuid, corpId, appType, layout, t
|
|
|
1638
1638
|
labelWeightMobile: 'normal',
|
|
1639
1639
|
},
|
|
1640
1640
|
condition: true,
|
|
1641
|
-
css: 'body{background-color:transparent}',
|
|
1642
1641
|
methods: {
|
|
1643
1642
|
__initMethods__: {
|
|
1644
1643
|
type: 'js',
|
|
@@ -1844,7 +1843,6 @@ function buildEmptyFormSchema() {
|
|
|
1844
1843
|
contentBgColorMobile: 'white',
|
|
1845
1844
|
},
|
|
1846
1845
|
condition: true,
|
|
1847
|
-
css: 'body{background-color:transparent}',
|
|
1848
1846
|
methods: {
|
|
1849
1847
|
__initMethods__: {
|
|
1850
1848
|
type: 'js',
|
|
@@ -133,7 +133,7 @@ function applyDesignTokens(template, markdown, previousMarkdown) {
|
|
|
133
133
|
const changed = Object.fromEntries(Object.entries(tokens).filter(([name, value]) => !previous || previous[name] !== value));
|
|
134
134
|
if (!Object.keys(changed).length && tone === previousTone) {
|
|
135
135
|
extractThemeColor(template);
|
|
136
|
-
return template;
|
|
136
|
+
return require('./application-style').applyApplicationStyle(template, metadata, tokens);
|
|
137
137
|
}
|
|
138
138
|
const root = /^:root\s*\{([\s\S]*?)^\}/m.exec(template);
|
|
139
139
|
if (!root) {throw new Error('应用主题模板缺少 :root');}
|
|
@@ -157,6 +157,7 @@ function applyDesignTokens(template, markdown, previousMarkdown) {
|
|
|
157
157
|
}
|
|
158
158
|
let css = `${template.slice(0, root.index)}:root {${body}}${tail}`;
|
|
159
159
|
if (tone) {css = applyNavigationTokens(css, tokens, changed, tone, previousTone);}
|
|
160
|
+
css = require('./application-style').applyApplicationStyle(css, metadata, tokens);
|
|
160
161
|
validateThemeCssContent(css);
|
|
161
162
|
extractThemeColor(css);
|
|
162
163
|
return css;
|