@numueg/theme-kit
v0.1.0
Published
Pure, React-free helpers shared across NUMU V3 storefront themes — i18n defaults, setting-value guards, money formatting, and image transforms.
Readme
@numueg/theme-kit
Pure, React-free, zero-dependency helpers shared across the NUMU V3 storefront themes.
These functions were copy-pasted (byte-for-byte, then slowly drifting) into every
theme's src/sections/_shared.ts. This package is the single canonical home for
them — increment 1 of "kill theme duplication". It ships ESM + CJS + .d.ts and
has no runtime dependencies (not even React), so it is safe to import from
section components, SSR utilities, loaders, and tests alike.
The React hooks/components (
useProduct,<Money>, …) stay in@numueg/theme-sdk. The kit holds only the pure helpers.
Install
npm install @numueg/theme-kitUsage
Import the whole surface, or a subpath to help bundlers tree-shake:
import { localized, asString, asImageUrl, readBlocks } from "@numueg/theme-kit";
// or, narrower:
import { formatMoney, centsToMajor } from "@numueg/theme-kit/money";
import { applyImageTransform } from "@numueg/theme-kit/image";API
@numueg/theme-kit/i18n
localized(locale, en, ar)— pick locale-appropriate default copy for a section's hardcoded empty-state text. Arabic whenlocalestarts with"ar"(case-insensitive); English otherwise (includingundefined/""). Merchant values still win at the call site:asString(s.x) || localized(locale, en, ar).
@numueg/theme-kit/settings
Type guards for the untyped Record<string, unknown> the customizer writes:
asString(v, fallback?),asNumber(v, fallback?)(finite only),asBool(v, fallback?)(no truthiness coercion),asArray<T>(v),asRecord(v).pickItems(s, key, fallback)— array setting, orfallbackwhen missing / wrong type / empty.asImageUrl(v, fallback?)/asImageAlt(v, fallback?)— read animage_pickervalue that may be a URL string or an{ url | src, alt }object.readBlocks(container, type)— a container's blocks oftype, inblock_order(falling back to insertion order), skipping disabled ones; returns each block'ssettingsbag. Also exports theBlockContainer/RawBlockshapes.
@numueg/theme-kit/money
formatMoney(amount, currency?, options?)— pure, locale-awareIntl.NumberFormatcurrency formatting. Expects MAJOR units (dollars, not cents). Resilient: empty/invalid currency →options.fallbackCurrency(default"USD"), never throws. This is the React-free core of the SDK's<Money>/formatMoney.centsToMajor(cents)— divide minor units by 100. Use it beforeformatMoneyon cent-denominated sources (cart API,variant.price.amount) — formatting cents directly shows 100× the price.
@numueg/theme-kit/image
Non-destructive image framing (focal / zoom / rotation), reproduced purely via CSS so the same upload can be framed differently per placement.
asImageTransform(v)— read the optionaltransformoff an image value.applyImageTransform(t, fit?)— CSS (transform,transformOrigin,objectFit,objectPosition) for an<img>filling a fixed-aspect frame. Clamps zoom to1..4, focal to0..1, normalizes rotation to[0, 360). Returns a plainImageTransformStyleobject (assignable to React'sstyle={...}without a React dependency).
Notes on canonicalization
applyImageTransformfollows the SDK implementation (numu-theme-sdk/src/utils/imageTransform.ts): with no transform it returns{ objectFit: fit }. Older theme_shared.tscopies returned{}here — the SDK version standardized on always settingobjectFit.formatMoneyis the pure extract of the SDK provider'sformatMoney; same fallback contract, minus React.
Development
npm install
npm run typecheck # tsc --noEmit
npm test # vitest run
npm run build # tsup → dist/ (esm + cjs + d.ts)License
MIT © NUMU
