@nascentdigital/funnel-core 4.4.15 → 4.4.17
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/schema/PageSnapshot.d.ts +1 -1
- package/dist/ui/block-layout/BlockLayout.d.ts +80 -49
- package/dist/ui/block-layout/BlockLayout.js +126 -56
- package/dist/ui/fields/Field.d.ts +4 -0
- package/dist/ui/fields/Field.js +33 -3
- package/dist/ui/fields/errors.json +4 -2
- package/dist/ui/fields/index.d.ts +1 -0
- package/dist/ui/fields/index.js +1 -0
- package/package.json +4 -3
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Tagged } from 'type-fest';
|
|
2
2
|
import { RequiredBy } from '../types';
|
|
3
3
|
import type { Page } from './Page';
|
|
4
|
-
export type PageSnapshot = RequiredBy<Pick<Page.Data
|
|
4
|
+
export type PageSnapshot = RequiredBy<Pick<Page.Data<any>, Exclude<Page.Data.Props.Id, 'id'> | Page.Data.Props.Content | 'createdOn' | 'updatedOn' | 'changeSetId' | 'publication'>, 'changeSetId'> & {
|
|
5
5
|
id: PageSnapshot.Id;
|
|
6
6
|
};
|
|
7
7
|
export declare namespace PageSnapshot {
|
|
@@ -1,63 +1,44 @@
|
|
|
1
|
+
import { JsonObject } from 'type-fest';
|
|
2
|
+
import { PartialBy } from '../../types';
|
|
1
3
|
export type BlockLayout = {
|
|
2
4
|
name: string;
|
|
3
5
|
root: BlockLayout.Root;
|
|
4
|
-
tight
|
|
5
|
-
tightMobile?: BlockLayout.Tight;
|
|
6
|
-
tightDesktop?: BlockLayout.Tight;
|
|
6
|
+
tight: BlockLayout.ResponsiveValue<BlockLayout.Tight>;
|
|
7
7
|
};
|
|
8
8
|
export declare namespace BlockLayout {
|
|
9
|
-
type Tight = 'above' | 'below' | 'both' | 'none';
|
|
10
|
-
namespace Tight {
|
|
11
|
-
const values: ReadonlyArray<Tight>;
|
|
12
|
-
function parse(value: string, fallback?: Tight): Tight;
|
|
13
|
-
}
|
|
14
|
-
type Ratio = '1/1' | '1/2' | '1/3' | '2/1' | '3/1' | '2/3' | '3/2';
|
|
15
|
-
namespace Ratio {
|
|
16
|
-
const values: ReadonlyArray<Ratio>;
|
|
17
|
-
function parse(value: string, fallback?: Ratio): Ratio;
|
|
18
|
-
}
|
|
19
|
-
namespace FullBleed {
|
|
20
|
-
function parse(value: string, fallback?: boolean): boolean;
|
|
21
|
-
}
|
|
22
9
|
type Root = Row | Column | Stack;
|
|
23
10
|
type Container = Row | Row.Nested | Column | Column.Nested | Stack | Stack.Nested;
|
|
24
|
-
|
|
11
|
+
namespace Container {
|
|
12
|
+
type Base = {
|
|
13
|
+
alignX?: Alignment;
|
|
14
|
+
alignY?: Alignment;
|
|
15
|
+
};
|
|
16
|
+
type Nested = {
|
|
17
|
+
items: ReadonlyArray<Panel>;
|
|
18
|
+
mobileOrder?: MobileOrder;
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
type Row = Container.Base & {
|
|
25
22
|
type: 'row';
|
|
26
23
|
items: ReadonlyArray<Column.Nested | Stack.Nested | Panel>;
|
|
27
|
-
|
|
28
|
-
alignY?: Alignment;
|
|
29
|
-
ratio?: Ratio;
|
|
30
|
-
ratioDesktop?: Ratio;
|
|
24
|
+
ratio: ResponsiveValue<Ratio>;
|
|
31
25
|
};
|
|
32
26
|
namespace Row {
|
|
33
|
-
type Nested = Omit<Row, 'items'> &
|
|
34
|
-
items: ReadonlyArray<Panel>;
|
|
35
|
-
mobileOrder?: MobileOrder;
|
|
36
|
-
};
|
|
27
|
+
type Nested = Omit<Row, 'items'> & Container.Nested;
|
|
37
28
|
}
|
|
38
|
-
type Column = {
|
|
29
|
+
type Column = Container.Base & {
|
|
39
30
|
type: 'column';
|
|
40
31
|
items: ReadonlyArray<Row.Nested | Stack.Nested | Panel>;
|
|
41
|
-
alignX?: Alignment;
|
|
42
|
-
alignY?: Alignment;
|
|
43
32
|
};
|
|
44
33
|
namespace Column {
|
|
45
|
-
type Nested = Omit<Column, 'items'> &
|
|
46
|
-
items: ReadonlyArray<Panel>;
|
|
47
|
-
mobileOrder?: MobileOrder;
|
|
48
|
-
};
|
|
34
|
+
type Nested = Omit<Column, 'items'> & Container.Nested;
|
|
49
35
|
}
|
|
50
|
-
type Stack = {
|
|
36
|
+
type Stack = Container.Base & {
|
|
51
37
|
type: 'stack';
|
|
52
38
|
items: ReadonlyArray<Row.Nested | Column.Nested | Panel>;
|
|
53
|
-
alignX?: Alignment;
|
|
54
|
-
alignY?: Alignment;
|
|
55
39
|
};
|
|
56
40
|
namespace Stack {
|
|
57
|
-
type Nested = Omit<Stack, 'items'> &
|
|
58
|
-
items: ReadonlyArray<Panel>;
|
|
59
|
-
mobileOrder?: MobileOrder;
|
|
60
|
-
};
|
|
41
|
+
type Nested = Omit<Stack, 'items'> & Container.Nested;
|
|
61
42
|
}
|
|
62
43
|
type NestedItem = Row.Nested | Column.Nested | Stack.Nested | Panel;
|
|
63
44
|
type Panel = Message | Visual | List;
|
|
@@ -69,22 +50,16 @@ export declare namespace BlockLayout {
|
|
|
69
50
|
alignX?: Alignment;
|
|
70
51
|
alignY?: Alignment;
|
|
71
52
|
size?: Size;
|
|
72
|
-
fullBleed
|
|
73
|
-
fullBleedMobile?: boolean;
|
|
74
|
-
fullBleedDesktop?: boolean;
|
|
53
|
+
fullBleed: ResponsiveValue<boolean>;
|
|
75
54
|
};
|
|
76
55
|
}
|
|
77
56
|
type Message = Panel.Base & {
|
|
78
57
|
type: 'message';
|
|
79
|
-
textAlign
|
|
80
|
-
textAlignMobile?: TextAlignment;
|
|
81
|
-
textAlignDesktop?: TextAlignment;
|
|
58
|
+
textAlign: ResponsiveValue<TextAlignment>;
|
|
82
59
|
};
|
|
83
60
|
type Visual = Panel.Base & {
|
|
84
61
|
type: 'visual';
|
|
85
|
-
aspectRatio: AspectRatio
|
|
86
|
-
aspectRatioMobile?: AspectRatio;
|
|
87
|
-
aspectRatioDesktop?: AspectRatio;
|
|
62
|
+
aspectRatio: ResponsiveValue<AspectRatio>;
|
|
88
63
|
};
|
|
89
64
|
type List = Panel.Base & {
|
|
90
65
|
type: 'list';
|
|
@@ -97,7 +72,20 @@ export declare namespace BlockLayout {
|
|
|
97
72
|
function parse(value: string, fallback?: ItemType): ItemType;
|
|
98
73
|
}
|
|
99
74
|
}
|
|
100
|
-
type
|
|
75
|
+
type Tight = 'above' | 'below' | 'both' | 'none';
|
|
76
|
+
namespace Tight {
|
|
77
|
+
const values: ReadonlyArray<Tight>;
|
|
78
|
+
function parse(value: string, fallback?: Tight): Tight;
|
|
79
|
+
}
|
|
80
|
+
type Ratio = '1/1' | '1/2' | '1/3' | '2/1' | '3/1' | '2/3' | '3/2';
|
|
81
|
+
namespace Ratio {
|
|
82
|
+
const values: ReadonlyArray<Ratio>;
|
|
83
|
+
function parse(value: string, fallback?: Ratio): Ratio;
|
|
84
|
+
}
|
|
85
|
+
namespace FullBleed {
|
|
86
|
+
function parse(value: string, fallback?: boolean): boolean;
|
|
87
|
+
}
|
|
88
|
+
type MobileOrder = 'first' | 'last' | 'auto';
|
|
101
89
|
namespace MobileOrder {
|
|
102
90
|
const values: ReadonlyArray<MobileOrder>;
|
|
103
91
|
function parse(value: string, fallback?: MobileOrder): MobileOrder | undefined;
|
|
@@ -122,5 +110,48 @@ export declare namespace BlockLayout {
|
|
|
122
110
|
const values: ReadonlyArray<AspectRatio>;
|
|
123
111
|
function parse(value: string, fallback?: AspectRatio): AspectRatio;
|
|
124
112
|
}
|
|
113
|
+
type ResponsiveValue<T extends string | boolean = string | boolean> = {
|
|
114
|
+
base: T;
|
|
115
|
+
mobile: T;
|
|
116
|
+
desktop: T;
|
|
117
|
+
};
|
|
118
|
+
namespace ResponsiveValue {
|
|
119
|
+
type ParseArgs<T extends string | boolean> = {
|
|
120
|
+
element: ParsedElement;
|
|
121
|
+
property: string;
|
|
122
|
+
parser: (value: string, fallback: T) => T;
|
|
123
|
+
fallback: T | PartialBy<ResponsiveValue<T>, 'desktop' | 'mobile'>;
|
|
124
|
+
};
|
|
125
|
+
function parse<T extends string | boolean>({ element, property, parser, fallback: fallbackRaw }: ParseArgs<T>): ResponsiveValue<T>;
|
|
126
|
+
}
|
|
127
|
+
type ResponsiveClassNames<T extends ResponsiveValue> = T['base'] extends string ? ResponsiveClassNames.ForString<T, T['base']> : T['base'] extends boolean ? ResponsiveClassNames.ForBoolean<T, T['base']> : never;
|
|
128
|
+
namespace ResponsiveClassNames {
|
|
129
|
+
type ForString<T extends ResponsiveValue<V>, V extends string = string> = Record<keyof T, Record<V, string>> & {
|
|
130
|
+
value: T;
|
|
131
|
+
};
|
|
132
|
+
type ForBoolean<T extends ResponsiveValue<V>, V extends boolean = boolean> = Record<keyof T, Record<ForBoolean.Key, string>> & {
|
|
133
|
+
value: T;
|
|
134
|
+
};
|
|
135
|
+
namespace ForBoolean {
|
|
136
|
+
type Key = 'true' | 'false';
|
|
137
|
+
}
|
|
138
|
+
function parse<T extends ResponsiveValue>(args: ResponsiveClassNames<T>): string;
|
|
139
|
+
}
|
|
125
140
|
function parse(xml: string): BlockLayout;
|
|
126
141
|
}
|
|
142
|
+
type ParsedElement<TExpected extends ParsedElement.Tag = ParsedElement.Tag> = {
|
|
143
|
+
tag: TExpected;
|
|
144
|
+
attributes: Record<string, string>;
|
|
145
|
+
children: JsonObject[];
|
|
146
|
+
};
|
|
147
|
+
declare namespace ParsedElement {
|
|
148
|
+
const tags: readonly ["block", "row", "col", "stack", "message", "visual", "list"];
|
|
149
|
+
type Tag = typeof tags[number];
|
|
150
|
+
type ParseArgs<TExpected extends Tag = Tag> = {
|
|
151
|
+
data: JsonObject;
|
|
152
|
+
expectedTags?: ReadonlyArray<TExpected>;
|
|
153
|
+
expectedChildren?: number | false;
|
|
154
|
+
};
|
|
155
|
+
function parse<TExpected extends Tag = Tag>({ data, expectedTags: expectedTagsRaw, expectedChildren }: ParseArgs<TExpected>): ParsedElement<TExpected>;
|
|
156
|
+
}
|
|
157
|
+
export {};
|
|
@@ -10,13 +10,41 @@ var __rest = (this && this.__rest) || function (s, e) {
|
|
|
10
10
|
}
|
|
11
11
|
return t;
|
|
12
12
|
};
|
|
13
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
14
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
15
|
+
};
|
|
13
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
17
|
exports.BlockLayout = void 0;
|
|
18
|
+
const classnames_1 = __importDefault(require("classnames"));
|
|
15
19
|
const fast_xml_parser_1 = require("fast-xml-parser");
|
|
16
20
|
const errors_1 = require("../../errors");
|
|
17
21
|
// extension
|
|
18
22
|
var BlockLayout;
|
|
19
23
|
(function (BlockLayout) {
|
|
24
|
+
let List;
|
|
25
|
+
(function (List) {
|
|
26
|
+
let ItemType;
|
|
27
|
+
(function (ItemType) {
|
|
28
|
+
// values
|
|
29
|
+
ItemType.values = ['message', 'message+visual'];
|
|
30
|
+
// helper
|
|
31
|
+
function parse(value, fallback) {
|
|
32
|
+
// return if it's a match
|
|
33
|
+
if (ItemType.values.includes(value)) {
|
|
34
|
+
return value;
|
|
35
|
+
}
|
|
36
|
+
// or fallback if we have one
|
|
37
|
+
else if (fallback) {
|
|
38
|
+
return fallback;
|
|
39
|
+
}
|
|
40
|
+
// or throw
|
|
41
|
+
else {
|
|
42
|
+
throw new errors_1.ArgumentError(`Invalid BlockLayout.List.ItemType "${value}"`, 'value');
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
ItemType.parse = parse;
|
|
46
|
+
})(ItemType = List.ItemType || (List.ItemType = {}));
|
|
47
|
+
})(List = BlockLayout.List || (BlockLayout.List = {}));
|
|
20
48
|
let Tight;
|
|
21
49
|
(function (Tight) {
|
|
22
50
|
// values
|
|
@@ -59,6 +87,7 @@ var BlockLayout;
|
|
|
59
87
|
}
|
|
60
88
|
Ratio.parse = parse;
|
|
61
89
|
})(Ratio = BlockLayout.Ratio || (BlockLayout.Ratio = {}));
|
|
90
|
+
// fullbleed (for panels)
|
|
62
91
|
let FullBleed;
|
|
63
92
|
(function (FullBleed) {
|
|
64
93
|
// helper
|
|
@@ -82,30 +111,6 @@ var BlockLayout;
|
|
|
82
111
|
}
|
|
83
112
|
FullBleed.parse = parse;
|
|
84
113
|
})(FullBleed = BlockLayout.FullBleed || (BlockLayout.FullBleed = {}));
|
|
85
|
-
let List;
|
|
86
|
-
(function (List) {
|
|
87
|
-
let ItemType;
|
|
88
|
-
(function (ItemType) {
|
|
89
|
-
// values
|
|
90
|
-
ItemType.values = ['message', 'message+visual'];
|
|
91
|
-
// helper
|
|
92
|
-
function parse(value, fallback) {
|
|
93
|
-
// return if it's a match
|
|
94
|
-
if (ItemType.values.includes(value)) {
|
|
95
|
-
return value;
|
|
96
|
-
}
|
|
97
|
-
// or fallback if we have one
|
|
98
|
-
else if (fallback) {
|
|
99
|
-
return fallback;
|
|
100
|
-
}
|
|
101
|
-
// or throw
|
|
102
|
-
else {
|
|
103
|
-
throw new errors_1.ArgumentError(`Invalid BlockLayout.List.ItemType "${value}"`, 'value');
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
ItemType.parse = parse;
|
|
107
|
-
})(ItemType = List.ItemType || (List.ItemType = {}));
|
|
108
|
-
})(List = BlockLayout.List || (BlockLayout.List = {}));
|
|
109
114
|
let MobileOrder;
|
|
110
115
|
(function (MobileOrder) {
|
|
111
116
|
// values
|
|
@@ -207,6 +212,50 @@ var BlockLayout;
|
|
|
207
212
|
}
|
|
208
213
|
AspectRatio.parse = parse;
|
|
209
214
|
})(AspectRatio = BlockLayout.AspectRatio || (BlockLayout.AspectRatio = {}));
|
|
215
|
+
let ResponsiveValue;
|
|
216
|
+
(function (ResponsiveValue) {
|
|
217
|
+
function parse({ element, property, parser, fallback: fallbackRaw }) {
|
|
218
|
+
var _a, _b;
|
|
219
|
+
// capture base
|
|
220
|
+
const { attributes } = element;
|
|
221
|
+
const fallbackBase = typeof fallbackRaw === 'string' || typeof fallbackRaw === 'boolean'
|
|
222
|
+
? fallbackRaw
|
|
223
|
+
: fallbackRaw.base;
|
|
224
|
+
const base = parser(attributes[property], fallbackBase);
|
|
225
|
+
// normalize the fallback
|
|
226
|
+
const fallback = typeof fallbackRaw === 'string' || typeof fallbackRaw === 'boolean'
|
|
227
|
+
? { base, mobile: base, desktop: base }
|
|
228
|
+
: { base, mobile: (_a = fallbackRaw.mobile) !== null && _a !== void 0 ? _a : base, desktop: (_b = fallbackRaw.desktop) !== null && _b !== void 0 ? _b : base };
|
|
229
|
+
// fetch the values from the element
|
|
230
|
+
return {
|
|
231
|
+
base,
|
|
232
|
+
mobile: parser(attributes[`${property}Mobile`], fallback.mobile),
|
|
233
|
+
desktop: parser(attributes[`${property}Desktop`], fallback.desktop)
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
ResponsiveValue.parse = parse;
|
|
237
|
+
})(ResponsiveValue = BlockLayout.ResponsiveValue || (BlockLayout.ResponsiveValue = {}));
|
|
238
|
+
let ResponsiveClassNames;
|
|
239
|
+
(function (ResponsiveClassNames) {
|
|
240
|
+
// helpers
|
|
241
|
+
function parse(args) {
|
|
242
|
+
// handle string types
|
|
243
|
+
if (typeof args.value.base === 'string') {
|
|
244
|
+
// destructure args
|
|
245
|
+
const { value: { mobile, base, desktop }, mobile: mobileClasses, base: baseClasses, desktop: desktopClasses } = args;
|
|
246
|
+
// return classes
|
|
247
|
+
return (0, classnames_1.default)(mobileClasses[mobile], baseClasses[base], desktopClasses[desktop]);
|
|
248
|
+
}
|
|
249
|
+
// or boolean
|
|
250
|
+
else {
|
|
251
|
+
// destructure args
|
|
252
|
+
const { value: { mobile, base, desktop }, mobile: mobileClasses, base: baseClasses, desktop: desktopClasses } = args;
|
|
253
|
+
// return classes
|
|
254
|
+
return (0, classnames_1.default)(mobileClasses[mobile ? 'true' : 'false'], baseClasses[base ? 'true' : 'false'], desktopClasses[desktop ? 'true' : 'false']);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
ResponsiveClassNames.parse = parse;
|
|
258
|
+
})(ResponsiveClassNames = BlockLayout.ResponsiveClassNames || (BlockLayout.ResponsiveClassNames = {}));
|
|
210
259
|
// parser
|
|
211
260
|
const xmlParser = new fast_xml_parser_1.XMLParser({
|
|
212
261
|
ignoreDeclaration: true,
|
|
@@ -224,26 +273,34 @@ var BlockLayout;
|
|
|
224
273
|
})(BlockLayout || (exports.BlockLayout = BlockLayout = {}));
|
|
225
274
|
// helpers
|
|
226
275
|
function parseBlock(json) {
|
|
227
|
-
// parse
|
|
228
|
-
const
|
|
229
|
-
const tight = BlockLayout.
|
|
276
|
+
// parse
|
|
277
|
+
const element = ParsedElement.parse({ data: json, expectedTags: ['block'], expectedChildren: 1 });
|
|
278
|
+
const tight = BlockLayout.ResponsiveValue.parse({
|
|
279
|
+
element,
|
|
280
|
+
property: 'tight',
|
|
281
|
+
parser: BlockLayout.Tight.parse,
|
|
282
|
+
fallback: 'none'
|
|
283
|
+
});
|
|
230
284
|
// return block
|
|
231
285
|
return {
|
|
232
|
-
name:
|
|
286
|
+
name: element.attributes['name'],
|
|
233
287
|
tight,
|
|
234
|
-
|
|
235
|
-
tightDesktop: BlockLayout.Tight.parse(block.attributes['tightDesktop'], tight),
|
|
236
|
-
root: parseRoot(ParsedElement.parse({ data: block.children[0], expectedTags: ['row', 'col', 'stack'] })),
|
|
288
|
+
root: parseRoot(ParsedElement.parse({ data: element.children[0], expectedTags: ['row', 'col', 'stack'] })),
|
|
237
289
|
};
|
|
238
290
|
}
|
|
239
|
-
function parseRoot(
|
|
240
|
-
|
|
241
|
-
|
|
291
|
+
function parseRoot(element) {
|
|
292
|
+
// parse
|
|
293
|
+
const { tag, attributes, children } = element;
|
|
242
294
|
const _a = parseItemAttributes(attributes), { size } = _a, itemAttributes = __rest(_a, ["size"]);
|
|
243
295
|
// create root
|
|
244
296
|
switch (tag) {
|
|
245
297
|
case 'row':
|
|
246
|
-
return Object.assign(Object.assign({ type: 'row' }, itemAttributes), { ratio
|
|
298
|
+
return Object.assign(Object.assign({ type: 'row' }, itemAttributes), { ratio: BlockLayout.ResponsiveValue.parse({
|
|
299
|
+
element,
|
|
300
|
+
property: 'ratio',
|
|
301
|
+
parser: BlockLayout.Ratio.parse,
|
|
302
|
+
fallback: '1/1'
|
|
303
|
+
}), items: children.map(data => parseNestedItem(ParsedElement.parse({
|
|
247
304
|
data,
|
|
248
305
|
expectedTags: ParsedElement.tags.filter(t => t !== tag)
|
|
249
306
|
}))) });
|
|
@@ -261,14 +318,19 @@ function parseRoot({ tag, attributes, children }) {
|
|
|
261
318
|
throw new errors_1.ArgumentError(`Invalid XML BlockLayout root encountered "${tag}" where instead of "row" or "col"`);
|
|
262
319
|
}
|
|
263
320
|
}
|
|
264
|
-
function parseNestedItem(
|
|
265
|
-
// parse
|
|
321
|
+
function parseNestedItem(element) {
|
|
322
|
+
// parse
|
|
323
|
+
const { tag, attributes, children } = element;
|
|
266
324
|
const _a = parseItemAttributes(attributes), { size } = _a, itemAttributes = __rest(_a, ["size"]);
|
|
267
|
-
const ratio = BlockLayout.Ratio.parse(attributes['ratio'], '1/1');
|
|
268
325
|
// create container
|
|
269
326
|
switch (tag) {
|
|
270
327
|
case 'row':
|
|
271
|
-
return Object.assign(Object.assign({ type: 'row' }, itemAttributes), { ratio
|
|
328
|
+
return Object.assign(Object.assign({ type: 'row' }, itemAttributes), { ratio: BlockLayout.ResponsiveValue.parse({
|
|
329
|
+
element,
|
|
330
|
+
property: 'ratio',
|
|
331
|
+
parser: BlockLayout.Ratio.parse,
|
|
332
|
+
fallback: '1/1'
|
|
333
|
+
}), items: children.map(data => parsePanel(Object.assign({}, ParsedElement.parse({
|
|
272
334
|
data,
|
|
273
335
|
expectedTags: ParsedElement.tags.filter(t => t !== 'row' && t !== 'col')
|
|
274
336
|
})))) });
|
|
@@ -282,38 +344,46 @@ function parseNestedItem({ tag, attributes, children }) {
|
|
|
282
344
|
return parsePanel({ tag, attributes, children });
|
|
283
345
|
}
|
|
284
346
|
}
|
|
285
|
-
function parsePanel(
|
|
347
|
+
function parsePanel(element) {
|
|
286
348
|
var _a;
|
|
349
|
+
// parse
|
|
350
|
+
const { tag, attributes } = element;
|
|
287
351
|
const key = (_a = attributes['key']) !== null && _a !== void 0 ? _a : tag;
|
|
288
352
|
const itemAttributes = parseItemAttributes(attributes);
|
|
289
|
-
const
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
353
|
+
const fullBleed = BlockLayout.ResponsiveValue.parse({
|
|
354
|
+
element,
|
|
355
|
+
property: 'fullBleed',
|
|
356
|
+
parser: BlockLayout.FullBleed.parse,
|
|
357
|
+
fallback: false
|
|
358
|
+
});
|
|
359
|
+
// create panel
|
|
294
360
|
switch (tag) {
|
|
295
361
|
case 'message':
|
|
296
|
-
return Object.assign(
|
|
297
|
-
|
|
298
|
-
|
|
362
|
+
return Object.assign({ type: 'message', key, textAlign: BlockLayout.ResponsiveValue.parse({
|
|
363
|
+
element,
|
|
364
|
+
property: 'textAlign',
|
|
365
|
+
parser: BlockLayout.TextAlignment.parse,
|
|
366
|
+
fallback: 'left'
|
|
367
|
+
}), fullBleed }, itemAttributes);
|
|
299
368
|
case 'visual':
|
|
300
|
-
return Object.assign(
|
|
301
|
-
|
|
302
|
-
|
|
369
|
+
return Object.assign({ type: 'visual', key, aspectRatio: BlockLayout.ResponsiveValue.parse({
|
|
370
|
+
element,
|
|
371
|
+
property: 'aspect',
|
|
372
|
+
parser: BlockLayout.AspectRatio.parse,
|
|
373
|
+
fallback: 'auto'
|
|
374
|
+
}), fullBleed }, itemAttributes);
|
|
303
375
|
case 'list':
|
|
304
|
-
return Object.assign(
|
|
305
|
-
fullBleedMobile,
|
|
306
|
-
fullBleedDesktop, itemType: BlockLayout.List.ItemType.parse(attributes['itemType'], 'message+visual') });
|
|
376
|
+
return Object.assign({ type: 'list', key, itemType: BlockLayout.List.ItemType.parse(attributes['itemType'], 'message+visual'), fullBleed }, itemAttributes);
|
|
307
377
|
default:
|
|
308
378
|
throw new errors_1.ArgumentError(`Invalid XML BlockLayout - encountered "${tag}" where instead of BlockLayout.Panel`);
|
|
309
379
|
}
|
|
310
380
|
}
|
|
311
381
|
function parseItemAttributes(attributes) {
|
|
312
382
|
return {
|
|
313
|
-
mobileOrder: BlockLayout.MobileOrder.parse(attributes['mobileOrder']),
|
|
383
|
+
mobileOrder: BlockLayout.MobileOrder.parse(attributes['mobileOrder'], 'auto'),
|
|
314
384
|
alignX: BlockLayout.Alignment.parse(attributes['alignX'], 'start'),
|
|
315
385
|
alignY: BlockLayout.Alignment.parse(attributes['alignY'], 'start'),
|
|
316
|
-
size: BlockLayout.Size.parse(attributes['size'], 'full')
|
|
386
|
+
size: BlockLayout.Size.parse(attributes['size'], 'full')
|
|
317
387
|
};
|
|
318
388
|
}
|
|
319
389
|
var ParsedElement;
|
|
@@ -17,6 +17,7 @@ export declare class Field<TSchema extends Schema.Field.Type = Schema.Field.Type
|
|
|
17
17
|
private _sandboxed;
|
|
18
18
|
private _sandboxedValue;
|
|
19
19
|
private readonly _validator;
|
|
20
|
+
private _customValidator?;
|
|
20
21
|
private _errors;
|
|
21
22
|
private _optIn?;
|
|
22
23
|
private _optOut?;
|
|
@@ -29,6 +30,8 @@ export declare class Field<TSchema extends Schema.Field.Type = Schema.Field.Type
|
|
|
29
30
|
get error(): FieldValidator.Error | undefined;
|
|
30
31
|
getErrors(level: FieldValidator.Error.Level): readonly FieldValidator.Error[];
|
|
31
32
|
get errors(): ReadonlyArray<FieldValidator.Error>;
|
|
33
|
+
get customValidator(): FieldValidator | undefined;
|
|
34
|
+
set customValidator(validator: FieldValidator | undefined);
|
|
32
35
|
get defaultValue(): Field.Value<TSchema> | undefined;
|
|
33
36
|
get initialValue(): Field.Value<TSchema> | undefined;
|
|
34
37
|
get hasValue(): boolean;
|
|
@@ -71,6 +74,7 @@ export declare namespace Field {
|
|
|
71
74
|
publishedValue?: Value<TSchema>;
|
|
72
75
|
initialValue?: Value<TSchema>;
|
|
73
76
|
required: boolean;
|
|
77
|
+
customValidator?: FieldValidator;
|
|
74
78
|
};
|
|
75
79
|
type Value<TSchema extends Schema.Field.Type = Schema.Field.Type> = Schema.Field.Data<TSchema>;
|
|
76
80
|
interface Event extends EventBus.Event<'Field', Event.Type> {
|
package/dist/ui/fields/Field.js
CHANGED
|
@@ -56,8 +56,12 @@ class Field {
|
|
|
56
56
|
this._editing = false;
|
|
57
57
|
this._sandboxed = false;
|
|
58
58
|
this._validator = FieldValidator_1.FieldValidator.create(this);
|
|
59
|
+
this._customValidator = args.customValidator;
|
|
59
60
|
// validate
|
|
60
61
|
this._errors = this._validator.validate(this, this._initialValue);
|
|
62
|
+
if (this._customValidator) {
|
|
63
|
+
this._errors = [...this._errors, ...this._customValidator.validate(this, this._initialValue)];
|
|
64
|
+
}
|
|
61
65
|
}
|
|
62
66
|
get events$() {
|
|
63
67
|
return this.eventBus.events$.pipe((0, rxjs_1.filter)(Field.Event.filter), (0, rxjs_1.filter)(e => e.field === this));
|
|
@@ -82,11 +86,32 @@ class Field {
|
|
|
82
86
|
return FieldValidator_1.FieldValidator.Error.mostRelevant(this._errors);
|
|
83
87
|
}
|
|
84
88
|
getErrors(level) {
|
|
85
|
-
|
|
89
|
+
// filter with fixed validator
|
|
90
|
+
const { _errors, _validator, _customValidator } = this;
|
|
91
|
+
let errors = _validator.filter(_errors, level);
|
|
92
|
+
// then with custom (if available)
|
|
93
|
+
if (_customValidator) {
|
|
94
|
+
errors = _customValidator.filter(errors, level);
|
|
95
|
+
}
|
|
96
|
+
// return errors
|
|
97
|
+
return errors;
|
|
86
98
|
}
|
|
87
99
|
get errors() {
|
|
88
100
|
return this._errors;
|
|
89
101
|
}
|
|
102
|
+
get customValidator() {
|
|
103
|
+
return this._customValidator;
|
|
104
|
+
}
|
|
105
|
+
set customValidator(validator) {
|
|
106
|
+
// ignore if unchanged
|
|
107
|
+
if (this._customValidator === validator) {
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
// update validator
|
|
111
|
+
this._customValidator = validator;
|
|
112
|
+
// revalidate
|
|
113
|
+
this.validate();
|
|
114
|
+
}
|
|
90
115
|
get defaultValue() {
|
|
91
116
|
// no default if it's not required
|
|
92
117
|
const { schema } = this;
|
|
@@ -231,8 +256,13 @@ class Field {
|
|
|
231
256
|
delete this._shouldFocus;
|
|
232
257
|
}
|
|
233
258
|
validate(silent = false) {
|
|
234
|
-
// validate (
|
|
235
|
-
const
|
|
259
|
+
// validate (use custom if available)
|
|
260
|
+
const { _value, _validator, customValidator } = this;
|
|
261
|
+
let errors = _validator.validate(this, _value);
|
|
262
|
+
if (customValidator) {
|
|
263
|
+
errors = [...errors, ...customValidator.validate(this, _value)];
|
|
264
|
+
}
|
|
265
|
+
// skip if nothing has changed
|
|
236
266
|
if (utils_1.Value.equals(errors, this._errors)) {
|
|
237
267
|
return this._errors;
|
|
238
268
|
}
|
|
@@ -18,7 +18,8 @@
|
|
|
18
18
|
"date.maxDate": "${label} cannot be after ${maxDate}",
|
|
19
19
|
"timestamp": "${label} is not a valid date/time",
|
|
20
20
|
"timestamp.minTime": "${label} cannot be before ${minTime}",
|
|
21
|
-
"timestamp.maxTime": "${label} cannot be after ${maxTime}"
|
|
21
|
+
"timestamp.maxTime": "${label} cannot be after ${maxTime}",
|
|
22
|
+
"duplicate": "${label} is already in use"
|
|
22
23
|
},
|
|
23
24
|
"fr": {
|
|
24
25
|
"required": "${label} is required",
|
|
@@ -39,6 +40,7 @@
|
|
|
39
40
|
"date.maxDate": "${label} cannot be after ${maxDate}",
|
|
40
41
|
"timestamp": "${label} is not a valid date/time",
|
|
41
42
|
"timestamp.minTime": "${label} cannot be before ${minTime}",
|
|
42
|
-
"timestamp.maxTime": "${label} cannot be after ${maxTime}"
|
|
43
|
+
"timestamp.maxTime": "${label} cannot be after ${maxTime}",
|
|
44
|
+
"duplicate": "${label} est déjà utilisé"
|
|
43
45
|
}
|
|
44
46
|
}
|
package/dist/ui/fields/index.js
CHANGED
|
@@ -21,3 +21,4 @@ __exportStar(require("./FieldModel"), exports);
|
|
|
21
21
|
__exportStar(require("./FieldSerializer"), exports);
|
|
22
22
|
__exportStar(require("./FieldValidator"), exports);
|
|
23
23
|
__exportStar(require("./ObjectField"), exports);
|
|
24
|
+
__exportStar(require("./validators/ValidatorHelper"), exports);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nascentdigital/funnel-core",
|
|
3
|
-
"version": "4.4.
|
|
3
|
+
"version": "4.4.17",
|
|
4
4
|
"repository": {
|
|
5
5
|
"url": "git+https://github.com/nascentdigital/funnel.git",
|
|
6
6
|
"directory": "libs/core"
|
|
@@ -37,6 +37,7 @@
|
|
|
37
37
|
"@nodable/flexible-xml-parser": "^1",
|
|
38
38
|
"blurhash": "^2",
|
|
39
39
|
"byte-size": "^9",
|
|
40
|
+
"classnames": "^2",
|
|
40
41
|
"clone-deep": "^4",
|
|
41
42
|
"css.escape": "^1",
|
|
42
43
|
"date-fns": "^4",
|
|
@@ -63,5 +64,5 @@
|
|
|
63
64
|
"jest-tsd": "^0.2.2",
|
|
64
65
|
"ts-jest": "^29.3.2"
|
|
65
66
|
},
|
|
66
|
-
"gitHead": "
|
|
67
|
-
}
|
|
67
|
+
"gitHead": "f343d2af0dff3dd7e8ae12a9ab83bceb93381ec2"
|
|
68
|
+
}
|