@wocart/theme 4.0.0 → 4.1.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 CHANGED
@@ -5,6 +5,37 @@ All notable changes to `@wocart/theme` are recorded here. The package follows
5
5
  major version, and an export is marked `@deprecated` for at least one minor
6
6
  release before a major removes it.
7
7
 
8
+ ## 4.1.0 — 2026-11-03
9
+
10
+ One content policy for every theme, and the theme key rule exported.
11
+ Additions only; works with `@wocart/storefront` 3.0.0 or newer 3.x.
12
+
13
+ ### Added
14
+
15
+ - `resolveThemeContent(theme, locale, overrides, options?)`: the theme's
16
+ words for one page — its pack for the language (else the default
17
+ language's: `options.defaultLocale`, else the first `locales` entry, else
18
+ the first pack), then the merchant's edits for that language, text only and
19
+ only for the pack's own keys. Takes `Pick<ThemeDefinition, "content" |
20
+ "locales">`, so a middleware can pass the packs without the component
21
+ catalog. Type `ResolveThemeContentOptions`.
22
+ - `THEME_KEY_PATTERN` from the root entry: the rule a theme's key follows
23
+ (lowercase kebab-case, at most 64 characters), the one `defineTheme` and
24
+ the platform apply, for a tool that checks a key before building a theme.
25
+
26
+ ### Fixed
27
+
28
+ - `ComponentRole`'s comment names both page types whose surfaces must
29
+ guarantee an `"order-form"` component: product and landing, as
30
+ `validateThemeDefinition` already checks.
31
+
32
+ ### Theme migration
33
+
34
+ - Replace a theme's own merge of its packs and `contentOverrides` with
35
+ `resolveThemeContent({ content, locales }, locale, config.contentOverrides?.[locale])`.
36
+ An edit that is not text, or names a key the pack lacks, no longer reaches
37
+ a page.
38
+
8
39
  ## 4.0.0 — 2026-11-01
9
40
 
10
41
  Search and contact are platform pages a theme composes, and the theme
package/dist/index.d.ts CHANGED
@@ -27,7 +27,10 @@ export type { DocumentEdit, DocumentIssue, DocumentIssueCode, InstanceLocation,
27
27
  export { THEME_SDK_VERSION } from "./version.js";
28
28
  export type { RichTextHtmlOptions } from "./rich-text.js";
29
29
  export { resolveThemeSettings, checkThemeSettings } from "./settings.js";
30
+ export { resolveThemeContent } from "./theme-content.js";
31
+ export type { ResolveThemeContentOptions } from "./theme-content.js";
30
32
  export { localize } from "./locales.js";
33
+ export { THEME_KEY_PATTERN } from "./patterns.js";
31
34
  export { PLURAL_CATEGORIES, formatMessage, messageForms, pluralFormIssues, pluralMessageKeys } from "./messages.js";
32
35
  export type { MessageOptions, MessageValues, PluralCategory } from "./messages.js";
33
36
  export { THEME_MANIFEST_CONTRACT_VERSION, THEME_MANIFEST_PATH, manifestCatalog, themeManifest, validateThemeManifest, } from "./manifest.js";
package/dist/index.js CHANGED
@@ -23,7 +23,9 @@ export { COLOR_ROLES, COLOR_SCHEMES_MAX, STYLE_BREAKPOINTS, STYLE_PANELS, STYLE_
23
23
  export { checkPageData, duplicateInstance, findInstance, insertInstance, moveInstance, newInstanceId, removeInstance, setAreaHidden, setInstanceHidden, setInstanceProps, } from "./operations.js";
24
24
  export { THEME_SDK_VERSION } from "./version.js";
25
25
  export { resolveThemeSettings, checkThemeSettings } from "./settings.js";
26
+ export { resolveThemeContent } from "./theme-content.js";
26
27
  export { localize } from "./locales.js";
28
+ export { THEME_KEY_PATTERN } from "./patterns.js";
27
29
  export { PLURAL_CATEGORIES, formatMessage, messageForms, pluralFormIssues, pluralMessageKeys } from "./messages.js";
28
30
  export { THEME_MANIFEST_CONTRACT_VERSION, THEME_MANIFEST_PATH, manifestCatalog, themeManifest, validateThemeManifest, } from "./manifest.js";
29
31
  export { diffThemeManifests } from "./manifest-diff.js";
@@ -0,0 +1,19 @@
1
+ /**
2
+ * The theme's words for one page: its own pack for the page's language, with
3
+ * the merchant's edits for that same language over it. One policy for every
4
+ * theme: an edit counts only when it is text and names a word the pack has,
5
+ * so a stale key, another theme's key or a value of the wrong kind never
6
+ * reaches a page, and another language's edits never mix in.
7
+ */
8
+ import type { LocaleCode, ThemeDefinition } from "./types.js";
9
+ export interface ResolveThemeContentOptions {
10
+ /** The pack used for a language the theme has none for. Default: the theme's first `locales` entry, else its first pack. */
11
+ defaultLocale?: LocaleCode;
12
+ }
13
+ /**
14
+ * The words a page renders in `locale`: the theme's pack for it (else the
15
+ * default language's), then `overrides` — the store's
16
+ * `contentOverrides[locale]` — for the pack's own keys, text only. Empty
17
+ * when the theme declares no content.
18
+ */
19
+ export declare function resolveThemeContent(theme: Pick<ThemeDefinition, "content" | "locales">, locale: LocaleCode, overrides: unknown, options?: ResolveThemeContentOptions): Record<string, string>;
@@ -0,0 +1,19 @@
1
+ /**
2
+ * The words a page renders in `locale`: the theme's pack for it (else the
3
+ * default language's), then `overrides` — the store's
4
+ * `contentOverrides[locale]` — for the pack's own keys, text only. Empty
5
+ * when the theme declares no content.
6
+ */
7
+ export function resolveThemeContent(theme, locale, overrides, options = {}) {
8
+ const packs = theme.content ?? {};
9
+ const fallback = options.defaultLocale ?? theme.locales?.[0] ?? Object.keys(packs)[0];
10
+ const pack = (Object.hasOwn(packs, locale) ? packs[locale] : fallback !== undefined && Object.hasOwn(packs, fallback) ? packs[fallback] : undefined) ?? {};
11
+ const words = { ...pack };
12
+ if (overrides === null || typeof overrides !== "object")
13
+ return words;
14
+ for (const [key, value] of Object.entries(overrides)) {
15
+ if (typeof value === "string" && Object.hasOwn(pack, key))
16
+ words[key] = value;
17
+ }
18
+ return words;
19
+ }
package/dist/types.d.ts CHANGED
@@ -460,7 +460,8 @@ export interface FixedBlockDefinition {
460
460
  }
461
461
  /**
462
462
  * What a component is to the platform. `"order-form"`: it places orders —
463
- * every product surface must guarantee one (`validateThemeDefinition`).
463
+ * every product and landing surface must guarantee one
464
+ * (`validateThemeDefinition`, `order-form-not-guaranteed`).
464
465
  */
465
466
  export type ComponentRole = "order-form";
466
467
  /**
package/dist/version.d.ts CHANGED
@@ -4,4 +4,4 @@
4
4
  * reads. Always equal to `package.json`'s version; the package check refuses
5
5
  * a release where they differ.
6
6
  */
7
- export declare const THEME_SDK_VERSION = "4.0.0";
7
+ export declare const THEME_SDK_VERSION = "4.1.0";
package/dist/version.js CHANGED
@@ -4,4 +4,4 @@
4
4
  * reads. Always equal to `package.json`'s version; the package check refuses
5
5
  * a release where they differ.
6
6
  */
7
- export const THEME_SDK_VERSION = "4.0.0";
7
+ export const THEME_SDK_VERSION = "4.1.0";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wocart/theme",
3
- "version": "4.0.0",
3
+ "version": "4.1.0",
4
4
  "description": "The Wocart theme contract: code-owned component definitions, JSON page documents, validation and resolution, and a reference Astro renderer.",
5
5
  "keywords": [
6
6
  "wocart",