@shoplix-ai/block-kit 1.0.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.
Files changed (51) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +49 -0
  3. package/dist/authoring.d.ts +55 -0
  4. package/dist/authoring.d.ts.map +1 -0
  5. package/dist/authoring.js +13 -0
  6. package/dist/authoring.js.map +1 -0
  7. package/dist/capabilities.d.ts +22 -0
  8. package/dist/capabilities.d.ts.map +1 -0
  9. package/dist/capabilities.js +10 -0
  10. package/dist/capabilities.js.map +1 -0
  11. package/dist/code-block.d.ts +31 -0
  12. package/dist/code-block.d.ts.map +1 -0
  13. package/dist/code-block.js +26 -0
  14. package/dist/code-block.js.map +1 -0
  15. package/dist/contract.d.ts +60 -0
  16. package/dist/contract.d.ts.map +1 -0
  17. package/dist/contract.js +14 -0
  18. package/dist/contract.js.map +1 -0
  19. package/dist/index.d.ts +19 -0
  20. package/dist/index.d.ts.map +1 -0
  21. package/dist/index.js +11 -0
  22. package/dist/index.js.map +1 -0
  23. package/dist/locale.d.ts +19 -0
  24. package/dist/locale.d.ts.map +1 -0
  25. package/dist/locale.js +36 -0
  26. package/dist/locale.js.map +1 -0
  27. package/dist/money.d.ts +6 -0
  28. package/dist/money.d.ts.map +1 -0
  29. package/dist/money.js +17 -0
  30. package/dist/money.js.map +1 -0
  31. package/dist/navigation.d.ts +15 -0
  32. package/dist/navigation.d.ts.map +1 -0
  33. package/dist/navigation.js +2 -0
  34. package/dist/navigation.js.map +1 -0
  35. package/dist/registry.d.ts +14 -0
  36. package/dist/registry.d.ts.map +1 -0
  37. package/dist/registry.js +22 -0
  38. package/dist/registry.js.map +1 -0
  39. package/dist/renditions.d.ts +13 -0
  40. package/dist/renditions.d.ts.map +1 -0
  41. package/dist/renditions.js +18 -0
  42. package/dist/renditions.js.map +1 -0
  43. package/dist/tokens.d.ts +8 -0
  44. package/dist/tokens.d.ts.map +1 -0
  45. package/dist/tokens.js +26 -0
  46. package/dist/tokens.js.map +1 -0
  47. package/dist/version.d.ts +9 -0
  48. package/dist/version.d.ts.map +1 -0
  49. package/dist/version.js +9 -0
  50. package/dist/version.js.map +1 -0
  51. package/package.json +50 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Rastova
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,49 @@
1
+ # @shoplix-ai/block-kit
2
+
3
+ The renderer contract. Every Block Type renderer, platform or Shop-owned, is
4
+ written against this package and nothing else from the runtime. It holds:
5
+
6
+ - **The contract.** A renderer is a React component that receives
7
+ `BlockRenderProps`: the block's settings, its Binding resolved into display
8
+ shapes (`BindingData | null`), the envelope's asset display entries for the
9
+ screen in hand, the Shop's tokens and resolved theme style,
10
+ the buyer's language and text direction with the Shop's default language as
11
+ fallback, and a capability object holding only
12
+ the capabilities the Block Type declared.
13
+ - **The registry.** `createBlockRegistry()` keyed by Block Type, one owner per
14
+ type. A second owner is refused; the same owner may register again. Packages
15
+ outside the app register through it. `defineBlock()` is the typed authoring
16
+ helper: settings and capabilities are inferred from the definition.
17
+ - **The capability set.** `addToCart`, `openCart`, `beginCheckout`. Closed, and
18
+ the same list the schema package lets a Block Definition declare.
19
+ - **The authoring shape of a Code Block.** `defineSettings()` and
20
+ `defineBinding()` type a block's settings and binding files; `SettingsValues`
21
+ derives the renderer's settings type from the settings file;
22
+ `defineCodeBlock()` holds the renderer with its renderer version, the
23
+ capabilities it reaches for and a height hint for the canvas card; and
24
+ `shopBlocks()` turns a Shop package's blocks into registrations under the
25
+ Shop's namespaced type ids. A component file names no Shop and no type: the
26
+ package stamps both.
27
+ - **The contract version.** `CONTRACT_VERSION` and `CONTRACT_MAJOR`, pinned to
28
+ this package's own version by a test. A Shop package is built against one
29
+ major; the api's package registry records it at push, and taking a version
30
+ refuses a major other than the runtime's before anything is built.
31
+ - **Helpers.** `resolveToken` (follow an alias to its value), `formatMoney`
32
+ (amount plus currency code, formatted in the buyer's language), `pickLocale`
33
+ (the buyer's language from the Shop's languages with default fallback),
34
+ `localize` (one string out of a locale object), `textDirection`,
35
+ `imageSourceFor` (the rendition to paint at a given display width).
36
+
37
+ No renderers live here. The package depends on `@shoplix-ai/sdui-schema` and on
38
+ React types only. Its runtime export list is pinned by a test; it is imported by
39
+ code outside this repo, so growing it is a reviewed change. The package follows
40
+ semver and is publishable: a change a Shop package would have to follow is a
41
+ major bump, announced with a migration note, and the runtime moves to the new
42
+ major before any Shop package may.
43
+
44
+ ```sh
45
+ pnpm build
46
+ pnpm typecheck
47
+ pnpm test
48
+ pnpm lint
49
+ ```
@@ -0,0 +1,55 @@
1
+ import type { Action, BlockBindingDeclaration, BlockPlacement, BlockSetting, ColorChoice, LocalizedText, RowFieldSetting } from '@shoplix-ai/sdui-schema';
2
+ /** The settings file of a block: its label and what a merchant can set on it. */
3
+ export interface SettingsFile {
4
+ readonly label: string;
5
+ readonly settings: readonly BlockSetting[];
6
+ }
7
+ /** The binding file of a block: what it binds, and where a merchant may place it. */
8
+ export type BindingFile = BlockBindingDeclaration & {
9
+ readonly placement: BlockPlacement;
10
+ };
11
+ /**
12
+ * The settings file's one export. It hands the literal back unchanged, typed
13
+ * so an editor checks every setting and keeps each key and option for the
14
+ * renderer's own props type.
15
+ */
16
+ export declare function defineSettings<const S extends SettingsFile>(file: S): S;
17
+ /** The binding file's one export, typed the same way. */
18
+ export declare function defineBinding<const B extends BindingFile>(file: B): B;
19
+ type LeafValue<S> = S extends {
20
+ type: 'text';
21
+ } ? LocalizedText : S extends {
22
+ type: 'toggle';
23
+ } ? boolean : S extends {
24
+ type: 'select';
25
+ options: ReadonlyArray<{
26
+ value: infer V;
27
+ }>;
28
+ } ? V : S extends {
29
+ type: 'number';
30
+ } ? number : S extends {
31
+ type: 'color';
32
+ } ? ColorChoice : S extends {
33
+ type: 'image';
34
+ } ? string | null : S extends {
35
+ type: 'action';
36
+ } ? Action : never;
37
+ type RowValue<F extends readonly RowFieldSetting[]> = {
38
+ readonly [K in F[number] as K['key']]: LeafValue<K>;
39
+ };
40
+ type SettingValue<S> = S extends {
41
+ type: 'rows';
42
+ fields: infer F extends readonly RowFieldSetting[];
43
+ } ? ReadonlyArray<RowValue<F>> : LeafValue<S>;
44
+ /**
45
+ * What a renderer receives as its settings, derived from the settings file:
46
+ * one key per setting that carries a value, each in the shape the merchant's
47
+ * panel writes it. A section header names a group and carries nothing.
48
+ */
49
+ export type SettingsValues<S extends SettingsFile> = {
50
+ readonly [K in Exclude<S['settings'][number], {
51
+ type: 'section';
52
+ }> as K['key']]: SettingValue<K>;
53
+ };
54
+ export {};
55
+ //# sourceMappingURL=authoring.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"authoring.d.ts","sourceRoot":"","sources":["../src/authoring.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,MAAM,EACN,uBAAuB,EACvB,cAAc,EACd,YAAY,EACZ,WAAW,EACX,aAAa,EACb,eAAe,EAChB,MAAM,yBAAyB,CAAC;AAEjC,iFAAiF;AACjF,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,QAAQ,EAAE,SAAS,YAAY,EAAE,CAAC;CAC5C;AAED,qFAAqF;AACrF,MAAM,MAAM,WAAW,GAAG,uBAAuB,GAAG;IAAE,QAAQ,CAAC,SAAS,EAAE,cAAc,CAAA;CAAE,CAAC;AAE3F;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,KAAK,CAAC,CAAC,SAAS,YAAY,EAAE,IAAI,EAAE,CAAC,GAAG,CAAC,CAEvE;AAED,yDAAyD;AACzD,wBAAgB,aAAa,CAAC,KAAK,CAAC,CAAC,SAAS,WAAW,EAAE,IAAI,EAAE,CAAC,GAAG,CAAC,CAErE;AAED,KAAK,SAAS,CAAC,CAAC,IAAI,CAAC,SAAS;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAC1C,aAAa,GACb,CAAC,SAAS;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,GAC1B,OAAO,GACP,CAAC,SAAS;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,OAAO,EAAE,aAAa,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC,CAAA;KAAE,CAAC,CAAA;CAAE,GACtE,CAAC,GACD,CAAC,SAAS;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,GAC1B,MAAM,GACN,CAAC,SAAS;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,GACzB,WAAW,GACX,CAAC,SAAS;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,GACzB,MAAM,GAAG,IAAI,GACb,CAAC,SAAS;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,GAC1B,MAAM,GACN,KAAK,CAAC;AAEtB,KAAK,QAAQ,CAAC,CAAC,SAAS,SAAS,eAAe,EAAE,IAAI;IACpD,QAAQ,EAAE,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,SAAS,CAAC,CAAC,CAAC;CACpD,CAAC;AAEF,KAAK,YAAY,CAAC,CAAC,IAAI,CAAC,SAAS;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC,SAAS,SAAS,eAAe,EAAE,CAAC;CACpD,GACG,aAAa,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,GAC1B,SAAS,CAAC,CAAC,CAAC,CAAC;AAEjB;;;;GAIG;AACH,MAAM,MAAM,cAAc,CAAC,CAAC,SAAS,YAAY,IAAI;IACnD,QAAQ,EAAE,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,EAAE;QAAE,IAAI,EAAE,SAAS,CAAA;KAAE,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,YAAY,CAAC,CAAC,CAAC;CACjG,CAAC"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * The settings file's one export. It hands the literal back unchanged, typed
3
+ * so an editor checks every setting and keeps each key and option for the
4
+ * renderer's own props type.
5
+ */
6
+ export function defineSettings(file) {
7
+ return file;
8
+ }
9
+ /** The binding file's one export, typed the same way. */
10
+ export function defineBinding(file) {
11
+ return file;
12
+ }
13
+ //# sourceMappingURL=authoring.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"authoring.js","sourceRoot":"","sources":["../src/authoring.ts"],"names":[],"mappings":"AAmBA;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAA+B,IAAO;IAClE,OAAO,IAAI,CAAC;AACd,CAAC;AAED,yDAAyD;AACzD,MAAM,UAAU,aAAa,CAA8B,IAAO;IAChE,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,22 @@
1
+ import { type BlockCapabilityName } from '@shoplix-ai/sdui-schema';
2
+ /**
3
+ * The closed capability set. A renderer reaches commerce only through these
4
+ * three; the Storefront token, the cart id and navigation never cross the
5
+ * contract. The set is code, never document content, and it does not grow
6
+ * without a new contract major. The schema package names the same list, so a
7
+ * Block Definition can declare only what a renderer can be handed.
8
+ */
9
+ export declare const CAPABILITY_NAMES: readonly ["addToCart", "openCart", "beginCheckout"];
10
+ export type CapabilityName = BlockCapabilityName;
11
+ export interface CartLineInput {
12
+ readonly variantId: string;
13
+ readonly quantity: number;
14
+ }
15
+ export interface Capabilities {
16
+ readonly addToCart: (line: CartLineInput) => Promise<void>;
17
+ readonly openCart: () => void;
18
+ readonly beginCheckout: () => Promise<void>;
19
+ }
20
+ /** What a renderer sees: exactly the capabilities its Block Type declared. */
21
+ export type CapabilityObject<K extends CapabilityName = never> = Pick<Capabilities, K>;
22
+ //# sourceMappingURL=capabilities.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capabilities.d.ts","sourceRoot":"","sources":["../src/capabilities.ts"],"names":[],"mappings":"AAAA,OAAO,EAA0B,KAAK,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAE3F;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB,qDAAyB,CAAC;AAEvD,MAAM,MAAM,cAAc,GAAG,mBAAmB,CAAC;AAEjD,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,SAAS,EAAE,CAAC,IAAI,EAAE,aAAa,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3D,QAAQ,CAAC,QAAQ,EAAE,MAAM,IAAI,CAAC;IAC9B,QAAQ,CAAC,aAAa,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC7C;AAED,8EAA8E;AAC9E,MAAM,MAAM,gBAAgB,CAAC,CAAC,SAAS,cAAc,GAAG,KAAK,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC"}
@@ -0,0 +1,10 @@
1
+ import { BLOCK_CAPABILITY_NAMES } from '@shoplix-ai/sdui-schema';
2
+ /**
3
+ * The closed capability set. A renderer reaches commerce only through these
4
+ * three; the Storefront token, the cart id and navigation never cross the
5
+ * contract. The set is code, never document content, and it does not grow
6
+ * without a new contract major. The schema package names the same list, so a
7
+ * Block Definition can declare only what a renderer can be handed.
8
+ */
9
+ export const CAPABILITY_NAMES = BLOCK_CAPABILITY_NAMES;
10
+ //# sourceMappingURL=capabilities.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capabilities.js","sourceRoot":"","sources":["../src/capabilities.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAA4B,MAAM,yBAAyB,CAAC;AAE3F;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,sBAAsB,CAAC"}
@@ -0,0 +1,31 @@
1
+ import type { CapabilityName } from './capabilities.js';
2
+ import type { BlockRegistration, BlockRenderer, BlockSettings } from './contract.js';
3
+ /**
4
+ * What a Code Block's component file exports: the renderer, the capabilities
5
+ * it reaches for, the version of this renderer, and how tall the canvas card
6
+ * should stand in for it. The block's type and owner are not here: the
7
+ * package that ships it stamps both, so a component never names a Shop.
8
+ */
9
+ export interface CodeBlockModule<TSettings extends BlockSettings = BlockSettings, K extends CapabilityName = never> {
10
+ readonly rendererVersion: number;
11
+ readonly capabilities?: readonly K[];
12
+ readonly heightHint?: number;
13
+ readonly render: BlockRenderer<TSettings, K>;
14
+ }
15
+ /** The stored shape: every field present, the renderer widened as `defineBlock` widens it. */
16
+ export interface CodeBlock {
17
+ readonly rendererVersion: number;
18
+ readonly capabilities: readonly CapabilityName[];
19
+ readonly heightHint: number | undefined;
20
+ readonly render: BlockRenderer;
21
+ }
22
+ /** The typed authoring shape of a Code Block: settings and capabilities are inferred. */
23
+ export declare function defineCodeBlock<TSettings extends BlockSettings = BlockSettings, const K extends CapabilityName = never>(module: CodeBlockModule<TSettings, K>): CodeBlock;
24
+ /**
25
+ * A Shop package's blocks as the registry takes them: each Code Block under
26
+ * its namespaced type id, owned by the Shop. The name is the block folder's
27
+ * name and the key the Block Definition was pushed under, so the two sides
28
+ * meet on one id by construction.
29
+ */
30
+ export declare function shopBlocks(shopSlug: string, blocks: Readonly<Record<string, CodeBlock>>): readonly BlockRegistration[];
31
+ //# sourceMappingURL=code-block.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"code-block.d.ts","sourceRoot":"","sources":["../src/code-block.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,KAAK,EAAE,iBAAiB,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAErF;;;;;GAKG;AACH,MAAM,WAAW,eAAe,CAC9B,SAAS,SAAS,aAAa,GAAG,aAAa,EAC/C,CAAC,SAAS,cAAc,GAAG,KAAK;IAEhC,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,YAAY,CAAC,EAAE,SAAS,CAAC,EAAE,CAAC;IACrC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC;CAC9C;AAED,8FAA8F;AAC9F,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,YAAY,EAAE,SAAS,cAAc,EAAE,CAAC;IACjD,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,CAAC;IACxC,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC;CAChC;AAED,yFAAyF;AACzF,wBAAgB,eAAe,CAC7B,SAAS,SAAS,aAAa,GAAG,aAAa,EAC/C,KAAK,CAAC,CAAC,SAAS,cAAc,GAAG,KAAK,EACtC,MAAM,EAAE,eAAe,CAAC,SAAS,EAAE,CAAC,CAAC,GAAG,SAAS,CAOlD;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CACxB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,GAC1C,SAAS,iBAAiB,EAAE,CAQ9B"}
@@ -0,0 +1,26 @@
1
+ import { privateBlockTypeId } from '@shoplix-ai/sdui-schema';
2
+ /** The typed authoring shape of a Code Block: settings and capabilities are inferred. */
3
+ export function defineCodeBlock(module) {
4
+ return {
5
+ rendererVersion: module.rendererVersion,
6
+ capabilities: module.capabilities ?? [],
7
+ heightHint: module.heightHint,
8
+ render: module.render,
9
+ };
10
+ }
11
+ /**
12
+ * A Shop package's blocks as the registry takes them: each Code Block under
13
+ * its namespaced type id, owned by the Shop. The name is the block folder's
14
+ * name and the key the Block Definition was pushed under, so the two sides
15
+ * meet on one id by construction.
16
+ */
17
+ export function shopBlocks(shopSlug, blocks) {
18
+ return Object.entries(blocks).map(([name, block]) => ({
19
+ type: privateBlockTypeId(shopSlug, name),
20
+ owner: shopSlug,
21
+ capabilities: block.capabilities,
22
+ rendererVersion: block.rendererVersion,
23
+ render: block.render,
24
+ }));
25
+ }
26
+ //# sourceMappingURL=code-block.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"code-block.js","sourceRoot":"","sources":["../src/code-block.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AA4B7D,yFAAyF;AACzF,MAAM,UAAU,eAAe,CAG7B,MAAqC;IACrC,OAAO;QACL,eAAe,EAAE,MAAM,CAAC,eAAe;QACvC,YAAY,EAAE,MAAM,CAAC,YAAY,IAAI,EAAE;QACvC,UAAU,EAAE,MAAM,CAAC,UAAU;QAC7B,MAAM,EAAE,MAAM,CAAC,MAAkC;KAClD,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,UAAU,CACxB,QAAgB,EAChB,MAA2C;IAE3C,OAAO,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,CAAC;QACpD,IAAI,EAAE,kBAAkB,CAAC,QAAQ,EAAE,IAAI,CAAC;QACxC,KAAK,EAAE,QAAQ;QACf,YAAY,EAAE,KAAK,CAAC,YAAY;QAChC,eAAe,EAAE,KAAK,CAAC,eAAe;QACtC,MAAM,EAAE,KAAK,CAAC,MAAM;KACrB,CAAC,CAAC,CAAC;AACN,CAAC"}
@@ -0,0 +1,60 @@
1
+ import type { ComponentType } from 'react';
2
+ import type { BindingData, EnvelopeAssets, LocaleCode, ThemeStyle, ThemeTokens } from '@shoplix-ai/sdui-schema';
3
+ import type { CapabilityName, CapabilityObject } from './capabilities.js';
4
+ import type { BlockNavigation } from './navigation.js';
5
+ export type TextDirection = 'ltr' | 'rtl';
6
+ export type BlockSettings = Readonly<Record<string, unknown>>;
7
+ /**
8
+ * Everything a renderer receives, and all it may know. Settings are the
9
+ * block's props from the document; data is its Binding resolved into display
10
+ * shapes, null when the block carries no Binding; assets are the envelope's
11
+ * display entries for the screen in hand, keyed by asset id; tokens and theme
12
+ * are the Shop's; language and direction are the buyer's, with the Shop's default
13
+ * language as the fallback every locale object resolves through; navigate is the
14
+ * closed way to move the buyer; capabilities hold only what the Block Type
15
+ * declared.
16
+ */
17
+ export interface BlockRenderProps<TSettings extends BlockSettings = BlockSettings, K extends CapabilityName = never> {
18
+ readonly blockId: string;
19
+ readonly settings: TSettings;
20
+ readonly data: BindingData | null;
21
+ readonly assets: EnvelopeAssets;
22
+ readonly tokens: ThemeTokens;
23
+ readonly theme: ThemeStyle;
24
+ readonly language: LocaleCode;
25
+ readonly defaultLanguage: LocaleCode;
26
+ readonly direction: TextDirection;
27
+ readonly navigate: BlockNavigation;
28
+ readonly capabilities: CapabilityObject<K>;
29
+ }
30
+ export type BlockRenderer<TSettings extends BlockSettings = BlockSettings, K extends CapabilityName = never> = ComponentType<BlockRenderProps<TSettings, K>>;
31
+ /** Who answers for a Block Type: the platform, or the Shop whose package registered it. */
32
+ export type BlockOwner = string;
33
+ /** The typed authoring shape: settings and capabilities are inferred from the definition. */
34
+ export interface BlockDefinition<TSettings extends BlockSettings = BlockSettings, K extends CapabilityName = never> {
35
+ readonly type: string;
36
+ readonly owner: BlockOwner;
37
+ readonly capabilities?: readonly K[];
38
+ readonly render: BlockRenderer<TSettings, K>;
39
+ }
40
+ /**
41
+ * The shape a registry stores and a host renders: one entry per Block Type.
42
+ * The host hands each renderer the capabilities its entry declares, so the
43
+ * stored renderer type promises none and the definition's type promises the
44
+ * declared ones.
45
+ */
46
+ export interface BlockRegistration {
47
+ readonly type: string;
48
+ readonly owner: BlockOwner;
49
+ readonly capabilities: readonly CapabilityName[];
50
+ /** A Code Block's renderer version, the one its Block Definition names; a platform block has none. */
51
+ readonly rendererVersion?: number;
52
+ readonly render: BlockRenderer;
53
+ }
54
+ /**
55
+ * Turns a typed definition into a registration. The settings a renderer
56
+ * receives come from a document parsed against the schema for its type, so
57
+ * the widening to the stored shape happens here, once, and nowhere else.
58
+ */
59
+ export declare function defineBlock<TSettings extends BlockSettings = BlockSettings, const K extends CapabilityName = never>(definition: BlockDefinition<TSettings, K>): BlockRegistration;
60
+ //# sourceMappingURL=contract.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contract.d.ts","sourceRoot":"","sources":["../src/contract.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAC3C,OAAO,KAAK,EACV,WAAW,EACX,cAAc,EACd,UAAU,EACV,UAAU,EACV,WAAW,EACZ,MAAM,yBAAyB,CAAC;AACjC,OAAO,KAAK,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAC1E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAEvD,MAAM,MAAM,aAAa,GAAG,KAAK,GAAG,KAAK,CAAC;AAE1C,MAAM,MAAM,aAAa,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;AAE9D;;;;;;;;;GASG;AACH,MAAM,WAAW,gBAAgB,CAC/B,SAAS,SAAS,aAAa,GAAG,aAAa,EAC/C,CAAC,SAAS,cAAc,GAAG,KAAK;IAEhC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAC;IAC7B,QAAQ,CAAC,IAAI,EAAE,WAAW,GAAG,IAAI,CAAC;IAClC,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAC;IAChC,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;IAC7B,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC;IAC3B,QAAQ,CAAC,QAAQ,EAAE,UAAU,CAAC;IAC9B,QAAQ,CAAC,eAAe,EAAE,UAAU,CAAC;IACrC,QAAQ,CAAC,SAAS,EAAE,aAAa,CAAC;IAClC,QAAQ,CAAC,QAAQ,EAAE,eAAe,CAAC;IACnC,QAAQ,CAAC,YAAY,EAAE,gBAAgB,CAAC,CAAC,CAAC,CAAC;CAC5C;AAED,MAAM,MAAM,aAAa,CACvB,SAAS,SAAS,aAAa,GAAG,aAAa,EAC/C,CAAC,SAAS,cAAc,GAAG,KAAK,IAC9B,aAAa,CAAC,gBAAgB,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,CAAC;AAElD,2FAA2F;AAC3F,MAAM,MAAM,UAAU,GAAG,MAAM,CAAC;AAEhC,6FAA6F;AAC7F,MAAM,WAAW,eAAe,CAC9B,SAAS,SAAS,aAAa,GAAG,aAAa,EAC/C,CAAC,SAAS,cAAc,GAAG,KAAK;IAEhC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC;IAC3B,QAAQ,CAAC,YAAY,CAAC,EAAE,SAAS,CAAC,EAAE,CAAC;IACrC,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC;CAC9C;AAED;;;;;GAKG;AACH,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC;IAC3B,QAAQ,CAAC,YAAY,EAAE,SAAS,cAAc,EAAE,CAAC;IACjD,sGAAsG;IACtG,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC;CAChC;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CACzB,SAAS,SAAS,aAAa,GAAG,aAAa,EAC/C,KAAK,CAAC,CAAC,SAAS,cAAc,GAAG,KAAK,EACtC,UAAU,EAAE,eAAe,CAAC,SAAS,EAAE,CAAC,CAAC,GAAG,iBAAiB,CAO9D"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Turns a typed definition into a registration. The settings a renderer
3
+ * receives come from a document parsed against the schema for its type, so
4
+ * the widening to the stored shape happens here, once, and nowhere else.
5
+ */
6
+ export function defineBlock(definition) {
7
+ return {
8
+ type: definition.type,
9
+ owner: definition.owner,
10
+ capabilities: definition.capabilities ?? [],
11
+ render: definition.render,
12
+ };
13
+ }
14
+ //# sourceMappingURL=contract.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contract.js","sourceRoot":"","sources":["../src/contract.ts"],"names":[],"mappings":"AA4EA;;;;GAIG;AACH,MAAM,UAAU,WAAW,CAGzB,UAAyC;IACzC,OAAO;QACL,IAAI,EAAE,UAAU,CAAC,IAAI;QACrB,KAAK,EAAE,UAAU,CAAC,KAAK;QACvB,YAAY,EAAE,UAAU,CAAC,YAAY,IAAI,EAAE;QAC3C,MAAM,EAAE,UAAU,CAAC,MAAkC;KACtD,CAAC;AACJ,CAAC"}
@@ -0,0 +1,19 @@
1
+ export { CAPABILITY_NAMES } from './capabilities.js';
2
+ export type { Capabilities, CapabilityName, CapabilityObject, CartLineInput, } from './capabilities.js';
3
+ export { defineBlock } from './contract.js';
4
+ export type { BlockDefinition, BlockOwner, BlockRegistration, BlockRenderProps, BlockRenderer, BlockSettings, TextDirection, } from './contract.js';
5
+ export type { BlockNavigation } from './navigation.js';
6
+ export { createBlockRegistry } from './registry.js';
7
+ export type { BlockRegistry } from './registry.js';
8
+ export { defineBinding, defineSettings } from './authoring.js';
9
+ export type { BindingFile, SettingsFile, SettingsValues } from './authoring.js';
10
+ export { defineCodeBlock, shopBlocks } from './code-block.js';
11
+ export type { CodeBlock, CodeBlockModule } from './code-block.js';
12
+ export { CONTRACT_MAJOR, CONTRACT_VERSION } from './version.js';
13
+ export { resolveToken } from './tokens.js';
14
+ export { formatMoney } from './money.js';
15
+ export { imageSourceFor } from './renditions.js';
16
+ export type { ImageSource } from './renditions.js';
17
+ export { localize, pickLocale, textDirection } from './locale.js';
18
+ export type { ShopLanguages } from './locale.js';
19
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACrD,YAAY,EACV,YAAY,EACZ,cAAc,EACd,gBAAgB,EAChB,aAAa,GACd,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,YAAY,EACV,eAAe,EACf,UAAU,EACV,iBAAiB,EACjB,gBAAgB,EAChB,aAAa,EACb,aAAa,EACb,aAAa,GACd,MAAM,eAAe,CAAC;AAEvB,YAAY,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAEvD,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AACpD,YAAY,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAEnD,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAC/D,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAEhF,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC9D,YAAY,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAElE,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAEhE,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACjD,YAAY,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAClE,YAAY,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,11 @@
1
+ export { CAPABILITY_NAMES } from './capabilities.js';
2
+ export { defineBlock } from './contract.js';
3
+ export { createBlockRegistry } from './registry.js';
4
+ export { defineBinding, defineSettings } from './authoring.js';
5
+ export { defineCodeBlock, shopBlocks } from './code-block.js';
6
+ export { CONTRACT_MAJOR, CONTRACT_VERSION } from './version.js';
7
+ export { resolveToken } from './tokens.js';
8
+ export { formatMoney } from './money.js';
9
+ export { imageSourceFor } from './renditions.js';
10
+ export { localize, pickLocale, textDirection } from './locale.js';
11
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAQrD,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAa5C,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAGpD,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAG/D,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAG9D,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAEhE,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEjD,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,19 @@
1
+ import type { LocaleCode, LocalizedText } from '@shoplix-ai/sdui-schema';
2
+ import type { TextDirection } from './contract.js';
3
+ export interface ShopLanguages {
4
+ readonly default: LocaleCode;
5
+ readonly supported: readonly LocaleCode[];
6
+ }
7
+ /**
8
+ * The buyer's language: the first preferred locale the Shop supports, by
9
+ * exact code, then by base language either way round; the Shop's default
10
+ * when nothing matches.
11
+ */
12
+ export declare function pickLocale(languages: ShopLanguages, preferred: readonly string[]): LocaleCode;
13
+ /**
14
+ * One string out of a full locale object: the buyer's language, its base
15
+ * language, the default language, then whatever the text carries first.
16
+ */
17
+ export declare function localize(text: LocalizedText, language: LocaleCode, fallback: LocaleCode): string;
18
+ export declare function textDirection(language: LocaleCode): TextDirection;
19
+ //# sourceMappingURL=locale.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"locale.d.ts","sourceRoot":"","sources":["../src/locale.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AACzE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAEnD,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,OAAO,EAAE,UAAU,CAAC;IAC7B,QAAQ,CAAC,SAAS,EAAE,SAAS,UAAU,EAAE,CAAC;CAC3C;AAQD;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,SAAS,EAAE,aAAa,EAAE,SAAS,EAAE,SAAS,MAAM,EAAE,GAAG,UAAU,CAQ7F;AAED;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,aAAa,EAAE,QAAQ,EAAE,UAAU,EAAE,QAAQ,EAAE,UAAU,GAAG,MAAM,CAShG;AAED,wBAAgB,aAAa,CAAC,QAAQ,EAAE,UAAU,GAAG,aAAa,CAEjE"}
package/dist/locale.js ADDED
@@ -0,0 +1,36 @@
1
+ const RTL_LANGUAGES = new Set(['ar', 'he', 'fa', 'ur']);
2
+ function baseOf(locale) {
3
+ return locale.split('-')[0].toLowerCase();
4
+ }
5
+ /**
6
+ * The buyer's language: the first preferred locale the Shop supports, by
7
+ * exact code, then by base language either way round; the Shop's default
8
+ * when nothing matches.
9
+ */
10
+ export function pickLocale(languages, preferred) {
11
+ for (const candidate of preferred) {
12
+ if (languages.supported.includes(candidate))
13
+ return candidate;
14
+ const base = baseOf(candidate);
15
+ const match = languages.supported.find((code) => baseOf(code) === base);
16
+ if (match !== undefined)
17
+ return match;
18
+ }
19
+ return languages.default;
20
+ }
21
+ /**
22
+ * One string out of a full locale object: the buyer's language, its base
23
+ * language, the default language, then whatever the text carries first.
24
+ */
25
+ export function localize(text, language, fallback) {
26
+ return (text[language] ??
27
+ text[baseOf(language)] ??
28
+ text[fallback] ??
29
+ text[baseOf(fallback)] ??
30
+ Object.values(text)[0] ??
31
+ '');
32
+ }
33
+ export function textDirection(language) {
34
+ return RTL_LANGUAGES.has(baseOf(language)) ? 'rtl' : 'ltr';
35
+ }
36
+ //# sourceMappingURL=locale.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"locale.js","sourceRoot":"","sources":["../src/locale.ts"],"names":[],"mappings":"AAQA,MAAM,aAAa,GAAG,IAAI,GAAG,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;AAExD,SAAS,MAAM,CAAC,MAAc;IAC5B,OAAO,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAE,CAAC,WAAW,EAAE,CAAC;AAC7C,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,UAAU,CAAC,SAAwB,EAAE,SAA4B;IAC/E,KAAK,MAAM,SAAS,IAAI,SAAS,EAAE,CAAC;QAClC,IAAI,SAAS,CAAC,SAAS,CAAC,QAAQ,CAAC,SAAS,CAAC;YAAE,OAAO,SAAS,CAAC;QAC9D,MAAM,IAAI,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC;QAC/B,MAAM,KAAK,GAAG,SAAS,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC,CAAC;QACxE,IAAI,KAAK,KAAK,SAAS;YAAE,OAAO,KAAK,CAAC;IACxC,CAAC;IACD,OAAO,SAAS,CAAC,OAAO,CAAC;AAC3B,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,QAAQ,CAAC,IAAmB,EAAE,QAAoB,EAAE,QAAoB;IACtF,OAAO,CACL,IAAI,CAAC,QAAQ,CAAC;QACd,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QACtB,IAAI,CAAC,QAAQ,CAAC;QACd,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QACtB,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACtB,EAAE,CACH,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,QAAoB;IAChD,OAAO,aAAa,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC;AAC7D,CAAC"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Display-only money, formatted on the device in the buyer's language. The
3
+ * charged price always comes from Shopify checkout, never from this string.
4
+ */
5
+ export declare function formatMoney(amount: string | number, currencyCode: string, language: string): string | null;
6
+ //# sourceMappingURL=money.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"money.d.ts","sourceRoot":"","sources":["../src/money.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,wBAAgB,WAAW,CACzB,MAAM,EAAE,MAAM,GAAG,MAAM,EACvB,YAAY,EAAE,MAAM,EACpB,QAAQ,EAAE,MAAM,GACf,MAAM,GAAG,IAAI,CAUf"}
package/dist/money.js ADDED
@@ -0,0 +1,17 @@
1
+ const CURRENCY_CODE = /^[A-Z]{3}$/;
2
+ /**
3
+ * Display-only money, formatted on the device in the buyer's language. The
4
+ * charged price always comes from Shopify checkout, never from this string.
5
+ */
6
+ export function formatMoney(amount, currencyCode, language) {
7
+ const value = typeof amount === 'number' ? amount : Number(amount);
8
+ if (!Number.isFinite(value) || !CURRENCY_CODE.test(currencyCode))
9
+ return null;
10
+ try {
11
+ return new Intl.NumberFormat(language, { style: 'currency', currency: currencyCode }).format(value);
12
+ }
13
+ catch {
14
+ return `${amount} ${currencyCode}`;
15
+ }
16
+ }
17
+ //# sourceMappingURL=money.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"money.js","sourceRoot":"","sources":["../src/money.ts"],"names":[],"mappings":"AAAA,MAAM,aAAa,GAAG,YAAY,CAAC;AAEnC;;;GAGG;AACH,MAAM,UAAU,WAAW,CACzB,MAAuB,EACvB,YAAoB,EACpB,QAAgB;IAEhB,MAAM,KAAK,GAAG,OAAO,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IACnE,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,YAAY,CAAC;QAAE,OAAO,IAAI,CAAC;IAC9E,IAAI,CAAC;QACH,OAAO,IAAI,IAAI,CAAC,YAAY,CAAC,QAAQ,EAAE,EAAE,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,YAAY,EAAE,CAAC,CAAC,MAAM,CAC1F,KAAK,CACN,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,GAAG,MAAM,IAAI,YAAY,EAAE,CAAC;IACrC,CAAC;AACH,CAAC"}
@@ -0,0 +1,15 @@
1
+ import type { Action } from '@shoplix-ai/sdui-schema';
2
+ /**
3
+ * The only way a renderer moves the buyer, and it is as closed as the
4
+ * capability set: the action the document itself carries, and the implicit
5
+ * taps a block owns by its own kind — a card opening its entity, a search bar
6
+ * opening search. A renderer never sees a route, never a screen the document
7
+ * did not name, and never the router that owns them.
8
+ */
9
+ export interface BlockNavigation {
10
+ readonly run: (action: Action) => void;
11
+ readonly openProduct: (productId: string) => void;
12
+ readonly openCollection: (collectionId: string) => void;
13
+ readonly openSearch: () => void;
14
+ }
15
+ //# sourceMappingURL=navigation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"navigation.d.ts","sourceRoot":"","sources":["../src/navigation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AAEtD;;;;;;GAMG;AACH,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,GAAG,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,QAAQ,CAAC,WAAW,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IAClD,QAAQ,CAAC,cAAc,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,IAAI,CAAC;IACxD,QAAQ,CAAC,UAAU,EAAE,MAAM,IAAI,CAAC;CACjC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=navigation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"navigation.js","sourceRoot":"","sources":["../src/navigation.ts"],"names":[],"mappings":""}
@@ -0,0 +1,14 @@
1
+ import type { BlockOwner, BlockRegistration } from './contract.js';
2
+ /**
3
+ * The registry keyed by Block Type. One owner per type: a second owner is
4
+ * refused, the same owner may register again (module reloads do). Hosts
5
+ * create one and hand it to every package that registers renderers.
6
+ */
7
+ export interface BlockRegistry {
8
+ register(registration: BlockRegistration): void;
9
+ resolve(type: string): BlockRegistration | undefined;
10
+ ownerOf(type: string): BlockOwner | undefined;
11
+ types(): readonly string[];
12
+ }
13
+ export declare function createBlockRegistry(): BlockRegistry;
14
+ //# sourceMappingURL=registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAEnE;;;;GAIG;AACH,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,YAAY,EAAE,iBAAiB,GAAG,IAAI,CAAC;IAChD,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,iBAAiB,GAAG,SAAS,CAAC;IACrD,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS,CAAC;IAC9C,KAAK,IAAI,SAAS,MAAM,EAAE,CAAC;CAC5B;AAED,wBAAgB,mBAAmB,IAAI,aAAa,CAsBnD"}
@@ -0,0 +1,22 @@
1
+ export function createBlockRegistry() {
2
+ const entries = new Map();
3
+ return {
4
+ register(registration) {
5
+ const current = entries.get(registration.type);
6
+ if (current !== undefined && current.owner !== registration.owner) {
7
+ throw new Error(`Block Type "${registration.type}" is owned by "${current.owner}"; "${registration.owner}" cannot register it`);
8
+ }
9
+ entries.set(registration.type, registration);
10
+ },
11
+ resolve(type) {
12
+ return entries.get(type);
13
+ },
14
+ ownerOf(type) {
15
+ return entries.get(type)?.owner;
16
+ },
17
+ types() {
18
+ return [...entries.keys()];
19
+ },
20
+ };
21
+ }
22
+ //# sourceMappingURL=registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAcA,MAAM,UAAU,mBAAmB;IACjC,MAAM,OAAO,GAAG,IAAI,GAAG,EAA6B,CAAC;IACrD,OAAO;QACL,QAAQ,CAAC,YAAY;YACnB,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;YAC/C,IAAI,OAAO,KAAK,SAAS,IAAI,OAAO,CAAC,KAAK,KAAK,YAAY,CAAC,KAAK,EAAE,CAAC;gBAClE,MAAM,IAAI,KAAK,CACb,eAAe,YAAY,CAAC,IAAI,kBAAkB,OAAO,CAAC,KAAK,OAAO,YAAY,CAAC,KAAK,sBAAsB,CAC/G,CAAC;YACJ,CAAC;YACD,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;QAC/C,CAAC;QACD,OAAO,CAAC,IAAI;YACV,OAAO,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAC3B,CAAC;QACD,OAAO,CAAC,IAAI;YACV,OAAO,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,KAAK,CAAC;QAClC,CAAC;QACD,KAAK;YACH,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;QAC7B,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,13 @@
1
+ import type { AssetDisplay } from '@shoplix-ai/sdui-schema';
2
+ export interface ImageSource {
3
+ readonly uri: string;
4
+ readonly width?: number;
5
+ readonly height?: number;
6
+ }
7
+ /**
8
+ * The source to paint at a given display width in device pixels: the
9
+ * narrowest rendition at least that wide, the widest one when none reaches
10
+ * it, the asset's base url when it carries no renditions.
11
+ */
12
+ export declare function imageSourceFor(display: AssetDisplay, targetWidth: number): ImageSource;
13
+ //# sourceMappingURL=renditions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"renditions.d.ts","sourceRoot":"","sources":["../src/renditions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAE5D,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,GAAG,WAAW,CAWtF"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * The source to paint at a given display width in device pixels: the
3
+ * narrowest rendition at least that wide, the widest one when none reaches
4
+ * it, the asset's base url when it carries no renditions.
5
+ */
6
+ export function imageSourceFor(display, targetWidth) {
7
+ const byWidth = [...display.renditions].sort((a, b) => a.width - b.width);
8
+ const rendition = byWidth.find((entry) => entry.width >= targetWidth) ?? byWidth.at(-1);
9
+ if (rendition !== undefined) {
10
+ return { uri: rendition.url, width: rendition.width, height: rendition.height };
11
+ }
12
+ return {
13
+ uri: display.url,
14
+ ...(display.width !== undefined ? { width: display.width } : {}),
15
+ ...(display.height !== undefined ? { height: display.height } : {}),
16
+ };
17
+ }
18
+ //# sourceMappingURL=renditions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"renditions.js","sourceRoot":"","sources":["../src/renditions.ts"],"names":[],"mappings":"AAQA;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAAC,OAAqB,EAAE,WAAmB;IACvE,MAAM,OAAO,GAAG,CAAC,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC;IAC1E,MAAM,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,IAAI,WAAW,CAAC,IAAI,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IACxF,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;QAC5B,OAAO,EAAE,GAAG,EAAE,SAAS,CAAC,GAAG,EAAE,KAAK,EAAE,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,CAAC,MAAM,EAAE,CAAC;IAClF,CAAC;IACD,OAAO;QACL,GAAG,EAAE,OAAO,CAAC,GAAG;QAChB,GAAG,CAAC,OAAO,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAChE,GAAG,CAAC,OAAO,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACpE,CAAC;AACJ,CAAC"}
@@ -0,0 +1,8 @@
1
+ import type { ThemeTokens, TokenValue } from '@shoplix-ai/sdui-schema';
2
+ /**
3
+ * The value at the end of a token's alias chain. Takes the alias form a
4
+ * document carries (`{semantic.action}`) or a bare dotted path; answers
5
+ * undefined when the path names no token.
6
+ */
7
+ export declare function resolveToken(tokens: ThemeTokens, reference: string): TokenValue | undefined;
8
+ //# sourceMappingURL=tokens.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tokens.d.ts","sourceRoot":"","sources":["../src/tokens.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAa,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAclF;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS,CAK3F"}
package/dist/tokens.js ADDED
@@ -0,0 +1,26 @@
1
+ import { terminalTokenPath } from '@shoplix-ai/sdui-schema';
2
+ const ALIAS_BRACES = /^\{(.+)\}$/;
3
+ function leafAt(tokens, path) {
4
+ let node = tokens;
5
+ for (const key of path.split('.')) {
6
+ if (typeof node !== 'object' || node === null)
7
+ return undefined;
8
+ node = node[key];
9
+ }
10
+ if (typeof node !== 'object' || node === null || !('$value' in node))
11
+ return undefined;
12
+ return node;
13
+ }
14
+ /**
15
+ * The value at the end of a token's alias chain. Takes the alias form a
16
+ * document carries (`{semantic.action}`) or a bare dotted path; answers
17
+ * undefined when the path names no token.
18
+ */
19
+ export function resolveToken(tokens, reference) {
20
+ const path = ALIAS_BRACES.exec(reference)?.[1] ?? reference;
21
+ const terminal = terminalTokenPath(tokens, path);
22
+ if (terminal === null)
23
+ return undefined;
24
+ return leafAt(tokens, terminal)?.$value;
25
+ }
26
+ //# sourceMappingURL=tokens.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tokens.js","sourceRoot":"","sources":["../src/tokens.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAG5D,MAAM,YAAY,GAAG,YAAY,CAAC;AAElC,SAAS,MAAM,CAAC,MAAmB,EAAE,IAAY;IAC/C,IAAI,IAAI,GAAY,MAAM,CAAC;IAC3B,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;QAClC,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,IAAI;YAAE,OAAO,SAAS,CAAC;QAChE,IAAI,GAAI,IAAgC,CAAC,GAAG,CAAC,CAAC;IAChD,CAAC;IACD,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,IAAI,IAAI,CAAC,CAAC,QAAQ,IAAI,IAAI,CAAC;QAAE,OAAO,SAAS,CAAC;IACvF,OAAO,IAAiB,CAAC;AAC3B,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,YAAY,CAAC,MAAmB,EAAE,SAAiB;IACjE,MAAM,IAAI,GAAG,YAAY,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,SAAS,CAAC;IAC5D,MAAM,QAAQ,GAAG,iBAAiB,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IACjD,IAAI,QAAQ,KAAK,IAAI;QAAE,OAAO,SAAS,CAAC;IACxC,OAAO,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;AAC1C,CAAC"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * The contract's own version, pinned here so a runtime and a Shop package can
3
+ * both read it without a package file. A test holds it equal to package.json.
4
+ * The major is the compatibility line: a Shop package built against another
5
+ * major never meets this runtime, and a major bump is an announced event.
6
+ */
7
+ export declare const CONTRACT_VERSION = "1.0.0";
8
+ export declare const CONTRACT_MAJOR = 1;
9
+ //# sourceMappingURL=version.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,UAAU,CAAC;AAExC,eAAO,MAAM,cAAc,IAAI,CAAC"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * The contract's own version, pinned here so a runtime and a Shop package can
3
+ * both read it without a package file. A test holds it equal to package.json.
4
+ * The major is the compatibility line: a Shop package built against another
5
+ * major never meets this runtime, and a major bump is an announced event.
6
+ */
7
+ export const CONTRACT_VERSION = '1.0.0';
8
+ export const CONTRACT_MAJOR = 1;
9
+ //# sourceMappingURL=version.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,OAAO,CAAC;AAExC,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,CAAC"}
package/package.json ADDED
@@ -0,0 +1,50 @@
1
+ {
2
+ "name": "@shoplix-ai/block-kit",
3
+ "version": "1.0.0",
4
+ "description": "The renderer contract every Block Type renderer is written against: what a renderer receives, how a Block Type is registered with its owner, the closed capability set, and the small helpers renderers share. Contract only, no renderers.",
5
+ "license": "MIT",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/Rastova/shoplix.git",
9
+ "directory": "packages/block-kit"
10
+ },
11
+ "type": "module",
12
+ "engines": {
13
+ "node": ">=22.13"
14
+ },
15
+ "exports": {
16
+ ".": {
17
+ "types": "./dist/index.d.ts",
18
+ "default": "./dist/index.js"
19
+ },
20
+ "./package.json": "./package.json"
21
+ },
22
+ "files": [
23
+ "dist"
24
+ ],
25
+ "publishConfig": {
26
+ "access": "public"
27
+ },
28
+ "dependencies": {
29
+ "@shoplix-ai/sdui-schema": "1.0.0"
30
+ },
31
+ "peerDependencies": {
32
+ "react": ">=19.0.0"
33
+ },
34
+ "devDependencies": {
35
+ "@eslint/js": "^9.39.1",
36
+ "@types/react": "~19.2.2",
37
+ "eslint": "^9.39.1",
38
+ "eslint-config-prettier": "^10.1.1",
39
+ "globals": "^16.5.0",
40
+ "typescript": "5.9.2",
41
+ "typescript-eslint": "^8.50.0",
42
+ "vitest": "^4.0.18"
43
+ },
44
+ "scripts": {
45
+ "build": "tsc -p tsconfig.build.json",
46
+ "typecheck": "tsc -p tsconfig.json --noEmit",
47
+ "test": "vitest run",
48
+ "lint": "eslint src/ tests/"
49
+ }
50
+ }