@bettercms-ai/types 1.29.1 → 1.31.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/dist/index.d.ts +59 -1
- package/dist/index.js +153 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -997,8 +997,31 @@ declare function componentInstanceAddresses(instanceBlockId: string, props: read
|
|
|
997
997
|
* render-page.ts. Unknown tokens are dropped — closed set, no arbitrary CSS.
|
|
998
998
|
*/
|
|
999
999
|
|
|
1000
|
+
/**
|
|
1001
|
+
* 🔴 The ONE place a free-form string is allowed near CSS: `bgImage` is author-supplied, so it is
|
|
1002
|
+
* rejected — never escaped — unless it is an http(s) or root-relative url with nothing that could
|
|
1003
|
+
* end a `url(…)` token or start a new declaration (quotes, parens, backslash, `;`, whitespace).
|
|
1004
|
+
* Returns "" for anything it does not fully trust. Twin of `safeCssUrl` in render-page.ts.
|
|
1005
|
+
*/
|
|
1006
|
+
declare function safeCssUrl(raw: unknown): string;
|
|
1000
1007
|
/** A CSS declaration object (key → value) usable as a React `style` prop, or undefined when empty. */
|
|
1001
1008
|
declare function blockStyleToCss(style: BlockStyle | undefined): Record<string, string | number> | undefined;
|
|
1009
|
+
/**
|
|
1010
|
+
* The content column: the declarations for the INNER box a renderer nests between a block's
|
|
1011
|
+
* style wrapper (`blockStyleToCss`, which carries the full-bleed background) and the block itself.
|
|
1012
|
+
* The outer box can't constrain width without shrinking its own background, so a width needs a
|
|
1013
|
+
* second box. `undefined` when there is no column (no `contentWidth`, `full`, or unknown) — a
|
|
1014
|
+
* renderer then emits no inner box at all.
|
|
1015
|
+
*
|
|
1016
|
+
* Placement is `contentAlign`, falling back to `align`. `align` alone used to mean both text
|
|
1017
|
+
* alignment (outer box) and column placement (here); `contentAlign` split them, and the fallback
|
|
1018
|
+
* keeps every style written before the split rendering identically. Twin: `styleTokensToInnerCss`
|
|
1019
|
+
* in render-page.ts, which the hosted lane serialises as `max-width:…;margin:…`.
|
|
1020
|
+
*/
|
|
1021
|
+
declare function blockStyleToInnerCss(style: BlockStyle | undefined): {
|
|
1022
|
+
maxWidth: string;
|
|
1023
|
+
margin: string;
|
|
1024
|
+
} | undefined;
|
|
1002
1025
|
/**
|
|
1003
1026
|
* HEADING-STYLE-PAINT — a heading's own size and weight, for the `<hN>` element itself.
|
|
1004
1027
|
*
|
|
@@ -1022,6 +1045,25 @@ declare function headingPaintCss(style: BlockStyle | undefined, opts?: {
|
|
|
1022
1045
|
fontSize?: string;
|
|
1023
1046
|
fontWeight?: number;
|
|
1024
1047
|
} | undefined;
|
|
1048
|
+
/**
|
|
1049
|
+
* Style keys that PLACE a block. A button keeps only these on its wrapper; the rest paints the
|
|
1050
|
+
* `<a>` itself. On the wrapper (where every other block's style goes) a fill, theme or corner
|
|
1051
|
+
* painted a box BEHIND the anchor, which kept its variant's own fill. 🔴 Twin of `PLACEMENT_KEYS`
|
|
1052
|
+
* in src/lib/sites/render-page.ts; src/__tests__/sites/block-style-parity.test.ts pins the two.
|
|
1053
|
+
*/
|
|
1054
|
+
declare const BUTTON_PLACEMENT_KEYS: readonly ["align", "contentAlign", "contentWidth", "marginTop", "marginBottom", "fullHeight", "spaceTop", "spaceBottom"];
|
|
1055
|
+
/**
|
|
1056
|
+
* A button's style split in two: `placement` (the keys its wrapper keeps — feed it to
|
|
1057
|
+
* `blockStyleToCss` / `blockStyleToInnerCss` exactly like any block's style) and `paint`, the
|
|
1058
|
+
* declarations for the `<a>` itself. `bg: "none"` paints the anchor transparent (and inherits the
|
|
1059
|
+
* text colour unless one is set), so it clears the variant's fill instead of doing nothing.
|
|
1060
|
+
* `hover` is not painted: the hosted lane draws it with classes its own stylesheet styles.
|
|
1061
|
+
* Either half is `undefined` when empty, so an unstyled button gets no wrapper and no `style`.
|
|
1062
|
+
*/
|
|
1063
|
+
declare function splitButtonStyle(style: BlockStyle | undefined): {
|
|
1064
|
+
placement: BlockStyle | undefined;
|
|
1065
|
+
paint: Record<string, string | number> | undefined;
|
|
1066
|
+
};
|
|
1025
1067
|
|
|
1026
1068
|
/**
|
|
1027
1069
|
* Generated from lucide-react@1.8.0 dynamic icon names.
|
|
@@ -1787,6 +1829,9 @@ declare function dockBudget(screen: DockScreen): DockBudget;
|
|
|
1787
1829
|
* 5. Two fields pair when their stem holds EXACTLY one text and one link candidate. Three or more
|
|
1788
1830
|
* candidates on a stem: none pair. A field that would pair two ways pairs neither way.
|
|
1789
1831
|
*
|
|
1832
|
+
* 0. Before all of that, an importer's spelling pairs outright (@see derivedPairs):
|
|
1833
|
+
* `<stem>-href` (link-typed) with the one text keyed `<stem>`, or `<stem>` with its tag swapped.
|
|
1834
|
+
*
|
|
1790
1835
|
* When the key's words say nothing, the visible LABEL is read the same way, its stems namespaced
|
|
1791
1836
|
* (`label:`) so a label reading only ever meets another label reading.
|
|
1792
1837
|
*/
|
|
@@ -1806,6 +1851,19 @@ type Role = {
|
|
|
1806
1851
|
};
|
|
1807
1852
|
/** The role one field plays, with every stem it offers, or null. */
|
|
1808
1853
|
declare function candidateRole(candidate: ButtonLinkCandidate): Role | null;
|
|
1854
|
+
/**
|
|
1855
|
+
* The pairs an IMPORTER's spelling names outright, before any role is read.
|
|
1856
|
+
*
|
|
1857
|
+
* Derive keys a call to action by the element it found it in: `equip-a-start-exploring-href` (link)
|
|
1858
|
+
* beside `equip-span-start-exploring` (text). Neither key ends in a role word, so the role pass
|
|
1859
|
+
* cannot pair them. Here a link-typed `<stem>-href` / `<stem>_href` pairs with the ONE text field
|
|
1860
|
+
* keyed `<stem>`, or `<stem>` with exactly one tag segment (a/span/button/div/strong) swapped for
|
|
1861
|
+
* another. Two candidate texts: none pairs.
|
|
1862
|
+
*/
|
|
1863
|
+
declare function derivedPairs(candidates: readonly ButtonLinkCandidate[]): Map<number, {
|
|
1864
|
+
pair: string;
|
|
1865
|
+
role: "text" | "link";
|
|
1866
|
+
}>;
|
|
1809
1867
|
/** Every unambiguous pair in one sibling list, as `[textIndex, linkIndex]`, in list order. */
|
|
1810
1868
|
declare function buttonLinkPairs(candidates: readonly ButtonLinkCandidate[]): Array<[number, number]>;
|
|
1811
1869
|
|
|
@@ -2409,4 +2467,4 @@ declare function regionOf<E extends {
|
|
|
2409
2467
|
el: E;
|
|
2410
2468
|
}[], el: unknown): string | null;
|
|
2411
2469
|
|
|
2412
|
-
export { type AlignToken, type ApiError, type ApiKey, type ApiKeyPermission, type ApiKeyTokenType, type ArrayZoneConfig, type AssertEqual, type AuthResponse, type AuthSession, type AuthUser, BLOCK_BINDINGS, BUTTON_ICONS, BUTTON_ICON_NAMES, BUTTON_LOOK_KEYS, BUTTON_SIZES, BUTTON_VARIANTS, type BetterCMSErrorCode, type BgToken, type BindingKind, type BlockBinding, type BlockHoverStyle, type BlockStyle, type BlockType, type ButtonBlock, type ButtonIcon, type ButtonLinkCandidate, type ButtonLookKey, type ButtonProps, type ButtonSizeName, type ButtonValue, type ButtonVariant, COMPONENT_PROP_TYPES, type CanonicalInputDefinition, type CollectionBlock, type CollectionProps, type ColorToken, type ColumnsBlock, type ColumnsProps, type Component, type ComponentBlock, type ComponentCategory, type ComponentFormPropRef, type ComponentPropDef, type ComponentPropType, type ComponentPropUi, type ComponentProps, type ComponentSubField, type ComponentVariantGroup, type Content, type ContentBlock, type ContentEntry, type ContentModel, type ContentModelField, type ContentModelFieldType, type ContentModelFieldUi, type ContentPageResult, type ContentResponse, type ContentWidthToken, type CornerToken, DIALOG_SELECTOR, DOCK_BUDGET, DOCK_ICON_NAMES, DOCK_ICON_NAME_SET, type DeepReadonly, type DeliveredLayout, type DeliveryComponent, type DeliveryEntry, type DeliveryEntrySeo, type DeliveryList, type DeliveryPage, type DerivedLocator, type DockBudget, type DockFieldLike, type DockFieldsetLike, type DockIconName, type DockLane, type DockNode, type DockPropGroupLike, type DockScreen, type ElementLike, type ExpandedBinding, FOOTER_SECTION_ID, type FieldConfig, type Fieldset, type FieldsetKind, type FieldsetUiBefore, type FontSizeToken, type FooterBlock, type FooterColumn, type FooterProps, type Form, type FormBlock, type FormField, type FormProps, type FormSubmission, type HeadingBlock, type HeadingProps, type ImageBlock, type ImageProps, LANDMARK_SELECTOR, LAYOUT_SECTION_ICONS, LAYOUT_SECTION_ICON_SET, type LandmarkChainElement, type LandmarkElement, type LayoutComponentItem, type LayoutDataDocument, type LayoutFieldDefinition, type LayoutFieldItem, type LayoutFieldType, type LayoutScalarFieldType, type LayoutSection, type LayoutSectionIcon, type LayoutSectionItem, type LayoutStructureDocument, type LayoutZone, type LocatorGrammar, MAIN_SELECTOR, type ManagementLayoutCommand, type MediaAsset, type MediaCaptionTrack, type MediaFieldValue, NAVIGATION_SECTION_ID, type NavLink, type NavbarBlock, type NavbarProps, PAGE_CONTENT_ANCHOR_ID, type Page, type PageLayoutOverrideDataDocument, type PageLayoutOverrideDocument, type PageLayoutOverrideState, type PageLayoutOverrideStructureDocument, type PageLayoutSectionOverride, type PageLayoutSectionStructureOverride, type PageMetaJson, type PageOnlyLayoutSection, type PageSectionPlacement, type PaginatedResult, type Perspective, type PortableTextDocument, type PortableTextNode, type PropGroup, type RadiusToken, type Redirect, type ReservedLayoutSection, type ResolvedLayoutNode, type RichTextBlock, type RichTextProps, SECTION_DOCTRINE, SECTION_SPACE_TOKENS, SPACE_BOTTOM_TOKENS, SPACE_STEP_TOKENS, type SectionBlock, type SectionProps, type SectionSpaceToken, type ShadowToken, type SignInInput, type SignUpInput, type SiteSeoDefaults, type SlideItem, type SliderBlock, type SliderProps, type SpaceStepToken, type SpaceToken, type SpacerBlock, type SpacerProps, type TabItem, type TabsBlock, type TabsProps, type TextBlock, type TextProps, type ThemeToken, type UiBefore, type UiOrigin, type VariantInputMapping, type VideoBlock, type VideoProps, type WeightToken, type Workspace, type ZoneField, blockStyleToCss, buttonIconOf, buttonIconSvg, buttonLinkPairs, buttonValueOfInstance, buttonValueProblem, buttonVariantOf, candidateRole, componentInstanceAddresses, componentPropTargetKey, dockBudget, dockScreens, expandBlockBindings, formatPropsAttribute, getBlockType, headingPaintCss, isBlock, isChromeLandmark, keyWords, landmarkRegions, locatorFor, parsePropsAttribute, readButtonValue, readPath, regionOf, spaceTokenCss, withButtonLookProps };
|
|
2470
|
+
export { type AlignToken, type ApiError, type ApiKey, type ApiKeyPermission, type ApiKeyTokenType, type ArrayZoneConfig, type AssertEqual, type AuthResponse, type AuthSession, type AuthUser, BLOCK_BINDINGS, BUTTON_ICONS, BUTTON_ICON_NAMES, BUTTON_LOOK_KEYS, BUTTON_PLACEMENT_KEYS, BUTTON_SIZES, BUTTON_VARIANTS, type BetterCMSErrorCode, type BgToken, type BindingKind, type BlockBinding, type BlockHoverStyle, type BlockStyle, type BlockType, type ButtonBlock, type ButtonIcon, type ButtonLinkCandidate, type ButtonLookKey, type ButtonProps, type ButtonSizeName, type ButtonValue, type ButtonVariant, COMPONENT_PROP_TYPES, type CanonicalInputDefinition, type CollectionBlock, type CollectionProps, type ColorToken, type ColumnsBlock, type ColumnsProps, type Component, type ComponentBlock, type ComponentCategory, type ComponentFormPropRef, type ComponentPropDef, type ComponentPropType, type ComponentPropUi, type ComponentProps, type ComponentSubField, type ComponentVariantGroup, type Content, type ContentBlock, type ContentEntry, type ContentModel, type ContentModelField, type ContentModelFieldType, type ContentModelFieldUi, type ContentPageResult, type ContentResponse, type ContentWidthToken, type CornerToken, DIALOG_SELECTOR, DOCK_BUDGET, DOCK_ICON_NAMES, DOCK_ICON_NAME_SET, type DeepReadonly, type DeliveredLayout, type DeliveryComponent, type DeliveryEntry, type DeliveryEntrySeo, type DeliveryList, type DeliveryPage, type DerivedLocator, type DockBudget, type DockFieldLike, type DockFieldsetLike, type DockIconName, type DockLane, type DockNode, type DockPropGroupLike, type DockScreen, type ElementLike, type ExpandedBinding, FOOTER_SECTION_ID, type FieldConfig, type Fieldset, type FieldsetKind, type FieldsetUiBefore, type FontSizeToken, type FooterBlock, type FooterColumn, type FooterProps, type Form, type FormBlock, type FormField, type FormProps, type FormSubmission, type HeadingBlock, type HeadingProps, type ImageBlock, type ImageProps, LANDMARK_SELECTOR, LAYOUT_SECTION_ICONS, LAYOUT_SECTION_ICON_SET, type LandmarkChainElement, type LandmarkElement, type LayoutComponentItem, type LayoutDataDocument, type LayoutFieldDefinition, type LayoutFieldItem, type LayoutFieldType, type LayoutScalarFieldType, type LayoutSection, type LayoutSectionIcon, type LayoutSectionItem, type LayoutStructureDocument, type LayoutZone, type LocatorGrammar, MAIN_SELECTOR, type ManagementLayoutCommand, type MediaAsset, type MediaCaptionTrack, type MediaFieldValue, NAVIGATION_SECTION_ID, type NavLink, type NavbarBlock, type NavbarProps, PAGE_CONTENT_ANCHOR_ID, type Page, type PageLayoutOverrideDataDocument, type PageLayoutOverrideDocument, type PageLayoutOverrideState, type PageLayoutOverrideStructureDocument, type PageLayoutSectionOverride, type PageLayoutSectionStructureOverride, type PageMetaJson, type PageOnlyLayoutSection, type PageSectionPlacement, type PaginatedResult, type Perspective, type PortableTextDocument, type PortableTextNode, type PropGroup, type RadiusToken, type Redirect, type ReservedLayoutSection, type ResolvedLayoutNode, type RichTextBlock, type RichTextProps, SECTION_DOCTRINE, SECTION_SPACE_TOKENS, SPACE_BOTTOM_TOKENS, SPACE_STEP_TOKENS, type SectionBlock, type SectionProps, type SectionSpaceToken, type ShadowToken, type SignInInput, type SignUpInput, type SiteSeoDefaults, type SlideItem, type SliderBlock, type SliderProps, type SpaceStepToken, type SpaceToken, type SpacerBlock, type SpacerProps, type TabItem, type TabsBlock, type TabsProps, type TextBlock, type TextProps, type ThemeToken, type UiBefore, type UiOrigin, type VariantInputMapping, type VideoBlock, type VideoProps, type WeightToken, type Workspace, type ZoneField, blockStyleToCss, blockStyleToInnerCss, buttonIconOf, buttonIconSvg, buttonLinkPairs, buttonValueOfInstance, buttonValueProblem, buttonVariantOf, candidateRole, componentInstanceAddresses, componentPropTargetKey, derivedPairs, dockBudget, dockScreens, expandBlockBindings, formatPropsAttribute, getBlockType, headingPaintCss, isBlock, isChromeLandmark, keyWords, landmarkRegions, locatorFor, parsePropsAttribute, readButtonValue, readPath, regionOf, safeCssUrl, spaceTokenCss, splitButtonStyle, withButtonLookProps };
|
package/dist/index.js
CHANGED
|
@@ -144,6 +144,38 @@ var FONT_SIZE_REM = {
|
|
|
144
144
|
var WEIGHT = { normal: 400, medium: 500, semibold: 600, bold: 700 };
|
|
145
145
|
var RADIUS_PX = { none: "0", sm: "4px", md: "8px", lg: "16px", full: "9999px" };
|
|
146
146
|
var COLOR_HEX = { white: "#ffffff", black: "#111111", muted: "#6b7280", mutedBg: "#f3f4f6", primary: "#111111", accent: "#4f46e5" };
|
|
147
|
+
var THEME = {
|
|
148
|
+
light: { colorScheme: "light", background: "#ffffff", color: "#111111" },
|
|
149
|
+
dark: { colorScheme: "dark", background: "#0b0b0d", color: "#f7f8f8" }
|
|
150
|
+
};
|
|
151
|
+
var BG_HEX = {
|
|
152
|
+
surface: "var(--bcms-bg-surface,#ffffff)",
|
|
153
|
+
muted: "var(--bcms-bg-muted,#f3f4f6)",
|
|
154
|
+
accent: "var(--bcms-bg-accent,#4f46e5)",
|
|
155
|
+
dark: "var(--bcms-bg-dark,#0b0b0d)"
|
|
156
|
+
};
|
|
157
|
+
var CORNER_PX = { "0": "0", s: "4px", m: "8px", l: "16px", xl: "24px", "2xl": "32px" };
|
|
158
|
+
var SHADOW_CSS = {
|
|
159
|
+
"0": "none",
|
|
160
|
+
s: "0 1px 2px rgba(0,0,0,.06)",
|
|
161
|
+
m: "0 4px 12px rgba(0,0,0,.08)",
|
|
162
|
+
l: "0 10px 24px rgba(0,0,0,.10)",
|
|
163
|
+
xl: "0 24px 48px rgba(0,0,0,.14)"
|
|
164
|
+
};
|
|
165
|
+
var HAIRLINE = "1px solid rgba(0,0,0,.10)";
|
|
166
|
+
var CONTENT_WIDTH_PX = { narrow: "640px", default: "1024px", wide: "1280px" };
|
|
167
|
+
var HEX = /^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/;
|
|
168
|
+
var clamp = (n, lo, hi) => Math.min(hi, Math.max(lo, n));
|
|
169
|
+
var own = (map, key) => typeof key === "string" && Object.prototype.hasOwnProperty.call(map, key) ? map[key] : void 0;
|
|
170
|
+
function safeCssUrl(raw) {
|
|
171
|
+
if (typeof raw !== "string") return "";
|
|
172
|
+
const url = raw.trim();
|
|
173
|
+
if (!url || url.length > 2e3) return "";
|
|
174
|
+
if (/["'()\\;]|\s/.test(url)) return "";
|
|
175
|
+
if (url.startsWith("//")) return "";
|
|
176
|
+
if (url.startsWith("/")) return url;
|
|
177
|
+
return /^https?:\/\//i.test(url) ? url : "";
|
|
178
|
+
}
|
|
147
179
|
function blockStyleToCss(style) {
|
|
148
180
|
if (!style || typeof style !== "object") return void 0;
|
|
149
181
|
const s = style;
|
|
@@ -178,9 +210,55 @@ function blockStyleToCss(style) {
|
|
|
178
210
|
if (s.fontSize && FONT_SIZE_REM[s.fontSize]) css.fontSize = FONT_SIZE_REM[s.fontSize];
|
|
179
211
|
if (s.weight && WEIGHT[s.weight] != null) css.fontWeight = WEIGHT[s.weight];
|
|
180
212
|
if (s.radius && RADIUS_PX[s.radius] != null) css.borderRadius = RADIUS_PX[s.radius];
|
|
213
|
+
const theme = own(THEME, s.theme);
|
|
214
|
+
if (theme) {
|
|
215
|
+
css.colorScheme = theme.colorScheme;
|
|
216
|
+
css.background = theme.background;
|
|
217
|
+
css.color = theme.color;
|
|
218
|
+
}
|
|
219
|
+
if (s.bg === "custom") {
|
|
220
|
+
if (HEX.test(s.bgCustom ?? "")) css.background = s.bgCustom;
|
|
221
|
+
} else if (own(BG_HEX, s.bg)) css.background = own(BG_HEX, s.bg);
|
|
222
|
+
const bgImage = safeCssUrl(s.bgImage);
|
|
223
|
+
if (bgImage) {
|
|
224
|
+
css.backgroundImage = `url(${bgImage})`;
|
|
225
|
+
css.backgroundSize = "cover";
|
|
226
|
+
css.backgroundPosition = "center";
|
|
227
|
+
}
|
|
228
|
+
const n = style;
|
|
229
|
+
if (!top && typeof n.paddingTop === "number") css.paddingTop = `${clamp(n.paddingTop, 0, 240)}px`;
|
|
230
|
+
if (!bottom && typeof n.paddingBottom === "number") css.paddingBottom = `${clamp(n.paddingBottom, 0, 240)}px`;
|
|
231
|
+
if (!sides && typeof n.paddingSides === "number") {
|
|
232
|
+
const px = `${clamp(n.paddingSides, 0, 240)}px`;
|
|
233
|
+
css.paddingLeft = px;
|
|
234
|
+
css.paddingRight = px;
|
|
235
|
+
}
|
|
236
|
+
if (n.fullHeight === true) {
|
|
237
|
+
css.minHeight = "100vh";
|
|
238
|
+
css.display = "flex";
|
|
239
|
+
css.flexDirection = "column";
|
|
240
|
+
css.justifyContent = "center";
|
|
241
|
+
}
|
|
242
|
+
if (typeof n.opacity === "number") css.opacity = clamp(n.opacity, 0, 100) / 100;
|
|
243
|
+
if (own(CORNER_PX, s.corner) != null) {
|
|
244
|
+
css.borderRadius = own(CORNER_PX, s.corner);
|
|
245
|
+
css.overflow = "hidden";
|
|
246
|
+
}
|
|
247
|
+
if (own(SHADOW_CSS, s.shadow)) css.boxShadow = own(SHADOW_CSS, s.shadow);
|
|
248
|
+
if (n.borderTop === true) css.borderTop = HAIRLINE;
|
|
249
|
+
if (n.borderBottom === true) css.borderBottom = HAIRLINE;
|
|
181
250
|
if (style.border === true) css.border = "1px solid currentColor";
|
|
182
251
|
return Object.keys(css).length ? css : void 0;
|
|
183
252
|
}
|
|
253
|
+
function blockStyleToInnerCss(style) {
|
|
254
|
+
if (!style || typeof style !== "object") return void 0;
|
|
255
|
+
const s = style;
|
|
256
|
+
const max = own(CONTENT_WIDTH_PX, s.contentWidth);
|
|
257
|
+
if (!max) return void 0;
|
|
258
|
+
const placement = s.contentAlign ?? s.align;
|
|
259
|
+
const margin = placement === "left" ? "0 auto 0 0" : placement === "right" ? "0 0 0 auto" : "0 auto";
|
|
260
|
+
return { maxWidth: max, margin };
|
|
261
|
+
}
|
|
184
262
|
function headingPaintCss(style, opts = {}) {
|
|
185
263
|
if (!style || typeof style !== "object") return void 0;
|
|
186
264
|
const s = style;
|
|
@@ -190,6 +268,35 @@ function headingPaintCss(style, opts = {}) {
|
|
|
190
268
|
if (s.weight && WEIGHT[s.weight] != null) css.fontWeight = WEIGHT[s.weight];
|
|
191
269
|
return css.fontSize !== void 0 || css.fontWeight !== void 0 ? css : void 0;
|
|
192
270
|
}
|
|
271
|
+
var BUTTON_PLACEMENT_KEYS = [
|
|
272
|
+
"align",
|
|
273
|
+
"contentAlign",
|
|
274
|
+
"contentWidth",
|
|
275
|
+
"marginTop",
|
|
276
|
+
"marginBottom",
|
|
277
|
+
"fullHeight",
|
|
278
|
+
"spaceTop",
|
|
279
|
+
"spaceBottom"
|
|
280
|
+
];
|
|
281
|
+
var PLACEMENT = new Set(BUTTON_PLACEMENT_KEYS);
|
|
282
|
+
function splitButtonStyle(style) {
|
|
283
|
+
if (!style || typeof style !== "object") return { placement: void 0, paint: void 0 };
|
|
284
|
+
const placement = {};
|
|
285
|
+
const rest = {};
|
|
286
|
+
for (const [k, v] of Object.entries(style)) {
|
|
287
|
+
if (k === "hover") continue;
|
|
288
|
+
(PLACEMENT.has(k) ? placement : rest)[k] = v;
|
|
289
|
+
}
|
|
290
|
+
const paint = { ...blockStyleToCss(rest) };
|
|
291
|
+
if (rest.bg === "none") {
|
|
292
|
+
paint.background = "transparent";
|
|
293
|
+
if (!rest.textColor) paint.color = "inherit";
|
|
294
|
+
}
|
|
295
|
+
return {
|
|
296
|
+
placement: Object.keys(placement).length ? placement : void 0,
|
|
297
|
+
paint: Object.keys(paint).length ? paint : void 0
|
|
298
|
+
};
|
|
299
|
+
}
|
|
193
300
|
|
|
194
301
|
// src/component.ts
|
|
195
302
|
var SECTION_DOCTRINE = "STRUCTURE (separate from schema): a page is composed of SECTIONS. NEVER build a page out of loose top-level heading/text/image/button/spacer blocks \u2014 they cannot be moved, duplicated or swapped as a unit, the visual editor cannot outline or name them, and every one of them becomes its own section in the editor. A hero of a headline, a lede and two CTAs is ONE section, not four. TWO SHAPES, and the choice is about REUSE. (1) A band that appears on more than one page, or that needs layout variants, is a COMPONENT with a `sectionType` \u2014 see create_component. Components sharing a `sectionType` are that section's VARIANTS (one Hero: 'Centered' for the home page and 'Two-column' for about, same prop keys so a swap keeps the content). This is also the only shape the editor's 'Add a section' picker can insert, and the only one that gets a family name and a variant switcher. (2) A genuinely one-off band on a single page is a `section` BLOCK whose `props.children` hold its blocks. THE TRADEOFF, stated in the present tense because it is real today: inside a component, ONLY the leaves a declared prop TARGETS are click-to-edit on the canvas \u2014 each declared prop's `target` is re-keyed to that PLACEMENT's own override address, so editing it changes this page and not the shared definition. A prop with no `target` still SHOWS as a dock control, but its override reaches no rendered slot, so editing it changes nothing on the page. Copy that no prop points at is worse still: no binding and no control, unreachable from click-to-edit AND from the dock, changeable only by editing the component definition, which rewrites every page that places it. A `section` block's children stay click-to-edit unconditionally. So when you choose a component, DECLARE A PROP \u2014 WITH A `target` \u2014 for every string, link and image a marketer will ever touch; a component with un-propped editable copy is the defect, not the component. In the dock an unset prop shows EMPTY and inherits the definition's default, so set props explicitly when you want the current copy visible there. An IMPORTED site's components are its own (read the repo); its nav, footer and modals are the Layout. On a blank site, do not hand-write a band's JSON: start from a built-in section blueprint (list_components returns locked `builtin:*` blueprints with no projectId \u2014 hero-centered, hero-split, feature-grid-three, cta-banner and nine more), each already rooted in a `section` block with its editable leaves declared as props. INLINE its blockJson as a `section` block for a one-off band; for a recurring band, materialize the blueprint with create_component so it becomes project-scoped before implementation validation, Output or publication. Direct `builtin:*` component references exist only for legacy delivery compatibility. Two consecutive call-to-action buttons are two sibling `button` blocks inside the same section \u2014 never a `columns` block, which is a `repeat(N,1fr)` grid and would stretch each CTA to half the container. Buttons are inline-level and flow side by side on their own.";
|
|
@@ -2593,8 +2700,48 @@ function candidateRole(candidate) {
|
|
|
2593
2700
|
const fromLabel = roleFromWords(candidate, keyWords(label.replace(/\s+/g, "_")));
|
|
2594
2701
|
return fromLabel ? { role: fromLabel.role, stems: fromLabel.stems.map((stem) => `label:${stem}`) } : null;
|
|
2595
2702
|
}
|
|
2703
|
+
var TAG_SEGMENTS = /* @__PURE__ */ new Set(["a", "span", "button", "div", "strong"]);
|
|
2704
|
+
var isScalarText = (value) => value === void 0 || value === null || typeof value === "string";
|
|
2705
|
+
function derivedPairs(candidates) {
|
|
2706
|
+
const out = /* @__PURE__ */ new Map();
|
|
2707
|
+
const leaf = (key) => key.split(".").pop() ?? "";
|
|
2708
|
+
const isText = (c) => TEXT_TYPES.has((c.type ?? "").toLowerCase()) && isScalarText(c.value) && !/[-_]href$/i.test(leaf(c.key));
|
|
2709
|
+
const sameButTag = (a, b) => {
|
|
2710
|
+
if (a === b) return true;
|
|
2711
|
+
const x = a.split(/[-_]/);
|
|
2712
|
+
const y = b.split(/[-_]/);
|
|
2713
|
+
if (x.length !== y.length) return false;
|
|
2714
|
+
let swapped = 0;
|
|
2715
|
+
for (let i = 0; i < x.length; i++) {
|
|
2716
|
+
if (x[i] === y[i]) continue;
|
|
2717
|
+
if (!TAG_SEGMENTS.has(x[i]) || !TAG_SEGMENTS.has(y[i])) return false;
|
|
2718
|
+
swapped++;
|
|
2719
|
+
}
|
|
2720
|
+
return swapped === 1;
|
|
2721
|
+
};
|
|
2722
|
+
candidates.forEach((link, linkIndex) => {
|
|
2723
|
+
if (out.has(linkIndex) || !LINK_TYPES.has((link.type ?? "").toLowerCase()) || !isScalarText(link.value)) return;
|
|
2724
|
+
const key = leaf(link.key);
|
|
2725
|
+
const suffix = /[-_]href$/i.exec(key);
|
|
2726
|
+
if (!suffix) return;
|
|
2727
|
+
const stem = key.slice(0, suffix.index);
|
|
2728
|
+
const parent = link.key.slice(0, link.key.length - key.length);
|
|
2729
|
+
const texts = candidates.map((text, textIndex) => ({ text, textIndex })).filter(
|
|
2730
|
+
({ text, textIndex }) => textIndex !== linkIndex && !out.has(textIndex) && isText(text) && text.key.startsWith(parent) && sameButTag(leaf(text.key), stem)
|
|
2731
|
+
);
|
|
2732
|
+
if (texts.length !== 1) return;
|
|
2733
|
+
const pair = `${texts[0].textIndex}:${linkIndex}`;
|
|
2734
|
+
out.set(texts[0].textIndex, { pair, role: "text" });
|
|
2735
|
+
out.set(linkIndex, { pair, role: "link" });
|
|
2736
|
+
});
|
|
2737
|
+
return out;
|
|
2738
|
+
}
|
|
2596
2739
|
function buttonLinkPairs(candidates) {
|
|
2597
|
-
const
|
|
2740
|
+
const derived = derivedPairs(candidates);
|
|
2741
|
+
const roles = candidates.map((candidate, index) => {
|
|
2742
|
+
const half = derived.get(index);
|
|
2743
|
+
return half ? { role: half.role, stems: [`derived:${half.pair}`] } : candidateRole(candidate);
|
|
2744
|
+
});
|
|
2598
2745
|
const byStem = /* @__PURE__ */ new Map();
|
|
2599
2746
|
roles.forEach((role, index) => {
|
|
2600
2747
|
if (!role) return;
|
|
@@ -2778,6 +2925,7 @@ export {
|
|
|
2778
2925
|
BUTTON_ICONS,
|
|
2779
2926
|
BUTTON_ICON_NAMES,
|
|
2780
2927
|
BUTTON_LOOK_KEYS,
|
|
2928
|
+
BUTTON_PLACEMENT_KEYS,
|
|
2781
2929
|
BUTTON_SIZES,
|
|
2782
2930
|
BUTTON_VARIANTS,
|
|
2783
2931
|
COMPONENT_PROP_TYPES,
|
|
@@ -2797,6 +2945,7 @@ export {
|
|
|
2797
2945
|
SPACE_BOTTOM_TOKENS,
|
|
2798
2946
|
SPACE_STEP_TOKENS,
|
|
2799
2947
|
blockStyleToCss,
|
|
2948
|
+
blockStyleToInnerCss,
|
|
2800
2949
|
buttonIconOf,
|
|
2801
2950
|
buttonIconSvg,
|
|
2802
2951
|
buttonLinkPairs,
|
|
@@ -2806,6 +2955,7 @@ export {
|
|
|
2806
2955
|
candidateRole,
|
|
2807
2956
|
componentInstanceAddresses,
|
|
2808
2957
|
componentPropTargetKey,
|
|
2958
|
+
derivedPairs,
|
|
2809
2959
|
dockBudget,
|
|
2810
2960
|
dockScreens,
|
|
2811
2961
|
expandBlockBindings,
|
|
@@ -2821,7 +2971,9 @@ export {
|
|
|
2821
2971
|
readButtonValue,
|
|
2822
2972
|
readPath,
|
|
2823
2973
|
regionOf,
|
|
2974
|
+
safeCssUrl,
|
|
2824
2975
|
spaceTokenCss,
|
|
2976
|
+
splitButtonStyle,
|
|
2825
2977
|
withButtonLookProps
|
|
2826
2978
|
};
|
|
2827
2979
|
//# sourceMappingURL=index.js.map
|