@orderlyshop/web-components 0.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/AGENTS.md +110 -0
- package/README.md +685 -0
- package/bin/orderly-build-category-pages.mjs +160 -0
- package/bin/orderly-generate-category-pages.mjs +308 -0
- package/bin/orderly-hydrate-static-pages.mjs +595 -0
- package/bin/orderly-init-navigation.mjs +327 -0
- package/bin/orderly-init-shop.mjs +876 -0
- package/bin/orderly-init-taxonomy.mjs +2 -0
- package/bin/orderly-publish-site.mjs +342 -0
- package/custom-elements.json +495 -0
- package/dist/browser/orderly-web-components.define.global.js +3085 -0
- package/dist/browser/orderly-web-components.define.global.js.map +1 -0
- package/dist/browser/orderly-web-components.global.js +3085 -0
- package/dist/browser/orderly-web-components.global.js.map +1 -0
- package/dist/default-shop-DWdB_MRd.d.ts +220 -0
- package/dist/default-shop.d.ts +6 -0
- package/dist/default-shop.js +762 -0
- package/dist/default-shop.js.map +1 -0
- package/dist/define-IAQk8OmQ.d.ts +9 -0
- package/dist/define.d.ts +2 -0
- package/dist/define.js +10266 -0
- package/dist/define.js.map +1 -0
- package/dist/index.d.ts +683 -0
- package/dist/index.js +10589 -0
- package/dist/index.js.map +1 -0
- package/dist/navigation.d.ts +51 -0
- package/dist/navigation.js +818 -0
- package/dist/navigation.js.map +1 -0
- package/dist/query.d.ts +31 -0
- package/dist/query.js +115 -0
- package/dist/query.js.map +1 -0
- package/dist/registry-CPDecU3g.d.ts +6 -0
- package/dist/shop-BnT1C6kG.d.ts +173 -0
- package/dist/shop-query.d.ts +8 -0
- package/dist/shop-query.js +100 -0
- package/dist/shop-query.js.map +1 -0
- package/dist/shop.d.ts +8 -0
- package/dist/shop.js +10359 -0
- package/dist/shop.js.map +1 -0
- package/dist/stores.d.ts +46 -0
- package/dist/stores.js +145 -0
- package/dist/stores.js.map +1 -0
- package/dist/taxonomy.d.ts +35 -0
- package/dist/taxonomy.js +247 -0
- package/dist/taxonomy.js.map +1 -0
- package/dist/types-CCQDd6Nd.d.ts +95 -0
- package/docs/components/README.md +610 -0
- package/docs/components/product-grid.md +176 -0
- package/docs/components/product-rail.md +174 -0
- package/examples/shop/README.md +71 -0
- package/examples/shop/package.json +28 -0
- package/examples/shop/src/category.html +20 -0
- package/examples/shop/src/checkout.html +21 -0
- package/examples/shop/src/forretningsbetingelser.html +80 -0
- package/examples/shop/src/includes/body-end.html +1 -0
- package/examples/shop/src/includes/body-start.html +2 -0
- package/examples/shop/src/includes/head.html +32 -0
- package/examples/shop/src/index.html +25 -0
- package/examples/shop/src/navigation.ts +154 -0
- package/examples/shop/src/product.html +24 -0
- package/examples/shop/src/templates/shop-footer.html +76 -0
- package/examples/shop/tsconfig.json +32 -0
- package/examples/shop/vite.config.mjs +184 -0
- package/html-custom-data.json +262 -0
- package/package.json +118 -0
- package/server/README.md +111 -0
- package/server/apache/.htaccess +18 -0
- package/server/nginx/orderly-products.conf +24 -0
- package/server/node/product-snapshot-server.mjs +133 -0
- package/server/php/orderly-product.php +204 -0
package/dist/stores.d.ts
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { DraftOrder } from '@orderlyshop/core-client';
|
|
2
|
+
import { C as CheckoutProfile } from './types-CCQDd6Nd.js';
|
|
3
|
+
import './query.js';
|
|
4
|
+
|
|
5
|
+
interface BasketStore {
|
|
6
|
+
load(): DraftOrder | undefined | Promise<DraftOrder | undefined>;
|
|
7
|
+
save(draft: DraftOrder): void | Promise<void>;
|
|
8
|
+
clear(): void | Promise<void>;
|
|
9
|
+
}
|
|
10
|
+
interface CheckoutProfileStore {
|
|
11
|
+
load(): CheckoutProfile | undefined | Promise<CheckoutProfile | undefined>;
|
|
12
|
+
save(profile: CheckoutProfile): void | Promise<void>;
|
|
13
|
+
clear(): void | Promise<void>;
|
|
14
|
+
}
|
|
15
|
+
declare const defaultBasketStorageKey = "orderly.web-components.basket.v1";
|
|
16
|
+
declare const defaultCheckoutProfileStorageKey = "orderly.web-components.checkout-profile.v1";
|
|
17
|
+
declare class MemoryBasketStore implements BasketStore {
|
|
18
|
+
private draft?;
|
|
19
|
+
load(): DraftOrder | undefined;
|
|
20
|
+
save(draft: DraftOrder): void;
|
|
21
|
+
clear(): void;
|
|
22
|
+
}
|
|
23
|
+
declare class LocalStorageBasketStore implements BasketStore {
|
|
24
|
+
private readonly key;
|
|
25
|
+
constructor(key?: string);
|
|
26
|
+
load(): DraftOrder | undefined;
|
|
27
|
+
save(draft: DraftOrder): void;
|
|
28
|
+
clear(): void;
|
|
29
|
+
}
|
|
30
|
+
declare class MemoryCheckoutProfileStore implements CheckoutProfileStore {
|
|
31
|
+
private profile?;
|
|
32
|
+
load(): CheckoutProfile | undefined;
|
|
33
|
+
save(profile: CheckoutProfile): void;
|
|
34
|
+
clear(): void;
|
|
35
|
+
}
|
|
36
|
+
declare class LocalStorageCheckoutProfileStore implements CheckoutProfileStore {
|
|
37
|
+
private readonly key;
|
|
38
|
+
constructor(key?: string);
|
|
39
|
+
load(): CheckoutProfile | undefined;
|
|
40
|
+
save(profile: CheckoutProfile): void;
|
|
41
|
+
clear(): void;
|
|
42
|
+
}
|
|
43
|
+
declare function createEmptyDraftOrder(): DraftOrder;
|
|
44
|
+
declare function sanitizeCheckoutProfile(profile: Partial<CheckoutProfile> | undefined): CheckoutProfile;
|
|
45
|
+
|
|
46
|
+
export { type BasketStore, type CheckoutProfileStore, LocalStorageBasketStore, LocalStorageCheckoutProfileStore, MemoryBasketStore, MemoryCheckoutProfileStore, createEmptyDraftOrder, defaultBasketStorageKey, defaultCheckoutProfileStorageKey, sanitizeCheckoutProfile };
|
package/dist/stores.js
ADDED
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
// src/stores.ts
|
|
2
|
+
import { create, fromJsonString, toJsonString } from "@bufbuild/protobuf";
|
|
3
|
+
import {
|
|
4
|
+
AddressSchema,
|
|
5
|
+
DraftOrderSchema,
|
|
6
|
+
PhoneNumberSchema
|
|
7
|
+
} from "@orderlyshop/core-client";
|
|
8
|
+
var defaultBasketStorageKey = "orderly.web-components.basket.v1";
|
|
9
|
+
var defaultCheckoutProfileStorageKey = "orderly.web-components.checkout-profile.v1";
|
|
10
|
+
var MemoryBasketStore = class {
|
|
11
|
+
draft;
|
|
12
|
+
load() {
|
|
13
|
+
return this.draft;
|
|
14
|
+
}
|
|
15
|
+
save(draft) {
|
|
16
|
+
this.draft = draft;
|
|
17
|
+
}
|
|
18
|
+
clear() {
|
|
19
|
+
this.draft = void 0;
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
var LocalStorageBasketStore = class {
|
|
23
|
+
constructor(key = defaultBasketStorageKey) {
|
|
24
|
+
this.key = key;
|
|
25
|
+
}
|
|
26
|
+
key;
|
|
27
|
+
load() {
|
|
28
|
+
const storage = getStorage();
|
|
29
|
+
if (!storage) {
|
|
30
|
+
return void 0;
|
|
31
|
+
}
|
|
32
|
+
const raw = storage.getItem(this.key);
|
|
33
|
+
if (!raw) {
|
|
34
|
+
return void 0;
|
|
35
|
+
}
|
|
36
|
+
try {
|
|
37
|
+
return fromJsonString(DraftOrderSchema, raw);
|
|
38
|
+
} catch {
|
|
39
|
+
return void 0;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
save(draft) {
|
|
43
|
+
const storage = getStorage();
|
|
44
|
+
if (!storage) {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
storage.setItem(this.key, toJsonString(DraftOrderSchema, draft));
|
|
48
|
+
}
|
|
49
|
+
clear() {
|
|
50
|
+
getStorage()?.removeItem(this.key);
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
var MemoryCheckoutProfileStore = class {
|
|
54
|
+
profile;
|
|
55
|
+
load() {
|
|
56
|
+
return this.profile;
|
|
57
|
+
}
|
|
58
|
+
save(profile) {
|
|
59
|
+
this.profile = sanitizeCheckoutProfile(profile);
|
|
60
|
+
}
|
|
61
|
+
clear() {
|
|
62
|
+
this.profile = void 0;
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
var LocalStorageCheckoutProfileStore = class {
|
|
66
|
+
constructor(key = defaultCheckoutProfileStorageKey) {
|
|
67
|
+
this.key = key;
|
|
68
|
+
}
|
|
69
|
+
key;
|
|
70
|
+
load() {
|
|
71
|
+
const storage = getStorage();
|
|
72
|
+
if (!storage) {
|
|
73
|
+
return void 0;
|
|
74
|
+
}
|
|
75
|
+
const raw = storage.getItem(this.key);
|
|
76
|
+
if (!raw) {
|
|
77
|
+
return void 0;
|
|
78
|
+
}
|
|
79
|
+
try {
|
|
80
|
+
const parsed = JSON.parse(raw);
|
|
81
|
+
return sanitizeCheckoutProfile({
|
|
82
|
+
address: parsed.address ? fromJsonString(AddressSchema, parsed.address) : void 0,
|
|
83
|
+
email: parsed.email,
|
|
84
|
+
phoneNumber: parsed.phoneNumber ? fromJsonString(PhoneNumberSchema, parsed.phoneNumber) : void 0,
|
|
85
|
+
updatedAt: parsed.updatedAt
|
|
86
|
+
});
|
|
87
|
+
} catch {
|
|
88
|
+
return void 0;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
save(profile) {
|
|
92
|
+
const storage = getStorage();
|
|
93
|
+
if (!storage) {
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
const sanitized = sanitizeCheckoutProfile(profile);
|
|
97
|
+
storage.setItem(this.key, JSON.stringify({
|
|
98
|
+
address: sanitized.address ? toJsonString(AddressSchema, sanitized.address) : void 0,
|
|
99
|
+
email: sanitized.email,
|
|
100
|
+
phoneNumber: sanitized.phoneNumber ? toJsonString(PhoneNumberSchema, sanitized.phoneNumber) : void 0,
|
|
101
|
+
updatedAt: sanitized.updatedAt
|
|
102
|
+
}));
|
|
103
|
+
}
|
|
104
|
+
clear() {
|
|
105
|
+
getStorage()?.removeItem(this.key);
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
function createEmptyDraftOrder() {
|
|
109
|
+
return create(DraftOrderSchema, {
|
|
110
|
+
OrderLines: [],
|
|
111
|
+
ExtraLines: [],
|
|
112
|
+
Errors: [],
|
|
113
|
+
PaymentOptions: [],
|
|
114
|
+
Discounts: [],
|
|
115
|
+
Vouchers: [],
|
|
116
|
+
Messages: [],
|
|
117
|
+
Related: []
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
function sanitizeCheckoutProfile(profile) {
|
|
121
|
+
return {
|
|
122
|
+
address: profile?.address ? create(AddressSchema, profile.address) : void 0,
|
|
123
|
+
email: typeof profile?.email === "string" && profile.email.length > 0 ? profile.email : void 0,
|
|
124
|
+
phoneNumber: profile?.phoneNumber ? create(PhoneNumberSchema, profile.phoneNumber) : void 0,
|
|
125
|
+
updatedAt: typeof profile?.updatedAt === "string" && profile.updatedAt.length > 0 ? profile.updatedAt : (/* @__PURE__ */ new Date()).toISOString()
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
function getStorage() {
|
|
129
|
+
try {
|
|
130
|
+
return globalThis.localStorage;
|
|
131
|
+
} catch {
|
|
132
|
+
return void 0;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
export {
|
|
136
|
+
LocalStorageBasketStore,
|
|
137
|
+
LocalStorageCheckoutProfileStore,
|
|
138
|
+
MemoryBasketStore,
|
|
139
|
+
MemoryCheckoutProfileStore,
|
|
140
|
+
createEmptyDraftOrder,
|
|
141
|
+
defaultBasketStorageKey,
|
|
142
|
+
defaultCheckoutProfileStorageKey,
|
|
143
|
+
sanitizeCheckoutProfile
|
|
144
|
+
};
|
|
145
|
+
//# sourceMappingURL=stores.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/stores.ts"],"sourcesContent":["import { create, fromJsonString, toJsonString } from \"@bufbuild/protobuf\";\nimport {\n AddressSchema,\n DraftOrderSchema,\n PhoneNumberSchema,\n type Address,\n type DraftOrder,\n type PhoneNumber\n} from \"@orderlyshop/core-client\";\nimport type { CheckoutProfile } from \"./types.js\";\n\nexport interface BasketStore {\n load(): DraftOrder | undefined | Promise<DraftOrder | undefined>;\n save(draft: DraftOrder): void | Promise<void>;\n clear(): void | Promise<void>;\n}\n\nexport interface CheckoutProfileStore {\n load(): CheckoutProfile | undefined | Promise<CheckoutProfile | undefined>;\n save(profile: CheckoutProfile): void | Promise<void>;\n clear(): void | Promise<void>;\n}\n\nexport const defaultBasketStorageKey = \"orderly.web-components.basket.v1\";\nexport const defaultCheckoutProfileStorageKey = \"orderly.web-components.checkout-profile.v1\";\n\nexport class MemoryBasketStore implements BasketStore {\n private draft?: DraftOrder;\n\n load(): DraftOrder | undefined {\n return this.draft;\n }\n\n save(draft: DraftOrder): void {\n this.draft = draft;\n }\n\n clear(): void {\n this.draft = undefined;\n }\n}\n\nexport class LocalStorageBasketStore implements BasketStore {\n constructor(private readonly key = defaultBasketStorageKey) {}\n\n load(): DraftOrder | undefined {\n const storage = getStorage();\n if (!storage) {\n return undefined;\n }\n const raw = storage.getItem(this.key);\n if (!raw) {\n return undefined;\n }\n try {\n return fromJsonString(DraftOrderSchema, raw);\n } catch {\n return undefined;\n }\n }\n\n save(draft: DraftOrder): void {\n const storage = getStorage();\n if (!storage) {\n return;\n }\n storage.setItem(this.key, toJsonString(DraftOrderSchema, draft));\n }\n\n clear(): void {\n getStorage()?.removeItem(this.key);\n }\n}\n\nexport class MemoryCheckoutProfileStore implements CheckoutProfileStore {\n private profile?: CheckoutProfile;\n\n load(): CheckoutProfile | undefined {\n return this.profile;\n }\n\n save(profile: CheckoutProfile): void {\n this.profile = sanitizeCheckoutProfile(profile);\n }\n\n clear(): void {\n this.profile = undefined;\n }\n}\n\nexport class LocalStorageCheckoutProfileStore implements CheckoutProfileStore {\n constructor(private readonly key = defaultCheckoutProfileStorageKey) {}\n\n load(): CheckoutProfile | undefined {\n const storage = getStorage();\n if (!storage) {\n return undefined;\n }\n const raw = storage.getItem(this.key);\n if (!raw) {\n return undefined;\n }\n try {\n const parsed = JSON.parse(raw) as StoredCheckoutProfile;\n return sanitizeCheckoutProfile({\n address: parsed.address ? fromJsonString(AddressSchema, parsed.address) : undefined,\n email: parsed.email,\n phoneNumber: parsed.phoneNumber ? fromJsonString(PhoneNumberSchema, parsed.phoneNumber) : undefined,\n updatedAt: parsed.updatedAt\n });\n } catch {\n return undefined;\n }\n }\n\n save(profile: CheckoutProfile): void {\n const storage = getStorage();\n if (!storage) {\n return;\n }\n const sanitized = sanitizeCheckoutProfile(profile);\n storage.setItem(this.key, JSON.stringify({\n address: sanitized.address ? toJsonString(AddressSchema, sanitized.address) : undefined,\n email: sanitized.email,\n phoneNumber: sanitized.phoneNumber ? toJsonString(PhoneNumberSchema, sanitized.phoneNumber) : undefined,\n updatedAt: sanitized.updatedAt\n } satisfies StoredCheckoutProfile));\n }\n\n clear(): void {\n getStorage()?.removeItem(this.key);\n }\n}\n\nexport function createEmptyDraftOrder(): DraftOrder {\n return create(DraftOrderSchema, {\n OrderLines: [],\n ExtraLines: [],\n Errors: [],\n PaymentOptions: [],\n Discounts: [],\n Vouchers: [],\n Messages: [],\n Related: []\n });\n}\n\nexport function sanitizeCheckoutProfile(profile: Partial<CheckoutProfile> | undefined): CheckoutProfile {\n return {\n address: profile?.address ? create(AddressSchema, profile.address as Address) : undefined,\n email: typeof profile?.email === \"string\" && profile.email.length > 0 ? profile.email : undefined,\n phoneNumber: profile?.phoneNumber ? create(PhoneNumberSchema, profile.phoneNumber as PhoneNumber) : undefined,\n updatedAt: typeof profile?.updatedAt === \"string\" && profile.updatedAt.length > 0\n ? profile.updatedAt\n : new Date().toISOString()\n };\n}\n\ninterface StoredCheckoutProfile {\n address?: string;\n email?: string;\n phoneNumber?: string;\n updatedAt: string;\n}\n\nfunction getStorage(): Storage | undefined {\n try {\n return globalThis.localStorage;\n } catch {\n return undefined;\n }\n}\n"],"mappings":";AAAA,SAAS,QAAQ,gBAAgB,oBAAoB;AACrD;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OAIK;AAeA,IAAM,0BAA0B;AAChC,IAAM,mCAAmC;AAEzC,IAAM,oBAAN,MAA+C;AAAA,EAC5C;AAAA,EAER,OAA+B;AAC7B,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,KAAK,OAAyB;AAC5B,SAAK,QAAQ;AAAA,EACf;AAAA,EAEA,QAAc;AACZ,SAAK,QAAQ;AAAA,EACf;AACF;AAEO,IAAM,0BAAN,MAAqD;AAAA,EAC1D,YAA6B,MAAM,yBAAyB;AAA/B;AAAA,EAAgC;AAAA,EAAhC;AAAA,EAE7B,OAA+B;AAC7B,UAAM,UAAU,WAAW;AAC3B,QAAI,CAAC,SAAS;AACZ,aAAO;AAAA,IACT;AACA,UAAM,MAAM,QAAQ,QAAQ,KAAK,GAAG;AACpC,QAAI,CAAC,KAAK;AACR,aAAO;AAAA,IACT;AACA,QAAI;AACF,aAAO,eAAe,kBAAkB,GAAG;AAAA,IAC7C,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EAEA,KAAK,OAAyB;AAC5B,UAAM,UAAU,WAAW;AAC3B,QAAI,CAAC,SAAS;AACZ;AAAA,IACF;AACA,YAAQ,QAAQ,KAAK,KAAK,aAAa,kBAAkB,KAAK,CAAC;AAAA,EACjE;AAAA,EAEA,QAAc;AACZ,eAAW,GAAG,WAAW,KAAK,GAAG;AAAA,EACnC;AACF;AAEO,IAAM,6BAAN,MAAiE;AAAA,EAC9D;AAAA,EAER,OAAoC;AAClC,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,KAAK,SAAgC;AACnC,SAAK,UAAU,wBAAwB,OAAO;AAAA,EAChD;AAAA,EAEA,QAAc;AACZ,SAAK,UAAU;AAAA,EACjB;AACF;AAEO,IAAM,mCAAN,MAAuE;AAAA,EAC5E,YAA6B,MAAM,kCAAkC;AAAxC;AAAA,EAAyC;AAAA,EAAzC;AAAA,EAE7B,OAAoC;AAClC,UAAM,UAAU,WAAW;AAC3B,QAAI,CAAC,SAAS;AACZ,aAAO;AAAA,IACT;AACA,UAAM,MAAM,QAAQ,QAAQ,KAAK,GAAG;AACpC,QAAI,CAAC,KAAK;AACR,aAAO;AAAA,IACT;AACA,QAAI;AACF,YAAM,SAAS,KAAK,MAAM,GAAG;AAC7B,aAAO,wBAAwB;AAAA,QAC7B,SAAS,OAAO,UAAU,eAAe,eAAe,OAAO,OAAO,IAAI;AAAA,QAC1E,OAAO,OAAO;AAAA,QACd,aAAa,OAAO,cAAc,eAAe,mBAAmB,OAAO,WAAW,IAAI;AAAA,QAC1F,WAAW,OAAO;AAAA,MACpB,CAAC;AAAA,IACH,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EAEA,KAAK,SAAgC;AACnC,UAAM,UAAU,WAAW;AAC3B,QAAI,CAAC,SAAS;AACZ;AAAA,IACF;AACA,UAAM,YAAY,wBAAwB,OAAO;AACjD,YAAQ,QAAQ,KAAK,KAAK,KAAK,UAAU;AAAA,MACvC,SAAS,UAAU,UAAU,aAAa,eAAe,UAAU,OAAO,IAAI;AAAA,MAC9E,OAAO,UAAU;AAAA,MACjB,aAAa,UAAU,cAAc,aAAa,mBAAmB,UAAU,WAAW,IAAI;AAAA,MAC9F,WAAW,UAAU;AAAA,IACvB,CAAiC,CAAC;AAAA,EACpC;AAAA,EAEA,QAAc;AACZ,eAAW,GAAG,WAAW,KAAK,GAAG;AAAA,EACnC;AACF;AAEO,SAAS,wBAAoC;AAClD,SAAO,OAAO,kBAAkB;AAAA,IAC9B,YAAY,CAAC;AAAA,IACb,YAAY,CAAC;AAAA,IACb,QAAQ,CAAC;AAAA,IACT,gBAAgB,CAAC;AAAA,IACjB,WAAW,CAAC;AAAA,IACZ,UAAU,CAAC;AAAA,IACX,UAAU,CAAC;AAAA,IACX,SAAS,CAAC;AAAA,EACZ,CAAC;AACH;AAEO,SAAS,wBAAwB,SAAgE;AACtG,SAAO;AAAA,IACL,SAAS,SAAS,UAAU,OAAO,eAAe,QAAQ,OAAkB,IAAI;AAAA,IAChF,OAAO,OAAO,SAAS,UAAU,YAAY,QAAQ,MAAM,SAAS,IAAI,QAAQ,QAAQ;AAAA,IACxF,aAAa,SAAS,cAAc,OAAO,mBAAmB,QAAQ,WAA0B,IAAI;AAAA,IACpG,WAAW,OAAO,SAAS,cAAc,YAAY,QAAQ,UAAU,SAAS,IAC5E,QAAQ,aACR,oBAAI,KAAK,GAAE,YAAY;AAAA,EAC7B;AACF;AASA,SAAS,aAAkC;AACzC,MAAI;AACF,WAAO,WAAW;AAAA,EACpB,QAAQ;AACN,WAAO;AAAA,EACT;AACF;","names":[]}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { a as NavigationDefinition, b as CategoryUrlMode, R as ResolvedNavigationItem } from './types-CCQDd6Nd.js';
|
|
2
|
+
export { c as CategoryDefinition, d as CategoryNavigationItem, e as NavigationMetadata } from './types-CCQDd6Nd.js';
|
|
3
|
+
import '@orderlyshop/core-client';
|
|
4
|
+
import './query.js';
|
|
5
|
+
|
|
6
|
+
declare const defaultCategoryPageRoot = "/categories/";
|
|
7
|
+
interface NavigationBuildOptions {
|
|
8
|
+
pageRoot?: string;
|
|
9
|
+
urlMode?: CategoryUrlMode;
|
|
10
|
+
description?: (input: NavigationDescriptionInput) => string;
|
|
11
|
+
}
|
|
12
|
+
type CategoryNavigationOptions = NavigationBuildOptions;
|
|
13
|
+
interface NavigationDescriptionInput {
|
|
14
|
+
definition: NavigationDefinition;
|
|
15
|
+
parent?: NavigationDefinition;
|
|
16
|
+
pathLabels: string[];
|
|
17
|
+
}
|
|
18
|
+
type CategoryDescriptionInput = NavigationDescriptionInput;
|
|
19
|
+
declare function createCategoryNavigation(definitions: NavigationDefinition[], options?: NavigationBuildOptions): ResolvedNavigationItem[];
|
|
20
|
+
interface NavigationValidationResult {
|
|
21
|
+
valid: boolean;
|
|
22
|
+
errors: string[];
|
|
23
|
+
}
|
|
24
|
+
declare function validateNavigationDefinitions(definitions: NavigationDefinition[]): NavigationValidationResult;
|
|
25
|
+
declare function navigationConfigurationError(definitions: NavigationDefinition[]): string | undefined;
|
|
26
|
+
declare function assertValidNavigationDefinitions(definitions: NavigationDefinition[]): void;
|
|
27
|
+
declare function flattenCategoryNavigation(items: ResolvedNavigationItem[]): ResolvedNavigationItem[];
|
|
28
|
+
declare function findCategoryById(id: string, items: ResolvedNavigationItem[]): ResolvedNavigationItem | undefined;
|
|
29
|
+
declare function findCategoryBySlug(slug: string, items: ResolvedNavigationItem[]): ResolvedNavigationItem | undefined;
|
|
30
|
+
declare function findCategoryByIdOrSlug(value: string, items: ResolvedNavigationItem[]): ResolvedNavigationItem | undefined;
|
|
31
|
+
declare function categoryPagePath(id: string, options?: NavigationBuildOptions): string;
|
|
32
|
+
declare function resolveCategoryUrlMode(url?: string | URL | Location, options?: Pick<NavigationBuildOptions, "pageRoot">): CategoryUrlMode;
|
|
33
|
+
declare function categoryFromUrl(url: string | URL | Location, items: ResolvedNavigationItem[], options?: NavigationBuildOptions): ResolvedNavigationItem;
|
|
34
|
+
|
|
35
|
+
export { type CategoryDescriptionInput, type CategoryNavigationOptions, CategoryUrlMode, type NavigationBuildOptions, NavigationDefinition, type NavigationDescriptionInput, type NavigationValidationResult, ResolvedNavigationItem, assertValidNavigationDefinitions, categoryFromUrl, categoryPagePath, createCategoryNavigation, defaultCategoryPageRoot, findCategoryById, findCategoryByIdOrSlug, findCategoryBySlug, flattenCategoryNavigation, navigationConfigurationError, resolveCategoryUrlMode, validateNavigationDefinitions };
|
package/dist/taxonomy.js
ADDED
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
// src/taxonomy.ts
|
|
2
|
+
import { clone, create as create2 } from "@bufbuild/protobuf";
|
|
3
|
+
import { SearchQuerySchema as SearchQuerySchema2 } from "@orderlyshop/core-client";
|
|
4
|
+
|
|
5
|
+
// src/query.ts
|
|
6
|
+
import { create } from "@bufbuild/protobuf";
|
|
7
|
+
import {
|
|
8
|
+
SearchQuerySchema,
|
|
9
|
+
TagSchema
|
|
10
|
+
} from "@orderlyshop/core-client";
|
|
11
|
+
function createSearchQuery(input = {}) {
|
|
12
|
+
return create(SearchQuerySchema, {
|
|
13
|
+
Query: input.query ?? input.keywords,
|
|
14
|
+
HiddenQuery: input.hiddenQuery,
|
|
15
|
+
Tags: (input.tags ?? []).map((tag) => create(TagSchema, { Value: tag })),
|
|
16
|
+
OrderBy: input.orderBy ?? [],
|
|
17
|
+
StoreId: input.storeId,
|
|
18
|
+
Featured: input.featured ?? false
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
function normalizeSearchQuery(input = {}) {
|
|
22
|
+
if (isCoreSearchQuery(input)) {
|
|
23
|
+
return create(SearchQuerySchema, input);
|
|
24
|
+
}
|
|
25
|
+
return createSearchQuery(input);
|
|
26
|
+
}
|
|
27
|
+
function isCoreSearchQuery(input) {
|
|
28
|
+
return "Query" in input || "HiddenQuery" in input || "Tags" in input || "OrderBy" in input || "StoreId" in input || "Featured" in input;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// src/taxonomy.ts
|
|
32
|
+
var defaultCategoryPageRoot = "/categories/";
|
|
33
|
+
function createCategoryNavigation(definitions, options = {}) {
|
|
34
|
+
assertValidNavigationDefinitions(definitions);
|
|
35
|
+
const pageRoot = options.pageRoot ?? defaultCategoryPageRoot;
|
|
36
|
+
const urlMode = options.urlMode ?? "path";
|
|
37
|
+
return definitions.map((definition) => {
|
|
38
|
+
return createCategoryItem({
|
|
39
|
+
definition,
|
|
40
|
+
pageRoot,
|
|
41
|
+
urlMode,
|
|
42
|
+
description: options.description,
|
|
43
|
+
pathLabels: [definition.label],
|
|
44
|
+
pathSlugs: [definition.slug]
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
function validateNavigationDefinitions(definitions) {
|
|
49
|
+
const errors = [];
|
|
50
|
+
const seenIds = /* @__PURE__ */ new Map();
|
|
51
|
+
const seenSlugs = /* @__PURE__ */ new Map();
|
|
52
|
+
if (!Array.isArray(definitions) || definitions.length === 0) {
|
|
53
|
+
errors.push("navigationDefinitions must contain at least one category.");
|
|
54
|
+
return { valid: false, errors };
|
|
55
|
+
}
|
|
56
|
+
validateNavigationLevel(definitions, {
|
|
57
|
+
errors,
|
|
58
|
+
seenIds,
|
|
59
|
+
seenSlugs,
|
|
60
|
+
pathLabels: [],
|
|
61
|
+
pathSlugs: []
|
|
62
|
+
});
|
|
63
|
+
return { valid: errors.length === 0, errors };
|
|
64
|
+
}
|
|
65
|
+
function navigationConfigurationError(definitions) {
|
|
66
|
+
const result = validateNavigationDefinitions(definitions);
|
|
67
|
+
return result.valid ? void 0 : `Navigation configuration error: ${result.errors.join(" ")}`;
|
|
68
|
+
}
|
|
69
|
+
function assertValidNavigationDefinitions(definitions) {
|
|
70
|
+
const error = navigationConfigurationError(definitions);
|
|
71
|
+
if (error) {
|
|
72
|
+
throw new Error(error);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
function flattenCategoryNavigation(items) {
|
|
76
|
+
return items.flatMap((item) => [item, ...flattenCategoryNavigation(item.children ?? [])]);
|
|
77
|
+
}
|
|
78
|
+
function findCategoryById(id, items) {
|
|
79
|
+
return flattenCategoryNavigation(items).find((item) => item.id === id);
|
|
80
|
+
}
|
|
81
|
+
function findCategoryBySlug(slug, items) {
|
|
82
|
+
return flattenCategoryNavigation(items).find((item) => item.metadata.slug === slug || item.id === slug);
|
|
83
|
+
}
|
|
84
|
+
function findCategoryByIdOrSlug(value, items) {
|
|
85
|
+
return findCategoryById(value, items) ?? findCategoryBySlug(value, items);
|
|
86
|
+
}
|
|
87
|
+
function categoryPagePath(id, options = {}) {
|
|
88
|
+
const pageRoot = options.pageRoot ?? defaultCategoryPageRoot;
|
|
89
|
+
if (options.urlMode === "hash") {
|
|
90
|
+
return `${pageRoot}#id=${encodeURIComponent(id)}`;
|
|
91
|
+
}
|
|
92
|
+
return `${pageRoot}${id}/`;
|
|
93
|
+
}
|
|
94
|
+
function resolveCategoryUrlMode(url = currentLocationUrl(), options = {}) {
|
|
95
|
+
const target = urlFromInput(url);
|
|
96
|
+
const pageRoot = options.pageRoot ?? defaultCategoryPageRoot;
|
|
97
|
+
if (categoryIdFromHash(target.hash)) {
|
|
98
|
+
return "hash";
|
|
99
|
+
}
|
|
100
|
+
return categoryIdFromPath(target.pathname, pageRoot) ? "path" : "hash";
|
|
101
|
+
}
|
|
102
|
+
function categoryFromUrl(url, items, options = {}) {
|
|
103
|
+
const target = urlFromInput(url);
|
|
104
|
+
const pageRoot = options.pageRoot ?? defaultCategoryPageRoot;
|
|
105
|
+
const requestedId = categoryIdFromHash(target.hash) ?? categoryIdFromPath(target.pathname, pageRoot);
|
|
106
|
+
return requestedId ? findCategoryByIdOrSlug(requestedId, items) ?? items[0] : items[0];
|
|
107
|
+
}
|
|
108
|
+
function createCategoryItem(input) {
|
|
109
|
+
const id = input.pathSlugs.join("/");
|
|
110
|
+
const query = categorySearchQuery(input.definition, input.parent, input.pathLabels);
|
|
111
|
+
const searchText = categorySearchText(query, input.pathLabels);
|
|
112
|
+
const metadata = {
|
|
113
|
+
slug: input.pathSlugs[input.pathSlugs.length - 1],
|
|
114
|
+
parentId: input.parentId,
|
|
115
|
+
pathSegments: input.pathSlugs,
|
|
116
|
+
query: clone(SearchQuerySchema2, query),
|
|
117
|
+
searchText,
|
|
118
|
+
description: input.definition.description ?? input.description?.({
|
|
119
|
+
definition: input.definition,
|
|
120
|
+
parent: input.parent,
|
|
121
|
+
pathLabels: input.pathLabels
|
|
122
|
+
}) ?? `Selected products in ${input.pathLabels.join(" ").toLowerCase()}.`,
|
|
123
|
+
heroImage: input.definition.heroImage ?? input.parent?.heroImage ?? "",
|
|
124
|
+
pagePath: input.pageRoot
|
|
125
|
+
};
|
|
126
|
+
return {
|
|
127
|
+
id,
|
|
128
|
+
label: input.definition.label,
|
|
129
|
+
href: categoryPagePath(id, { pageRoot: input.pageRoot, urlMode: input.urlMode }),
|
|
130
|
+
query: clone(SearchQuerySchema2, query),
|
|
131
|
+
metadata,
|
|
132
|
+
children: (input.definition.children ?? []).map((child) => createCategoryItem({
|
|
133
|
+
definition: child,
|
|
134
|
+
parent: input.definition,
|
|
135
|
+
pageRoot: input.pageRoot,
|
|
136
|
+
urlMode: input.urlMode,
|
|
137
|
+
description: input.description,
|
|
138
|
+
parentId: id,
|
|
139
|
+
pathLabels: [...input.pathLabels, child.label],
|
|
140
|
+
pathSlugs: [...input.pathSlugs, child.slug]
|
|
141
|
+
}))
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
function validateNavigationLevel(definitions, context) {
|
|
145
|
+
definitions.forEach((definition, index) => {
|
|
146
|
+
const label = definition?.label?.trim();
|
|
147
|
+
const location2 = [...context.pathLabels, label || `item ${index + 1}`].join(" > ");
|
|
148
|
+
const slug = definition?.slug?.trim();
|
|
149
|
+
if (!label) {
|
|
150
|
+
context.errors.push(`Category ${location2} is missing label.`);
|
|
151
|
+
}
|
|
152
|
+
if (!slug) {
|
|
153
|
+
context.errors.push(`Category ${location2} is missing slug.`);
|
|
154
|
+
} else if (!/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(slug)) {
|
|
155
|
+
context.errors.push(`Category ${location2} has invalid slug "${slug}". Use lowercase letters, numbers, and hyphens only.`);
|
|
156
|
+
}
|
|
157
|
+
const nextPathSlugs = slug ? [...context.pathSlugs, slug] : context.pathSlugs;
|
|
158
|
+
const id = nextPathSlugs.join("/");
|
|
159
|
+
if (id) {
|
|
160
|
+
const existing = context.seenIds.get(id);
|
|
161
|
+
if (existing) {
|
|
162
|
+
context.errors.push(`Category ${location2} duplicates category id "${id}" already used by ${existing}.`);
|
|
163
|
+
} else {
|
|
164
|
+
context.seenIds.set(id, location2);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
if (slug) {
|
|
168
|
+
const existing = context.seenSlugs.get(slug);
|
|
169
|
+
if (existing) {
|
|
170
|
+
context.errors.push(`Category ${location2} duplicates slug "${slug}" already used by ${existing}. Slugs must be globally unique.`);
|
|
171
|
+
} else {
|
|
172
|
+
context.seenSlugs.set(slug, location2);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
if (definition.children?.length) {
|
|
176
|
+
validateNavigationLevel(definition.children, {
|
|
177
|
+
...context,
|
|
178
|
+
pathLabels: [...context.pathLabels, label || `item ${index + 1}`],
|
|
179
|
+
pathSlugs: nextPathSlugs
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
function categorySearchQuery(definition, parent, pathLabels) {
|
|
185
|
+
if (definition.query) {
|
|
186
|
+
return normalizeSearchQuery(definition.query);
|
|
187
|
+
}
|
|
188
|
+
const parentQuery = parent?.query ? normalizeSearchQuery(parent.query) : void 0;
|
|
189
|
+
const inherited = parentQuery ? clone(SearchQuerySchema2, parentQuery) : create2(SearchQuerySchema2);
|
|
190
|
+
const parentText = parentQuery ? categorySearchText(parentQuery, pathLabels.slice(0, -1)) : parent?.label;
|
|
191
|
+
inherited.Query = [definition.label, parentText].filter(Boolean).join(" ");
|
|
192
|
+
return inherited;
|
|
193
|
+
}
|
|
194
|
+
function categorySearchText(query, pathLabels) {
|
|
195
|
+
return query.Query || query.HiddenQuery || query.Tags.map((tag) => tag.Value).filter(Boolean).join(" ") || pathLabels.join(" ");
|
|
196
|
+
}
|
|
197
|
+
function categoryIdFromPath(pathname, pageRoot) {
|
|
198
|
+
const path = pathname.replace(/\/index\.html$/, "/");
|
|
199
|
+
if (!path.startsWith(pageRoot) || path === pageRoot) {
|
|
200
|
+
return void 0;
|
|
201
|
+
}
|
|
202
|
+
const normalized = path.slice(pageRoot.length).replace(/^\/+|\/+$/g, "");
|
|
203
|
+
return normalized ? normalized.split("/").map(decodeURIComponent).join("/") : void 0;
|
|
204
|
+
}
|
|
205
|
+
function categoryIdFromHash(hash) {
|
|
206
|
+
const value = hash.startsWith("#") ? hash.slice(1) : hash;
|
|
207
|
+
if (!value) {
|
|
208
|
+
return void 0;
|
|
209
|
+
}
|
|
210
|
+
const params = new URLSearchParams(value.startsWith("?") ? value.slice(1) : value);
|
|
211
|
+
const id = params.get("id");
|
|
212
|
+
if (id) {
|
|
213
|
+
return id.trim() || void 0;
|
|
214
|
+
}
|
|
215
|
+
if (value.includes("=")) {
|
|
216
|
+
return void 0;
|
|
217
|
+
}
|
|
218
|
+
try {
|
|
219
|
+
return decodeURIComponent(value).trim() || void 0;
|
|
220
|
+
} catch {
|
|
221
|
+
return value.trim() || void 0;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
function urlFromInput(url) {
|
|
225
|
+
if (typeof url === "string") {
|
|
226
|
+
return new URL(url, currentLocationUrl());
|
|
227
|
+
}
|
|
228
|
+
return new URL(url.href);
|
|
229
|
+
}
|
|
230
|
+
function currentLocationUrl() {
|
|
231
|
+
return typeof location === "undefined" ? new URL(defaultCategoryPageRoot, "https://example.test") : new URL(location.href);
|
|
232
|
+
}
|
|
233
|
+
export {
|
|
234
|
+
assertValidNavigationDefinitions,
|
|
235
|
+
categoryFromUrl,
|
|
236
|
+
categoryPagePath,
|
|
237
|
+
createCategoryNavigation,
|
|
238
|
+
defaultCategoryPageRoot,
|
|
239
|
+
findCategoryById,
|
|
240
|
+
findCategoryByIdOrSlug,
|
|
241
|
+
findCategoryBySlug,
|
|
242
|
+
flattenCategoryNavigation,
|
|
243
|
+
navigationConfigurationError,
|
|
244
|
+
resolveCategoryUrlMode,
|
|
245
|
+
validateNavigationDefinitions
|
|
246
|
+
};
|
|
247
|
+
//# sourceMappingURL=taxonomy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/taxonomy.ts","../src/query.ts"],"sourcesContent":["import { clone, create } from \"@bufbuild/protobuf\";\nimport { SearchQuerySchema, type SearchQuery } from \"@orderlyshop/core-client\";\nimport { normalizeSearchQuery } from \"./query.js\";\nimport type {\n CategoryUrlMode,\n NavigationDefinition,\n NavigationMetadata,\n ResolvedNavigationItem\n} from \"./types.js\";\nexport type {\n CategoryDefinition,\n CategoryNavigationItem,\n CategoryUrlMode,\n NavigationDefinition,\n NavigationMetadata,\n ResolvedNavigationItem\n} from \"./types.js\";\n\nexport const defaultCategoryPageRoot = \"/categories/\";\n\nexport interface NavigationBuildOptions {\n pageRoot?: string;\n urlMode?: CategoryUrlMode;\n description?: (input: NavigationDescriptionInput) => string;\n}\n\nexport type CategoryNavigationOptions = NavigationBuildOptions;\n\nexport interface NavigationDescriptionInput {\n definition: NavigationDefinition;\n parent?: NavigationDefinition;\n pathLabels: string[];\n}\n\nexport type CategoryDescriptionInput = NavigationDescriptionInput;\n\nexport function createCategoryNavigation(\n definitions: NavigationDefinition[],\n options: NavigationBuildOptions = {}\n): ResolvedNavigationItem[] {\n assertValidNavigationDefinitions(definitions);\n const pageRoot = options.pageRoot ?? defaultCategoryPageRoot;\n const urlMode = options.urlMode ?? \"path\";\n return definitions.map((definition) => {\n return createCategoryItem({\n definition,\n pageRoot,\n urlMode,\n description: options.description,\n pathLabels: [definition.label],\n pathSlugs: [definition.slug]\n });\n });\n}\n\nexport interface NavigationValidationResult {\n valid: boolean;\n errors: string[];\n}\n\nexport function validateNavigationDefinitions(definitions: NavigationDefinition[]): NavigationValidationResult {\n const errors: string[] = [];\n const seenIds = new Map<string, string>();\n const seenSlugs = new Map<string, string>();\n if (!Array.isArray(definitions) || definitions.length === 0) {\n errors.push(\"navigationDefinitions must contain at least one category.\");\n return { valid: false, errors };\n }\n validateNavigationLevel(definitions, {\n errors,\n seenIds,\n seenSlugs,\n pathLabels: [],\n pathSlugs: []\n });\n return { valid: errors.length === 0, errors };\n}\n\nexport function navigationConfigurationError(definitions: NavigationDefinition[]): string | undefined {\n const result = validateNavigationDefinitions(definitions);\n return result.valid ? undefined : `Navigation configuration error: ${result.errors.join(\" \")}`;\n}\n\nexport function assertValidNavigationDefinitions(definitions: NavigationDefinition[]): void {\n const error = navigationConfigurationError(definitions);\n if (error) {\n throw new Error(error);\n }\n}\n\nexport function flattenCategoryNavigation(items: ResolvedNavigationItem[]): ResolvedNavigationItem[] {\n return items.flatMap((item) => [item, ...flattenCategoryNavigation(item.children ?? [])]);\n}\n\nexport function findCategoryById(\n id: string,\n items: ResolvedNavigationItem[]\n): ResolvedNavigationItem | undefined {\n return flattenCategoryNavigation(items).find((item) => item.id === id);\n}\n\nexport function findCategoryBySlug(\n slug: string,\n items: ResolvedNavigationItem[]\n): ResolvedNavigationItem | undefined {\n return flattenCategoryNavigation(items).find((item) => item.metadata.slug === slug || item.id === slug);\n}\n\nexport function findCategoryByIdOrSlug(\n value: string,\n items: ResolvedNavigationItem[]\n): ResolvedNavigationItem | undefined {\n return findCategoryById(value, items) ?? findCategoryBySlug(value, items);\n}\n\nexport function categoryPagePath(\n id: string,\n options: NavigationBuildOptions = {}\n): string {\n const pageRoot = options.pageRoot ?? defaultCategoryPageRoot;\n if (options.urlMode === \"hash\") {\n return `${pageRoot}#id=${encodeURIComponent(id)}`;\n }\n return `${pageRoot}${id}/`;\n}\n\nexport function resolveCategoryUrlMode(\n url: string | URL | Location = currentLocationUrl(),\n options: Pick<NavigationBuildOptions, \"pageRoot\"> = {}\n): CategoryUrlMode {\n const target = urlFromInput(url);\n const pageRoot = options.pageRoot ?? defaultCategoryPageRoot;\n if (categoryIdFromHash(target.hash)) {\n return \"hash\";\n }\n return categoryIdFromPath(target.pathname, pageRoot) ? \"path\" : \"hash\";\n}\n\nexport function categoryFromUrl(\n url: string | URL | Location,\n items: ResolvedNavigationItem[],\n options: NavigationBuildOptions = {}\n): ResolvedNavigationItem {\n const target = urlFromInput(url);\n const pageRoot = options.pageRoot ?? defaultCategoryPageRoot;\n const requestedId = categoryIdFromHash(target.hash) ?? categoryIdFromPath(target.pathname, pageRoot);\n return requestedId ? findCategoryByIdOrSlug(requestedId, items) ?? items[0] : items[0];\n}\n\nfunction createCategoryItem(input: {\n definition: NavigationDefinition;\n parent?: NavigationDefinition;\n pageRoot: string;\n urlMode: CategoryUrlMode;\n description?: NavigationBuildOptions[\"description\"];\n pathLabels: string[];\n pathSlugs: string[];\n parentId?: string;\n}): ResolvedNavigationItem {\n const id = input.pathSlugs.join(\"/\");\n const query = categorySearchQuery(input.definition, input.parent, input.pathLabels);\n const searchText = categorySearchText(query, input.pathLabels);\n const metadata: NavigationMetadata = {\n slug: input.pathSlugs[input.pathSlugs.length - 1],\n parentId: input.parentId,\n pathSegments: input.pathSlugs,\n query: clone(SearchQuerySchema, query),\n searchText,\n description: input.definition.description\n ?? input.description?.({\n definition: input.definition,\n parent: input.parent,\n pathLabels: input.pathLabels\n })\n ?? `Selected products in ${input.pathLabels.join(\" \").toLowerCase()}.`,\n heroImage: input.definition.heroImage ?? input.parent?.heroImage ?? \"\",\n pagePath: input.pageRoot\n };\n return {\n id,\n label: input.definition.label,\n href: categoryPagePath(id, { pageRoot: input.pageRoot, urlMode: input.urlMode }),\n query: clone(SearchQuerySchema, query),\n metadata,\n children: (input.definition.children ?? []).map((child) => createCategoryItem({\n definition: child,\n parent: input.definition,\n pageRoot: input.pageRoot,\n urlMode: input.urlMode,\n description: input.description,\n parentId: id,\n pathLabels: [...input.pathLabels, child.label],\n pathSlugs: [...input.pathSlugs, child.slug]\n }))\n };\n}\n\nfunction validateNavigationLevel(\n definitions: NavigationDefinition[],\n context: {\n errors: string[];\n seenIds: Map<string, string>;\n seenSlugs: Map<string, string>;\n pathLabels: string[];\n pathSlugs: string[];\n }\n): void {\n definitions.forEach((definition, index) => {\n const label = definition?.label?.trim();\n const location = [...context.pathLabels, label || `item ${index + 1}`].join(\" > \");\n const slug = definition?.slug?.trim();\n if (!label) {\n context.errors.push(`Category ${location} is missing label.`);\n }\n if (!slug) {\n context.errors.push(`Category ${location} is missing slug.`);\n } else if (!/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(slug)) {\n context.errors.push(`Category ${location} has invalid slug \"${slug}\". Use lowercase letters, numbers, and hyphens only.`);\n }\n const nextPathSlugs = slug ? [...context.pathSlugs, slug] : context.pathSlugs;\n const id = nextPathSlugs.join(\"/\");\n if (id) {\n const existing = context.seenIds.get(id);\n if (existing) {\n context.errors.push(`Category ${location} duplicates category id \"${id}\" already used by ${existing}.`);\n } else {\n context.seenIds.set(id, location);\n }\n }\n if (slug) {\n const existing = context.seenSlugs.get(slug);\n if (existing) {\n context.errors.push(`Category ${location} duplicates slug \"${slug}\" already used by ${existing}. Slugs must be globally unique.`);\n } else {\n context.seenSlugs.set(slug, location);\n }\n }\n if (definition.children?.length) {\n validateNavigationLevel(definition.children, {\n ...context,\n pathLabels: [...context.pathLabels, label || `item ${index + 1}`],\n pathSlugs: nextPathSlugs\n });\n }\n });\n}\n\nfunction categorySearchQuery(\n definition: NavigationDefinition,\n parent: NavigationDefinition | undefined,\n pathLabels: string[]\n): SearchQuery {\n if (definition.query) {\n return normalizeSearchQuery(definition.query);\n }\n const parentQuery = parent?.query ? normalizeSearchQuery(parent.query) : undefined;\n const inherited = parentQuery ? clone(SearchQuerySchema, parentQuery) : create(SearchQuerySchema);\n const parentText = parentQuery ? categorySearchText(parentQuery, pathLabels.slice(0, -1)) : parent?.label;\n inherited.Query = [definition.label, parentText].filter(Boolean).join(\" \");\n return inherited;\n}\n\nfunction categorySearchText(query: SearchQuery, pathLabels: string[]): string {\n return query.Query\n || query.HiddenQuery\n || query.Tags.map((tag) => tag.Value).filter(Boolean).join(\" \")\n || pathLabels.join(\" \");\n}\n\nfunction categoryIdFromPath(pathname: string, pageRoot: string): string | undefined {\n const path = pathname.replace(/\\/index\\.html$/, \"/\");\n if (!path.startsWith(pageRoot) || path === pageRoot) {\n return undefined;\n }\n const normalized = path.slice(pageRoot.length).replace(/^\\/+|\\/+$/g, \"\");\n return normalized ? normalized.split(\"/\").map(decodeURIComponent).join(\"/\") : undefined;\n}\n\nfunction categoryIdFromHash(hash: string): string | undefined {\n const value = hash.startsWith(\"#\") ? hash.slice(1) : hash;\n if (!value) {\n return undefined;\n }\n const params = new URLSearchParams(value.startsWith(\"?\") ? value.slice(1) : value);\n const id = params.get(\"id\");\n if (id) {\n return id.trim() || undefined;\n }\n if (value.includes(\"=\")) {\n return undefined;\n }\n try {\n return decodeURIComponent(value).trim() || undefined;\n } catch {\n return value.trim() || undefined;\n }\n}\n\nfunction urlFromInput(url: string | URL | Location): URL {\n if (typeof url === \"string\") {\n return new URL(url, currentLocationUrl());\n }\n return new URL(url.href);\n}\n\nfunction currentLocationUrl(): URL {\n return typeof location === \"undefined\"\n ? new URL(defaultCategoryPageRoot, \"https://example.test\")\n : new URL(location.href);\n}\n","import { create } from \"@bufbuild/protobuf\";\nimport {\n SearchQuerySchema,\n TagSchema,\n type SearchQuery\n} from \"@orderlyshop/core-client\";\n\nexport const declarativeQueryAttributes = [\n \"keywords\",\n \"tags\",\n \"hidden-query\",\n \"order-by\",\n \"store-id\",\n \"featured\"\n];\n\nexport interface SearchQueryInput {\n query?: string;\n keywords?: string;\n hiddenQuery?: string;\n tags?: string[];\n orderBy?: string[];\n storeId?: string;\n featured?: boolean;\n}\n\nexport type SearchQueryConfig = SearchQuery | SearchQueryInput;\n\n/**\n * Creates a Core SearchQuery from plain JavaScript values.\n *\n * This is mainly useful for vanilla browser setups that load the standalone\n * bundle and do not want to import protobuf helpers directly.\n */\nexport function createSearchQuery(input: SearchQueryInput = {}): SearchQuery {\n return create(SearchQuerySchema, {\n Query: input.query ?? input.keywords,\n HiddenQuery: input.hiddenQuery,\n Tags: (input.tags ?? []).map((tag) => create(TagSchema, { Value: tag })),\n OrderBy: input.orderBy ?? [],\n StoreId: input.storeId,\n Featured: input.featured ?? false\n });\n}\n\nexport function normalizeSearchQuery(input: SearchQueryConfig = {}): SearchQuery {\n if (isCoreSearchQuery(input)) {\n return create(SearchQuerySchema, input);\n }\n return createSearchQuery(input);\n}\n\n/**\n * Builds a SearchQuery from simple HTML configuration.\n *\n * Supported on product grids, product rails, and collection pages. Typed\n * JavaScript `query` properties take precedence in the components; this helper\n * only covers the common declarative fields that are safe to express as text.\n */\nexport function declarativeSearchQuery(host: Element): SearchQuery | undefined {\n const queryElement = directQueryElement(host);\n const keywords = readQueryValue(host, queryElement, \"keywords\");\n const hiddenQuery = readQueryValue(host, queryElement, \"hidden-query\");\n const storeId = readQueryValue(host, queryElement, \"store-id\");\n const featured = readQueryBoolean(host, queryElement, \"featured\");\n const tags = readQueryList(host, queryElement, \"tags\");\n const orderBy = readQueryList(host, queryElement, \"order-by\");\n\n if (!keywords && !hiddenQuery && !storeId && featured === undefined && tags.length === 0 && orderBy.length === 0) {\n return undefined;\n }\n\n return create(SearchQuerySchema, {\n Query: keywords || undefined,\n HiddenQuery: hiddenQuery || undefined,\n Tags: tags.map((tag) => create(TagSchema, { Value: tag })),\n OrderBy: orderBy,\n StoreId: storeId || undefined,\n Featured: featured ?? false\n });\n}\n\nfunction directQueryElement(host: Element): Element | undefined {\n const queryElement = [...host.children].find((child) => child.localName === \"query\");\n if (queryElement instanceof HTMLElement) {\n queryElement.hidden = true;\n }\n return queryElement;\n}\n\nfunction isCoreSearchQuery(input: SearchQueryConfig): input is SearchQuery {\n return \"Query\" in input\n || \"HiddenQuery\" in input\n || \"Tags\" in input\n || \"OrderBy\" in input\n || \"StoreId\" in input\n || \"Featured\" in input;\n}\n\nfunction readQueryValue(host: Element, queryElement: Element | undefined, name: string): string {\n return firstValue(\n host.getAttribute(name),\n queryElement?.getAttribute(name),\n childText(queryElement, name)\n );\n}\n\nfunction readQueryList(host: Element, queryElement: Element | undefined, name: string): string[] {\n return uniqueValues([\n ...splitList(host.getAttribute(name)),\n ...splitList(queryElement?.getAttribute(name)),\n ...splitList(childText(queryElement, name))\n ]);\n}\n\nfunction readQueryBoolean(host: Element, queryElement: Element | undefined, name: string): boolean | undefined {\n if (host.hasAttribute(name) && !host.getAttribute(name)) {\n return true;\n }\n if (queryElement?.hasAttribute(name) && !queryElement.getAttribute(name)) {\n return true;\n }\n return parseBoolean(readQueryValue(host, queryElement, name));\n}\n\nfunction childText(queryElement: Element | undefined, name: string): string | undefined {\n const child = [...queryElement?.children ?? []].find((element) => element.localName === name);\n return child?.textContent?.trim();\n}\n\nfunction firstValue(...values: Array<string | null | undefined>): string {\n return values.map((value) => value?.trim()).find(Boolean) ?? \"\";\n}\n\nfunction splitList(value: string | null | undefined): string[] {\n return (value ?? \"\")\n .split(/[\\n,]/g)\n .map((item) => item.trim())\n .filter(Boolean);\n}\n\nfunction uniqueValues(values: string[]): string[] {\n return [...new Set(values)];\n}\n\nfunction parseBoolean(value: string): boolean | undefined {\n if (!value) {\n return undefined;\n }\n if ([\"true\", \"1\", \"yes\", \"\"].includes(value.toLowerCase())) {\n return true;\n }\n if ([\"false\", \"0\", \"no\"].includes(value.toLowerCase())) {\n return false;\n }\n return undefined;\n}\n"],"mappings":"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","names":["create","SearchQuerySchema","SearchQuerySchema","location","create"]}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { DraftOrder, SearchQuery, WebsitePage, UIMenu, Address, PhoneNumber, TransportMethod, SearchObject, Login, OrderlyClient } from '@orderlyshop/core-client';
|
|
2
|
+
import { SearchQueryConfig } from './query.js';
|
|
3
|
+
|
|
4
|
+
type StorefrontClient = OrderlyClient;
|
|
5
|
+
interface SortOption {
|
|
6
|
+
label: string;
|
|
7
|
+
orderBy: string[];
|
|
8
|
+
}
|
|
9
|
+
interface NavigationDefinition {
|
|
10
|
+
label: string;
|
|
11
|
+
slug: string;
|
|
12
|
+
heroImage?: string;
|
|
13
|
+
query?: SearchQueryConfig;
|
|
14
|
+
description?: string;
|
|
15
|
+
children?: NavigationDefinition[];
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Derived values created from NavigationDefinition for rendered storefront pages.
|
|
19
|
+
*/
|
|
20
|
+
interface NavigationMetadata {
|
|
21
|
+
slug: string;
|
|
22
|
+
parentId?: string;
|
|
23
|
+
pathSegments: string[];
|
|
24
|
+
query: SearchQuery;
|
|
25
|
+
searchText: string;
|
|
26
|
+
description: string;
|
|
27
|
+
heroImage: string;
|
|
28
|
+
pagePath: string;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Runtime navigation item consumed by default shop/page components.
|
|
32
|
+
*/
|
|
33
|
+
interface ResolvedNavigationItem extends NavigationItem {
|
|
34
|
+
metadata: NavigationMetadata;
|
|
35
|
+
children?: ResolvedNavigationItem[];
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Backward-compatible aliases for the earlier category naming.
|
|
39
|
+
*/
|
|
40
|
+
type CategoryDefinition = NavigationDefinition;
|
|
41
|
+
type CategoryMetadata = NavigationMetadata;
|
|
42
|
+
type CategoryNavigationItem = ResolvedNavigationItem;
|
|
43
|
+
type CategoryUrlMode = "path" | "hash";
|
|
44
|
+
type ProductGridPagingMode = "manual" | "button" | "infinite" | "dynamic";
|
|
45
|
+
interface ProductGridState {
|
|
46
|
+
loading: boolean;
|
|
47
|
+
error?: unknown;
|
|
48
|
+
products: SearchObject[];
|
|
49
|
+
count: number;
|
|
50
|
+
estimatedTotalCount?: number;
|
|
51
|
+
hasMore: boolean;
|
|
52
|
+
}
|
|
53
|
+
type BasketChangeReason = "load" | "set-draft" | "add-product" | "set-quantity" | "remove-line" | "clear" | "verify";
|
|
54
|
+
type BasketChangeEvent = CustomEvent<DraftOrder> & {
|
|
55
|
+
reason?: BasketChangeReason;
|
|
56
|
+
};
|
|
57
|
+
interface ProductEventDetail {
|
|
58
|
+
product: SearchObject;
|
|
59
|
+
controllerUpdated?: boolean;
|
|
60
|
+
}
|
|
61
|
+
interface OrderCreatedDetail {
|
|
62
|
+
order: unknown;
|
|
63
|
+
draft: DraftOrder;
|
|
64
|
+
}
|
|
65
|
+
interface CheckoutProfile {
|
|
66
|
+
address?: Address;
|
|
67
|
+
email?: string;
|
|
68
|
+
phoneNumber?: PhoneNumber;
|
|
69
|
+
updatedAt: string;
|
|
70
|
+
}
|
|
71
|
+
interface NavigationItem {
|
|
72
|
+
id: string;
|
|
73
|
+
label: string;
|
|
74
|
+
href?: string;
|
|
75
|
+
target?: "_self" | "_blank";
|
|
76
|
+
query?: SearchQuery;
|
|
77
|
+
page?: WebsitePage;
|
|
78
|
+
menu?: UIMenu;
|
|
79
|
+
children?: NavigationItem[];
|
|
80
|
+
disabled?: boolean;
|
|
81
|
+
metadata?: unknown;
|
|
82
|
+
}
|
|
83
|
+
interface NavigationSelectionDetail {
|
|
84
|
+
item: NavigationItem;
|
|
85
|
+
}
|
|
86
|
+
interface CheckoutReadyDetail {
|
|
87
|
+
draft: DraftOrder;
|
|
88
|
+
profile: CheckoutProfile;
|
|
89
|
+
transportMethod?: TransportMethod;
|
|
90
|
+
}
|
|
91
|
+
interface SessionDetail {
|
|
92
|
+
login?: Login;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export type { BasketChangeReason as B, CheckoutProfile as C, NavigationItem as N, OrderCreatedDetail as O, ProductGridPagingMode as P, ResolvedNavigationItem as R, SortOption as S, NavigationDefinition as a, CategoryUrlMode as b, CategoryDefinition as c, CategoryNavigationItem as d, NavigationMetadata as e, ProductGridState as f, BasketChangeEvent as g, CategoryMetadata as h, CheckoutReadyDetail as i, NavigationSelectionDetail as j, ProductEventDetail as k, SessionDetail as l, StorefrontClient as m };
|