@vectoriox/iox-ui 5.55.0 → 5.56.1
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/fesm2022/vectoriox-iox-ui-generation-core.mjs +431 -12
- package/fesm2022/vectoriox-iox-ui-generation-core.mjs.map +1 -1
- package/fesm2022/vectoriox-iox-ui-harness-core.mjs +28 -1
- package/fesm2022/vectoriox-iox-ui-harness-core.mjs.map +1 -1
- package/generation-core/index.d.ts +223 -4
- package/harness-core/index.d.ts +20 -2
- package/package.json +1 -1
- package/src/generation-core/audit-site.ts +386 -0
- package/src/generation-core/public-api.ts +2 -0
- package/src/generation-core/site-build-run.ts +7 -0
- package/src/generation-core/stock-photos.ts +137 -0
- package/src/harness-core/public-api.ts +1 -0
- package/src/harness-core/starting-design.ts +44 -0
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { NEW_NODE_STYLE_DEFAULTS, defaultElementStyleFor, elementStyleById, ownedTraitsOf, applyElementStyle, flavorPackById, parseHexColor, SPEC_AXES, LinkType, COLOR_SCHEMES, setColorScheme, resolveDesignChoices } from '@vectoriox/iox-ui/design-core';
|
|
2
|
-
import { formPresetById } from '@vectoriox/iox-ui/forms-core';
|
|
1
|
+
import { NEW_NODE_STYLE_DEFAULTS, defaultElementStyleFor, elementStyleById, ownedTraitsOf, applyElementStyle, flavorPackById, parseHexColor, SPEC_AXES, LinkType, COLOR_SCHEMES, setColorScheme, resolveDesignChoices, auditDesignContrast } from '@vectoriox/iox-ui/design-core';
|
|
2
|
+
import { formPresetById, ControlType, FORM_NODE_TYPE, collectFormSpec, FIELD_NODE_TYPE } from '@vectoriox/iox-ui/forms-core';
|
|
3
3
|
import { segmentedOptions, ITEM_OPEN_STATE, CardRole, CardLayout, CARD_LAYOUTS, CARD_PARTS, BADGE_TONES, buildCardRecipe, findByRole, buildSegmentedRecipe, AccordionRole, buildAccordionRecipe, ACCORDION_WORDS, accordionItems, accordionQuestionOf, accordionAnswerOf, ACCORDION_BIND_PROP, pickAccordionAutoBinds, ACCORDION_CONTENT_LIMIT, buildTabsRecipe, TABS_WORDS, tabsTriggers, tabLabelNodeOf, TABS_LABEL_BIND_PROP, tabsPanels, tabPanelTextOf, TABS_TEXT_BIND_PROP, tabPanelImageOf, pickTabsAutoBinds, tabsListOf, tabsPanelsOf, TABS_CONTENT_LIMIT, TABS_IMAGE_BIND_PROP, buildCarouselRecipe, SLIDE_TYPE, buildLightboxRecipe, LIGHTBOX_LABEL, SLIDE_TO_ROW } from '@vectoriox/iox-ui/composite-core';
|
|
4
|
+
import { ELEMENT_ACTION_DESCRIPTORS, resolveActionAvailability } from '@vectoriox/iox-ui/actions-core';
|
|
4
5
|
|
|
5
6
|
// GENERATED from iox-ai-guidance flavor-spec.v1.json — do not edit; re-run scripts/gen-flavor-spec.mjs
|
|
6
7
|
// (npm run gen:flavor-spec). The JSON is itself generated by iox-ai-guidance
|
|
@@ -8927,7 +8928,7 @@ function stableHash(text) {
|
|
|
8927
8928
|
return h.toString(36).padStart(7, '0').slice(-6);
|
|
8928
8929
|
}
|
|
8929
8930
|
const create = (id, type, props = {}, elementStyle) => createSerializedNode(id, type, props, elementStyle, COMPOSED);
|
|
8930
|
-
function nonEmpty(v) {
|
|
8931
|
+
function nonEmpty$1(v) {
|
|
8931
8932
|
return typeof v === 'string' && v.trim() !== '';
|
|
8932
8933
|
}
|
|
8933
8934
|
/** A pattern's own words with the compose-time variables filled: `{year}`, `{business.name}`. */
|
|
@@ -8939,16 +8940,16 @@ function fillVariables(text, ctx) {
|
|
|
8939
8940
|
function chooseText(pn, ctx) {
|
|
8940
8941
|
const fact = pn.ph && FACT_KEYS.includes(pn.ph) ? pn.ph : null;
|
|
8941
8942
|
const slotValue = pn.slot ? ctx.section?.slots?.[pn.slot] : undefined;
|
|
8942
|
-
if (nonEmpty(slotValue))
|
|
8943
|
+
if (nonEmpty$1(slotValue))
|
|
8943
8944
|
return { value: slotValue };
|
|
8944
8945
|
if (pn.fromBusiness) {
|
|
8945
8946
|
const v = ctx.plan.business[pn.fromBusiness];
|
|
8946
|
-
if (nonEmpty(v))
|
|
8947
|
+
if (nonEmpty$1(v))
|
|
8947
8948
|
return { value: v };
|
|
8948
8949
|
}
|
|
8949
8950
|
if (fact) {
|
|
8950
8951
|
const given = ctx.plan.business.facts?.[fact];
|
|
8951
|
-
return nonEmpty(given) ? { value: given } : { value: SITE_FACT_LABELS[fact], placeholder: { kind: PlaceholderKind.Fact, fact } };
|
|
8952
|
+
return nonEmpty$1(given) ? { value: given } : { value: SITE_FACT_LABELS[fact], placeholder: { kind: PlaceholderKind.Fact, fact } };
|
|
8952
8953
|
}
|
|
8953
8954
|
const own = pn.text === undefined ? undefined : fillVariables(pn.text, ctx);
|
|
8954
8955
|
if (pn.ph === PatternPlaceholder.Copy)
|
|
@@ -9656,7 +9657,7 @@ function composeSite(plan, context) {
|
|
|
9656
9657
|
const issues = [];
|
|
9657
9658
|
const routes = new Set(plan.pages.map(p => p.route));
|
|
9658
9659
|
const relatives = new Map(plan.dataSources.map(d => [d.alias, d.type === PlanDataSourceType.Relative ? { type: d.type, of: d.of, op: d.op } : { type: d.type }]));
|
|
9659
|
-
const email = nonEmpty(plan.business.facts?.email) ? plan.business.facts.email.trim() : null;
|
|
9660
|
+
const email = nonEmpty$1(plan.business.facts?.email) ? plan.business.facts.email.trim() : null;
|
|
9660
9661
|
const base = { plan, placeholders, issues, routes, year: context.year, email, navPage: null };
|
|
9661
9662
|
const pages = plan.pages.map(page => {
|
|
9662
9663
|
const nextAlias = page.routeSource ? nextSourceOf(relatives, page.routeSource) : null;
|
|
@@ -9730,14 +9731,14 @@ function navPagePlans(pages) {
|
|
|
9730
9731
|
* no /contact page: an email to the business, else removed), and the pattern's phone shape. Pure.
|
|
9731
9732
|
*/
|
|
9732
9733
|
function composeNavHeader(input, options) {
|
|
9733
|
-
if (!nonEmpty(options?.id))
|
|
9734
|
+
if (!nonEmpty$1(options?.id))
|
|
9734
9735
|
throw new ComposeError('composeNavHeader needs the header id');
|
|
9735
9736
|
const pattern = patternById(SITE_HEADER_PATTERN);
|
|
9736
9737
|
const all = navPagePlans(input.pages);
|
|
9737
9738
|
const navRoutes = new Set(siteNavPages(input.pages).map(p => p.route));
|
|
9738
9739
|
const pages = all.map(p => ({ ...p, inNav: navRoutes.has(p.route) }));
|
|
9739
9740
|
const plan = { business: input.business, pages, dataSources: [], contentTypes: [] };
|
|
9740
|
-
const email = nonEmpty(input.business.facts?.email) ? input.business.facts.email.trim() : null;
|
|
9741
|
+
const email = nonEmpty$1(input.business.facts?.email) ? input.business.facts.email.trim() : null;
|
|
9741
9742
|
const issues = [];
|
|
9742
9743
|
const ctx = {
|
|
9743
9744
|
owner: GlobalSlot.Header, page: null, section: null, plan, year: 0, email, navPage: null, nextAlias: null,
|
|
@@ -9761,7 +9762,7 @@ const PRICING_PATTERN = 'pricing.tiers';
|
|
|
9761
9762
|
* words, unlinked, for the author to link. Pure.
|
|
9762
9763
|
*/
|
|
9763
9764
|
function composeSection(patternId, input, options) {
|
|
9764
|
-
if (!nonEmpty(options?.id))
|
|
9765
|
+
if (!nonEmpty$1(options?.id))
|
|
9765
9766
|
throw new ComposeError('composeSection needs the section id');
|
|
9766
9767
|
const pattern = patternById(patternId);
|
|
9767
9768
|
if (!pattern)
|
|
@@ -9771,7 +9772,7 @@ function composeSection(patternId, input, options) {
|
|
|
9771
9772
|
const business = input.business ?? { name: '' };
|
|
9772
9773
|
const pages = navPagePlans(input.pages ?? []);
|
|
9773
9774
|
const plan = { business, pages, dataSources: [], contentTypes: [] };
|
|
9774
|
-
const email = nonEmpty(business.facts?.email) ? business.facts.email.trim() : null;
|
|
9775
|
+
const email = nonEmpty$1(business.facts?.email) ? business.facts.email.trim() : null;
|
|
9775
9776
|
const placeholders = [];
|
|
9776
9777
|
const issues = [];
|
|
9777
9778
|
const ctx = {
|
|
@@ -9935,6 +9936,8 @@ var BuildStep;
|
|
|
9935
9936
|
BuildStep["Preflight"] = "preflight";
|
|
9936
9937
|
BuildStep["ContentTypes"] = "content-types";
|
|
9937
9938
|
BuildStep["SampleImages"] = "sample-images";
|
|
9939
|
+
/** I2: the curated stock photos the plan's empty picture slots take, copied into the studio (never hot-linked). */
|
|
9940
|
+
BuildStep["StockPhotos"] = "stock-photos";
|
|
9938
9941
|
BuildStep["Items"] = "items";
|
|
9939
9942
|
BuildStep["DataSources"] = "data-sources";
|
|
9940
9943
|
BuildStep["Pages"] = "pages";
|
|
@@ -9956,6 +9959,8 @@ var CreatedKind;
|
|
|
9956
9959
|
/** Fields the build added to a content type it found (types are shared by every organization of a studio). */
|
|
9957
9960
|
CreatedKind["ContentTypeFields"] = "content-type-fields";
|
|
9958
9961
|
CreatedKind["SampleImage"] = "sample-image";
|
|
9962
|
+
/** A stock photo copied into the studio's storage (`media/stock/…`), with its assets row. */
|
|
9963
|
+
CreatedKind["StockPhoto"] = "stock-photo";
|
|
9959
9964
|
CreatedKind["Item"] = "item";
|
|
9960
9965
|
CreatedKind["DataSource"] = "data-source";
|
|
9961
9966
|
CreatedKind["Page"] = "page";
|
|
@@ -9977,6 +9982,8 @@ var BuildNoticeCode;
|
|
|
9977
9982
|
BuildNoticeCode["NoStorage"] = "no-storage";
|
|
9978
9983
|
/** A content type the build reuses is not public in this studio: the site will not show its items. */
|
|
9979
9984
|
BuildNoticeCode["ContentTypeNotPublic"] = "content-type-not-public";
|
|
9985
|
+
/** The stock library could not be read: the picture slots keep the empty box, and the run says so. */
|
|
9986
|
+
BuildNoticeCode["StockUnavailable"] = "stock-unavailable";
|
|
9980
9987
|
})(BuildNoticeCode || (BuildNoticeCode = {}));
|
|
9981
9988
|
var PreflightRefusalCode;
|
|
9982
9989
|
(function (PreflightRefusalCode) {
|
|
@@ -10008,6 +10015,7 @@ const buildKeys = {
|
|
|
10008
10015
|
contentTypeFields: (name) => `schema-fields:${name}`,
|
|
10009
10016
|
item: (contentType, n) => `item:${contentType}:${n}`,
|
|
10010
10017
|
sampleImage: (n) => `sample-image:${n}`,
|
|
10018
|
+
stockPhoto: (libraryKey) => `stock-photo:${libraryKey}`,
|
|
10011
10019
|
dataSource: (alias) => `data-source:${alias}`,
|
|
10012
10020
|
page: (key) => `page:${key}`,
|
|
10013
10021
|
global: (nodeId) => `global:${nodeId}`,
|
|
@@ -10927,6 +10935,417 @@ function planWordIssues(plan, ctx) {
|
|
|
10927
10935
|
return issues;
|
|
10928
10936
|
}
|
|
10929
10937
|
|
|
10938
|
+
/**
|
|
10939
|
+
* THE Publishable gate (AI plan §3e, M1-7): ONE pure function over a snapshot of a site — its pages, globals, the
|
|
10940
|
+
* connectors' health, the look's token rows, what a build left to fill — run by the Publish dialog, the builder's
|
|
10941
|
+
* Needs attention and the server on publish (iox-cms refuses with the same findings). Works on any site, generated
|
|
10942
|
+
* or hand-built. Severity is decision D8: an unfilled fact, a policy placeholder or an action that points at nothing
|
|
10943
|
+
* BLOCKS; samples, copy placeholders and stock photos ASK ("Publish anyway"); the rest WARN. Design advice
|
|
10944
|
+
* (harness-core `lintDesign`) is not one of the eight — the caller adds it, and it never blocks.
|
|
10945
|
+
*/
|
|
10946
|
+
var SiteCheckId;
|
|
10947
|
+
(function (SiteCheckId) {
|
|
10948
|
+
SiteCheckId["Navigation"] = "navigation";
|
|
10949
|
+
SiteCheckId["Forms"] = "forms";
|
|
10950
|
+
SiteCheckId["Consent"] = "consent";
|
|
10951
|
+
SiteCheckId["Seo"] = "seo";
|
|
10952
|
+
SiteCheckId["Facts"] = "facts";
|
|
10953
|
+
SiteCheckId["Accessibility"] = "accessibility";
|
|
10954
|
+
SiteCheckId["Tokens"] = "tokens";
|
|
10955
|
+
SiteCheckId["Actions"] = "actions";
|
|
10956
|
+
})(SiteCheckId || (SiteCheckId = {}));
|
|
10957
|
+
/** The eight, in §3e's order. */
|
|
10958
|
+
const SITE_CHECKS = Object.values(SiteCheckId);
|
|
10959
|
+
var CheckSeverity;
|
|
10960
|
+
(function (CheckSeverity) {
|
|
10961
|
+
CheckSeverity["Block"] = "block";
|
|
10962
|
+
CheckSeverity["Ask"] = "ask";
|
|
10963
|
+
CheckSeverity["Warn"] = "warn";
|
|
10964
|
+
})(CheckSeverity || (CheckSeverity = {}));
|
|
10965
|
+
var SiteFindingCode;
|
|
10966
|
+
(function (SiteFindingCode) {
|
|
10967
|
+
SiteFindingCode["NoHeader"] = "no-header";
|
|
10968
|
+
SiteFindingCode["NoPhoneMenu"] = "no-phone-menu";
|
|
10969
|
+
SiteFindingCode["FormWithoutId"] = "form-without-id";
|
|
10970
|
+
SiteFindingCode["EmailNeedsMailer"] = "email-needs-mailer";
|
|
10971
|
+
SiteFindingCode["TrackerWithoutBanner"] = "tracker-without-banner";
|
|
10972
|
+
SiteFindingCode["NoTitle"] = "no-title";
|
|
10973
|
+
SiteFindingCode["NoDescription"] = "no-description";
|
|
10974
|
+
SiteFindingCode["UnfilledFact"] = "unfilled-fact";
|
|
10975
|
+
SiteFindingCode["CopyPlaceholder"] = "copy-placeholder";
|
|
10976
|
+
SiteFindingCode["SampleItems"] = "sample-items";
|
|
10977
|
+
SiteFindingCode["StockPhoto"] = "stock-photo";
|
|
10978
|
+
SiteFindingCode["NoPrivacyPage"] = "no-privacy-page";
|
|
10979
|
+
SiteFindingCode["PrivacyPagePlaceholder"] = "privacy-page-placeholder";
|
|
10980
|
+
SiteFindingCode["LowContrast"] = "low-contrast";
|
|
10981
|
+
SiteFindingCode["HeadingOrder"] = "heading-order";
|
|
10982
|
+
SiteFindingCode["ImageWithoutAlt"] = "image-without-alt";
|
|
10983
|
+
SiteFindingCode["LiteralColour"] = "literal-colour";
|
|
10984
|
+
SiteFindingCode["DeadLink"] = "dead-link";
|
|
10985
|
+
SiteFindingCode["DeadDialogTarget"] = "dead-dialog-target";
|
|
10986
|
+
SiteFindingCode["ActionNeedsConnector"] = "action-needs-connector";
|
|
10987
|
+
})(SiteFindingCode || (SiteFindingCode = {}));
|
|
10988
|
+
/** Each finding's severity — one table (D8), never decided at a call site. */
|
|
10989
|
+
const FINDING_SEVERITY = {
|
|
10990
|
+
[SiteFindingCode.NoHeader]: CheckSeverity.Warn,
|
|
10991
|
+
[SiteFindingCode.NoPhoneMenu]: CheckSeverity.Warn,
|
|
10992
|
+
[SiteFindingCode.FormWithoutId]: CheckSeverity.Block,
|
|
10993
|
+
[SiteFindingCode.EmailNeedsMailer]: CheckSeverity.Warn,
|
|
10994
|
+
[SiteFindingCode.TrackerWithoutBanner]: CheckSeverity.Warn,
|
|
10995
|
+
[SiteFindingCode.NoTitle]: CheckSeverity.Warn,
|
|
10996
|
+
[SiteFindingCode.NoDescription]: CheckSeverity.Warn,
|
|
10997
|
+
[SiteFindingCode.UnfilledFact]: CheckSeverity.Block,
|
|
10998
|
+
[SiteFindingCode.CopyPlaceholder]: CheckSeverity.Ask,
|
|
10999
|
+
[SiteFindingCode.SampleItems]: CheckSeverity.Ask,
|
|
11000
|
+
[SiteFindingCode.StockPhoto]: CheckSeverity.Ask,
|
|
11001
|
+
[SiteFindingCode.NoPrivacyPage]: CheckSeverity.Ask,
|
|
11002
|
+
[SiteFindingCode.PrivacyPagePlaceholder]: CheckSeverity.Block,
|
|
11003
|
+
[SiteFindingCode.LowContrast]: CheckSeverity.Warn,
|
|
11004
|
+
[SiteFindingCode.HeadingOrder]: CheckSeverity.Warn,
|
|
11005
|
+
[SiteFindingCode.ImageWithoutAlt]: CheckSeverity.Warn,
|
|
11006
|
+
[SiteFindingCode.LiteralColour]: CheckSeverity.Warn,
|
|
11007
|
+
[SiteFindingCode.DeadLink]: CheckSeverity.Block,
|
|
11008
|
+
[SiteFindingCode.DeadDialogTarget]: CheckSeverity.Block,
|
|
11009
|
+
[SiteFindingCode.ActionNeedsConnector]: CheckSeverity.Block,
|
|
11010
|
+
};
|
|
11011
|
+
const CHECK_OF = {
|
|
11012
|
+
[SiteFindingCode.NoHeader]: SiteCheckId.Navigation,
|
|
11013
|
+
[SiteFindingCode.NoPhoneMenu]: SiteCheckId.Navigation,
|
|
11014
|
+
[SiteFindingCode.FormWithoutId]: SiteCheckId.Forms,
|
|
11015
|
+
[SiteFindingCode.EmailNeedsMailer]: SiteCheckId.Forms,
|
|
11016
|
+
[SiteFindingCode.TrackerWithoutBanner]: SiteCheckId.Consent,
|
|
11017
|
+
[SiteFindingCode.NoTitle]: SiteCheckId.Seo,
|
|
11018
|
+
[SiteFindingCode.NoDescription]: SiteCheckId.Seo,
|
|
11019
|
+
[SiteFindingCode.UnfilledFact]: SiteCheckId.Facts,
|
|
11020
|
+
[SiteFindingCode.CopyPlaceholder]: SiteCheckId.Facts,
|
|
11021
|
+
[SiteFindingCode.SampleItems]: SiteCheckId.Facts,
|
|
11022
|
+
[SiteFindingCode.StockPhoto]: SiteCheckId.Facts,
|
|
11023
|
+
[SiteFindingCode.NoPrivacyPage]: SiteCheckId.Facts,
|
|
11024
|
+
[SiteFindingCode.PrivacyPagePlaceholder]: SiteCheckId.Facts,
|
|
11025
|
+
[SiteFindingCode.LowContrast]: SiteCheckId.Accessibility,
|
|
11026
|
+
[SiteFindingCode.HeadingOrder]: SiteCheckId.Accessibility,
|
|
11027
|
+
[SiteFindingCode.ImageWithoutAlt]: SiteCheckId.Accessibility,
|
|
11028
|
+
[SiteFindingCode.LiteralColour]: SiteCheckId.Tokens,
|
|
11029
|
+
[SiteFindingCode.DeadLink]: SiteCheckId.Actions,
|
|
11030
|
+
[SiteFindingCode.DeadDialogTarget]: SiteCheckId.Actions,
|
|
11031
|
+
[SiteFindingCode.ActionNeedsConnector]: SiteCheckId.Actions,
|
|
11032
|
+
};
|
|
11033
|
+
const LINKING_TYPES = new Set(['Link', 'Heading', 'Button', 'ButtonBlock', 'LinkedContainer', 'Image']);
|
|
11034
|
+
const PAGE_LINK = 'page';
|
|
11035
|
+
const PERSONAL_CONTROLS = new Set([ControlType.Email, ControlType.Tel, ControlType.Text, ControlType.Textarea]);
|
|
11036
|
+
const PRIVACY_PAGE = /privacy|פרטיות|מדיניות/i;
|
|
11037
|
+
const MAILER = 'mailer';
|
|
11038
|
+
const EMAIL_DELIVERY = 'email';
|
|
11039
|
+
const LITERAL_COLOUR = /#[0-9a-f]{3,8}\b|rgba?\(|hsla?\(/i;
|
|
11040
|
+
const COLOUR_TRAITS = /color|Color|^background$|boxShadow|textShadow/;
|
|
11041
|
+
const HEADING_LEVEL = /^h([1-6])$/;
|
|
11042
|
+
const DIALOG_TYPE = 'Dialog';
|
|
11043
|
+
const SELF = 'self';
|
|
11044
|
+
/** A route pattern (`/work/:slug`) matches a concrete path (`/work/blue-bowl`). */
|
|
11045
|
+
function routeMatches(pattern, path) {
|
|
11046
|
+
const a = pattern.split('/').filter(Boolean);
|
|
11047
|
+
const b = String(path ?? '').split(/[?#]/)[0].split('/').filter(Boolean);
|
|
11048
|
+
return a.length === b.length && a.every((seg, i) => seg.startsWith(':') || seg === b[i]);
|
|
11049
|
+
}
|
|
11050
|
+
const nonEmpty = (v) => typeof v === 'string' && v.trim() !== '';
|
|
11051
|
+
/** A stored SEO field (a string, or `{ override, binding, auto }`) has a value, or may be derived. */
|
|
11052
|
+
function seoField(raw, derivable) {
|
|
11053
|
+
if (nonEmpty(raw))
|
|
11054
|
+
return true;
|
|
11055
|
+
if (raw && typeof raw === 'object') {
|
|
11056
|
+
const v = raw;
|
|
11057
|
+
if (nonEmpty(v.override) || v.binding)
|
|
11058
|
+
return true;
|
|
11059
|
+
if (v.auto === false)
|
|
11060
|
+
return false;
|
|
11061
|
+
}
|
|
11062
|
+
return derivable;
|
|
11063
|
+
}
|
|
11064
|
+
function hasContent(layout, type) {
|
|
11065
|
+
let found = false;
|
|
11066
|
+
walkSerialized(layout, n => {
|
|
11067
|
+
if (n.type !== type || found)
|
|
11068
|
+
return;
|
|
11069
|
+
found = nonEmpty(n.props['content']) || n.bindings.some(b => b.prop === 'content');
|
|
11070
|
+
});
|
|
11071
|
+
return found;
|
|
11072
|
+
}
|
|
11073
|
+
function add(ctx, code, message, where = {}) {
|
|
11074
|
+
ctx.out.push({ check: CHECK_OF[code], severity: FINDING_SEVERITY[code], code, message, ...where });
|
|
11075
|
+
}
|
|
11076
|
+
/** Every node of a page or a global, with where it lives. */
|
|
11077
|
+
function eachNode(snapshot, pages, visit) {
|
|
11078
|
+
for (const page of pages)
|
|
11079
|
+
walkSerialized(page.layout, n => visit(n, { pageId: page.id }));
|
|
11080
|
+
for (const global of snapshot.globals) {
|
|
11081
|
+
const owner = global.globalPosition === PatternGlobalPosition.Before ? 'header' : 'footer';
|
|
11082
|
+
walkSerialized([global], n => visit(n, { owner }));
|
|
11083
|
+
}
|
|
11084
|
+
}
|
|
11085
|
+
function checkNavigation(ctx, snapshot) {
|
|
11086
|
+
const header = snapshot.globals.find(g => g.globalPosition === PatternGlobalPosition.Before);
|
|
11087
|
+
if (!header)
|
|
11088
|
+
return add(ctx, SiteFindingCode.NoHeader, 'The site has no header, so visitors have no menu to move around with.');
|
|
11089
|
+
if (!navShapeOf(snapshot.globals))
|
|
11090
|
+
add(ctx, SiteFindingCode.NoPhoneMenu, 'The header has no phone menu — on a phone its links are hard to reach.', { owner: 'header', nodeId: header.id });
|
|
11091
|
+
}
|
|
11092
|
+
function checkForms(ctx, snapshot, pages) {
|
|
11093
|
+
let personal = false;
|
|
11094
|
+
eachNode(snapshot, pages, (n, where) => {
|
|
11095
|
+
if (n.type !== FORM_NODE_TYPE)
|
|
11096
|
+
return;
|
|
11097
|
+
const spec = collectFormSpec(n);
|
|
11098
|
+
if (!spec || !nonEmpty(spec.formId))
|
|
11099
|
+
add(ctx, SiteFindingCode.FormWithoutId, 'A form has no id, so what visitors send is never stored.', { ...where, nodeId: n.id });
|
|
11100
|
+
if (spec?.actions.some(a => a.type === EMAIL_DELIVERY) && snapshot.connectors[MAILER] !== true) {
|
|
11101
|
+
add(ctx, SiteFindingCode.EmailNeedsMailer, 'A form emails what visitors send, but Email is not connected — it is stored and never sent.', { ...where, nodeId: n.id });
|
|
11102
|
+
}
|
|
11103
|
+
walkSerialized(n.children ?? [], f => {
|
|
11104
|
+
if (f.type === FIELD_NODE_TYPE && PERSONAL_CONTROLS.has(String(f.props['control'] ?? ControlType.Text)))
|
|
11105
|
+
personal = true;
|
|
11106
|
+
});
|
|
11107
|
+
});
|
|
11108
|
+
return personal;
|
|
11109
|
+
}
|
|
11110
|
+
function checkConsent(ctx, snapshot) {
|
|
11111
|
+
if (!snapshot.trackers?.length)
|
|
11112
|
+
return;
|
|
11113
|
+
let banner = false;
|
|
11114
|
+
for (const g of snapshot.globals)
|
|
11115
|
+
walkSerialized([g], n => { if (n.type === DIALOG_TYPE && n.props['consentRole'] === true)
|
|
11116
|
+
banner = true; });
|
|
11117
|
+
if (!banner)
|
|
11118
|
+
add(ctx, SiteFindingCode.TrackerWithoutBanner, `${snapshot.trackers.join(', ')} is connected, but the site has no cookie banner — it stays off for every visitor.`);
|
|
11119
|
+
}
|
|
11120
|
+
function checkSeo(ctx, pages) {
|
|
11121
|
+
for (const page of pages) {
|
|
11122
|
+
const seo = (page.seo ?? {});
|
|
11123
|
+
if (!seoField(seo['title'], hasContent(page.layout, 'Heading')))
|
|
11124
|
+
add(ctx, SiteFindingCode.NoTitle, `"${page.name}" has no title for search results.`, { pageId: page.id });
|
|
11125
|
+
if (!seoField(seo['description'], hasContent(page.layout, 'Text')))
|
|
11126
|
+
add(ctx, SiteFindingCode.NoDescription, `"${page.name}" has no description for search results.`, { pageId: page.id });
|
|
11127
|
+
}
|
|
11128
|
+
}
|
|
11129
|
+
function checkFacts(ctx, snapshot, pages, personal) {
|
|
11130
|
+
const inScope = (p) => !p.pageId || pages.some(page => page.id === p.pageId);
|
|
11131
|
+
for (const p of (snapshot.placeholders ?? []).filter(p => !p.filled && inScope(p))) {
|
|
11132
|
+
const where = { pageId: p.pageId, nodeId: p.nodeId, ...(p.pageId ? {} : { owner: p.owner }) };
|
|
11133
|
+
if (blocksPublish(p.kind))
|
|
11134
|
+
add(ctx, SiteFindingCode.UnfilledFact, `"${p.text || p.fact || p.kind}" is still blank — fill it in before the site goes live.`, where);
|
|
11135
|
+
else if (p.kind === PlaceholderKind.Copy)
|
|
11136
|
+
add(ctx, SiteFindingCode.CopyPlaceholder, 'Some words are still the template\'s.', where);
|
|
11137
|
+
}
|
|
11138
|
+
for (const s of snapshot.samples ?? [])
|
|
11139
|
+
add(ctx, SiteFindingCode.SampleItems, `"${s.label ?? s.id}" is a sample — replace or remove it.`, { nodeId: s.id });
|
|
11140
|
+
for (const s of (snapshot.stock ?? []).filter(inScope))
|
|
11141
|
+
add(ctx, SiteFindingCode.StockPhoto, 'A stock photo stands in for one of yours.', { pageId: s.pageId, nodeId: s.nodeId, owner: s.owner });
|
|
11142
|
+
if (!personal)
|
|
11143
|
+
return;
|
|
11144
|
+
const privacy = snapshot.pages.find(p => PRIVACY_PAGE.test(p.route) || PRIVACY_PAGE.test(p.name));
|
|
11145
|
+
if (!privacy)
|
|
11146
|
+
return add(ctx, SiteFindingCode.NoPrivacyPage, 'A form asks for personal details, and the site has no privacy page saying what you do with them.');
|
|
11147
|
+
if ((snapshot.placeholders ?? []).some(p => p.pageId === privacy.id && !p.filled)) {
|
|
11148
|
+
add(ctx, SiteFindingCode.PrivacyPagePlaceholder, 'The privacy page still holds template words — only you can write it.', { pageId: privacy.id });
|
|
11149
|
+
}
|
|
11150
|
+
}
|
|
11151
|
+
function checkAccessibility(ctx, snapshot, pages) {
|
|
11152
|
+
for (const mode of snapshot.design?.modes ?? []) {
|
|
11153
|
+
const failing = auditDesignContrast(snapshot.design.rows, mode).filter(f => !f.pass);
|
|
11154
|
+
if (failing.length)
|
|
11155
|
+
add(ctx, SiteFindingCode.LowContrast, `${failing.length} text and background pair(s) are hard to read in ${mode} mode.`);
|
|
11156
|
+
}
|
|
11157
|
+
for (const page of pages) {
|
|
11158
|
+
let last = 0;
|
|
11159
|
+
let h1 = 0;
|
|
11160
|
+
walkSerialized(page.layout, n => {
|
|
11161
|
+
const level = n.type === 'Heading' ? HEADING_LEVEL.exec(String(n.props['level'] ?? ''))?.[1] : undefined;
|
|
11162
|
+
if (!level)
|
|
11163
|
+
return;
|
|
11164
|
+
const l = Number(level);
|
|
11165
|
+
if (l === 1)
|
|
11166
|
+
h1++;
|
|
11167
|
+
if (last && l > last + 1)
|
|
11168
|
+
add(ctx, SiteFindingCode.HeadingOrder, `A heading on "${page.name}" skips a level (h${last} → h${l}).`, { pageId: page.id, nodeId: n.id });
|
|
11169
|
+
last = l;
|
|
11170
|
+
});
|
|
11171
|
+
if (h1 > 1)
|
|
11172
|
+
add(ctx, SiteFindingCode.HeadingOrder, `"${page.name}" has ${h1} main headings (h1); one is clearer.`, { pageId: page.id });
|
|
11173
|
+
}
|
|
11174
|
+
eachNode(snapshot, pages, (n, where) => {
|
|
11175
|
+
if (n.type !== 'Image')
|
|
11176
|
+
return;
|
|
11177
|
+
const decorative = n.props['alt'] === '' && n.props['decorative'] === true;
|
|
11178
|
+
const bound = n.bindings.some(b => b.prop === 'alt');
|
|
11179
|
+
if (!decorative && !bound && !nonEmpty(n.props['alt']))
|
|
11180
|
+
add(ctx, SiteFindingCode.ImageWithoutAlt, 'A picture has no description for people who cannot see it.', { ...where, nodeId: n.id });
|
|
11181
|
+
});
|
|
11182
|
+
}
|
|
11183
|
+
function checkTokens(ctx, snapshot, pages) {
|
|
11184
|
+
eachNode(snapshot, pages, (n, where) => {
|
|
11185
|
+
if (!n.elementStyle)
|
|
11186
|
+
return;
|
|
11187
|
+
const maps = [n.styleProps, ...Object.values(n.stateStyles ?? {}), ...Object.values(n.responsive ?? {}).map(l => l?.styleProps)];
|
|
11188
|
+
const literal = maps.some(map => Object.entries(map ?? {}).some(([k, v]) => COLOUR_TRAITS.test(k) && LITERAL_COLOUR.test(String(v)) && !(k === 'borderColor' && n.styleProps['borderWidth'] === '0px')));
|
|
11189
|
+
if (literal)
|
|
11190
|
+
add(ctx, SiteFindingCode.LiteralColour, 'An element paints a fixed colour, so a new look will not reach it.', { ...where, nodeId: n.id });
|
|
11191
|
+
});
|
|
11192
|
+
}
|
|
11193
|
+
function checkActions(ctx, snapshot, pages) {
|
|
11194
|
+
const routeExists = (route) => typeof route === 'string' && ctx.routes.some(r => routeMatches(r, route));
|
|
11195
|
+
eachNode(snapshot, pages, (n, where) => {
|
|
11196
|
+
if (LINKING_TYPES.has(n.type) && n.props['linkType'] === PAGE_LINK && !routeExists(n.props['pageRoute'])) {
|
|
11197
|
+
add(ctx, SiteFindingCode.DeadLink, `"${String(n.props['label'] ?? n.props['content'] ?? n.label ?? n.type)}" links to ${String(n.props['pageRoute'] || 'no page')}, which is not a page of the site.`, { ...where, nodeId: n.id });
|
|
11198
|
+
}
|
|
11199
|
+
for (const ix of (n.interactions ?? [])) {
|
|
11200
|
+
for (const action of ix?.actions ?? []) {
|
|
11201
|
+
if (!action || action.disabled)
|
|
11202
|
+
continue;
|
|
11203
|
+
const descriptor = ELEMENT_ACTION_DESCRIPTORS.find(d => d.type === action.type);
|
|
11204
|
+
if (!descriptor)
|
|
11205
|
+
continue;
|
|
11206
|
+
const types = descriptor.target?.types;
|
|
11207
|
+
if (descriptor.target?.required && action.target !== SELF) {
|
|
11208
|
+
const targetType = action.target ? ctx.nodeIds.get(action.target) : undefined;
|
|
11209
|
+
if (!targetType || (types && !types.includes(targetType))) {
|
|
11210
|
+
add(ctx, SiteFindingCode.DeadDialogTarget, `"${n.label ?? n.type}" opens something that is no longer on the site.`, { ...where, nodeId: n.id });
|
|
11211
|
+
}
|
|
11212
|
+
}
|
|
11213
|
+
if (action.type === 'navigate' && action.params?.['navigateTo'] === PAGE_LINK && !routeExists(action.params?.['page'])) {
|
|
11214
|
+
add(ctx, SiteFindingCode.DeadLink, `"${n.label ?? n.type}" goes to a page the site does not have.`, { ...where, nodeId: n.id });
|
|
11215
|
+
}
|
|
11216
|
+
// A connector the snapshot does not say is usable is not: unknown is never "fine".
|
|
11217
|
+
const connectors = descriptor.connector ? { [descriptor.connector]: snapshot.connectors[descriptor.connector] === true } : {};
|
|
11218
|
+
const availability = resolveActionAvailability(descriptor, { connectors });
|
|
11219
|
+
if (availability.state === 'connector-missing') {
|
|
11220
|
+
add(ctx, SiteFindingCode.ActionNeedsConnector, `"${n.label ?? n.type}" needs ${availability.connector} connected.`, { ...where, nodeId: n.id });
|
|
11221
|
+
}
|
|
11222
|
+
}
|
|
11223
|
+
}
|
|
11224
|
+
});
|
|
11225
|
+
}
|
|
11226
|
+
/** Run the eight checks. `pageId` narrows the page checks to the page being published; site-wide ones always run. */
|
|
11227
|
+
function auditSite(snapshot, options = {}) {
|
|
11228
|
+
const pages = options.pageId ? snapshot.pages.filter(p => p.id === options.pageId) : snapshot.pages;
|
|
11229
|
+
const nodeIds = new Map();
|
|
11230
|
+
eachNode(snapshot, snapshot.pages, n => nodeIds.set(n.id, n.type));
|
|
11231
|
+
const ctx = { out: [], routes: snapshot.pages.map(p => p.route), nodeIds };
|
|
11232
|
+
checkNavigation(ctx, snapshot);
|
|
11233
|
+
const personal = checkForms(ctx, snapshot, pages);
|
|
11234
|
+
checkConsent(ctx, snapshot);
|
|
11235
|
+
checkSeo(ctx, pages);
|
|
11236
|
+
checkFacts(ctx, snapshot, pages, personal);
|
|
11237
|
+
checkAccessibility(ctx, snapshot, pages);
|
|
11238
|
+
checkTokens(ctx, snapshot, pages);
|
|
11239
|
+
checkActions(ctx, snapshot, pages);
|
|
11240
|
+
const checks = SITE_CHECKS.map(id => {
|
|
11241
|
+
const findings = ctx.out.filter(f => f.check === id);
|
|
11242
|
+
return { id, passed: !findings.some(f => f.severity !== CheckSeverity.Warn), findings };
|
|
11243
|
+
});
|
|
11244
|
+
return {
|
|
11245
|
+
checks,
|
|
11246
|
+
blocking: ctx.out.filter(f => f.severity === CheckSeverity.Block).length,
|
|
11247
|
+
asking: ctx.out.filter(f => f.severity === CheckSeverity.Ask).length,
|
|
11248
|
+
};
|
|
11249
|
+
}
|
|
11250
|
+
/** What a publish request must acknowledge: every ASK finding's code (a BLOCK cannot be acknowledged). */
|
|
11251
|
+
function requiredAcknowledgements(audit) {
|
|
11252
|
+
return [...new Set(audit.checks.flatMap(c => c.findings).filter(f => f.severity === CheckSeverity.Ask).map(f => f.code))];
|
|
11253
|
+
}
|
|
11254
|
+
/** The publish verdict: blocked (never acknowledgeable), needs these acknowledgements, or free to go. */
|
|
11255
|
+
function publishVerdict(audit, acknowledged = []) {
|
|
11256
|
+
const missing = requiredAcknowledgements(audit).filter(code => !acknowledged.includes(code));
|
|
11257
|
+
const blocked = audit.blocking > 0;
|
|
11258
|
+
return { ok: !blocked && missing.length === 0, blocked, missing };
|
|
11259
|
+
}
|
|
11260
|
+
|
|
11261
|
+
/**
|
|
11262
|
+
* Stock photos in a built site (AI plan §3g / §3m, I2): a FREE picture from the platform's curated library, copied
|
|
11263
|
+
* into the studio's own storage (never hot-linked), placed only in an EMPTY picture slot of a section that may show
|
|
11264
|
+
* one — never the owner's work (a collection, a detail page, a gallery: what the nine portfolio types sell is theirs),
|
|
11265
|
+
* never a person (testimonials, the team), never anywhere when the business type says `stock: false`. Its alt text is
|
|
11266
|
+
* the provider's description of what it shows (never a claim), and the credit line its licence requires is placed in
|
|
11267
|
+
* the footer. Pure: the build step does the copying.
|
|
11268
|
+
*/
|
|
11269
|
+
/** Where a stock photo comes from (the library's provider). */
|
|
11270
|
+
var StockProviderId;
|
|
11271
|
+
(function (StockProviderId) {
|
|
11272
|
+
StockProviderId["Magnific"] = "magnific";
|
|
11273
|
+
})(StockProviderId || (StockProviderId = {}));
|
|
11274
|
+
/** The section families a stock photo may stand in for a picture in. */
|
|
11275
|
+
const STOCK_FAMILIES = new Set(['hero', 'feature', 'content', 'story', 'cta', 'contact', 'header']);
|
|
11276
|
+
/** The empty picture slots of a composed site a stock photo may fill, in page and section order. */
|
|
11277
|
+
function stockSlots(plan, composed) {
|
|
11278
|
+
const empty = new Set(composed.placeholders.filter(p => p.kind === PlaceholderKind.Image).map(p => p.nodeId));
|
|
11279
|
+
const out = [];
|
|
11280
|
+
composed.pages.forEach((page, p) => {
|
|
11281
|
+
page.layout.forEach((root, s) => {
|
|
11282
|
+
const pattern = plan.pages[p]?.sections[s]?.pattern;
|
|
11283
|
+
const family = patternById(pattern)?.family;
|
|
11284
|
+
if (!pattern || !family || !STOCK_FAMILIES.has(family))
|
|
11285
|
+
return;
|
|
11286
|
+
walkSerialized([root], n => {
|
|
11287
|
+
if (n.type === 'Image' && empty.has(n.id) && !n.bindings.length)
|
|
11288
|
+
out.push({ nodeId: n.id, owner: page.key, pattern });
|
|
11289
|
+
});
|
|
11290
|
+
});
|
|
11291
|
+
});
|
|
11292
|
+
return out;
|
|
11293
|
+
}
|
|
11294
|
+
/** Which photo goes where: the library's photos in order, one per slot, never twice; none when the type says no stock. */
|
|
11295
|
+
function planStockPhotos(slots, photos, stockAllowed) {
|
|
11296
|
+
if (!stockAllowed)
|
|
11297
|
+
return [];
|
|
11298
|
+
return slots.slice(0, photos.length).map((slot, i) => ({ ...slot, photo: photos[i] }));
|
|
11299
|
+
}
|
|
11300
|
+
/** A placed photo's copy in the studio's storage: the key the build writes it under. */
|
|
11301
|
+
function stockCopyKey(photo) {
|
|
11302
|
+
return `media/stock/${photo.key.replace(/[^a-zA-Z0-9._-]+/g, '-')}`;
|
|
11303
|
+
}
|
|
11304
|
+
/** Put the studio's copy of each photo into its slot (src + the provider's alt). Returns the nodes changed. */
|
|
11305
|
+
function applyStockPhotos(trees, placed) {
|
|
11306
|
+
const byId = new Map(placed.map(p => [p.nodeId, p]));
|
|
11307
|
+
let changed = 0;
|
|
11308
|
+
walkSerialized(trees, n => {
|
|
11309
|
+
const p = byId.get(n.id);
|
|
11310
|
+
if (!p || n.type !== 'Image')
|
|
11311
|
+
return;
|
|
11312
|
+
n.props['src'] = p.url;
|
|
11313
|
+
n.props['alt'] = p.alt;
|
|
11314
|
+
changed++;
|
|
11315
|
+
});
|
|
11316
|
+
return changed;
|
|
11317
|
+
}
|
|
11318
|
+
/** The credit lines a set of photos needs — one per distinct line (a free Magnific photo: "Designed by Magnific"). */
|
|
11319
|
+
function stockCreditLines(photos) {
|
|
11320
|
+
const seen = new Map();
|
|
11321
|
+
for (const p of photos)
|
|
11322
|
+
if (!seen.has(p.credit.line))
|
|
11323
|
+
seen.set(p.credit.line, p.credit.lineUrl);
|
|
11324
|
+
return [...seen.entries()].map(([line, url]) => ({ line, url }));
|
|
11325
|
+
}
|
|
11326
|
+
/** The footer node id of a credit line (stable — a build that runs twice finds it). */
|
|
11327
|
+
const stockCreditNodeId = (index) => `stock-credit-${index + 1}`;
|
|
11328
|
+
/**
|
|
11329
|
+
* The credit line, as the builder would create a Link (a plain node the owner may move or restyle): the licence's words,
|
|
11330
|
+
* linking where it asks, opening in a new tab. Placed at the end of the footer — the place the licence names for a site.
|
|
11331
|
+
*/
|
|
11332
|
+
function stockCreditNode(index, credit) {
|
|
11333
|
+
return createSerializedNode(stockCreditNodeId(index), 'Link', { label: credit.line, linkType: 'external', url: credit.url, target: '_blank' }, 'link');
|
|
11334
|
+
}
|
|
11335
|
+
/** Append the credit lines to the footer root (once each). Returns how many it added. */
|
|
11336
|
+
function addStockCredits(footer, credits) {
|
|
11337
|
+
footer.children ??= [];
|
|
11338
|
+
let added = 0;
|
|
11339
|
+
credits.forEach((credit, i) => {
|
|
11340
|
+
const id = stockCreditNodeId(i);
|
|
11341
|
+
if (footer.children.some(c => c.id === id))
|
|
11342
|
+
return;
|
|
11343
|
+
footer.children.push(stockCreditNode(i, credit));
|
|
11344
|
+
added++;
|
|
11345
|
+
});
|
|
11346
|
+
return added;
|
|
11347
|
+
}
|
|
11348
|
+
|
|
10930
11349
|
/**
|
|
10931
11350
|
* @vectoriox/iox-ui/generation-core — the shared, FRAMEWORK-FREE site-plan core (design-system plan
|
|
10932
11351
|
* §6b, W1): the Site Plan shape + its validator, the pattern library and the Studio template (both
|
|
@@ -10943,5 +11362,5 @@ function planWordIssues(plan, ctx) {
|
|
|
10943
11362
|
* Generated bundle index. Do not edit.
|
|
10944
11363
|
*/
|
|
10945
11364
|
|
|
10946
|
-
export { ACTIVE_BUILD_STATUSES, AI_REFUSAL_NEXT, AI_REFUSAL_STATUS, AI_STEPS, AI_STEP_LABELS, AI_STEP_NEEDS, AI_STEP_TYPICAL_TOKENS, AiCallStatus, AiCapability, AiGenerationStage, AiKeyMode, AiNextKind, AiProviderId, AiRefusalCode, AiStep, BAR_ITEMS_MAX, BAR_ITEMS_MIN, BASELINE_ROLES, BUILD_STEPS, BaselineRole, BindScope, BuildNoticeCode, BuildStep, CREDITS_PER_USD, CardBindTarget, ComposeError, ComposeIssueCode, ContentTypeAction, CreatedKind, DANGLING_LINK_CODES, DEFAULT_PHONE_MENU_BREAKPOINT, ENTRANCE_EASING, ENTRANCE_ORIGIN_LOOK, ENTRANCE_TRIGGER, EntrancePart, FACT_KEYS, FINAL_GENERATION_STAGES, GlobalSlot, JSON_SCHEMA_BANNED_KEYWORDS, JsonSchemaShapeError, KeptReason, NAV_PART_LABELS, NAV_SHAPE_COPY, NEUTRAL_STYLE_PROPS, NODE_BASELINES, NO_TOKENS, NavPagesSource, NavRole, NavShape, NavShapeError, PLAN_EDITS_ANSWER_SHAPE, PLAN_EDITS_SCHEMA_NAME, PLAN_EDIT_SHAPE, PRICING_PATTERN, PUBLISH_BLOCKING_PLACEHOLDERS, PageDataKind, PathIssueCollector, PatternDirective, PatternGlobalPosition, PatternOpens, PatternPlaceholder, PatternRecipe, PhoneMenuBreakpoint, PlaceholderKind, PlanChangeAction, PlanChangeKind, PlanDataSourceMode, PlanDataSourceType, PlanEditIssueCode, PlanEditOp, PlanEditsOutcome, PlanWordIssueCode, PreflightRefusalCode, RelativeOp, SAMPLE_IMAGE_REF, SITE_FACT_LABELS, SITE_HEADER_PATTERN, SITE_PATTERNS, SITE_PLAN_SCHEMA_NAME, SITE_PLAN_VERSION, SITE_TEMPLATES, SPEC_SITE_FACTS, SPEC_SITE_LIBRARY, SPEC_SITE_PATTERNS, SPEC_SITE_PLAN_SHAPE, SPEC_SITE_TEMPLATES, STUDIO_TEMPLATE, SiteBuildKind, SiteBuildStatus, SitePlanError, SitePlanIssueCode, SitePlanSourceKind, SitePlanWireKey, SiteTemplateError, SiteTemplateId, StepState, addBarItem, altSourceScopes, applyPlanEdits, assertStyleSlots, assertValidSitePlan, barIconForRoute, blocksPublish, buildKeys, buildStepFacts, builtHomePageId, composeNavHeader, composeSection, composeSite, contentTypeFromWire, contentTypeJsonSchema, costUsd, createSerializedNode, creditsOfUsd, dataSourceJsonSchema, describePlanData, describeShapeKey, entranceAction, entranceInteraction, estimateStepCredits, failedBuildStep, fieldJsonSchema, findNavRoot, isActiveBuild, isNonEmptyString, isPlainObject, jsonAnyOf, jsonBoolean, jsonClosedObject, jsonInteger, jsonListOf, jsonOneOf, jsonSchemaKeywords, jsonSchemaObjects, jsonShapedObject, jsonText, modelCanDo, moveBarItem, navPages, navShapeBreakpoint, navShapeOf, nextSourceOf, nodeBindPaths, pageJsonSchema, parseSampleImageRef, pathAt, patternById, patternNeedsBinding, patternNodes, patternOptionalParts, patternScopes, patternSlots, patternTakesBinding, phoneMenuPages, planEditsFromWire, planEditsJsonSchema, planFromTemplate, planNavShape, planWordIssues, releasedLayoutDefaults, removeBarItem, requiredShapeKeys, routeParams, sampleImageRef, sectionEntrances, sectionFromWire, sectionJsonSchema, sectionPatternIds, setStyleProps, shapeKeys, siteNavPages, sitePlanFromWire, sitePlanJsonSchema, sitePlanToWire, staggerDelay, validatePlanEdits, validateSitePlan, walkSerialized, wordPattern, writtenTexts };
|
|
11365
|
+
export { ACTIVE_BUILD_STATUSES, AI_REFUSAL_NEXT, AI_REFUSAL_STATUS, AI_STEPS, AI_STEP_LABELS, AI_STEP_NEEDS, AI_STEP_TYPICAL_TOKENS, AiCallStatus, AiCapability, AiGenerationStage, AiKeyMode, AiNextKind, AiProviderId, AiRefusalCode, AiStep, BAR_ITEMS_MAX, BAR_ITEMS_MIN, BASELINE_ROLES, BUILD_STEPS, BaselineRole, BindScope, BuildNoticeCode, BuildStep, CREDITS_PER_USD, CardBindTarget, CheckSeverity, ComposeError, ComposeIssueCode, ContentTypeAction, CreatedKind, DANGLING_LINK_CODES, DEFAULT_PHONE_MENU_BREAKPOINT, ENTRANCE_EASING, ENTRANCE_ORIGIN_LOOK, ENTRANCE_TRIGGER, EntrancePart, FACT_KEYS, FINAL_GENERATION_STAGES, FINDING_SEVERITY, GlobalSlot, JSON_SCHEMA_BANNED_KEYWORDS, JsonSchemaShapeError, KeptReason, NAV_PART_LABELS, NAV_SHAPE_COPY, NEUTRAL_STYLE_PROPS, NODE_BASELINES, NO_TOKENS, NavPagesSource, NavRole, NavShape, NavShapeError, PLAN_EDITS_ANSWER_SHAPE, PLAN_EDITS_SCHEMA_NAME, PLAN_EDIT_SHAPE, PRICING_PATTERN, PUBLISH_BLOCKING_PLACEHOLDERS, PageDataKind, PathIssueCollector, PatternDirective, PatternGlobalPosition, PatternOpens, PatternPlaceholder, PatternRecipe, PhoneMenuBreakpoint, PlaceholderKind, PlanChangeAction, PlanChangeKind, PlanDataSourceMode, PlanDataSourceType, PlanEditIssueCode, PlanEditOp, PlanEditsOutcome, PlanWordIssueCode, PreflightRefusalCode, RelativeOp, SAMPLE_IMAGE_REF, SITE_CHECKS, SITE_FACT_LABELS, SITE_HEADER_PATTERN, SITE_PATTERNS, SITE_PLAN_SCHEMA_NAME, SITE_PLAN_VERSION, SITE_TEMPLATES, SPEC_SITE_FACTS, SPEC_SITE_LIBRARY, SPEC_SITE_PATTERNS, SPEC_SITE_PLAN_SHAPE, SPEC_SITE_TEMPLATES, STOCK_FAMILIES, STUDIO_TEMPLATE, SiteBuildKind, SiteBuildStatus, SiteCheckId, SiteFindingCode, SitePlanError, SitePlanIssueCode, SitePlanSourceKind, SitePlanWireKey, SiteTemplateError, SiteTemplateId, StepState, StockProviderId, addBarItem, addStockCredits, altSourceScopes, applyPlanEdits, applyStockPhotos, assertStyleSlots, assertValidSitePlan, auditSite, barIconForRoute, blocksPublish, buildKeys, buildStepFacts, builtHomePageId, composeNavHeader, composeSection, composeSite, contentTypeFromWire, contentTypeJsonSchema, costUsd, createSerializedNode, creditsOfUsd, dataSourceJsonSchema, describePlanData, describeShapeKey, entranceAction, entranceInteraction, estimateStepCredits, failedBuildStep, fieldJsonSchema, findNavRoot, isActiveBuild, isNonEmptyString, isPlainObject, jsonAnyOf, jsonBoolean, jsonClosedObject, jsonInteger, jsonListOf, jsonOneOf, jsonSchemaKeywords, jsonSchemaObjects, jsonShapedObject, jsonText, modelCanDo, moveBarItem, navPages, navShapeBreakpoint, navShapeOf, nextSourceOf, nodeBindPaths, pageJsonSchema, parseSampleImageRef, pathAt, patternById, patternNeedsBinding, patternNodes, patternOptionalParts, patternScopes, patternSlots, patternTakesBinding, phoneMenuPages, planEditsFromWire, planEditsJsonSchema, planFromTemplate, planNavShape, planStockPhotos, planWordIssues, publishVerdict, releasedLayoutDefaults, removeBarItem, requiredAcknowledgements, requiredShapeKeys, routeMatches, routeParams, sampleImageRef, sectionEntrances, sectionFromWire, sectionJsonSchema, sectionPatternIds, setStyleProps, shapeKeys, siteNavPages, sitePlanFromWire, sitePlanJsonSchema, sitePlanToWire, staggerDelay, stockCopyKey, stockCreditLines, stockCreditNode, stockCreditNodeId, stockSlots, validatePlanEdits, validateSitePlan, walkSerialized, wordPattern, writtenTexts };
|
|
10947
11366
|
//# sourceMappingURL=vectoriox-iox-ui-generation-core.mjs.map
|