@vectoriox/iox-ui 5.42.0 → 5.44.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/data-core/index.d.ts +360 -0
- package/data-core/package.json +3 -0
- package/design-core/index.d.ts +215 -3
- package/fesm2022/vectoriox-iox-ui-data-core.mjs +491 -0
- package/fesm2022/vectoriox-iox-ui-data-core.mjs.map +1 -0
- package/fesm2022/vectoriox-iox-ui-design-core.mjs +276 -3
- package/fesm2022/vectoriox-iox-ui-design-core.mjs.map +1 -1
- package/fesm2022/vectoriox-iox-ui-generation-core.mjs +7 -1
- package/fesm2022/vectoriox-iox-ui-generation-core.mjs.map +1 -1
- package/fesm2022/vectoriox-iox-ui.mjs +179 -526
- package/fesm2022/vectoriox-iox-ui.mjs.map +1 -1
- package/generation-core/index.d.ts +3 -0
- package/index.d.ts +112 -381
- package/package.json +5 -1
- package/src/data-core/data-source-resolver.ts +378 -0
- package/src/data-core/public-api.ts +12 -0
- package/src/data-core/relative-sources.ts +282 -0
- package/src/design-core/design-apply.ts +56 -3
- package/src/design-core/design-settings.ts +32 -3
- package/src/design-core/design-token.model.ts +23 -0
- package/src/design-core/flavor-spec.generated.ts +202 -0
- package/src/design-core/flavor-tokens.ts +2 -1
- package/src/generation-core/site-spec.generated.ts +4 -1
- package/src/generation-core/validate-site-plan.ts +3 -0
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { deriveBrandTokens } from './brand';
|
|
2
|
-
import { SPEC_LEGACY_ALIASES } from './flavor-spec.generated';
|
|
2
|
+
import { FLAVOR_SPEC_VERSION, SPEC_LEGACY_ALIASES } from './flavor-spec.generated';
|
|
3
3
|
import { SWISS_FLAVOR } from './flavor';
|
|
4
4
|
import { buildFlavorTokens, legacyFlavorTokens } from './flavor-tokens';
|
|
5
5
|
import {
|
|
6
|
-
FlavorRevertPlan, FlavorSeedOptions, FlavorSeedPlan, planFlavorRevert, planFlavorSeed, SeedBaseline,
|
|
6
|
+
FlavorRevertPlan, FlavorRevertSnapshot, FlavorSeedOptions, FlavorSeedPlan, flavorSeedWrites, planFlavorRevert, planFlavorSeed, SeedBaseline,
|
|
7
|
+
SeedExpectation, untouchedSeedRow,
|
|
7
8
|
} from './flavor-seed';
|
|
8
9
|
import { DesignChoices, DesignTokenRow, flavorSourceStamp, StoredDesignTokenRow } from './design-token.model';
|
|
9
10
|
import { fontFamilyKey, FontFamilyToken, fontRoleReferences, parseFontFamilies } from './fonts';
|
|
10
|
-
import { flavorPackById, isRetiredFlavorId, packDesignChoices, StoredDesign } from './design-settings';
|
|
11
|
+
import { DesignConfigEntry, DesignConfigKey, designConfigEntries, flavorPackById, isRetiredFlavorId, packDesignChoices, StoredDesign } from './design-settings';
|
|
11
12
|
|
|
12
13
|
/**
|
|
13
14
|
* Applying a look (design-system DS4): the COMPLETE `buildFlavorTokens` set for the chosen
|
|
@@ -125,6 +126,58 @@ export function planDesignRevert(current: ReadonlyArray<StoredDesignTokenRow>, d
|
|
|
125
126
|
return planFlavorRevert(current, snapshot.tokens, snapshot.wrote ?? designTokenRows(design.choices));
|
|
126
127
|
}
|
|
127
128
|
|
|
129
|
+
/** The revert snapshot an Apply stores in `settings.design` (board F7): design-core's snapshot plus the design
|
|
130
|
+
* row's previous config VERBATIM, so a revert restores every choice (pair, axes, mode, fonts), not only the
|
|
131
|
+
* flavor id and seed. */
|
|
132
|
+
export interface DesignRevertSnapshot extends FlavorRevertSnapshot {
|
|
133
|
+
fromConfig?: DesignConfigEntry[];
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* What an Apply of `plan` stores as its revert snapshot — the ONE rule the builder's Apply and the
|
|
138
|
+
* server-side site build (W2) share: the whole pre-apply token set, what the apply writes into each row,
|
|
139
|
+
* and where a revert goes back to — never a null flavor (a studio with no design row wore its design's
|
|
140
|
+
* defaults, so that is what it returns to). An apply that writes nothing keeps the previous snapshot:
|
|
141
|
+
* clobbering a useful one with "nothing changed" would be a lie.
|
|
142
|
+
*/
|
|
143
|
+
export function designApplySnapshot(
|
|
144
|
+
previous: StoredDesign,
|
|
145
|
+
previousConfig: ReadonlyArray<DesignConfigEntry> | null | undefined,
|
|
146
|
+
existing: ReadonlyArray<StoredDesignTokenRow>,
|
|
147
|
+
plan: FlavorSeedPlan,
|
|
148
|
+
appliedAt: number,
|
|
149
|
+
): DesignRevertSnapshot | null {
|
|
150
|
+
if (!plan.create.length && !plan.update.length) return previous.revert;
|
|
151
|
+
const origin: Pick<DesignRevertSnapshot, 'from' | 'fromConfig'> = previous.storedFlavorId
|
|
152
|
+
? {
|
|
153
|
+
from: { flavorId: previous.storedFlavorId, flavorVersion: previous.flavorVersion, brandSeed: previous.storedSeed },
|
|
154
|
+
fromConfig: (previousConfig ?? []).filter(kv => kv?.key !== DesignConfigKey.Revert),
|
|
155
|
+
}
|
|
156
|
+
: {
|
|
157
|
+
from: { flavorId: previous.choices.flavorId, flavorVersion: String(FLAVOR_SPEC_VERSION), brandSeed: previous.choices.seed },
|
|
158
|
+
fromConfig: designConfigEntries(previous.choices, FLAVOR_SPEC_VERSION, null),
|
|
159
|
+
};
|
|
160
|
+
return {
|
|
161
|
+
appliedAt,
|
|
162
|
+
...origin,
|
|
163
|
+
tokens: (existing ?? []).map(r => ({ name: r.name, type: r.type, value: r.value, values: r.values, source: r.source, group: r.group, tier: r.tier })),
|
|
164
|
+
wrote: flavorSeedWrites(plan, existing),
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/** The config a revert puts back: the snapshot's verbatim config, else (a snapshot older than `fromConfig`)
|
|
169
|
+
* the identity it recorded. */
|
|
170
|
+
export function designRevertConfig(snapshot: DesignRevertSnapshot): DesignConfigEntry[] {
|
|
171
|
+
if (snapshot.fromConfig) return snapshot.fromConfig;
|
|
172
|
+
return [
|
|
173
|
+
...(snapshot.from.flavorId ? [
|
|
174
|
+
{ key: DesignConfigKey.FlavorId, value: snapshot.from.flavorId },
|
|
175
|
+
{ key: DesignConfigKey.FlavorVersion, value: snapshot.from.flavorVersion ?? '' },
|
|
176
|
+
] : []),
|
|
177
|
+
...(snapshot.from.brandSeed ? [{ key: DesignConfigKey.BrandSeed, value: snapshot.from.brandSeed }] : []),
|
|
178
|
+
];
|
|
179
|
+
}
|
|
180
|
+
|
|
128
181
|
/** The rows a design is missing by name — the builder-load top-up (never touches an existing row). */
|
|
129
182
|
export function missingDesignRows(existing: ReadonlyArray<{ name: string }>, choices: DesignChoices): DesignTokenRow[] {
|
|
130
183
|
const have = new Set((existing ?? []).map(r => r.name));
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { SPEC_AXES, SPEC_FONT_ROLES } from './flavor-spec.generated';
|
|
2
2
|
import { parseHexColor } from './brand';
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
AnimateId, BetweenId, DesignChoices, DesignMode, DesignMotion, FlavorPackV2, FontRoleToken, PRE_MOTION, PRE_TINT_DEFAULT, ScrollId,
|
|
5
|
+
SPEC_FLAVORS, TintId,
|
|
6
|
+
} from './design-token.model';
|
|
4
7
|
import type { FlavorRevertSnapshot } from './flavor-seed';
|
|
5
8
|
|
|
6
9
|
/**
|
|
@@ -32,6 +35,9 @@ export enum DesignConfigKey {
|
|
|
32
35
|
Mode = 'mode',
|
|
33
36
|
Tint = 'tint',
|
|
34
37
|
Fonts = 'fonts',
|
|
38
|
+
Scroll = 'scroll',
|
|
39
|
+
Animate = 'animate',
|
|
40
|
+
Between = 'between',
|
|
35
41
|
Revert = 'revert',
|
|
36
42
|
}
|
|
37
43
|
|
|
@@ -124,6 +130,16 @@ export function resolveDesignChoices(partial: Partial<DesignChoices> | null | un
|
|
|
124
130
|
mode: (MODES.includes(asString(partial?.mode) ?? '') ? asString(partial?.mode) : pack.defaults.mode) as DesignMode,
|
|
125
131
|
tint: keyOf(SPEC_AXES.tints, asString(partial?.tint)) ?? pack.defaults.tint,
|
|
126
132
|
...(fonts ? { fonts } : {}),
|
|
133
|
+
...resolveDesignMotion(partial),
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/** The look's motion, completed: an absent or unknown choice reads `PRE_MOTION` — what the site already does. */
|
|
138
|
+
export function resolveDesignMotion(partial: Readonly<Partial<Record<keyof DesignMotion, unknown>>> | null | undefined): DesignMotion {
|
|
139
|
+
return {
|
|
140
|
+
scroll: keyOf<ScrollId>(SPEC_AXES.scrolls, asString(partial?.scroll)) ?? PRE_MOTION.scroll,
|
|
141
|
+
animate: keyOf<AnimateId>(SPEC_AXES.animations, asString(partial?.animate)) ?? PRE_MOTION.animate,
|
|
142
|
+
between: keyOf<BetweenId>(SPEC_AXES.betweens, asString(partial?.between)) ?? PRE_MOTION.between,
|
|
127
143
|
};
|
|
128
144
|
}
|
|
129
145
|
|
|
@@ -135,12 +151,13 @@ export function packDesignChoices(flavorId: string): DesignChoices {
|
|
|
135
151
|
/**
|
|
136
152
|
* What picking a pack card means, given the design the studio wears: the applied pack → the applied
|
|
137
153
|
* choices; another pack → that pack's defaults, CARRYING the author's chosen fonts (§5b — a font the
|
|
138
|
-
* author chose survives a pack switch unless the author changes it)
|
|
154
|
+
* author chose survives a pack switch unless the author changes it) and the site's motion (rev 3.1 MO-D3 —
|
|
155
|
+
* how it scrolls and changes page is not a pack's, so a Look pick never resets it). Both picker homes call this.
|
|
139
156
|
*/
|
|
140
157
|
export function choicesForPack(flavorId: string, applied: DesignChoices | null | undefined): DesignChoices {
|
|
141
158
|
const pack = flavorPackById(flavorId) ?? defaultPack();
|
|
142
159
|
if (applied && resolveDesignChoices(applied).flavorId === pack.id) return resolveDesignChoices(applied);
|
|
143
|
-
return resolveDesignChoices({ flavorId: pack.id, fonts: applied?.fonts });
|
|
160
|
+
return resolveDesignChoices({ flavorId: pack.id, fonts: applied?.fonts, ...resolveDesignMotion(applied) });
|
|
144
161
|
}
|
|
145
162
|
|
|
146
163
|
/**
|
|
@@ -164,6 +181,9 @@ export function readDesignConfig(config: ReadonlyArray<DesignConfigEntry> | null
|
|
|
164
181
|
mode: map.get(DesignConfigKey.Mode) as DesignMode,
|
|
165
182
|
tint: (storedTint ?? undefined) as TintId | undefined,
|
|
166
183
|
fonts: map.get(DesignConfigKey.Fonts) as DesignChoices['fonts'],
|
|
184
|
+
scroll: map.get(DesignConfigKey.Scroll) as ScrollId,
|
|
185
|
+
animate: map.get(DesignConfigKey.Animate) as AnimateId,
|
|
186
|
+
between: map.get(DesignConfigKey.Between) as BetweenId,
|
|
167
187
|
});
|
|
168
188
|
return {
|
|
169
189
|
choices,
|
|
@@ -180,6 +200,11 @@ export function designModeOf(config: ReadonlyArray<DesignConfigEntry> | null | u
|
|
|
180
200
|
return readDesignConfig(config).choices.mode;
|
|
181
201
|
}
|
|
182
202
|
|
|
203
|
+
/** The look's motion of a stored config — what the public page read hands the engine (`designMotion`). */
|
|
204
|
+
export function designMotionOf(config: ReadonlyArray<DesignConfigEntry> | null | undefined): DesignMotion {
|
|
205
|
+
return resolveDesignMotion(readDesignConfig(config).choices);
|
|
206
|
+
}
|
|
207
|
+
|
|
183
208
|
/** Resolved choices (+ the revert snapshot) → the config array a settings row stores. */
|
|
184
209
|
export function designConfigEntries(
|
|
185
210
|
choices: DesignChoices,
|
|
@@ -198,6 +223,9 @@ export function designConfigEntries(
|
|
|
198
223
|
{ key: DesignConfigKey.PillButtons, value: String(c.pillButtons) },
|
|
199
224
|
{ key: DesignConfigKey.Mode, value: c.mode },
|
|
200
225
|
{ key: DesignConfigKey.Tint, value: c.tint },
|
|
226
|
+
{ key: DesignConfigKey.Scroll, value: c.scroll },
|
|
227
|
+
{ key: DesignConfigKey.Animate, value: c.animate },
|
|
228
|
+
{ key: DesignConfigKey.Between, value: c.between },
|
|
201
229
|
...(c.fonts ? [{ key: DesignConfigKey.Fonts, value: JSON.stringify(c.fonts) }] : []),
|
|
202
230
|
...(revert ? [{ key: DesignConfigKey.Revert, value: JSON.stringify(revert) }] : []),
|
|
203
231
|
];
|
|
@@ -210,5 +238,6 @@ export function sameDesignChoices(a: DesignChoices, b: DesignChoices): boolean {
|
|
|
210
238
|
return x.flavorId === y.flavorId && x.seed.toLowerCase() === y.seed.toLowerCase() && x.pairId === y.pairId
|
|
211
239
|
&& x.shape === y.shape && x.density === y.density && x.motion === y.motion
|
|
212
240
|
&& x.pillButtons === y.pillButtons && x.mode === y.mode && x.tint === y.tint
|
|
241
|
+
&& x.scroll === y.scroll && x.animate === y.animate && x.between === y.between
|
|
213
242
|
&& JSON.stringify(x.fonts ?? {}) === JSON.stringify(y.fonts ?? {});
|
|
214
243
|
}
|
|
@@ -46,6 +46,25 @@ export type TintId = keyof typeof SPEC_AXES.tints;
|
|
|
46
46
|
export const TINT_IDS = Object.keys(SPEC_AXES.tints) as ReadonlyArray<TintId>;
|
|
47
47
|
/** What a studio that stored its look BEFORE the tint existed wears: exactly the look's own palette. */
|
|
48
48
|
export const PRE_TINT_DEFAULT: TintId = 'neutral';
|
|
49
|
+
/** How the site scrolls (AI plan rev 3.1 §3p): Normal (the browser's own) · Smooth · Extra smooth. */
|
|
50
|
+
export type ScrollId = keyof typeof SPEC_AXES.scrolls;
|
|
51
|
+
/** How much the sections move in as they scroll into view: Still · Subtle · Standard · Lively. */
|
|
52
|
+
export type AnimateId = keyof typeof SPEC_AXES.animations;
|
|
53
|
+
/** What plays between pages: None · Fade · Slide · Cinematic. */
|
|
54
|
+
export type BetweenId = keyof typeof SPEC_AXES.betweens;
|
|
55
|
+
export const SCROLL_IDS = Object.keys(SPEC_AXES.scrolls) as ReadonlyArray<ScrollId>;
|
|
56
|
+
export const ANIMATE_IDS = Object.keys(SPEC_AXES.animations) as ReadonlyArray<AnimateId>;
|
|
57
|
+
export const BETWEEN_IDS = Object.keys(SPEC_AXES.betweens) as ReadonlyArray<BetweenId>;
|
|
58
|
+
/** The look's motion — the three choices the runtime and the composer read from `settings.design`. */
|
|
59
|
+
export interface DesignMotion {
|
|
60
|
+
scroll: ScrollId;
|
|
61
|
+
animate: AnimateId;
|
|
62
|
+
between: BetweenId;
|
|
63
|
+
}
|
|
64
|
+
/** What a look stored BEFORE rev 3.1 wears: exactly what every live site did (Smooth · Still · Cinematic). */
|
|
65
|
+
export const PRE_MOTION: Readonly<DesignMotion> = SPEC_AXES.motionChoices.pre;
|
|
66
|
+
/** What a visitor who asks for reduced motion always gets, whatever the look chose. */
|
|
67
|
+
export const REDUCED_DESIGN_MOTION: Readonly<DesignMotion> = SPEC_AXES.motionChoices.reduced;
|
|
49
68
|
export type SchemeId = keyof typeof SPEC_SCHEMES;
|
|
50
69
|
export type FontRoleToken = (typeof SPEC_FONT_ROLES)[number]['token'];
|
|
51
70
|
|
|
@@ -63,6 +82,10 @@ export interface DesignChoices {
|
|
|
63
82
|
* `neutral` — the palette it was applied with. */
|
|
64
83
|
tint?: TintId;
|
|
65
84
|
fonts?: Partial<Record<FontRoleToken, string>>;
|
|
85
|
+
/** Absent = `PRE_MOTION` (a row stored before rev 3.1 reads what its site already did). */
|
|
86
|
+
scroll?: ScrollId;
|
|
87
|
+
animate?: AnimateId;
|
|
88
|
+
between?: BetweenId;
|
|
66
89
|
}
|
|
67
90
|
|
|
68
91
|
export interface FlavorSpecToken {
|
|
@@ -1429,6 +1429,208 @@ export const SPEC_AXES = {
|
|
|
1429
1429
|
"inverse-line": 0.03
|
|
1430
1430
|
}
|
|
1431
1431
|
}
|
|
1432
|
+
},
|
|
1433
|
+
"scrolls": {
|
|
1434
|
+
"normal": {
|
|
1435
|
+
"label": "Normal",
|
|
1436
|
+
"he": "רגילה",
|
|
1437
|
+
"hint": "The browser's own scrolling.",
|
|
1438
|
+
"lenis": null
|
|
1439
|
+
},
|
|
1440
|
+
"smooth": {
|
|
1441
|
+
"label": "Smooth",
|
|
1442
|
+
"he": "חלקה",
|
|
1443
|
+
"hint": "A short glide after each wheel turn — what every IOX site does today.",
|
|
1444
|
+
"lenis": {
|
|
1445
|
+
"duration": 1.2,
|
|
1446
|
+
"easing": "expo-out",
|
|
1447
|
+
"wheelMultiplier": 1,
|
|
1448
|
+
"syncTouch": false
|
|
1449
|
+
}
|
|
1450
|
+
},
|
|
1451
|
+
"extra": {
|
|
1452
|
+
"label": "Extra smooth",
|
|
1453
|
+
"he": "חלקה מאוד",
|
|
1454
|
+
"hint": "A longer, softer glide; each wheel turn moves a little less.",
|
|
1455
|
+
"lenis": {
|
|
1456
|
+
"duration": 1.8,
|
|
1457
|
+
"easing": "expo-out",
|
|
1458
|
+
"wheelMultiplier": 0.9,
|
|
1459
|
+
"syncTouch": false
|
|
1460
|
+
}
|
|
1461
|
+
}
|
|
1462
|
+
},
|
|
1463
|
+
"animations": {
|
|
1464
|
+
"still": {
|
|
1465
|
+
"label": "Still",
|
|
1466
|
+
"he": "ללא",
|
|
1467
|
+
"hint": "Nothing moves in as you scroll. Buttons and cards still respond to the pointer (Speed).",
|
|
1468
|
+
"parts": {}
|
|
1469
|
+
},
|
|
1470
|
+
"subtle": {
|
|
1471
|
+
"label": "Subtle",
|
|
1472
|
+
"he": "עדינה",
|
|
1473
|
+
"hint": "Each section's content fades in once, together.",
|
|
1474
|
+
"parts": {
|
|
1475
|
+
"content": {
|
|
1476
|
+
"type": "fadeIn",
|
|
1477
|
+
"duration": 500
|
|
1478
|
+
}
|
|
1479
|
+
}
|
|
1480
|
+
},
|
|
1481
|
+
"standard": {
|
|
1482
|
+
"label": "Standard",
|
|
1483
|
+
"he": "רגילה",
|
|
1484
|
+
"hint": "Headings rise in; cards, prices and steps follow one after another.",
|
|
1485
|
+
"parts": {
|
|
1486
|
+
"heading": {
|
|
1487
|
+
"type": "moveUp",
|
|
1488
|
+
"distance": 16,
|
|
1489
|
+
"duration": 500
|
|
1490
|
+
},
|
|
1491
|
+
"items": {
|
|
1492
|
+
"type": "moveUp",
|
|
1493
|
+
"distance": 16,
|
|
1494
|
+
"duration": 450,
|
|
1495
|
+
"stagger": 80,
|
|
1496
|
+
"cap": 6
|
|
1497
|
+
},
|
|
1498
|
+
"media": {
|
|
1499
|
+
"type": "fadeIn",
|
|
1500
|
+
"duration": 600
|
|
1501
|
+
}
|
|
1502
|
+
}
|
|
1503
|
+
},
|
|
1504
|
+
"lively": {
|
|
1505
|
+
"label": "Lively",
|
|
1506
|
+
"he": "תוססת",
|
|
1507
|
+
"hint": "Bigger, longer entrances; side-by-side rows slide in from their side; the hero's words fade in.",
|
|
1508
|
+
"parts": {
|
|
1509
|
+
"heroText": {
|
|
1510
|
+
"type": "fadeIn",
|
|
1511
|
+
"duration": 400
|
|
1512
|
+
},
|
|
1513
|
+
"heading": {
|
|
1514
|
+
"type": "moveUp",
|
|
1515
|
+
"distance": 24,
|
|
1516
|
+
"duration": 600
|
|
1517
|
+
},
|
|
1518
|
+
"items": {
|
|
1519
|
+
"type": "moveUp",
|
|
1520
|
+
"distance": 24,
|
|
1521
|
+
"duration": 600,
|
|
1522
|
+
"stagger": 100,
|
|
1523
|
+
"cap": 8
|
|
1524
|
+
},
|
|
1525
|
+
"media": {
|
|
1526
|
+
"type": "fadeIn",
|
|
1527
|
+
"duration": 700
|
|
1528
|
+
},
|
|
1529
|
+
"rowMedia": {
|
|
1530
|
+
"type": "moveLeft",
|
|
1531
|
+
"mirror": "moveRight",
|
|
1532
|
+
"distance": 24,
|
|
1533
|
+
"duration": 600
|
|
1534
|
+
}
|
|
1535
|
+
}
|
|
1536
|
+
}
|
|
1537
|
+
},
|
|
1538
|
+
"animationFamilies": {
|
|
1539
|
+
"nav": [],
|
|
1540
|
+
"footer": [],
|
|
1541
|
+
"hero": [
|
|
1542
|
+
"heroText"
|
|
1543
|
+
],
|
|
1544
|
+
"header": [
|
|
1545
|
+
"heading"
|
|
1546
|
+
],
|
|
1547
|
+
"detail": [
|
|
1548
|
+
"heading",
|
|
1549
|
+
"media"
|
|
1550
|
+
],
|
|
1551
|
+
"proof": [
|
|
1552
|
+
"content",
|
|
1553
|
+
"heading",
|
|
1554
|
+
"items"
|
|
1555
|
+
],
|
|
1556
|
+
"feature": [
|
|
1557
|
+
"content",
|
|
1558
|
+
"heading",
|
|
1559
|
+
"items",
|
|
1560
|
+
"media",
|
|
1561
|
+
"rowMedia"
|
|
1562
|
+
],
|
|
1563
|
+
"collection": [
|
|
1564
|
+
"content",
|
|
1565
|
+
"heading",
|
|
1566
|
+
"items"
|
|
1567
|
+
],
|
|
1568
|
+
"story": [
|
|
1569
|
+
"content",
|
|
1570
|
+
"heading",
|
|
1571
|
+
"media"
|
|
1572
|
+
],
|
|
1573
|
+
"cta": [
|
|
1574
|
+
"content",
|
|
1575
|
+
"heading"
|
|
1576
|
+
],
|
|
1577
|
+
"contact": [
|
|
1578
|
+
"content",
|
|
1579
|
+
"heading"
|
|
1580
|
+
],
|
|
1581
|
+
"faq": [
|
|
1582
|
+
"content",
|
|
1583
|
+
"heading"
|
|
1584
|
+
],
|
|
1585
|
+
"pricing": [
|
|
1586
|
+
"content",
|
|
1587
|
+
"heading",
|
|
1588
|
+
"items"
|
|
1589
|
+
]
|
|
1590
|
+
},
|
|
1591
|
+
"betweens": {
|
|
1592
|
+
"none": {
|
|
1593
|
+
"label": "None",
|
|
1594
|
+
"he": "ללא",
|
|
1595
|
+
"hint": "The next page simply appears.",
|
|
1596
|
+
"transition": "none"
|
|
1597
|
+
},
|
|
1598
|
+
"fade": {
|
|
1599
|
+
"label": "Fade",
|
|
1600
|
+
"he": "דהייה",
|
|
1601
|
+
"hint": "The page fades into the next.",
|
|
1602
|
+
"transition": "fade",
|
|
1603
|
+
"feel": "snappy"
|
|
1604
|
+
},
|
|
1605
|
+
"slide": {
|
|
1606
|
+
"label": "Slide",
|
|
1607
|
+
"he": "החלקה",
|
|
1608
|
+
"hint": "The next page pushes this one aside (from the left on a Hebrew site). On phones: Fade.",
|
|
1609
|
+
"transition": "move-left",
|
|
1610
|
+
"rtl": "move-right",
|
|
1611
|
+
"feel": "smooth",
|
|
1612
|
+
"phone": "fade"
|
|
1613
|
+
},
|
|
1614
|
+
"cinematic": {
|
|
1615
|
+
"label": "Cinematic",
|
|
1616
|
+
"he": "קולנועית",
|
|
1617
|
+
"hint": "This page sinks back while the next rises over it. On phones: Fade.",
|
|
1618
|
+
"transition": "parallax-up",
|
|
1619
|
+
"feel": "cinematic",
|
|
1620
|
+
"phone": "fade"
|
|
1621
|
+
}
|
|
1622
|
+
},
|
|
1623
|
+
"motionChoices": {
|
|
1624
|
+
"pre": {
|
|
1625
|
+
"scroll": "smooth",
|
|
1626
|
+
"animate": "still",
|
|
1627
|
+
"between": "cinematic"
|
|
1628
|
+
},
|
|
1629
|
+
"reduced": {
|
|
1630
|
+
"scroll": "normal",
|
|
1631
|
+
"animate": "still",
|
|
1632
|
+
"between": "none"
|
|
1633
|
+
}
|
|
1432
1634
|
}
|
|
1433
1635
|
} as const;
|
|
1434
1636
|
|
|
@@ -3,7 +3,7 @@ import { flavorColours, FlavorColours, preTintAccentGrounds } from './brand-neut
|
|
|
3
3
|
import { fontStackWithout, formatFontFamily } from './fonts';
|
|
4
4
|
import { SPEC_AXES } from './flavor-spec.generated';
|
|
5
5
|
import {
|
|
6
|
-
DesignChoices, DesignTokenRow, FlavorPackV2, FlavorSpecToken, flavorSourceStamp, USER_TOKEN_SOURCE,
|
|
6
|
+
DesignChoices, DesignTokenRow, FlavorPackV2, FlavorSpecToken, flavorSourceStamp, PRE_MOTION, USER_TOKEN_SOURCE,
|
|
7
7
|
} from './design-token.model';
|
|
8
8
|
|
|
9
9
|
/**
|
|
@@ -37,6 +37,7 @@ export function defaultDesignChoices(pack: FlavorPackV2): DesignChoices {
|
|
|
37
37
|
seed: pack.seed,
|
|
38
38
|
pairId: pack.pairs[0]?.id ?? '',
|
|
39
39
|
...pack.defaults,
|
|
40
|
+
...PRE_MOTION,
|
|
40
41
|
};
|
|
41
42
|
}
|
|
42
43
|
|
|
@@ -37,7 +37,10 @@ export const SPEC_SITE_PLAN_SHAPE = {
|
|
|
37
37
|
"pillButtons": "boolean",
|
|
38
38
|
"mode": "'light' | 'dark' | 'auto'",
|
|
39
39
|
"tint?": "string — axes.tints (DS9 neutral tint)",
|
|
40
|
-
"fonts?": "object — uploaded font families per role (DS5)"
|
|
40
|
+
"fonts?": "object — uploaded font families per role (DS5)",
|
|
41
|
+
"scroll?": "string — axes.scrolls: how the site scrolls (rev 3.1; absent = axes.motionChoices.pre)",
|
|
42
|
+
"animate?": "string — axes.animations: how much the sections move in as they scroll into view",
|
|
43
|
+
"between?": "string — axes.betweens: what plays between pages"
|
|
41
44
|
},
|
|
42
45
|
"contentType": {
|
|
43
46
|
"name": "string — unique",
|
|
@@ -200,6 +200,9 @@ function validateDesign(c: Collector, design: unknown): void {
|
|
|
200
200
|
axis('density', SPEC_AXES.densities);
|
|
201
201
|
axis('motion', SPEC_AXES.motions);
|
|
202
202
|
axis('tint', SPEC_AXES.tints);
|
|
203
|
+
axis('scroll', SPEC_AXES.scrolls);
|
|
204
|
+
axis('animate', SPEC_AXES.animations);
|
|
205
|
+
axis('between', SPEC_AXES.betweens);
|
|
203
206
|
if (design['mode'] !== undefined && !(SPEC_AXES.modes as ReadonlyArray<unknown>).includes(design['mode'])) bad('mode', `must be one of ${SPEC_AXES.modes.join(', ')}`);
|
|
204
207
|
if (design['pillButtons'] !== undefined && typeof design['pillButtons'] !== 'boolean') bad('pillButtons', 'must be a boolean');
|
|
205
208
|
if (design['fonts'] !== undefined && !isObject(design['fonts'])) bad('fonts', 'must be an object');
|