@vectoriox/iox-ui 5.39.0 → 5.40.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.
@@ -6911,14 +6911,14 @@ const GLOBAL_POSITION = {
6911
6911
  [GlobalSlot.Footer]: PatternGlobalPosition.After,
6912
6912
  };
6913
6913
  const ROUTE = /^\/(?:(?:[a-z0-9]+(?:-[a-z0-9]+)*|:[a-zA-Z_][a-zA-Z0-9_]*)(?:\/(?:[a-z0-9]+(?:-[a-z0-9]+)*|:[a-zA-Z_][a-zA-Z0-9_]*))*)?$/;
6914
- const ROUTE_PARAM = /:([a-zA-Z_][a-zA-Z0-9_]*)/g;
6914
+ const ROUTE_PARAM$1 = /:([a-zA-Z_][a-zA-Z0-9_]*)/g;
6915
6915
  const isObject = (v) => !!v && typeof v === 'object' && !Array.isArray(v);
6916
6916
  const isNonEmptyString = (v) => typeof v === 'string' && v.trim() !== '';
6917
6917
  const has = (table, key) => Object.prototype.hasOwnProperty.call(table, key);
6918
6918
  const at = (path, key) => (path ? `${path}.${key}` : key);
6919
6919
  /** The `:param` names of a route, in order. */
6920
6920
  function routeParams(route) {
6921
- return [...route.matchAll(ROUTE_PARAM)].map(m => m[1]);
6921
+ return [...route.matchAll(ROUTE_PARAM$1)].map(m => m[1]);
6922
6922
  }
6923
6923
  class Collector {
6924
6924
  constructor() {
@@ -7485,6 +7485,21 @@ function navPages(root) {
7485
7485
  const source = links.length ? links : collectHeaderLinks(root);
7486
7486
  return source.filter(isPageLink).map(n => ({ label: textOf(n), route: String(prop(n, 'pageRoute')) }));
7487
7487
  }
7488
+ /** Where a phone menu's pages come from: the header's own page Links, else the studio's pages. */
7489
+ var NavPagesSource;
7490
+ (function (NavPagesSource) {
7491
+ NavPagesSource["Header"] = "header";
7492
+ NavPagesSource["Site"] = "site";
7493
+ NavPagesSource["None"] = "none";
7494
+ })(NavPagesSource || (NavPagesSource = {}));
7495
+ /** The pages a phone menu lists: the header's (`navPages`), else `sitePages` — a hand-built header with no
7496
+ * page links still gets a working menu. */
7497
+ function phoneMenuPages(root, sitePages = []) {
7498
+ const own = navPages(root);
7499
+ if (own.length)
7500
+ return { pages: own, source: NavPagesSource.Header };
7501
+ return sitePages.length ? { pages: [...sitePages], source: NavPagesSource.Site } : { pages: [], source: NavPagesSource.None };
7502
+ }
7488
7503
  /** A hand-built header: every page Link outside a drawer. */
7489
7504
  function collectHeaderLinks(root) {
7490
7505
  const out = [];
@@ -7708,7 +7723,7 @@ function planNavShape(globals, shape, options = {}, navId) {
7708
7723
  throw new NavShapeError(`a phone menu cannot switch at "${at}"`);
7709
7724
  const kit = makeKit(out, root.id, options.newId);
7710
7725
  adoptRoles(root);
7711
- const pages = navPages(root);
7726
+ const { pages } = phoneMenuPages(root, options.pages);
7712
7727
  const wantDrawer = shape !== NavShape.Bar;
7713
7728
  const wantBar = shape !== NavShape.Drawer;
7714
7729
  const wantMenuButton = shape === NavShape.Drawer;
@@ -7828,7 +7843,7 @@ function addBarItem(globals, options = {}) {
7828
7843
  if (kids.length >= BAR_ITEMS_MAX)
7829
7844
  return { globals: out, added: false };
7830
7845
  const linked = new Set(kids.filter(c => c.role === NavRole.BarItem).map(c => prop(c, 'pageRoute')));
7831
- const page = barPages(root, navPages(root), BAR_ITEMS_MAX + 1).find(p => !linked.has(p.route))
7846
+ const page = barPages(root, phoneMenuPages(root, options.pages).pages, BAR_ITEMS_MAX + 1).find(p => !linked.has(p.route))
7832
7847
  ?? { label: NAV_SHAPE_COPY.home, route: HOME_ROUTE };
7833
7848
  const item = barItem(makeKit(out, root.id, options.newId), kids.length, page);
7834
7849
  const more = kids.findIndex(c => c.role === NavRole.More);
@@ -7838,6 +7853,32 @@ function addBarItem(globals, options = {}) {
7838
7853
  kids.push(item);
7839
7854
  return { globals: out, added: true };
7840
7855
  }
7856
+ function barOf(globals) {
7857
+ const out = clone$1(globals);
7858
+ const b = find(out, NavRole.Bar);
7859
+ return { out, kids: b ? (b.children ?? (b.children = [])) : null };
7860
+ }
7861
+ /**
7862
+ * The bar's Items list "Remove" (board 2): the item goes, More included — refused below three items (Q2:
7863
+ * 3–5), so the bar never shrinks into something a thumb cannot use. Input not mutated.
7864
+ */
7865
+ function removeBarItem(globals, itemId) {
7866
+ const { out, kids } = barOf(globals);
7867
+ const i = kids ? kids.findIndex(c => c.id === itemId) : -1;
7868
+ if (!kids || i < 0 || kids.length <= BAR_ITEMS_MIN)
7869
+ return { globals: out, changed: false };
7870
+ kids.splice(i, 1);
7871
+ return { globals: out, changed: true };
7872
+ }
7873
+ /** The bar's Items list drag-to-reorder (board 2): item `from` moves to `to`. Input not mutated. */
7874
+ function moveBarItem(globals, from, to) {
7875
+ const { out, kids } = barOf(globals);
7876
+ if (!kids || from === to || from < 0 || to < 0 || from >= kids.length || to >= kids.length)
7877
+ return { globals: out, changed: false };
7878
+ const [item] = kids.splice(from, 1);
7879
+ kids.splice(to, 0, item);
7880
+ return { globals: out, changed: true };
7881
+ }
7841
7882
 
7842
7883
  /**
7843
7884
  * THE composer — a Site Plan in, ordinary IOX data out (design-system plan §6b, W1). Deterministic and
@@ -8634,6 +8675,54 @@ function composeSite(plan, context) {
8634
8675
  issues,
8635
8676
  };
8636
8677
  }
8678
+ // ── The site header on its own (CC1.1) ──────────────────────────────────────────────────────────
8679
+ /** The header pattern the Studio template stamps — and the builder palette's "Navigation bar". */
8680
+ const SITE_HEADER_PATTERN = 'nav.inline-cta';
8681
+ const ROUTE_PARAM = ':';
8682
+ const HOME_PATH = '/';
8683
+ const KEY_UNSAFE = /[^a-z0-9]+/gi;
8684
+ /** The pages a navigation links to: every page but Home (the brand links there) and template pages
8685
+ * (a `/work/:slug` route has no single address), in the studio's order. */
8686
+ function siteNavPages(pages) {
8687
+ return pages.filter(p => !!p.route && !p.isHome && p.route !== HOME_PATH && !p.route.includes(ROUTE_PARAM));
8688
+ }
8689
+ function navPagePlans(pages) {
8690
+ const used = new Set();
8691
+ return pages.map((p, i) => {
8692
+ let key = p.route.replace(KEY_UNSAFE, '-').replace(/^-+|-+$/g, '').toLowerCase() || `page-${i}`;
8693
+ for (let n = 2; used.has(key); n++)
8694
+ key = `${key}-${n}`;
8695
+ used.add(key);
8696
+ return { key, name: p.name, route: p.route, inNav: true, isHome: p.isHome === true, sections: [] };
8697
+ });
8698
+ }
8699
+ /**
8700
+ * The Studio template's header, composed for a studio that has no Site Plan — the builder palette's
8701
+ * "Navigation bar". THE SAME pattern and the same composer as `composeSite`: the brand (the business name),
8702
+ * one plain Link per navigation page, the call to action (W1.1's one dangling-link rule when the studio has
8703
+ * no /contact page: an email to the business, else removed), and the pattern's phone shape. Pure.
8704
+ */
8705
+ function composeNavHeader(input, options) {
8706
+ if (!nonEmpty(options?.id))
8707
+ throw new ComposeError('composeNavHeader needs the header id');
8708
+ const pattern = patternById(SITE_HEADER_PATTERN);
8709
+ const all = navPagePlans(input.pages);
8710
+ const navRoutes = new Set(siteNavPages(input.pages).map(p => p.route));
8711
+ const pages = all.map(p => ({ ...p, inNav: navRoutes.has(p.route) }));
8712
+ const plan = { business: input.business, pages, dataSources: [], contentTypes: [] };
8713
+ const email = nonEmpty(input.business.facts?.email) ? input.business.facts.email.trim() : null;
8714
+ const issues = [];
8715
+ const ctx = {
8716
+ owner: GlobalSlot.Header, page: null, section: null, plan, year: 0, email, navPage: null, nextAlias: null,
8717
+ placeholders: [], issues, routes: new Set(pages.map(p => p.route)),
8718
+ };
8719
+ const root = composePattern(pattern, options.id, ctx);
8720
+ root.isGlobal = true;
8721
+ root.globalPosition = pattern.global;
8722
+ const shape = pattern.phoneMenu;
8723
+ const header = shape ? planNavShape([root], shape, { newId: options.newId }, root.id).globals[0] : root;
8724
+ return { header, issues };
8725
+ }
8637
8726
 
8638
8727
  /**
8639
8728
  * @vectoriox/iox-ui/generation-core — the shared, FRAMEWORK-FREE site-plan core (design-system plan
@@ -8651,5 +8740,5 @@ function composeSite(plan, context) {
8651
8740
  * Generated bundle index. Do not edit.
8652
8741
  */
8653
8742
 
8654
- export { BAR_ITEMS_MAX, BAR_ITEMS_MIN, BASELINE_ROLES, BaselineRole, BindScope, CardBindTarget, ComposeError, ComposeIssueCode, DANGLING_LINK_CODES, DEFAULT_PHONE_MENU_BREAKPOINT, FACT_KEYS, GlobalSlot, NAV_PART_LABELS, NAV_SHAPE_COPY, NEUTRAL_STYLE_PROPS, NODE_BASELINES, NavRole, NavShape, NavShapeError, PatternDirective, PatternGlobalPosition, PatternOpens, PatternPlaceholder, PatternRecipe, PhoneMenuBreakpoint, PlaceholderKind, PlanDataSourceMode, PlanDataSourceType, RelativeOp, SAMPLE_IMAGE_REF, SITE_FACT_LABELS, SITE_PATTERNS, SITE_PLAN_VERSION, SITE_TEMPLATES, SPEC_SITE_FACTS, SPEC_SITE_PATTERNS, SPEC_SITE_PLAN_SHAPE, SPEC_SITE_TEMPLATES, STUDIO_TEMPLATE, SitePlanError, SitePlanIssueCode, SitePlanSourceKind, SiteTemplateError, SiteTemplateId, addBarItem, altSourceScopes, assertStyleSlots, assertValidSitePlan, barIconForRoute, composeSite, createSerializedNode, findNavRoot, navPages, navShapeBreakpoint, navShapeOf, nextSourceOf, nodeBindPaths, parseSampleImageRef, patternById, patternNeedsBinding, patternNodes, patternOptionalParts, patternScopes, patternSlots, patternTakesBinding, planFromTemplate, planNavShape, releasedLayoutDefaults, requiredShapeKeys, routeParams, sampleImageRef, setStyleProps, shapeKeys, validateSitePlan, walkSerialized };
8743
+ export { BAR_ITEMS_MAX, BAR_ITEMS_MIN, BASELINE_ROLES, BaselineRole, BindScope, CardBindTarget, ComposeError, ComposeIssueCode, DANGLING_LINK_CODES, DEFAULT_PHONE_MENU_BREAKPOINT, FACT_KEYS, GlobalSlot, NAV_PART_LABELS, NAV_SHAPE_COPY, NEUTRAL_STYLE_PROPS, NODE_BASELINES, NavPagesSource, NavRole, NavShape, NavShapeError, PatternDirective, PatternGlobalPosition, PatternOpens, PatternPlaceholder, PatternRecipe, PhoneMenuBreakpoint, PlaceholderKind, PlanDataSourceMode, PlanDataSourceType, RelativeOp, SAMPLE_IMAGE_REF, SITE_FACT_LABELS, SITE_HEADER_PATTERN, SITE_PATTERNS, SITE_PLAN_VERSION, SITE_TEMPLATES, SPEC_SITE_FACTS, SPEC_SITE_PATTERNS, SPEC_SITE_PLAN_SHAPE, SPEC_SITE_TEMPLATES, STUDIO_TEMPLATE, SitePlanError, SitePlanIssueCode, SitePlanSourceKind, SiteTemplateError, SiteTemplateId, addBarItem, altSourceScopes, assertStyleSlots, assertValidSitePlan, barIconForRoute, composeNavHeader, composeSite, createSerializedNode, findNavRoot, moveBarItem, navPages, navShapeBreakpoint, navShapeOf, nextSourceOf, nodeBindPaths, parseSampleImageRef, patternById, patternNeedsBinding, patternNodes, patternOptionalParts, patternScopes, patternSlots, patternTakesBinding, phoneMenuPages, planFromTemplate, planNavShape, releasedLayoutDefaults, removeBarItem, requiredShapeKeys, routeParams, sampleImageRef, setStyleProps, shapeKeys, siteNavPages, validateSitePlan, walkSerialized };
8655
8744
  //# sourceMappingURL=vectoriox-iox-ui-generation-core.mjs.map