bearminion 1.1.0 → 1.2.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/CHANGELOG.md +18 -0
- package/README.md +2 -2
- package/dist/astro.d.ts +2 -2
- package/dist/astro.js +15 -2
- package/dist/content.d.ts +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.js +60 -8
- package/dist/{options-CxRzVfhi.d.ts → options-CLrSA8kL.d.ts} +1 -1
- package/dist/{page-DgQlGree.d.ts → page-dUWFHv9j.d.ts} +41 -8
- package/dist/preview-BqrZLvQ6.js +125 -0
- package/dist/rich-text.d.ts +1 -1
- package/dist/rich-text.js +18 -1
- package/dist/theme-q19C8cIc.js +58 -0
- package/dist/ui/mount.js +246 -65
- package/package.json +1 -1
- package/dist/preview-C9MHO88K.js +0 -55
- package/dist/theme-DZkec408.js +0 -33
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
# bearminion
|
|
2
2
|
|
|
3
|
+
## 1.2.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 4c3f823: Rich text has inline code: text between backticks is stored as `` `code` ``, rendered as `<code>`, and toggled with a new Code button in the on-page format bar. Nothing inside code is parsed as markdown. List items under `points` are edited as rich text in the sidebar.
|
|
8
|
+
- 19c1e5a: Section tab controls follow the section's schema instead of guessing from values:
|
|
9
|
+
|
|
10
|
+
- Any string enum inside a section's props (such as a list item's `icon`) is a choice in the sidebar instead of a free text box. A new `icons` option on `defineSection` draws the choices of a field as an icon grid: `icons: { 'steps[].icon': { terminal: 'M4 5h16…', … } }`, SVG path data on a 24 × 24 grid, one per choice.
|
|
11
|
+
- A new `showWhen` option on `defineSection` hides props the section's options make unused, such as `{ poster: { kind: 'video' } }`. A list matches any of its values, and `variant`, `tone` and `motion` count as options. Hidden props keep their value in the file.
|
|
12
|
+
- Variant, tone and choice options with up to four choices are segmented controls instead of selects.
|
|
13
|
+
- An image prop that is missing from the content now offers an image slot whatever it is called. It used to be a text box unless the prop was named `image` or `logo`, so a missing `poster` could not be set.
|
|
14
|
+
|
|
15
|
+
`defineSection` checks `icons` and `showWhen` against the schema and options and throws on a mistake. `GET /schema` serves `fieldChoices`, `fieldIcons`, `fieldImages` and `showWhen`.
|
|
16
|
+
|
|
17
|
+
### Patch Changes
|
|
18
|
+
|
|
19
|
+
- 9261888: The live preview now runs the scripts of a section type that was not on the page before, so a section added from the picker works before you save (a copy button, a looping video). A sidebar value that has no text of its own on the page, such as a video link or a section option, now updates the preview as you change it instead of after a save.
|
|
20
|
+
|
|
3
21
|
## 1.1.0
|
|
4
22
|
|
|
5
23
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -33,8 +33,8 @@ It asks for the site's name and web address. Open the address `npm run dev` prin
|
|
|
33
33
|
|
|
34
34
|
## What you can change
|
|
35
35
|
|
|
36
|
-
- **Text** right on the page, with bold, italic, links and lists
|
|
37
|
-
- **Sections**:
|
|
36
|
+
- **Text** right on the page, with bold, italic, code, links and lists
|
|
37
|
+
- **Sections**: thirteen ready-made types, each with three layouts, added from a visual picker
|
|
38
38
|
- **Pages, menus and footer**, with titles and descriptions for search and sharing
|
|
39
39
|
- **Images**: upload, choose how they fill their frame and which part stays in view
|
|
40
40
|
- **Colors**: pick three, and the editor builds a full light and dark palette that stays readable
|
package/dist/astro.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { a as StoreKeyError, c as createFileStore, i as FileStoreOptions, n as EditorContext, o as StoreOperation, r as ContentStore, s as UploadStore, t as BearminionOptions } from "./options-
|
|
1
|
+
import { M as SiteDefinition, N as SiteOf, g as SectionRegistry, h as ContentModel, jt as ContentMigrator, t as Page, u as SectionOf } from "./page-dUWFHv9j.js";
|
|
2
|
+
import { a as StoreKeyError, c as createFileStore, i as FileStoreOptions, n as EditorContext, o as StoreOperation, r as ContentStore, s as UploadStore, t as BearminionOptions } from "./options-CLrSA8kL.js";
|
|
3
3
|
import { AstroIntegration } from "astro";
|
|
4
4
|
//#region src/integration.d.ts
|
|
5
5
|
interface BearminionIntegration extends AstroIntegration {
|
package/dist/astro.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { a as ContentReadError,
|
|
1
|
+
import { a as imageFields, c as ContentReadError, l as ContentValidationError, r as loadThemePreview, t as PreviewUnavailableError } from "./preview-BqrZLvQ6.js";
|
|
2
|
+
import { t as defaultTheme } from "./theme-q19C8cIc.js";
|
|
2
3
|
import { i as isSystemPage, n as createPageSchema$1, r as createTolerantPageSchema, s as withoutOrphanSections, u as isOrphanSection } from "./page-C0l3CIuz.js";
|
|
3
|
-
import { t as defaultTheme } from "./theme-DZkec408.js";
|
|
4
4
|
import { a as DEFAULT_UPLOADS_DIR, i as DEFAULT_CONTENT_DIR, n as createMigrator, r as API_PREFIX, t as SCHEMA_VERSION_KEY } from "./migrate-B56wxCiC.js";
|
|
5
5
|
import { a as JSON_BODY_LIMIT, c as isInside, d as resolveDir, f as resolveInside, i as IMAGE_BYTE_LIMIT, l as isLocalRequest, n as contentReloadPlugin, o as MULTIPART_BODY_LIMIT, r as dropEarlyReloadAfterSave, s as asDirectory, u as readSlug } from "./reload-COk8Nncw.js";
|
|
6
6
|
import { S as isAssetPath, b as describeSiteRef, c as projectId, v as assetRefs, y as describePageRef } from "./draft-store-1Y4-sn45.js";
|
|
@@ -657,6 +657,10 @@ async function getSchema(context) {
|
|
|
657
657
|
const sectionOptions = {};
|
|
658
658
|
const optionalContent = {};
|
|
659
659
|
const contentCounts = { ...context.site.counts };
|
|
660
|
+
const fieldChoices = {};
|
|
661
|
+
const fieldIcons = {};
|
|
662
|
+
const showWhen = {};
|
|
663
|
+
const fieldImages = {};
|
|
660
664
|
for (const definition of Object.values(context.sections)) {
|
|
661
665
|
const type = definition.type;
|
|
662
666
|
sectionDefaults[type] = definition.defaults;
|
|
@@ -666,6 +670,11 @@ async function getSchema(context) {
|
|
|
666
670
|
sectionOptions[type] = definition.options;
|
|
667
671
|
optionalContent[type] = definition.optional;
|
|
668
672
|
if (Object.keys(definition.counts).length > 0) contentCounts[type] = { ...definition.counts };
|
|
673
|
+
if (Object.keys(definition.choices).length > 0) fieldChoices[type] = definition.choices;
|
|
674
|
+
if (Object.keys(definition.icons).length > 0) fieldIcons[type] = definition.icons;
|
|
675
|
+
if (Object.keys(definition.showWhen).length > 0) showWhen[type] = definition.showWhen;
|
|
676
|
+
const images = imageFields(definition.schema);
|
|
677
|
+
if (images.length > 0) fieldImages[type] = images;
|
|
669
678
|
}
|
|
670
679
|
return json(200, {
|
|
671
680
|
sectionOptions,
|
|
@@ -674,6 +683,10 @@ async function getSchema(context) {
|
|
|
674
683
|
theme: context.theme,
|
|
675
684
|
contentCounts,
|
|
676
685
|
optionalContent,
|
|
686
|
+
fieldChoices,
|
|
687
|
+
fieldIcons,
|
|
688
|
+
fieldImages,
|
|
689
|
+
showWhen,
|
|
677
690
|
sectionDefaults,
|
|
678
691
|
sectionLabels,
|
|
679
692
|
sectionDescriptions,
|
package/dist/content.d.ts
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { $ as textMarkSchema, A as Site, At as
|
|
1
|
+
import { $ as textMarkSchema, A as Site, At as ContentMigration, B as themeColorsSchema, C as DEFAULT_MAX_FOOTER_COLUMNS, Ct as toneOption, D as FooterConfig, Dt as FieldIcons, E as FooterColumn, Et as FieldChoices, F as SiteWith, Ft as createMigrator, G as MAX_NAV_DEPTH, H as ButtonStyle, I as Theme, J as Tone, K as RichText, L as brandLogoSchema, M as SiteDefinition, Mt as ContentVersioning, N as SiteOf, Nt as DocumentKind, O as Header, Ot as ShowCondition, P as SiteSeo, Pt as SCHEMA_VERSION_KEY, Q as richTextSchema, R as defineSite, S as BRAND_LOGO_HEIGHT, St as themeModes, T as Footer, Tt as variantOption, U as Image, V as themeSchema, W as Link, X as imageSchema, Y as htmlIdSchema, Z as linkSchema, _ as ThemeConfig, _t as NumberOption, a as isSystemPage, at as SectionDefinition, b as defaultTheme, bt as buttonStyles, c as BaseSection, ct as WireRect, d as anchorSchema, dt as wireKinds, et as textSchema, f as createSectionSchema, ft as wireframeIssues, g as SectionRegistry, gt as EnumOption, h as ContentModel, ht as CountRule, i as createPageSchema, it as SectionConfig, j as SiteConfig, jt as ContentMigrator, k as HeaderConfig, kt as ShowWhen, l as PropsOf, lt as Wireframe, m as API_PREFIX, mt as BooleanOption, n as SYSTEM_PAGES, nt as trackingIdSchema, o as seoSchema, ot as defineSection, p as sectionIdSchema, pt as OptionalContent, q as Text, r as Seo, rt as withEmphasis, s as withoutOrphanSections, st as WireKind, t as Page, tt as toneSchema, u as SectionOf, ut as defineWireframe, v as ThemeDefinition, vt as Option, w as DEFAULT_MAX_HEADER_ACTIONS, wt as tones, x as defineTheme, xt as motionOption, y as ThemeFont, yt as StringOption, z as siteSeoSchema } from "./page-dUWFHv9j.js";
|
|
2
2
|
import { _ as renderMarkedHtml, a as WeightMark, f as markClass, g as reconcileMarks, i as TextRun, l as fontMarks, m as marksFromEmphasis, o as applyTextMark, r as TextMark, t as FontMark, v as splitMarkedText, y as weightMarks } from "./marks-BzLa48Y9.js";
|
|
3
|
-
import "./options-
|
|
3
|
+
import "./options-CLrSA8kL.js";
|
|
4
4
|
//#region src/errors.d.ts
|
|
5
5
|
/** One schema problem, addressed by a dot path such as `sections.0.props.heading`. */
|
|
6
6
|
interface ContentIssue {
|
|
@@ -224,4 +224,4 @@ interface ContrastCheck {
|
|
|
224
224
|
/** Text pairs a visitor reads: text on its background, label on the accent fill, link on its background. */
|
|
225
225
|
export declare function contrastChecks(colors: ThemeColors | undefined): ContrastCheck[];
|
|
226
226
|
//#endregion
|
|
227
|
-
export { API_PREFIX, type ApiIssue, type ApiProblem, BRAND_LOGO_HEIGHT, type BaseSection, type BooleanOption, type ButtonStyle, type ChangedFile, type CommitRequest, type CommitResult, type ContentIssue, type ContentMigration, type ContentMigrator, type ContentModel, type ContentVersioning, type ContrastCheck, type CountRule, type CreatePageRequest, DEFAULT_MAX_FOOTER_COLUMNS, DEFAULT_MAX_HEADER_ACTIONS, type DocumentKind, type EnumOption, type FontMark, type Footer, type FooterColumn, type FooterConfig, type GitInfo, type Header, type HeaderConfig, type HistoryEntry, type Image, type ImageFit, type ImagePosition, type Link, MAX_NAV_DEPTH, type NumberOption, type Option, type OptionalContent, type Page, type PageListItem, type PropsOf, type RichText, SCHEMA_VERSION_KEY, SYSTEM_PAGES, type SaveRequest, type SaveResponse, type SectionConfig, type SectionDefinition, type SectionOf, type SectionRegistry, type Seo, type Site, type SiteConfig, type SiteDefinition, type SiteOf, type SitePreview, type SitePreviewHtml, type SiteSeo, type SiteWith, type StringOption, type Text, type TextMark, type TextRun, type Theme, type ThemeColors, type ThemeConfig, type ThemeDefinition, type ThemeFont, type ThemePreview, type Tone, type UploadedImage, type WeightMark, type WireKind, type WireRect, type Wireframe, anchorSchema, applyTextMark, brandLogoSchema, buttonStyles, createMigrator, createPageSchema, createSectionSchema, defaultTheme, defineSection, defineSite, defineTheme, defineWireframe, fontMarks, htmlIdSchema, imageSchema, isSystemPage, linkSchema, markClass, marksFromEmphasis, motionOption, reconcileMarks, renderMarkedHtml, richTextSchema, sectionIdSchema, seoSchema, siteSeoSchema, splitMarkedText, textMarkSchema, textSchema, themeColorsSchema, themeModes, themeSchema, toneOption, toneSchema, tones, trackingIdSchema, variantOption, weightMarks, wireKinds, wireframeIssues, withEmphasis, withoutOrphanSections };
|
|
227
|
+
export { API_PREFIX, type ApiIssue, type ApiProblem, BRAND_LOGO_HEIGHT, type BaseSection, type BooleanOption, type ButtonStyle, type ChangedFile, type CommitRequest, type CommitResult, type ContentIssue, type ContentMigration, type ContentMigrator, type ContentModel, type ContentVersioning, type ContrastCheck, type CountRule, type CreatePageRequest, DEFAULT_MAX_FOOTER_COLUMNS, DEFAULT_MAX_HEADER_ACTIONS, type DocumentKind, type EnumOption, type FieldChoices, type FieldIcons, type FontMark, type Footer, type FooterColumn, type FooterConfig, type GitInfo, type Header, type HeaderConfig, type HistoryEntry, type Image, type ImageFit, type ImagePosition, type Link, MAX_NAV_DEPTH, type NumberOption, type Option, type OptionalContent, type Page, type PageListItem, type PropsOf, type RichText, SCHEMA_VERSION_KEY, SYSTEM_PAGES, type SaveRequest, type SaveResponse, type SectionConfig, type SectionDefinition, type SectionOf, type SectionRegistry, type Seo, type ShowCondition, type ShowWhen, type Site, type SiteConfig, type SiteDefinition, type SiteOf, type SitePreview, type SitePreviewHtml, type SiteSeo, type SiteWith, type StringOption, type Text, type TextMark, type TextRun, type Theme, type ThemeColors, type ThemeConfig, type ThemeDefinition, type ThemeFont, type ThemePreview, type Tone, type UploadedImage, type WeightMark, type WireKind, type WireRect, type Wireframe, anchorSchema, applyTextMark, brandLogoSchema, buttonStyles, createMigrator, createPageSchema, createSectionSchema, defaultTheme, defineSection, defineSite, defineTheme, defineWireframe, fontMarks, htmlIdSchema, imageSchema, isSystemPage, linkSchema, markClass, marksFromEmphasis, motionOption, reconcileMarks, renderMarkedHtml, richTextSchema, sectionIdSchema, seoSchema, siteSeoSchema, splitMarkedText, textMarkSchema, textSchema, themeColorsSchema, themeModes, themeSchema, toneOption, toneSchema, tones, trackingIdSchema, variantOption, weightMarks, wireKinds, wireframeIssues, withEmphasis, withoutOrphanSections };
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { c as ContentReadError, i as enumFields, l as ContentValidationError, n as defineThemePreview, o as schemaProps, s as ContentError, u as formatContentIssues } from "./preview-BqrZLvQ6.js";
|
|
2
|
+
import { n as defineTheme, t as defaultTheme } from "./theme-q19C8cIc.js";
|
|
2
3
|
import { C as withEmphasis, D as IMAGE_POSITIONS, E as IMAGE_FITS, F as tones, I as variantOption, M as motionOption, N as themeModes, O as isImageFit, P as toneOption, S as trackingIdSchema, T as DEFAULT_IMAGE_POSITION, _ as linkSchema, a as seoSchema, b as textSchema, c as anchorSchema, d as sectionIdSchema, f as walkLinkIds, g as imageSchema, h as htmlIdSchema, i as isSystemPage, j as buttonStyles, k as isImagePosition, l as createSectionSchema, m as addMarkIssues, n as createPageSchema, p as MAX_NAV_DEPTH, s as withoutOrphanSections, t as SYSTEM_PAGES, v as richTextSchema, w as DEFAULT_IMAGE_FIT, x as toneSchema, y as textMarkSchema } from "./page-C0l3CIuz.js";
|
|
3
4
|
import { applyTextMark, fontMarks, markClass, marksFromEmphasis, reconcileMarks, renderMarkedHtml, splitMarkedText, weightMarks } from "./marks.js";
|
|
4
|
-
import { n as defineTheme, t as defaultTheme } from "./theme-DZkec408.js";
|
|
5
5
|
import { n as createMigrator, r as API_PREFIX, t as SCHEMA_VERSION_KEY } from "./migrate-B56wxCiC.js";
|
|
6
6
|
import { a as contrastRatio, c as hasThemeColors, d as tokenToHex, i as contrastChecks, l as hexToToken, n as HEX_COLOR, o as derivePalette, s as hasOverrides, u as themeCss } from "./theme-colors-BneXpLYG.js";
|
|
7
7
|
import { z } from "zod";
|
|
@@ -79,6 +79,17 @@ function defineSection(config) {
|
|
|
79
79
|
if (!config.variants.includes(config.defaultVariant)) throw new Error(`Section "${config.type}": the default variant "${config.defaultVariant}" is not one of its variants.`);
|
|
80
80
|
const wireIssues = wireframeIssues(config.wireframe);
|
|
81
81
|
if (wireIssues.length > 0) throw new Error(`Invalid wireframe for section "${config.type}":\n${wireIssues.join("\n")}`);
|
|
82
|
+
const options = [
|
|
83
|
+
variantOption(config.variants, config.defaultVariant),
|
|
84
|
+
toneOption,
|
|
85
|
+
motionOption,
|
|
86
|
+
...config.options ?? []
|
|
87
|
+
];
|
|
88
|
+
const choices = enumFields(config.schema);
|
|
89
|
+
const icons = config.icons ?? {};
|
|
90
|
+
const showWhen = config.showWhen ?? {};
|
|
91
|
+
const ruleIssues = [...iconIssues(icons, choices), ...showWhenIssues(showWhen, options, schemaProps(config.schema))];
|
|
92
|
+
if (ruleIssues.length > 0) throw new Error(`Invalid field rules for section "${config.type}":\n${ruleIssues.map((issue) => ` - ${issue}`).join("\n")}`);
|
|
82
93
|
return Object.freeze({
|
|
83
94
|
type: config.type,
|
|
84
95
|
label: config.label,
|
|
@@ -87,18 +98,59 @@ function defineSection(config) {
|
|
|
87
98
|
defaults: parsed.data,
|
|
88
99
|
variants: config.variants,
|
|
89
100
|
defaultVariant: config.defaultVariant,
|
|
90
|
-
options: Object.freeze(
|
|
91
|
-
variantOption(config.variants, config.defaultVariant),
|
|
92
|
-
toneOption,
|
|
93
|
-
motionOption,
|
|
94
|
-
...config.options ?? []
|
|
95
|
-
]),
|
|
101
|
+
options: Object.freeze(options),
|
|
96
102
|
optional: config.optional,
|
|
97
103
|
counts: config.counts ?? {},
|
|
98
104
|
wireframe: config.wireframe,
|
|
105
|
+
choices,
|
|
106
|
+
icons,
|
|
107
|
+
showWhen,
|
|
99
108
|
refine: config.refine
|
|
100
109
|
});
|
|
101
110
|
}
|
|
111
|
+
function iconIssues(icons, choices) {
|
|
112
|
+
const issues = [];
|
|
113
|
+
for (const [key, byChoice] of Object.entries(icons)) {
|
|
114
|
+
const values = choices[key];
|
|
115
|
+
if (!values) {
|
|
116
|
+
issues.push(`icons.${key}: no field "${key}" with fixed choices in the schema`);
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
for (const value of values) if (typeof byChoice[value] !== "string" || byChoice[value] === "") issues.push(`icons.${key}: no icon for "${value}"`);
|
|
120
|
+
for (const value of Object.keys(byChoice)) if (!values.includes(value)) issues.push(`icons.${key}: "${value}" is not one of its choices`);
|
|
121
|
+
}
|
|
122
|
+
return issues;
|
|
123
|
+
}
|
|
124
|
+
function showWhenIssues(showWhen, options, props) {
|
|
125
|
+
const issues = [];
|
|
126
|
+
const optionNames = new Set(options.map((option) => option.name));
|
|
127
|
+
for (const [prop, rule] of Object.entries(showWhen)) {
|
|
128
|
+
if (!props.includes(prop)) issues.push(`showWhen.${prop}: no prop "${prop}" in the schema`);
|
|
129
|
+
if (optionNames.has(prop)) issues.push(`showWhen.${prop}: "${prop}" is an option; showWhen applies to content props`);
|
|
130
|
+
for (const [name, condition] of Object.entries(rule)) {
|
|
131
|
+
const option = options.find((item) => item.name === name);
|
|
132
|
+
if (!option) {
|
|
133
|
+
issues.push(`showWhen.${prop}.${name}: no option "${name}"`);
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
if (option.type === "boolean") {
|
|
137
|
+
if (typeof condition !== "boolean") issues.push(`showWhen.${prop}.${name}: "${name}" is on or off, so use true or false`);
|
|
138
|
+
continue;
|
|
139
|
+
}
|
|
140
|
+
if (option.type !== "enum") {
|
|
141
|
+
issues.push(`showWhen.${prop}.${name}: only choice and on/off options can show or hide a prop`);
|
|
142
|
+
continue;
|
|
143
|
+
}
|
|
144
|
+
const wanted = typeof condition === "string" ? [condition] : Array.isArray(condition) ? condition : null;
|
|
145
|
+
if (wanted === null || wanted.length === 0) {
|
|
146
|
+
issues.push(`showWhen.${prop}.${name}: use one of ${option.choices.join(", ")}, or a list of them`);
|
|
147
|
+
continue;
|
|
148
|
+
}
|
|
149
|
+
for (const value of wanted) if (!option.choices.includes(value)) issues.push(`showWhen.${prop}.${name}: "${value}" is not one of ${option.choices.join(", ")}`);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
return issues;
|
|
153
|
+
}
|
|
102
154
|
//#endregion
|
|
103
155
|
//#region src/site.ts
|
|
104
156
|
const hexColor = z.string().regex(HEX_COLOR, "Use a #rrggbb color.");
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { M as SiteDefinition, g as SectionRegistry, h as ContentModel, jt as ContentMigrator, v as ThemeDefinition } from "./page-dUWFHv9j.js";
|
|
2
2
|
//#region src/images.d.ts
|
|
3
3
|
type ImageKind = 'png' | 'jpeg' | 'webp' | 'gif' | 'avif';
|
|
4
4
|
interface SavedImage {
|
|
@@ -36,6 +36,22 @@ interface ContentMigrator {
|
|
|
36
36
|
}
|
|
37
37
|
declare function createMigrator(versioning?: ContentVersioning): ContentMigrator;
|
|
38
38
|
//#endregion
|
|
39
|
+
//#region src/field-rules.d.ts
|
|
40
|
+
/**
|
|
41
|
+
* Field rules a section declares beside its schema, in a form the editor overlay can read without zod.
|
|
42
|
+
*
|
|
43
|
+
* - Field keys name a place in `props` the same way for every item of a list: `steps[].icon`, `badge.tag`.
|
|
44
|
+
* - `showWhen` keeps a prop out of the sidebar unless the section's options have the given values.
|
|
45
|
+
*/
|
|
46
|
+
/** A choice an option must have, or a list of choices any of which will do. */
|
|
47
|
+
type ShowCondition = string | boolean | readonly string[];
|
|
48
|
+
/** Prop name → option name → the value(s) that show it. Every option listed must match. */
|
|
49
|
+
type ShowWhen = Readonly<Record<string, Readonly<Record<string, ShowCondition>>>>;
|
|
50
|
+
/** Field key → fixed choices, derived from the schema's enums. */
|
|
51
|
+
type FieldChoices = Readonly<Record<string, readonly string[]>>;
|
|
52
|
+
/** Field key → choice → SVG path data on a 24 × 24 grid, drawn as a stroke. */
|
|
53
|
+
type FieldIcons = Readonly<Record<string, Readonly<Record<string, string>>>>;
|
|
54
|
+
//#endregion
|
|
39
55
|
//#region src/section-options.d.ts
|
|
40
56
|
/**
|
|
41
57
|
* Design-system option catalog.
|
|
@@ -154,6 +170,9 @@ declare function defineWireframe(wireframe: Wireframe): Wireframe;
|
|
|
154
170
|
* - `optional` names the props an author may drop.
|
|
155
171
|
* - `counts` holds item-count rules per array prop.
|
|
156
172
|
* - `wireframe` is the thumbnail in the Add section picker.
|
|
173
|
+
* - `choices` lists every string enum in `props` (derived from the schema); the sidebar offers them as choices.
|
|
174
|
+
* - `icons` draws those choices as icons in the sidebar's picker.
|
|
175
|
+
* - `showWhen` hides props in the sidebar while the section's options make them unused.
|
|
157
176
|
*/
|
|
158
177
|
interface SectionDefinition<TType extends string = string, TSchema extends z.ZodType = z.ZodType, TVariant extends string = string> {
|
|
159
178
|
readonly type: TType;
|
|
@@ -168,6 +187,9 @@ interface SectionDefinition<TType extends string = string, TSchema extends z.Zod
|
|
|
168
187
|
readonly optional: OptionalContent;
|
|
169
188
|
readonly counts: Readonly<Record<string, CountRule>>;
|
|
170
189
|
readonly wireframe: Wireframe;
|
|
190
|
+
readonly choices: FieldChoices;
|
|
191
|
+
readonly icons: FieldIcons;
|
|
192
|
+
readonly showWhen: ShowWhen;
|
|
171
193
|
/** Cross-field rules the schema cannot express, such as a variant that needs an exact item count. */
|
|
172
194
|
refine?(section: {
|
|
173
195
|
variant: TVariant;
|
|
@@ -187,6 +209,17 @@ interface SectionConfig<TType extends string, TSchema extends z.ZodType, TVarian
|
|
|
187
209
|
optional: OptionalContent;
|
|
188
210
|
counts?: Readonly<Record<string, CountRule>>;
|
|
189
211
|
wireframe: Wireframe;
|
|
212
|
+
/**
|
|
213
|
+
* Icons for a fixed-choice field, shown in the sidebar's picker instead of the choice names alone. Keyed by field
|
|
214
|
+
* (`steps[].icon`, list items as `[]`), then by choice: SVG path data on a 24 × 24 grid, drawn as a 1.8 stroke.
|
|
215
|
+
* Every choice of the field needs one.
|
|
216
|
+
*/
|
|
217
|
+
icons?: FieldIcons;
|
|
218
|
+
/**
|
|
219
|
+
* Props the sidebar shows only while options have these values, such as `{ poster: { kind: 'video' } }`. A list
|
|
220
|
+
* means any of its values; `variant`, `tone` and `motion` count as options. A hidden prop keeps its value in the file.
|
|
221
|
+
*/
|
|
222
|
+
showWhen?: ShowWhen;
|
|
190
223
|
refine?(section: {
|
|
191
224
|
variant: TVariants[number];
|
|
192
225
|
props: z.infer<TSchema>;
|
|
@@ -238,10 +271,10 @@ declare const textMarkSchema: z.ZodObject<{
|
|
|
238
271
|
start: z.ZodNumber;
|
|
239
272
|
end: z.ZodNumber;
|
|
240
273
|
weight: z.ZodOptional<z.ZodEnum<{
|
|
274
|
+
bold: "bold";
|
|
241
275
|
regular: "regular";
|
|
242
276
|
medium: "medium";
|
|
243
277
|
semibold: "semibold";
|
|
244
|
-
bold: "bold";
|
|
245
278
|
}>>;
|
|
246
279
|
italic: z.ZodOptional<z.ZodBoolean>;
|
|
247
280
|
font: z.ZodOptional<z.ZodEnum<{
|
|
@@ -282,10 +315,10 @@ declare function withEmphasis<T extends z.ZodRawShape>(shape: T): z.ZodPipe<z.Zo
|
|
|
282
315
|
start: z.ZodNumber;
|
|
283
316
|
end: z.ZodNumber;
|
|
284
317
|
weight: z.ZodOptional<z.ZodEnum<{
|
|
318
|
+
bold: "bold";
|
|
285
319
|
regular: "regular";
|
|
286
320
|
medium: "medium";
|
|
287
321
|
semibold: "semibold";
|
|
288
|
-
bold: "bold";
|
|
289
322
|
}>>;
|
|
290
323
|
italic: z.ZodOptional<z.ZodBoolean>;
|
|
291
324
|
font: z.ZodOptional<z.ZodEnum<{
|
|
@@ -300,10 +333,10 @@ declare function withEmphasis<T extends z.ZodRawShape>(shape: T): z.ZodPipe<z.Zo
|
|
|
300
333
|
start: z.ZodNumber;
|
|
301
334
|
end: z.ZodNumber;
|
|
302
335
|
weight: z.ZodOptional<z.ZodEnum<{
|
|
336
|
+
bold: "bold";
|
|
303
337
|
regular: "regular";
|
|
304
338
|
medium: "medium";
|
|
305
339
|
semibold: "semibold";
|
|
306
|
-
bold: "bold";
|
|
307
340
|
}>>;
|
|
308
341
|
italic: z.ZodOptional<z.ZodBoolean>;
|
|
309
342
|
font: z.ZodOptional<z.ZodEnum<{
|
|
@@ -320,10 +353,10 @@ declare function withEmphasis<T extends z.ZodRawShape>(shape: T): z.ZodPipe<z.Zo
|
|
|
320
353
|
start: z.ZodNumber;
|
|
321
354
|
end: z.ZodNumber;
|
|
322
355
|
weight: z.ZodOptional<z.ZodEnum<{
|
|
356
|
+
bold: "bold";
|
|
323
357
|
regular: "regular";
|
|
324
358
|
medium: "medium";
|
|
325
359
|
semibold: "semibold";
|
|
326
|
-
bold: "bold";
|
|
327
360
|
}>>;
|
|
328
361
|
italic: z.ZodOptional<z.ZodBoolean>;
|
|
329
362
|
font: z.ZodOptional<z.ZodEnum<{
|
|
@@ -553,10 +586,10 @@ declare function createSiteSchema(header: HeaderParts, footer: FooterParts): z.Z
|
|
|
553
586
|
start: z.ZodNumber;
|
|
554
587
|
end: z.ZodNumber;
|
|
555
588
|
weight: z.ZodOptional<z.ZodEnum<{
|
|
589
|
+
bold: "bold";
|
|
556
590
|
regular: "regular";
|
|
557
591
|
medium: "medium";
|
|
558
592
|
semibold: "semibold";
|
|
559
|
-
bold: "bold";
|
|
560
593
|
}>>;
|
|
561
594
|
italic: z.ZodOptional<z.ZodBoolean>;
|
|
562
595
|
font: z.ZodOptional<z.ZodEnum<{
|
|
@@ -769,7 +802,7 @@ declare function createSiteSchema(header: HeaderParts, footer: FooterParts): z.Z
|
|
|
769
802
|
nameMarks: {
|
|
770
803
|
start: number;
|
|
771
804
|
end: number;
|
|
772
|
-
weight?: "
|
|
805
|
+
weight?: "bold" | "regular" | "medium" | "semibold" | undefined;
|
|
773
806
|
italic?: boolean | undefined;
|
|
774
807
|
font?: "sans" | "serif" | "mono" | undefined;
|
|
775
808
|
}[] | undefined;
|
|
@@ -1010,7 +1043,7 @@ declare function createSiteSchema(header: HeaderParts, footer: FooterParts): z.Z
|
|
|
1010
1043
|
nameMarks?: {
|
|
1011
1044
|
start: number;
|
|
1012
1045
|
end: number;
|
|
1013
|
-
weight?: "
|
|
1046
|
+
weight?: "bold" | "regular" | "medium" | "semibold" | undefined;
|
|
1014
1047
|
italic?: boolean | undefined;
|
|
1015
1048
|
font?: "sans" | "serif" | "mono" | undefined;
|
|
1016
1049
|
}[] | undefined;
|
|
@@ -1224,4 +1257,4 @@ declare function withoutOrphanSections<TPage extends {
|
|
|
1224
1257
|
sections: readonly unknown[];
|
|
1225
1258
|
}>(page: TPage, registry: SectionRegistry): TPage;
|
|
1226
1259
|
//#endregion
|
|
1227
|
-
export { textMarkSchema as $, Site as A,
|
|
1260
|
+
export { textMarkSchema as $, Site as A, ContentMigration as At, themeColorsSchema as B, DEFAULT_MAX_FOOTER_COLUMNS as C, toneOption as Ct, FooterConfig as D, FieldIcons as Dt, FooterColumn as E, FieldChoices as Et, SiteWith as F, createMigrator as Ft, MAX_NAV_DEPTH as G, ButtonStyle as H, Theme as I, Tone as J, RichText as K, brandLogoSchema as L, SiteDefinition as M, ContentVersioning as Mt, SiteOf as N, DocumentKind as Nt, Header as O, ShowCondition as Ot, SiteSeo as P, SCHEMA_VERSION_KEY as Pt, richTextSchema as Q, defineSite as R, BRAND_LOGO_HEIGHT as S, themeModes as St, Footer as T, variantOption as Tt, Image as U, themeSchema as V, Link as W, imageSchema as X, htmlIdSchema as Y, linkSchema as Z, ThemeConfig as _, NumberOption as _t, isSystemPage as a, SectionDefinition as at, defaultTheme as b, buttonStyles as bt, BaseSection as c, WireRect as ct, anchorSchema as d, wireKinds as dt, textSchema as et, createSectionSchema as f, wireframeIssues as ft, SectionRegistry as g, EnumOption as gt, ContentModel as h, CountRule as ht, createPageSchema as i, SectionConfig as it, SiteConfig as j, ContentMigrator as jt, HeaderConfig as k, ShowWhen as kt, PropsOf as l, Wireframe as lt, API_PREFIX as m, BooleanOption as mt, SYSTEM_PAGES as n, trackingIdSchema as nt, seoSchema as o, defineSection as ot, sectionIdSchema as p, OptionalContent as pt, Text as q, Seo as r, withEmphasis as rt, withoutOrphanSections as s, WireKind as st, Page as t, toneSchema as tt, SectionOf as u, defineWireframe as ut, ThemeDefinition as v, Option as vt, DEFAULT_MAX_HEADER_ACTIONS as w, tones as wt, defineTheme as x, motionOption as xt, ThemeFont as y, StringOption as yt, siteSeoSchema as z };
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { r as fieldKey } from "./theme-q19C8cIc.js";
|
|
2
|
+
//#region src/errors.ts
|
|
3
|
+
function formatContentIssues(issues) {
|
|
4
|
+
return issues.map((issue) => {
|
|
5
|
+
return ` - ${issue.path.length > 0 ? issue.path.map(String).join(".") : "(root)"}: ${issue.message}`;
|
|
6
|
+
}).join("\n");
|
|
7
|
+
}
|
|
8
|
+
/** Base error for content that cannot be loaded. `filePath` is the file or directory involved. */
|
|
9
|
+
var ContentError = class extends Error {
|
|
10
|
+
filePath;
|
|
11
|
+
constructor(filePath, message) {
|
|
12
|
+
super(message);
|
|
13
|
+
this.name = new.target.name;
|
|
14
|
+
this.filePath = filePath;
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
/** `site.json` or a page file failed schema validation. */
|
|
18
|
+
var ContentValidationError = class extends ContentError {
|
|
19
|
+
issues;
|
|
20
|
+
constructor(filePath, issues) {
|
|
21
|
+
super(filePath, `Invalid content in ${filePath}:\n${formatContentIssues(issues)}`);
|
|
22
|
+
this.issues = issues;
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
/** A content file or directory is missing, unreadable, or not valid JSON. */
|
|
26
|
+
var ContentReadError = class extends ContentError {};
|
|
27
|
+
//#endregion
|
|
28
|
+
//#region src/section-fields.ts
|
|
29
|
+
const WRAPPERS = /* @__PURE__ */ new Set([
|
|
30
|
+
"optional",
|
|
31
|
+
"nullable",
|
|
32
|
+
"default",
|
|
33
|
+
"prefault",
|
|
34
|
+
"readonly",
|
|
35
|
+
"catch",
|
|
36
|
+
"nonoptional"
|
|
37
|
+
]);
|
|
38
|
+
function defOf(schema) {
|
|
39
|
+
return schema._zod.def;
|
|
40
|
+
}
|
|
41
|
+
/** Strips optional, default, transforms and the like down to the schema that holds the data. */
|
|
42
|
+
function unwrap(schema) {
|
|
43
|
+
let current = schema;
|
|
44
|
+
for (let depth = 0; depth < 16; depth++) {
|
|
45
|
+
const def = defOf(current);
|
|
46
|
+
if (def.type === "pipe" && def.in) current = def.in;
|
|
47
|
+
else if (WRAPPERS.has(def.type) && def.innerType) current = def.innerType;
|
|
48
|
+
else return current;
|
|
49
|
+
}
|
|
50
|
+
return current;
|
|
51
|
+
}
|
|
52
|
+
/** Top-level prop names of a section schema. Empty when `props` is not an object. */
|
|
53
|
+
function schemaProps(schema) {
|
|
54
|
+
const def = defOf(unwrap(schema));
|
|
55
|
+
return def.type === "object" && def.shape ? Object.keys(def.shape) : [];
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Every string enum inside a section's props, by field key (`kind`, `steps[].icon`).
|
|
59
|
+
* The sidebar offers these as choices instead of a free text box.
|
|
60
|
+
*/
|
|
61
|
+
function enumFields(schema) {
|
|
62
|
+
const found = {};
|
|
63
|
+
const visit = (node, path) => {
|
|
64
|
+
const def = defOf(unwrap(node));
|
|
65
|
+
if (def.type === "enum" && def.entries) {
|
|
66
|
+
const values = Object.values(def.entries);
|
|
67
|
+
if (path !== "" && values.every((value) => typeof value === "string")) found[fieldKey(path)] = values;
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
if (def.type === "array" && def.element) visit(def.element, `${path}.0`);
|
|
71
|
+
else if (def.type === "object" && def.shape) for (const [key, child] of Object.entries(def.shape)) visit(child, path === "" ? key : `${path}.${key}`);
|
|
72
|
+
};
|
|
73
|
+
visit(schema, "");
|
|
74
|
+
return found;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Every image inside a section's props (an object with `src` and `alt`), by field key (`poster`, `items[].image`).
|
|
78
|
+
* The sidebar offers an image slot for these even while the prop is missing, whatever the prop is called.
|
|
79
|
+
*/
|
|
80
|
+
function imageFields(schema) {
|
|
81
|
+
const found = [];
|
|
82
|
+
const visit = (node, path) => {
|
|
83
|
+
const def = defOf(unwrap(node));
|
|
84
|
+
if (def.type === "array" && def.element) visit(def.element, `${path}.0`);
|
|
85
|
+
else if (def.type === "object" && def.shape) {
|
|
86
|
+
if (path !== "" && "src" in def.shape && "alt" in def.shape) {
|
|
87
|
+
found.push(fieldKey(path));
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
for (const [key, child] of Object.entries(def.shape)) visit(child, path === "" ? key : `${path}.${key}`);
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
visit(schema, "");
|
|
94
|
+
return found;
|
|
95
|
+
}
|
|
96
|
+
//#endregion
|
|
97
|
+
//#region src/preview.ts
|
|
98
|
+
/**
|
|
99
|
+
* Declare a theme's preview renderer. Default-export it from the module named by `previewModule`
|
|
100
|
+
* (default `/src/lib/render-preview.ts`). The model type ties the inputs to your section registry and site:
|
|
101
|
+
*
|
|
102
|
+
* ```ts
|
|
103
|
+
* export default defineThemePreview<typeof contentModel>({
|
|
104
|
+
* async page({ sections, motion }) { ... },
|
|
105
|
+
* async site({ site, pathname }) { ... },
|
|
106
|
+
* })
|
|
107
|
+
* ```
|
|
108
|
+
*/
|
|
109
|
+
function defineThemePreview(preview) {
|
|
110
|
+
if (typeof preview?.page !== "function") throw new TypeError("defineThemePreview needs a `page` function.");
|
|
111
|
+
if (preview.site !== void 0 && typeof preview.site !== "function") throw new TypeError("defineThemePreview: `site` must be a function when given.");
|
|
112
|
+
return preview;
|
|
113
|
+
}
|
|
114
|
+
/** The theme has no renderer for this preview. The API answers 501 instead of 500. */
|
|
115
|
+
var PreviewUnavailableError = class extends Error {};
|
|
116
|
+
/** Load the preview module through the Vite SSR runner and check it default-exports a preview. */
|
|
117
|
+
async function loadThemePreview(environment, previewModule) {
|
|
118
|
+
const runner = environment.runner;
|
|
119
|
+
if (!runner?.import) throw new PreviewUnavailableError("The SSR dev environment cannot render a preview.");
|
|
120
|
+
const preview = (await runner.import(previewModule))?.default;
|
|
121
|
+
if (!preview || typeof preview.page !== "function") throw new Error(`${previewModule} must default-export defineThemePreview({ page, site? }).`);
|
|
122
|
+
return preview;
|
|
123
|
+
}
|
|
124
|
+
//#endregion
|
|
125
|
+
export { imageFields as a, ContentReadError as c, enumFields as i, ContentValidationError as l, defineThemePreview as n, schemaProps as o, loadThemePreview as r, ContentError as s, PreviewUnavailableError as t, formatContentIssues as u };
|
package/dist/rich-text.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
//#region src/rich-text.d.ts
|
|
2
2
|
/**
|
|
3
|
-
* The subset the editor toolbar writes: paragraphs, line breaks, bold, italic,
|
|
3
|
+
* The subset the editor toolbar writes: paragraphs, line breaks, bold, italic, inline code (backticks),
|
|
4
4
|
* links, and bulleted or numbered lists. Headings and images are not supported.
|
|
5
5
|
* Stored as markdown. Rendered as a fixed set of tags, with text escaped.
|
|
6
6
|
*
|
package/dist/rich-text.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
//#region src/rich-text.ts
|
|
2
2
|
/**
|
|
3
|
-
* The subset the editor toolbar writes: paragraphs, line breaks, bold, italic,
|
|
3
|
+
* The subset the editor toolbar writes: paragraphs, line breaks, bold, italic, inline code (backticks),
|
|
4
4
|
* links, and bulleted or numbered lists. Headings and images are not supported.
|
|
5
5
|
* Stored as markdown. Rendered as a fixed set of tags, with text escaped.
|
|
6
6
|
*
|
|
@@ -55,6 +55,14 @@ function renderInline(source) {
|
|
|
55
55
|
let index = 0;
|
|
56
56
|
let html = "";
|
|
57
57
|
while (index < source.length) {
|
|
58
|
+
if (source[index] === "`") {
|
|
59
|
+
const end = source.indexOf("`", index + 1);
|
|
60
|
+
if (end > index + 1) {
|
|
61
|
+
html += `<code>${escapeHtml(source.slice(index + 1, end))}</code>`;
|
|
62
|
+
index = end + 1;
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
58
66
|
if (source.startsWith("***", index)) {
|
|
59
67
|
const end = source.indexOf("***", index + 3);
|
|
60
68
|
if (end !== -1) {
|
|
@@ -230,6 +238,7 @@ function blockOf(name) {
|
|
|
230
238
|
function markOf(name, style) {
|
|
231
239
|
if (name === "strong" || name === "b") return "strong";
|
|
232
240
|
if (name === "em" || name === "i") return "em";
|
|
241
|
+
if (name === "code" || name === "kbd" || name === "samp") return "code";
|
|
233
242
|
if (name === "a") return "link";
|
|
234
243
|
if (name === "span") {
|
|
235
244
|
if (/font-weight\s*:\s*(?:bold|[7-9]00)/i.test(style)) return "strong";
|
|
@@ -277,6 +286,10 @@ function listItemText(node) {
|
|
|
277
286
|
}
|
|
278
287
|
function serializeInline(node) {
|
|
279
288
|
if (node.mark === "text") return node.text ?? "";
|
|
289
|
+
if (node.mark === "code") {
|
|
290
|
+
const text = plainText(node).replace(/`/g, "").replace(/\n+/g, " ");
|
|
291
|
+
return text.trim() === "" ? text : `\`${text}\``;
|
|
292
|
+
}
|
|
280
293
|
if (node.mark === "ul" || node.mark === "ol") return serializeList(node);
|
|
281
294
|
if (node.mark === "li" || node.mark === "block" || node.mark === "root") return serializeFlow(node.children);
|
|
282
295
|
const inner = node.children.map((child) => serializeInline(child)).join("");
|
|
@@ -290,6 +303,10 @@ function serializeInline(node) {
|
|
|
290
303
|
}
|
|
291
304
|
return inner;
|
|
292
305
|
}
|
|
306
|
+
function plainText(node) {
|
|
307
|
+
if (node.mark === "text") return node.text ?? "";
|
|
308
|
+
return node.children.map((child) => plainText(child)).join("");
|
|
309
|
+
}
|
|
293
310
|
function cleanup(value) {
|
|
294
311
|
return value.replace(/\u00a0/g, " ").replace(/[ \t]+\n/g, "\n").replace(/\n{3,}/g, "\n\n").trim();
|
|
295
312
|
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { F as tones, N as themeModes, j as buttonStyles } from "./page-C0l3CIuz.js";
|
|
2
|
+
import { fontMarks } from "./marks.js";
|
|
3
|
+
//#region src/field-rules.ts
|
|
4
|
+
/**
|
|
5
|
+
* Field key of a path below a section's `props`: list indexes become `[]`.
|
|
6
|
+
* `steps.2.icon` → `steps[].icon`, `badge.tag` → `badge.tag`.
|
|
7
|
+
*/
|
|
8
|
+
function fieldKey(propPath) {
|
|
9
|
+
return propPath.split(".").filter((part) => part !== "").reduce((key, part) => /^\d+$/.test(part) ? `${key}[]` : key === "" ? part : `${key}.${part}`, "");
|
|
10
|
+
}
|
|
11
|
+
/** Field key of a full draft path such as `sections.3.props.steps.0.icon`, or null when it is not inside a section's props. */
|
|
12
|
+
function sectionFieldKey(path) {
|
|
13
|
+
const match = /^sections\.\d+\.props\.(.+)$/.exec(path);
|
|
14
|
+
return match?.[1] ? fieldKey(match[1]) : null;
|
|
15
|
+
}
|
|
16
|
+
/** True when every option named in the prop's rule has one of its values. A prop without a rule is always shown. */
|
|
17
|
+
function isPropShown(showWhen, prop, readOption) {
|
|
18
|
+
const rule = showWhen?.[prop];
|
|
19
|
+
if (!rule) return true;
|
|
20
|
+
return Object.entries(rule).every(([option, condition]) => matches(condition, readOption(option)));
|
|
21
|
+
}
|
|
22
|
+
function matches(condition, value) {
|
|
23
|
+
if (typeof condition === "boolean") return value === condition;
|
|
24
|
+
if (typeof condition === "string") return value === condition;
|
|
25
|
+
return typeof value === "string" && condition.includes(value);
|
|
26
|
+
}
|
|
27
|
+
//#endregion
|
|
28
|
+
//#region src/theme.ts
|
|
29
|
+
const SYSTEM_FONTS = {
|
|
30
|
+
sans: {
|
|
31
|
+
label: "Sans",
|
|
32
|
+
family: "ui-sans-serif, system-ui, sans-serif"
|
|
33
|
+
},
|
|
34
|
+
serif: {
|
|
35
|
+
label: "Serif",
|
|
36
|
+
family: "ui-serif, Georgia, serif"
|
|
37
|
+
},
|
|
38
|
+
mono: {
|
|
39
|
+
label: "Mono",
|
|
40
|
+
family: "ui-monospace, SFMono-Regular, Menlo, monospace"
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
/** What a theme tells the editor about itself. Pass the result as `theme` in the content model. */
|
|
44
|
+
function defineTheme(config = {}) {
|
|
45
|
+
return {
|
|
46
|
+
fonts: Object.fromEntries(fontMarks.map((slot) => [slot, {
|
|
47
|
+
...SYSTEM_FONTS[slot],
|
|
48
|
+
...config.fonts?.[slot]
|
|
49
|
+
}])),
|
|
50
|
+
tones,
|
|
51
|
+
modes: themeModes,
|
|
52
|
+
buttonStyles
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
/** Used when the content model has no `theme`. */
|
|
56
|
+
const defaultTheme = defineTheme();
|
|
57
|
+
//#endregion
|
|
58
|
+
export { sectionFieldKey as a, isPropShown as i, defineTheme as n, fieldKey as r, defaultTheme as t };
|