@lasterp/shared 1.0.0-alpha.9 → 1.0.0-beta.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.
@@ -1,28 +1,101 @@
1
1
  interface Item {
2
- itemCode: string;
2
+ item_code: string;
3
3
  area: string;
4
4
  model: string;
5
5
  region: string;
6
6
  grade: string;
7
- gradeIssuer: string;
7
+ grade_issuer: string;
8
8
  color: string;
9
9
  storage: string;
10
10
  memory: string;
11
11
  connectivity: string;
12
- carrierCompatibility: string;
12
+ carrier_compatibility: string;
13
13
  }
14
14
  interface ItemVariant extends Item {
15
- itemVariant: string;
15
+ item_variant: string;
16
16
  }
17
17
  interface Model {
18
- modelNumber: string;
19
- simCardType: string;
18
+ model_number: string;
19
+ sim_card_type: string;
20
20
  connectivity: string;
21
21
  }
22
22
  interface Colour {
23
23
  color: string;
24
24
  hex: string;
25
- colorSystem: string;
25
+ color_system: string;
26
+ }
27
+ interface Globals {
28
+ header: Header;
29
+ footer: Footer;
30
+ }
31
+ interface Brand {
32
+ brandImage?: string;
33
+ }
34
+ interface NavbarItem {
35
+ label: string;
36
+ enableDropdown: boolean;
37
+ enableLink: boolean;
38
+ link?: string;
39
+ dropdownDescription?: string;
40
+ dropdownCTALabel?: string;
41
+ dropdownCTALink?: string;
42
+ groups?: NavbarSubItemGroup[];
43
+ }
44
+ interface NavbarSubItemGroup {
45
+ title: string;
46
+ items: NavbarSubItem[];
47
+ }
48
+ interface NavbarSubItem {
49
+ label: string;
50
+ description?: string;
51
+ image?: string;
52
+ link?: string;
53
+ }
54
+ interface Topbar {
55
+ enabled: boolean;
56
+ layout: string;
57
+ items: TopbarItem[];
58
+ }
59
+ interface TopbarItem {
60
+ icon?: string;
61
+ label: string;
62
+ link?: string;
63
+ }
64
+ interface Header {
65
+ headerType?: string;
66
+ brand: Brand;
67
+ tabs: NavbarItem[];
68
+ topbar: Topbar;
69
+ }
70
+ interface FooterItemGroup {
71
+ title: string;
72
+ items: FooterItem[];
73
+ }
74
+ interface FooterItem {
75
+ label: string;
76
+ link?: string;
77
+ }
78
+ interface Footer {
79
+ footerType?: string;
80
+ groups: FooterItemGroup[];
81
+ copyright?: string;
82
+ address?: string;
83
+ country?: string;
84
+ phone?: string;
85
+ email?: string;
86
+ }
87
+ interface Hero {
88
+ type: string;
89
+ data: Record<string, unknown>;
90
+ }
91
+ interface Block {
92
+ type: string;
93
+ data: Record<string, unknown>;
94
+ }
95
+ interface Page {
96
+ slug: string;
97
+ hero?: Hero;
98
+ blocks: Block[];
26
99
  }
27
100
  import { FrappeApp, FrappeAuth, FrappeCall } from "frappe-js-sdk";
28
101
  import { FrappeDB } from "frappe-js-sdk/lib/db";
@@ -513,79 +586,62 @@ declare const useFrappeUpdateDoc: <T = any>() => {
513
586
  isCompleted: boolean;
514
587
  reset: () => void;
515
588
  };
516
- interface Globals {
517
- header: Header;
518
- footer: Footer;
519
- }
520
- interface Brand {
521
- brandImage?: string;
522
- }
523
- interface NavbarItem {
524
- label: string;
525
- enableDropdown: boolean;
526
- enableLink: boolean;
527
- link?: string;
528
- dropdownDescription?: string;
529
- dropdownCTALabel?: string;
530
- dropdownCTALink?: string;
531
- groups?: NavbarSubItemGroup[];
532
- }
533
- interface NavbarSubItemGroup {
534
- title: string;
535
- items: NavbarSubItem[];
536
- }
537
- interface NavbarSubItem {
538
- label: string;
539
- description?: string;
540
- image?: string;
541
- link?: string;
589
+ interface VariantSelectorProps<T extends {
590
+ id: string;
591
+ specs: Record<string, string>;
592
+ }> {
593
+ variants: T[];
594
+ attributes: {
595
+ key: string;
596
+ values: string[];
597
+ }[];
598
+ defaultId?: string;
542
599
  }
543
- interface Topbar {
544
- enabled: boolean;
545
- layout: string;
546
- items: TopbarItem[];
547
- }
548
- interface TopbarItem {
549
- icon?: string;
550
- label: string;
551
- link?: string;
552
- }
553
- interface Header {
554
- headerType?: string;
555
- brand: Brand;
556
- tabs: NavbarItem[];
557
- topbar: Topbar;
600
+ interface VariantSelectorOption {
601
+ key: string;
602
+ value: string;
603
+ state: "selected" | "available" | "unavailable";
558
604
  }
559
- interface FooterItemGroup {
560
- title: string;
561
- items: FooterItem[];
605
+ interface VariantSelectorResult {
606
+ variantId?: string;
607
+ onOptionSelect: (key: string, value: string) => void;
608
+ getOptions: (key: string) => VariantSelectorOption[];
562
609
  }
563
- interface FooterItem {
564
- label: string;
565
- link?: string;
610
+ declare const useVariantSelector: <T extends {
611
+ id: string;
612
+ specs: Record<string, string>;
613
+ }>(props: VariantSelectorProps<T>) => VariantSelectorResult;
614
+ interface Category {
615
+ name: string;
566
616
  }
567
- interface Footer {
568
- footerType?: string;
569
- groups: FooterItemGroup[];
570
- copyright?: string;
571
- address?: string;
572
- country?: string;
573
- phone?: string;
574
- email?: string;
617
+ interface Product {
618
+ name: string;
619
+ image: string;
620
+ item_code: string;
621
+ description: string;
575
622
  }
576
- interface Hero {
577
- type: string;
578
- data: Record<string, unknown>;
623
+ interface ProductVariant extends ItemVariant {
624
+ name: string;
625
+ currency: string;
626
+ rate: number;
627
+ qty: number;
628
+ images: string[];
629
+ specs: Record<string, string>;
579
630
  }
580
- interface Block {
581
- type: string;
582
- data: Record<string, unknown>;
631
+ interface ShopContext {
632
+ categories: Category[];
633
+ grades: string[];
634
+ selected_category?: Category;
635
+ selected_grade?: string;
636
+ products: Product[];
583
637
  }
584
- interface Page {
585
- slug: string;
586
- hero?: Hero;
587
- blocks: Block[];
638
+ interface ProductContext {
639
+ product: Product;
640
+ specs: Record<string, string[]>;
641
+ variants: ProductVariant[];
642
+ models: Record<string, Model>;
643
+ colors: Record<string, Colour>;
588
644
  }
589
645
  import { camelize, decamelize, camelizeKeys, decamelizeKeys } from "humps";
590
646
  declare function equalsIgnoreCase(str1: string, str2: string): boolean;
591
- export { useSearch, useFrappeUpdateDoc, useFrappePutCall, useFrappePrefetchDoc, useFrappePostCall, useFrappeGetDocList, useFrappeGetDocCount, useFrappeGetDoc, useFrappeGetCall, useFrappeFileUpload, useFrappeEventListener, useFrappeDocumentEventListener, useFrappeDocTypeEventListener, useFrappeDeleteDoc, useFrappeDeleteCall, useFrappeCreateDoc, useFrappeAuth, equalsIgnoreCase, decamelizeKeys, decamelize, camelizeKeys, camelize, ViewerEventData, UseFrappeFileUploadReturnType, TopbarItem, Topbar, TokenParams, SearchResult, Page, NavbarSubItemGroup, NavbarSubItem, NavbarItem, Model, ItemVariant, Item, Hero, Header, Globals, FrappeProviderProps, FrappeProvider, FrappeMutationResult, FrappeFileUploadResponse, FrappeError, FrappeContext, FrappeConfig, FooterItemGroup, FooterItem, Footer, DocumentUpdateEventData, DocTypeListUpdateEventData, Colour, Brand, Block };
647
+ export { useVariantSelector, useSearch, useFrappeUpdateDoc, useFrappePutCall, useFrappePrefetchDoc, useFrappePostCall, useFrappeGetDocList, useFrappeGetDocCount, useFrappeGetDoc, useFrappeGetCall, useFrappeFileUpload, useFrappeEventListener, useFrappeDocumentEventListener, useFrappeDocTypeEventListener, useFrappeDeleteDoc, useFrappeDeleteCall, useFrappeCreateDoc, useFrappeAuth, equalsIgnoreCase, decamelizeKeys, decamelize, camelizeKeys, camelize, ViewerEventData, VariantSelectorResult, VariantSelectorProps, VariantSelectorOption, UseFrappeFileUploadReturnType, TopbarItem, Topbar, TokenParams, ShopContext, SearchResult, ProductVariant, ProductContext, Product, Page, NavbarSubItemGroup, NavbarSubItem, NavbarItem, Model, ItemVariant, Item, Hero, Header, Globals, FrappeProviderProps, FrappeProvider, FrappeMutationResult, FrappeFileUploadResponse, FrappeError, FrappeContext, FrappeConfig, FooterItemGroup, FooterItem, Footer, DocumentUpdateEventData, DocTypeListUpdateEventData, Colour, Category, Brand, Block };
@@ -46,7 +46,7 @@ class SocketIO {
46
46
  }
47
47
 
48
48
  // src/frappe/provider.tsx
49
- import { jsxDEV } from "react/jsx-dev-runtime";
49
+ import { jsx } from "react/jsx-runtime";
50
50
 
51
51
  var FrappeContext = createContext(null);
52
52
  var FrappeProvider = ({
@@ -71,10 +71,10 @@ var FrappeProvider = ({
71
71
  socket: enableSocket ? new SocketIO(url, siteName, socketPort, tokenParams).socket : undefined
72
72
  };
73
73
  }, [url, tokenParams, enableSocket, socketPort, siteName, customHeaders]);
74
- return /* @__PURE__ */ jsxDEV(FrappeContext.Provider, {
74
+ return /* @__PURE__ */ jsx(FrappeContext.Provider, {
75
75
  value: frappeConfig,
76
76
  children
77
- }, undefined, false, undefined, this);
77
+ });
78
78
  };
79
79
  // src/frappe/hooks/auth.ts
80
80
  import { useCallback, useContext, useState, useEffect } from "react";
@@ -465,12 +465,118 @@ var useFrappeUpdateDoc = () => {
465
465
  reset
466
466
  };
467
467
  };
468
+ // src/hooks/use-variant-selector/hook.ts
469
+ import { useCallback as useCallback4, useMemo as useMemo2, useState as useState5 } from "react";
470
+
471
+ // src/hooks/use-variant-selector/utils.ts
472
+ function findVariant(variants, specs, caseInsensitive) {
473
+ return variants.find((variant) => {
474
+ return Object.entries(specs).every(([key, value]) => {
475
+ const vv = variant.specs[key];
476
+ if (!vv)
477
+ return false;
478
+ if (caseInsensitive) {
479
+ return vv.toLowerCase() === value.toLowerCase();
480
+ }
481
+ return vv === value;
482
+ });
483
+ });
484
+ }
485
+ function findVariants(variants, specs, caseInsensitive) {
486
+ return variants.filter((variant) => {
487
+ return Object.entries(specs).every(([key, value]) => {
488
+ const vv = variant.specs[key];
489
+ if (!vv)
490
+ return false;
491
+ if (caseInsensitive) {
492
+ return vv.toLowerCase() === value.toLowerCase();
493
+ }
494
+ return vv === value;
495
+ });
496
+ });
497
+ }
498
+
499
+ // src/hooks/use-variant-selector/hook.ts
500
+ var useVariantSelector = (props) => {
501
+ const { variants, attributes, defaultId } = props;
502
+ const [selectedSpecs, setSelectedSpecs] = useState5(() => {
503
+ if (defaultId) {
504
+ const variant = variants.find((v) => v.id === defaultId);
505
+ return variant?.specs || {};
506
+ }
507
+ return {};
508
+ });
509
+ const variantId = useMemo2(() => {
510
+ const complete = attributes.every((attr) => selectedSpecs[attr.key]);
511
+ if (!complete)
512
+ return;
513
+ const variant = findVariant(variants, selectedSpecs);
514
+ return variant?.id;
515
+ }, [variants, selectedSpecs, attributes]);
516
+ const options = useMemo2(() => {
517
+ const result = {};
518
+ attributes.forEach((attr, attrIndex) => {
519
+ const constraints = {};
520
+ for (let i = 0;i < attrIndex; i++) {
521
+ const key = attributes[i]?.key;
522
+ if (key && selectedSpecs[key])
523
+ constraints[key] = selectedSpecs[key];
524
+ }
525
+ const matchingVariants = findVariants(variants, constraints);
526
+ const availableValues = new Set(matchingVariants.map((v) => v.specs[attr.key]));
527
+ result[attr.key] = attr.values.map((value) => {
528
+ const isSelected = selectedSpecs[attr.key] === value;
529
+ const isAvailable = availableValues.has(value);
530
+ return {
531
+ key: attr.key,
532
+ value,
533
+ state: isSelected ? "selected" : isAvailable ? "available" : "unavailable"
534
+ };
535
+ });
536
+ });
537
+ return result;
538
+ }, [variants, attributes, selectedSpecs]);
539
+ const onOptionSelect = useCallback4((key, value) => {
540
+ setSelectedSpecs((prev) => {
541
+ const newSpecs = { ...prev, [key]: value };
542
+ const attrIndex = attributes.findIndex((a) => a.key === key);
543
+ for (let i = attrIndex + 1;i < attributes.length; i++) {
544
+ const downstreamAttr = attributes[i];
545
+ if (!downstreamAttr)
546
+ continue;
547
+ const constraints = {};
548
+ for (let j = 0;j < i; j++) {
549
+ const k = attributes[j]?.key;
550
+ if (k && newSpecs[k])
551
+ constraints[k] = newSpecs[k];
552
+ }
553
+ const matching = findVariants(variants, constraints);
554
+ const availableValues = new Set(matching.map((v) => v.specs[downstreamAttr.key]));
555
+ if (!availableValues.has(newSpecs[downstreamAttr.key])) {
556
+ const firstAvailable = downstreamAttr.values.find((v) => availableValues.has(v));
557
+ if (firstAvailable) {
558
+ newSpecs[downstreamAttr.key] = firstAvailable;
559
+ } else {
560
+ delete newSpecs[downstreamAttr.key];
561
+ }
562
+ }
563
+ }
564
+ return newSpecs;
565
+ });
566
+ }, [attributes, variants]);
567
+ return {
568
+ variantId,
569
+ onOptionSelect,
570
+ getOptions: (key) => options[key] || []
571
+ };
572
+ };
468
573
  // src/utils/char.ts
469
574
  import { camelize, decamelize, camelizeKeys, decamelizeKeys } from "humps";
470
575
  function equalsIgnoreCase(str1, str2) {
471
576
  return str1.localeCompare(str2, undefined, { sensitivity: "accent" }) === 0;
472
577
  }
473
578
  export {
579
+ useVariantSelector,
474
580
  useSearch,
475
581
  useFrappeUpdateDoc,
476
582
  useFrappePutCall,
@@ -1,28 +1,101 @@
1
1
  interface Item {
2
- itemCode: string;
2
+ item_code: string;
3
3
  area: string;
4
4
  model: string;
5
5
  region: string;
6
6
  grade: string;
7
- gradeIssuer: string;
7
+ grade_issuer: string;
8
8
  color: string;
9
9
  storage: string;
10
10
  memory: string;
11
11
  connectivity: string;
12
- carrierCompatibility: string;
12
+ carrier_compatibility: string;
13
13
  }
14
14
  interface ItemVariant extends Item {
15
- itemVariant: string;
15
+ item_variant: string;
16
16
  }
17
17
  interface Model {
18
- modelNumber: string;
19
- simCardType: string;
18
+ model_number: string;
19
+ sim_card_type: string;
20
20
  connectivity: string;
21
21
  }
22
22
  interface Colour {
23
23
  color: string;
24
24
  hex: string;
25
- colorSystem: string;
25
+ color_system: string;
26
+ }
27
+ interface Globals {
28
+ header: Header;
29
+ footer: Footer;
30
+ }
31
+ interface Brand {
32
+ brandImage?: string;
33
+ }
34
+ interface NavbarItem {
35
+ label: string;
36
+ enableDropdown: boolean;
37
+ enableLink: boolean;
38
+ link?: string;
39
+ dropdownDescription?: string;
40
+ dropdownCTALabel?: string;
41
+ dropdownCTALink?: string;
42
+ groups?: NavbarSubItemGroup[];
43
+ }
44
+ interface NavbarSubItemGroup {
45
+ title: string;
46
+ items: NavbarSubItem[];
47
+ }
48
+ interface NavbarSubItem {
49
+ label: string;
50
+ description?: string;
51
+ image?: string;
52
+ link?: string;
53
+ }
54
+ interface Topbar {
55
+ enabled: boolean;
56
+ layout: string;
57
+ items: TopbarItem[];
58
+ }
59
+ interface TopbarItem {
60
+ icon?: string;
61
+ label: string;
62
+ link?: string;
63
+ }
64
+ interface Header {
65
+ headerType?: string;
66
+ brand: Brand;
67
+ tabs: NavbarItem[];
68
+ topbar: Topbar;
69
+ }
70
+ interface FooterItemGroup {
71
+ title: string;
72
+ items: FooterItem[];
73
+ }
74
+ interface FooterItem {
75
+ label: string;
76
+ link?: string;
77
+ }
78
+ interface Footer {
79
+ footerType?: string;
80
+ groups: FooterItemGroup[];
81
+ copyright?: string;
82
+ address?: string;
83
+ country?: string;
84
+ phone?: string;
85
+ email?: string;
86
+ }
87
+ interface Hero {
88
+ type: string;
89
+ data: Record<string, unknown>;
90
+ }
91
+ interface Block {
92
+ type: string;
93
+ data: Record<string, unknown>;
94
+ }
95
+ interface Page {
96
+ slug: string;
97
+ hero?: Hero;
98
+ blocks: Block[];
26
99
  }
27
100
  import { FrappeApp, FrappeAuth, FrappeCall } from "frappe-js-sdk";
28
101
  import { FrappeDB } from "frappe-js-sdk/lib/db";
@@ -513,79 +586,62 @@ declare const useFrappeUpdateDoc: <T = any>() => {
513
586
  isCompleted: boolean;
514
587
  reset: () => void;
515
588
  };
516
- interface Globals {
517
- header: Header;
518
- footer: Footer;
519
- }
520
- interface Brand {
521
- brandImage?: string;
522
- }
523
- interface NavbarItem {
524
- label: string;
525
- enableDropdown: boolean;
526
- enableLink: boolean;
527
- link?: string;
528
- dropdownDescription?: string;
529
- dropdownCTALabel?: string;
530
- dropdownCTALink?: string;
531
- groups?: NavbarSubItemGroup[];
532
- }
533
- interface NavbarSubItemGroup {
534
- title: string;
535
- items: NavbarSubItem[];
536
- }
537
- interface NavbarSubItem {
538
- label: string;
539
- description?: string;
540
- image?: string;
541
- link?: string;
589
+ interface VariantSelectorProps<T extends {
590
+ id: string;
591
+ specs: Record<string, string>;
592
+ }> {
593
+ variants: T[];
594
+ attributes: {
595
+ key: string;
596
+ values: string[];
597
+ }[];
598
+ defaultId?: string;
542
599
  }
543
- interface Topbar {
544
- enabled: boolean;
545
- layout: string;
546
- items: TopbarItem[];
547
- }
548
- interface TopbarItem {
549
- icon?: string;
550
- label: string;
551
- link?: string;
552
- }
553
- interface Header {
554
- headerType?: string;
555
- brand: Brand;
556
- tabs: NavbarItem[];
557
- topbar: Topbar;
600
+ interface VariantSelectorOption {
601
+ key: string;
602
+ value: string;
603
+ state: "selected" | "available" | "unavailable";
558
604
  }
559
- interface FooterItemGroup {
560
- title: string;
561
- items: FooterItem[];
605
+ interface VariantSelectorResult {
606
+ variantId?: string;
607
+ onOptionSelect: (key: string, value: string) => void;
608
+ getOptions: (key: string) => VariantSelectorOption[];
562
609
  }
563
- interface FooterItem {
564
- label: string;
565
- link?: string;
610
+ declare const useVariantSelector: <T extends {
611
+ id: string;
612
+ specs: Record<string, string>;
613
+ }>(props: VariantSelectorProps<T>) => VariantSelectorResult;
614
+ interface Category {
615
+ name: string;
566
616
  }
567
- interface Footer {
568
- footerType?: string;
569
- groups: FooterItemGroup[];
570
- copyright?: string;
571
- address?: string;
572
- country?: string;
573
- phone?: string;
574
- email?: string;
617
+ interface Product {
618
+ name: string;
619
+ image: string;
620
+ item_code: string;
621
+ description: string;
575
622
  }
576
- interface Hero {
577
- type: string;
578
- data: Record<string, unknown>;
623
+ interface ProductVariant extends ItemVariant {
624
+ name: string;
625
+ currency: string;
626
+ rate: number;
627
+ qty: number;
628
+ images: string[];
629
+ specs: Record<string, string>;
579
630
  }
580
- interface Block {
581
- type: string;
582
- data: Record<string, unknown>;
631
+ interface ShopContext {
632
+ categories: Category[];
633
+ grades: string[];
634
+ selected_category?: Category;
635
+ selected_grade?: string;
636
+ products: Product[];
583
637
  }
584
- interface Page {
585
- slug: string;
586
- hero?: Hero;
587
- blocks: Block[];
638
+ interface ProductContext {
639
+ product: Product;
640
+ specs: Record<string, string[]>;
641
+ variants: ProductVariant[];
642
+ models: Record<string, Model>;
643
+ colors: Record<string, Colour>;
588
644
  }
589
645
  import { camelize, decamelize, camelizeKeys, decamelizeKeys } from "humps";
590
646
  declare function equalsIgnoreCase(str1: string, str2: string): boolean;
591
- export { useSearch, useFrappeUpdateDoc, useFrappePutCall, useFrappePrefetchDoc, useFrappePostCall, useFrappeGetDocList, useFrappeGetDocCount, useFrappeGetDoc, useFrappeGetCall, useFrappeFileUpload, useFrappeEventListener, useFrappeDocumentEventListener, useFrappeDocTypeEventListener, useFrappeDeleteDoc, useFrappeDeleteCall, useFrappeCreateDoc, useFrappeAuth, equalsIgnoreCase, decamelizeKeys, decamelize, camelizeKeys, camelize, ViewerEventData, UseFrappeFileUploadReturnType, TopbarItem, Topbar, TokenParams, SearchResult, Page, NavbarSubItemGroup, NavbarSubItem, NavbarItem, Model, ItemVariant, Item, Hero, Header, Globals, FrappeProviderProps, FrappeProvider, FrappeMutationResult, FrappeFileUploadResponse, FrappeError, FrappeContext, FrappeConfig, FooterItemGroup, FooterItem, Footer, DocumentUpdateEventData, DocTypeListUpdateEventData, Colour, Brand, Block };
647
+ export { useVariantSelector, useSearch, useFrappeUpdateDoc, useFrappePutCall, useFrappePrefetchDoc, useFrappePostCall, useFrappeGetDocList, useFrappeGetDocCount, useFrappeGetDoc, useFrappeGetCall, useFrappeFileUpload, useFrappeEventListener, useFrappeDocumentEventListener, useFrappeDocTypeEventListener, useFrappeDeleteDoc, useFrappeDeleteCall, useFrappeCreateDoc, useFrappeAuth, equalsIgnoreCase, decamelizeKeys, decamelize, camelizeKeys, camelize, ViewerEventData, VariantSelectorResult, VariantSelectorProps, VariantSelectorOption, UseFrappeFileUploadReturnType, TopbarItem, Topbar, TokenParams, ShopContext, SearchResult, ProductVariant, ProductContext, Product, Page, NavbarSubItemGroup, NavbarSubItem, NavbarItem, Model, ItemVariant, Item, Hero, Header, Globals, FrappeProviderProps, FrappeProvider, FrappeMutationResult, FrappeFileUploadResponse, FrappeError, FrappeContext, FrappeConfig, FooterItemGroup, FooterItem, Footer, DocumentUpdateEventData, DocTypeListUpdateEventData, Colour, Category, Brand, Block };
package/dist/rn/index.js CHANGED
@@ -46,7 +46,7 @@ class SocketIO {
46
46
  }
47
47
 
48
48
  // src/frappe/provider.tsx
49
- import { jsxDEV } from "react/jsx-dev-runtime";
49
+ import { jsx } from "react/jsx-runtime";
50
50
 
51
51
  var FrappeContext = createContext(null);
52
52
  var FrappeProvider = ({
@@ -71,10 +71,10 @@ var FrappeProvider = ({
71
71
  socket: enableSocket ? new SocketIO(url, siteName, socketPort, tokenParams).socket : undefined
72
72
  };
73
73
  }, [url, tokenParams, enableSocket, socketPort, siteName, customHeaders]);
74
- return /* @__PURE__ */ jsxDEV(FrappeContext.Provider, {
74
+ return /* @__PURE__ */ jsx(FrappeContext.Provider, {
75
75
  value: frappeConfig,
76
76
  children
77
- }, undefined, false, undefined, this);
77
+ });
78
78
  };
79
79
  // src/frappe/hooks/auth.ts
80
80
  import { useCallback, useContext, useState, useEffect } from "react";
@@ -465,12 +465,118 @@ var useFrappeUpdateDoc = () => {
465
465
  reset
466
466
  };
467
467
  };
468
+ // src/hooks/use-variant-selector/hook.ts
469
+ import { useCallback as useCallback4, useMemo as useMemo2, useState as useState5 } from "react";
470
+
471
+ // src/hooks/use-variant-selector/utils.ts
472
+ function findVariant(variants, specs, caseInsensitive) {
473
+ return variants.find((variant) => {
474
+ return Object.entries(specs).every(([key, value]) => {
475
+ const vv = variant.specs[key];
476
+ if (!vv)
477
+ return false;
478
+ if (caseInsensitive) {
479
+ return vv.toLowerCase() === value.toLowerCase();
480
+ }
481
+ return vv === value;
482
+ });
483
+ });
484
+ }
485
+ function findVariants(variants, specs, caseInsensitive) {
486
+ return variants.filter((variant) => {
487
+ return Object.entries(specs).every(([key, value]) => {
488
+ const vv = variant.specs[key];
489
+ if (!vv)
490
+ return false;
491
+ if (caseInsensitive) {
492
+ return vv.toLowerCase() === value.toLowerCase();
493
+ }
494
+ return vv === value;
495
+ });
496
+ });
497
+ }
498
+
499
+ // src/hooks/use-variant-selector/hook.ts
500
+ var useVariantSelector = (props) => {
501
+ const { variants, attributes, defaultId } = props;
502
+ const [selectedSpecs, setSelectedSpecs] = useState5(() => {
503
+ if (defaultId) {
504
+ const variant = variants.find((v) => v.id === defaultId);
505
+ return variant?.specs || {};
506
+ }
507
+ return {};
508
+ });
509
+ const variantId = useMemo2(() => {
510
+ const complete = attributes.every((attr) => selectedSpecs[attr.key]);
511
+ if (!complete)
512
+ return;
513
+ const variant = findVariant(variants, selectedSpecs);
514
+ return variant?.id;
515
+ }, [variants, selectedSpecs, attributes]);
516
+ const options = useMemo2(() => {
517
+ const result = {};
518
+ attributes.forEach((attr, attrIndex) => {
519
+ const constraints = {};
520
+ for (let i = 0;i < attrIndex; i++) {
521
+ const key = attributes[i]?.key;
522
+ if (key && selectedSpecs[key])
523
+ constraints[key] = selectedSpecs[key];
524
+ }
525
+ const matchingVariants = findVariants(variants, constraints);
526
+ const availableValues = new Set(matchingVariants.map((v) => v.specs[attr.key]));
527
+ result[attr.key] = attr.values.map((value) => {
528
+ const isSelected = selectedSpecs[attr.key] === value;
529
+ const isAvailable = availableValues.has(value);
530
+ return {
531
+ key: attr.key,
532
+ value,
533
+ state: isSelected ? "selected" : isAvailable ? "available" : "unavailable"
534
+ };
535
+ });
536
+ });
537
+ return result;
538
+ }, [variants, attributes, selectedSpecs]);
539
+ const onOptionSelect = useCallback4((key, value) => {
540
+ setSelectedSpecs((prev) => {
541
+ const newSpecs = { ...prev, [key]: value };
542
+ const attrIndex = attributes.findIndex((a) => a.key === key);
543
+ for (let i = attrIndex + 1;i < attributes.length; i++) {
544
+ const downstreamAttr = attributes[i];
545
+ if (!downstreamAttr)
546
+ continue;
547
+ const constraints = {};
548
+ for (let j = 0;j < i; j++) {
549
+ const k = attributes[j]?.key;
550
+ if (k && newSpecs[k])
551
+ constraints[k] = newSpecs[k];
552
+ }
553
+ const matching = findVariants(variants, constraints);
554
+ const availableValues = new Set(matching.map((v) => v.specs[downstreamAttr.key]));
555
+ if (!availableValues.has(newSpecs[downstreamAttr.key])) {
556
+ const firstAvailable = downstreamAttr.values.find((v) => availableValues.has(v));
557
+ if (firstAvailable) {
558
+ newSpecs[downstreamAttr.key] = firstAvailable;
559
+ } else {
560
+ delete newSpecs[downstreamAttr.key];
561
+ }
562
+ }
563
+ }
564
+ return newSpecs;
565
+ });
566
+ }, [attributes, variants]);
567
+ return {
568
+ variantId,
569
+ onOptionSelect,
570
+ getOptions: (key) => options[key] || []
571
+ };
572
+ };
468
573
  // src/utils/char.ts
469
574
  import { camelize, decamelize, camelizeKeys, decamelizeKeys } from "humps";
470
575
  function equalsIgnoreCase(str1, str2) {
471
576
  return str1.localeCompare(str2, undefined, { sensitivity: "accent" }) === 0;
472
577
  }
473
578
  export {
579
+ useVariantSelector,
474
580
  useSearch,
475
581
  useFrappeUpdateDoc,
476
582
  useFrappePutCall,
package/package.json CHANGED
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "name": "@lasterp/shared",
3
- "version": "1.0.0-alpha.9",
3
+ "version": "1.0.0-beta.0",
4
4
  "description": "Shared repo for webapp and native app",
5
5
  "license": "MIT",
6
6
  "files": [
7
7
  "dist"
8
8
  ],
9
9
  "scripts": {
10
- "build": "bunup",
10
+ "build": "NODE_ENV=production bunup",
11
11
  "dev": "bunup --watch",
12
12
  "type-check": "tsc --noEmit"
13
13
  },
package/dist/index.d.ts DELETED
@@ -1,2 +0,0 @@
1
- declare function greet(name: string): string;
2
- export { greet };
package/dist/index.js DELETED
@@ -1,7 +0,0 @@
1
- // src/index.ts
2
- function greet(name) {
3
- return `Hello, ${name}!`;
4
- }
5
- export {
6
- greet
7
- };