@appsemble/lang-sdk 0.40.10 → 0.40.11-test.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/constants/patterns.d.ts +6 -0
- package/constants/patterns.js +6 -0
- package/package.json +1 -1
- package/schemas/BlockDefinition.js +14 -1
- package/schemas/Theme.js +33 -1
- package/types/block.d.ts +8 -0
- package/types/theme.d.ts +7 -0
- package/validation.js +70 -1
package/constants/patterns.d.ts
CHANGED
|
@@ -18,6 +18,12 @@ export declare const partialNormalized: RegExp;
|
|
|
18
18
|
* A pattern for exactly matching a lower case hyphen separated string.
|
|
19
19
|
*/
|
|
20
20
|
export declare const normalized: RegExp;
|
|
21
|
+
/**
|
|
22
|
+
* A pattern for validating a theme variable (custom CSS property) value.
|
|
23
|
+
*
|
|
24
|
+
* Any single-line CSS value that cannot escape its declaration block is allowed.
|
|
25
|
+
*/
|
|
26
|
+
export declare const themeVariableValue: RegExp;
|
|
21
27
|
/**
|
|
22
28
|
* A pattern for matching the block name pattern of @organization/project.
|
|
23
29
|
*/
|
package/constants/patterns.js
CHANGED
|
@@ -19,6 +19,12 @@ export const partialNormalized = /([0-9a-z](?:(?!.*--)[-0-9a-z]*[0-9a-z])?)/;
|
|
|
19
19
|
* A pattern for exactly matching a lower case hyphen separated string.
|
|
20
20
|
*/
|
|
21
21
|
export const normalized = new RegExp(`^${partialNormalized.source}$`);
|
|
22
|
+
/**
|
|
23
|
+
* A pattern for validating a theme variable (custom CSS property) value.
|
|
24
|
+
*
|
|
25
|
+
* Any single-line CSS value that cannot escape its declaration block is allowed.
|
|
26
|
+
*/
|
|
27
|
+
export const themeVariableValue = /^[^\n\r;{}]+$/;
|
|
22
28
|
/**
|
|
23
29
|
* A pattern for matching the block name pattern of @organization/project.
|
|
24
30
|
*/
|
package/package.json
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { partialNormalized, semver } from '../constants/index.js';
|
|
1
|
+
import { normalized, partialNormalized, semver } from '../constants/index.js';
|
|
2
2
|
export const BlockDefinition = {
|
|
3
3
|
type: 'object',
|
|
4
4
|
description: 'A block that is displayed on a page.',
|
|
@@ -29,6 +29,19 @@ Some examples:
|
|
|
29
29
|
|
|
30
30
|
Since blocks may change over time, a version must be specified in order to ensure that the block
|
|
31
31
|
will remain the same until it is manually updated.
|
|
32
|
+
`,
|
|
33
|
+
},
|
|
34
|
+
name: {
|
|
35
|
+
type: 'string',
|
|
36
|
+
pattern: normalized.source,
|
|
37
|
+
maxLength: 40,
|
|
38
|
+
description: `A name which identifies this single block instance.
|
|
39
|
+
|
|
40
|
+
The name is rendered as a \`data-block-name\` attribute on the wrapper element of the block, so app
|
|
41
|
+
styles can target one instance instead of every block of the same type. Names must be lower case and
|
|
42
|
+
hyphen separated.
|
|
43
|
+
|
|
44
|
+
For example, a block named \`screen-title\` is targeted with \`[data-block-name='screen-title']\`.
|
|
32
45
|
`,
|
|
33
46
|
},
|
|
34
47
|
layout: {
|
package/schemas/Theme.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { baseTheme } from '../constants/baseTheme.js';
|
|
2
|
-
import { hexColor } from '../constants/patterns.js';
|
|
2
|
+
import { hexColor, normalized, themeVariableValue } from '../constants/patterns.js';
|
|
3
3
|
export const Theme = {
|
|
4
4
|
type: 'object',
|
|
5
5
|
description: 'A generic theme definition.',
|
|
@@ -90,6 +90,38 @@ the CSS of the app and its blocks. It falls back to the body font.
|
|
|
90
90
|
{ $ref: '#/components/schemas/GoogleFontDefinition' },
|
|
91
91
|
],
|
|
92
92
|
},
|
|
93
|
+
variables: {
|
|
94
|
+
type: 'object',
|
|
95
|
+
description: `Custom CSS properties (design tokens) exposed on \`:root\` in the theme CSS.
|
|
96
|
+
|
|
97
|
+
Each entry is emitted as a \`--<name>\` custom property. Names must be lower case and hyphen
|
|
98
|
+
separated. Custom properties inherit into every block's shadow DOM, so tokens defined once are
|
|
99
|
+
usable in core, shared, and block styles.
|
|
100
|
+
|
|
101
|
+
For example:
|
|
102
|
+
|
|
103
|
+
\`\`\`yaml
|
|
104
|
+
theme:
|
|
105
|
+
variables:
|
|
106
|
+
night: '#0e1220'
|
|
107
|
+
font-display: "'Baloo 2', sans-serif"
|
|
108
|
+
\`\`\`
|
|
109
|
+
|
|
110
|
+
These can be referenced in custom CSS as \`var(--night)\` and \`var(--font-display)\`.
|
|
111
|
+
`,
|
|
112
|
+
minProperties: 1,
|
|
113
|
+
maxProperties: 32,
|
|
114
|
+
// The validator supports propertyNames, but the OpenAPI schema object type does not know it.
|
|
115
|
+
propertyNames: {
|
|
116
|
+
pattern: normalized.source,
|
|
117
|
+
maxLength: 40,
|
|
118
|
+
},
|
|
119
|
+
additionalProperties: {
|
|
120
|
+
type: 'string',
|
|
121
|
+
pattern: themeVariableValue.source,
|
|
122
|
+
maxLength: 128,
|
|
123
|
+
},
|
|
124
|
+
},
|
|
93
125
|
},
|
|
94
126
|
};
|
|
95
127
|
//# sourceMappingURL=Theme.js.map
|
package/types/block.d.ts
CHANGED
|
@@ -48,6 +48,14 @@ export interface BlockDefinition extends ControllerDefinition {
|
|
|
48
48
|
* ^\d+\.\d+\.\d+$
|
|
49
49
|
*/
|
|
50
50
|
version: string;
|
|
51
|
+
/**
|
|
52
|
+
* A name which identifies this single block instance.
|
|
53
|
+
*
|
|
54
|
+
* It is rendered as a `data-block-name` attribute on the wrapper element of the block, so app
|
|
55
|
+
* styles can target one instance instead of every block of the same type. Names must be lower
|
|
56
|
+
* case and hyphen separated.
|
|
57
|
+
*/
|
|
58
|
+
name?: string;
|
|
51
59
|
/**
|
|
52
60
|
* An optional header to render above the block.
|
|
53
61
|
*/
|
package/types/theme.d.ts
CHANGED
|
@@ -51,6 +51,13 @@ export interface Theme {
|
|
|
51
51
|
* The name of a font available on Google fonts.
|
|
52
52
|
*/
|
|
53
53
|
font: FontDefinition;
|
|
54
|
+
/**
|
|
55
|
+
* Custom CSS properties (design tokens) exposed on `:root` in the compiled theme CSS.
|
|
56
|
+
*
|
|
57
|
+
* Each entry is emitted as a `--<name>` custom property. Custom properties inherit into every
|
|
58
|
+
* block's shadow DOM, so tokens defined once are usable in core, shared, and block styles.
|
|
59
|
+
*/
|
|
60
|
+
variables?: Record<string, string>;
|
|
54
61
|
/**
|
|
55
62
|
* A second font family the app loads, exposed as the `--font-family-display` custom property for
|
|
56
63
|
* the CSS of the app and its blocks.
|
package/validation.js
CHANGED
|
@@ -9,7 +9,7 @@ import { findPageByName } from './findPageByName.js';
|
|
|
9
9
|
import { isAppLink } from './pageUtils.js';
|
|
10
10
|
import { bottomNavigationGridArea, breadcrumbsGridArea, builtinPagesGridAreaOrder, getBuiltinPagesDefaultGridLayout, getCascadedGridTemplateAreas, getGridTemplateAreas, gridDeviceOrder, resendBannerGridArea, } from './gridUtils.js';
|
|
11
11
|
import { isValidIconName, parseIconReference } from './icons.js';
|
|
12
|
-
import { iterApp } from './iterApp.js';
|
|
12
|
+
import { iterApp, iterBlockList } from './iterApp.js';
|
|
13
13
|
import { has } from './miscellaneous.js';
|
|
14
14
|
import { normalize } from './normalize.js';
|
|
15
15
|
import { serverActions } from './serverActions.js';
|
|
@@ -167,6 +167,74 @@ function validatePageParents(definition, report) {
|
|
|
167
167
|
}
|
|
168
168
|
});
|
|
169
169
|
}
|
|
170
|
+
/**
|
|
171
|
+
* Validates the blocks in the app definition to ensure there are no duplicate block names.
|
|
172
|
+
*
|
|
173
|
+
* A block name identifies a single block within the screen it is rendered in. A page renders one
|
|
174
|
+
* of its tabs or steps at a time, so uniqueness is scoped to the block list the block belongs to.
|
|
175
|
+
* The same name may be used on other pages, tabs and steps, which lets an app style the same role
|
|
176
|
+
* everywhere with one rule.
|
|
177
|
+
*
|
|
178
|
+
* @param definition The definition of the app
|
|
179
|
+
* @param report A function used to report a value.
|
|
180
|
+
*/
|
|
181
|
+
function validateUniqueBlockNames(definition, report) {
|
|
182
|
+
function checkBlockList(blocks, path) {
|
|
183
|
+
const names = new Set();
|
|
184
|
+
iterBlockList(blocks, {
|
|
185
|
+
onBlock(block, blockPath) {
|
|
186
|
+
if (block.name) {
|
|
187
|
+
if (names.has(block.name)) {
|
|
188
|
+
report(block.name, 'is a duplicate block name', [...blockPath, 'name']);
|
|
189
|
+
}
|
|
190
|
+
else {
|
|
191
|
+
names.add(block.name);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
},
|
|
195
|
+
}, path);
|
|
196
|
+
}
|
|
197
|
+
iterApp(definition, {
|
|
198
|
+
onPage(page, path) {
|
|
199
|
+
// Basic page
|
|
200
|
+
if (page.type === 'page' || page.type === undefined) {
|
|
201
|
+
checkBlockList(page.blocks, [...path, 'blocks']);
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
// Tabs page
|
|
205
|
+
if (page.type === 'tabs') {
|
|
206
|
+
const tabsPage = page;
|
|
207
|
+
if (tabsPage.tabs) {
|
|
208
|
+
for (const [tabId, tab] of tabsPage.tabs.entries()) {
|
|
209
|
+
checkBlockList(tab.blocks, [...path, 'tabs', tabId, 'blocks']);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
else if (tabsPage.definition?.foreach) {
|
|
213
|
+
checkBlockList(tabsPage.definition.foreach.blocks, [
|
|
214
|
+
...path,
|
|
215
|
+
'definition',
|
|
216
|
+
'foreach',
|
|
217
|
+
'blocks',
|
|
218
|
+
]);
|
|
219
|
+
}
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
// Flow page
|
|
223
|
+
if (page.type === 'flow' && page.steps) {
|
|
224
|
+
const flowPage = page;
|
|
225
|
+
for (const [stepId, step] of flowPage.steps.entries()) {
|
|
226
|
+
checkBlockList(step.blocks, [...path, 'steps', stepId, 'blocks']);
|
|
227
|
+
}
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
// Loop page
|
|
231
|
+
if (page.type === 'loop') {
|
|
232
|
+
const loopPage = page;
|
|
233
|
+
checkBlockList(loopPage.foreach.blocks, [...path, 'foreach', 'blocks']);
|
|
234
|
+
}
|
|
235
|
+
},
|
|
236
|
+
});
|
|
237
|
+
}
|
|
170
238
|
function validateMembersSchema(definition, report) {
|
|
171
239
|
if (!definition.members?.properties) {
|
|
172
240
|
return;
|
|
@@ -1869,6 +1937,7 @@ export async function validateAppDefinition(definition, getBlockVersions, contro
|
|
|
1869
1937
|
check(() => validateActions(clonedDefinition, report));
|
|
1870
1938
|
check(() => validateEvents(clonedDefinition, blockVersionMap, report));
|
|
1871
1939
|
check(() => validateUniquePageNames(clonedDefinition, report));
|
|
1940
|
+
check(() => validateUniqueBlockNames(clonedDefinition, report));
|
|
1872
1941
|
check(() => validateGridLayout(clonedDefinition, report));
|
|
1873
1942
|
}
|
|
1874
1943
|
catch (error) {
|