@dropins/storefront-pdp 1.3.1-alpha001 → 1.3.1-alpha101
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/chunks/Swatches.js +1 -1
- package/chunks/Swatches.js.map +1 -1
- package/package.json +1 -1
package/chunks/Swatches.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
/*! Copyright 2025 Adobe
|
|
2
2
|
All Rights Reserved. */
|
|
3
|
-
import{jsx as
|
|
3
|
+
import{jsx as f,jsxs as R}from"@dropins/tools/preact-jsx-runtime.js";import{useState as z,useEffect as P,useMemo as A,useCallback as _}from"@dropins/tools/preact-compat.js";import{classes as C}from"@dropins/tools/lib.js";import{Picker as y,ColorSwatch as B,ImageSwatch as D,TextSwatch as F}from"@dropins/tools/components.js";/* empty css */import{useText as q}from"@dropins/tools/i18n.js";const G=["text","image","color","dropdown"],H=d=>d.map(h=>({...h,text:h.label,disabled:!h.inStock}));function K(d,h){return d.reduce((m,w)=>{const n=h==null?void 0:h.find(i=>i.items.find(S=>S.id===w));if(!n)return m;const b=n.items.find(i=>i.id===w);return{...m,[n.id]:{label:b.label,value:b.id}}},{})}const T=({options:d,hideSelectedValue:h,disablePreselections:m,selectedUIDs:w,onValues:n,onErrors:b,defaultOptions:i,selectionsToUpdate:S,className:L,children:Q,imageSwatchNode:O,...M})=>{const j=q("PDP.Swatches.Required.label").label,g=q("PDP.Swatches.ChooseOption.label").label,[v,x]=z(()=>d==null?void 0:d.reduce((r,e)=>{const{items:a}=e,c=a==null?void 0:a.find(s=>i==null?void 0:i.includes(s.id)),u=a==null?void 0:a.find(s=>s.selected);return c?{...r,[e.id]:{label:c.label,value:c.id}}:u?{...r,[e.id]:{label:u.label,value:u.id}}:r},{}));P(()=>{if(w){const l=K(w,d);if(JSON.stringify(l)===JSON.stringify(v))return;x(r=>{let e={...r,...l};return n==null||n(e),e})}},[w]),P(()=>{S==null||S.forEach(l=>{x(r=>{var c;const e=(c=l==null?void 0:l.items)==null?void 0:c.find(u=>u.selected);return e?{...r,[l.id]:{label:e==null?void 0:e.label,value:e==null?void 0:e.id}}:r})})},[S,x]),A(()=>{const l=d==null?void 0:d.reduce((r,e)=>{var c;let a=!1;return(c=e==null?void 0:e.items)==null||c.forEach(u=>{var t;((t=v[e.id])==null?void 0:t.value)===u.id&&(a=!0)}),e.required&&!a&&(r[e.id]=j),r},{});return b==null||b(l),l},[v]);const $=_((l,r,e)=>{x(a=>{let c={...a,...l&&{[l]:{label:r,value:e}}};return r===g&&delete c[l],n==null||n(c,e),c})},[n]),N=_((l,r)=>{var a;const e=((a=r.selectedOptions[0])==null?void 0:a.label)??"";$(l,e,r.value)},[$]),J=_(({items:l,id:r,required:e,type:a,selected:c,label:u})=>{const s=`pdp-swatch-${r}=${Math.random().toString(36)}`;return(l==null?void 0:l.length)>0&&f("div",{className:C(["pdp-swatches__options"]),children:(a==null?void 0:a.toLowerCase())==="dropdown"?f(y,{id:s,name:r,"aria-label":u,placeholder:m?g:void 0,handleSelect:t=>N(r,t.target),options:H(l),value:c}):l==null?void 0:l.map(t=>{const k={key:t.id,id:`${s}-${t.id}`,name:r,value:t.value,label:t.label,groupAriaLabel:u,selected:c===t.id,outOfStock:!t.inStock,required:e===null?!0:e,onValue:()=>{$(r,t.label,t.id)}};switch(a){case"text":return f(F,{...k,label:t.label});case"image":return f(D,{...k,src:t.value,alt:t.label,imageNode:O});case"color":return f(B,{...k,size:"large",color:t.value});default:return console.warn(`Invalid swatch type ${a}`),null}})})},[g,$,N]);return f("div",{...M,className:C(["pdp-swatches",L]),children:d==null?void 0:d.map(({type:l,label:r,id:e,multiple:a,required:c,items:u})=>{var s;return G.includes(l)||console.warn(`Invalid swatch type ${l}`),a&&console.warn("Multiple selection swatches are not currently supported."),R("div",{id:`swatch-item-${e}`,"data-slot-key":`product-swatch--${e}`,className:"pdp-swatches__field",children:[f("div",{className:"pdp-swatches__field__label",children:v[e]?h?`${r}`:`${r}: ${v[e].label}`:r}),f(J,{id:e,type:l,required:c,items:u,label:r,selected:(s=v[e])==null?void 0:s.value})]},`swatch-item-${e}`)})})};export{T as S};
|
|
4
4
|
//# sourceMappingURL=Swatches.js.map
|
package/chunks/Swatches.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Swatches.js","sources":["/@dropins/storefront-pdp/src/components/Swatches/Swatches.tsx"],"sourcesContent":["/**\n * ADOBE CONFIDENTIAL\n * __________________\n * Copyright 2023 Adobe\n * All Rights Reserved.\n * __________________\n * NOTICE: All information contained herein is, and remains\n * the property of Adobe and its suppliers, if any. The intellectual\n * and technical concepts contained herein are proprietary to Adobe\n * and its suppliers and are protected by all applicable intellectual\n * property laws, including trade secret and copyright laws.\n * Dissemination of this information or reproduction of this material\n * is strictly forbidden unless prior written permission is obtained\n * from Adobe.\n */\n\nimport { FunctionComponent, VNode } from 'preact';\nimport {\n HTMLAttributes,\n useState,\n useMemo,\n useCallback,\n useEffect,\n JSX,\n} from 'preact/compat';\nimport { classes } from '@adobe-commerce/elsie/lib';\nimport { useText } from '@adobe-commerce/elsie/i18n';\nimport {\n ColorSwatch,\n ImageSwatch,\n TextSwatch,\n Picker,\n PickerOption,\n ImageNodeRenderProps,\n} from '@adobe-commerce/elsie/components';\n\nimport '@/pdp/components/Swatches/Swatches.css';\n\nconst supportedTypes = ['text', 'image', 'color', 'dropdown'];\n\nconst mapToPickerOptions = (items: OptionValue[]): PickerOption[] => {\n return items.map((item: OptionValue) => ({\n ...item,\n text: item.label,\n disabled: !item.inStock,\n }));\n};\n\ntype OptionValue = {\n id: string;\n label: string;\n inStock: boolean;\n value: string;\n selected?: boolean;\n};\n\nexport type Option = {\n id: string;\n type: (typeof supportedTypes)[number];\n label: string;\n required?: boolean;\n multiple?: boolean;\n items: OptionValue[];\n};\n\ntype Selection = { [id: string]: { label: string; value: string } };\n\nfunction optionUIDsToSelection(\n optionUIDs: string[],\n options: Array<Option>\n): Selection {\n return optionUIDs.reduce((accum, optionUID) => {\n const option = options?.find((option) =>\n option.items.find((item) => item.id === optionUID)\n );\n if (!option) return accum;\n\n const item = option.items.find((item) => item.id === optionUID);\n\n return {\n ...accum,\n [option.id]: {\n label: item!.label,\n value: item!.id,\n },\n };\n }, {});\n}\n\nexport interface SwatchesProps extends HTMLAttributes<HTMLDivElement> {\n options: Array<Option>;\n hideSelectedValue?: boolean;\n disablePreselections?: boolean;\n defaultOptions?: string[];\n selectionsToUpdate?: Option[];\n onValues?: (uids: Selection, current: string) => void;\n onErrors?: (errors: { [id: string]: string }) => void;\n selectedUIDs?: string[];\n imageSwatchNode?: VNode | ((props: ImageNodeRenderProps) => JSX.Element);\n}\n\nexport const Swatches: FunctionComponent<SwatchesProps> = ({\n options,\n hideSelectedValue,\n disablePreselections,\n selectedUIDs,\n onValues,\n onErrors,\n defaultOptions,\n selectionsToUpdate,\n className,\n children,\n imageSwatchNode,\n ...props\n}) => {\n // i18n\n const RequiredLabel = useText('PDP.Swatches.Required.label').label;\n const ChooseOptionLabel = useText('PDP.Swatches.ChooseOption.label').label;\n\n const [selections, setSelections] = useState<Selection>(() => {\n const initial = options?.reduce((accum, option) => {\n const { items } = option;\n const defaultSelection = items?.find((item) =>\n defaultOptions?.includes(item.id)\n );\n const selected = items?.find((item) => item.selected);\n if (defaultSelection) {\n return {\n ...accum,\n [option.id]: {\n label: defaultSelection.label,\n value: defaultSelection.id,\n },\n };\n } else if (selected) {\n return {\n ...accum,\n [option.id]: { label: selected.label, value: selected.id },\n };\n }\n return accum;\n }, {} as Selection);\n\n return initial;\n });\n\n // set selected options from props\n useEffect(() => {\n if (selectedUIDs) {\n const selection = optionUIDsToSelection(selectedUIDs, options);\n // if the internal state is already the same as the props, do nothing\n if (JSON.stringify(selection) === JSON.stringify(selections)) return;\n\n setSelections((prev) => {\n let next = {\n ...prev,\n ...selection,\n };\n onValues?.(next);\n return next;\n });\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [selectedUIDs]);\n\n // this only applies for the case with anchor options\n // update selections in the swatches if they are updated in the parent component\n useEffect(() => {\n selectionsToUpdate?.forEach((selectionToUpdate) => {\n setSelections((prev) => {\n const selectedItem = selectionToUpdate?.items?.find(\n (item) => item.selected\n );\n if (!selectedItem) return prev;\n\n const next = {\n ...prev,\n [selectionToUpdate.id]: {\n label: selectedItem?.label,\n value: selectedItem?.id,\n },\n };\n return next;\n });\n });\n }, [selectionsToUpdate, setSelections]);\n\n // Update invalid options\n useMemo(() => {\n const errors = options?.reduce((accum, option) => {\n let valueSelected = false;\n option?.items?.forEach((item) => {\n const selected = selections[option.id]?.value === item.id;\n if (selected) {\n valueSelected = true;\n }\n });\n\n // Validate required\n if (option.required && !valueSelected) {\n accum[option.id] = RequiredLabel;\n }\n return accum;\n }, {} as { [id: string]: string });\n\n // Call the callback\n onErrors?.(errors);\n\n return errors;\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [selections]);\n\n const handleOnSelection = useCallback(\n (id: string, label: string, optionId: string) => {\n setSelections((prev) => {\n let next = {\n ...prev,\n ...(id && { [id]: { label, value: optionId } }),\n };\n\n if (label === ChooseOptionLabel) {\n delete next[id];\n }\n\n // Call the callback\n onValues?.(next, optionId);\n\n // Return the next state\n return next;\n });\n },\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [onValues]\n );\n\n // Function to handle the picker selection\n const handlePickerSelect = useCallback(\n (optionId: string, selection: any) => {\n const label = selection.selectedOptions[0]?.label ?? '';\n handleOnSelection(optionId, label, selection.value);\n },\n [handleOnSelection]\n );\n\n const Swatches = useCallback(\n ({ items, id, required, type, selected, label }: any) => {\n return (\n items?.length > 0 && (\n <div className={classes(['pdp-swatches__options'])}>\n {type?.toLowerCase() === 'dropdown' ? (\n <Picker\n aria-label={label}\n placeholder={\n disablePreselections ? ChooseOptionLabel : undefined\n }\n handleSelect={(event) => handlePickerSelect(id, event.target)}\n options={mapToPickerOptions(items)}\n value={selected}\n />\n ) : (\n items?.map((option: any) => {\n const common = {\n key: option.id,\n id: option.id,\n name: id,\n value: option.value,\n label: option.label,\n groupAriaLabel: label,\n selected: selected === option.id,\n outOfStock: !option.inStock,\n // API may return null, we default to true as all swatches are required.\n // we still comply to this in case the api return \"false\".\n required: required === null ? true : required,\n onValue: () => {\n handleOnSelection(id, option.label, option.id);\n },\n };\n\n switch (type) {\n case 'text':\n return <TextSwatch {...common} label={option.label} />;\n\n case 'image':\n return (\n <ImageSwatch\n {...common}\n src={option.value}\n alt={option.label}\n imageNode={imageSwatchNode}\n />\n );\n\n case 'color':\n return (\n <ColorSwatch\n {...common}\n size=\"large\"\n color={option.value}\n />\n );\n\n default:\n console.warn(`Invalid swatch type ${type}`);\n return null;\n }\n })\n )}\n </div>\n )\n );\n },\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [ChooseOptionLabel, handleOnSelection, handlePickerSelect]\n );\n\n return (\n <div {...props} className={classes(['pdp-swatches', className])}>\n {options?.map(({ type, label, id, multiple, required, items }) => {\n // Only render supported types\n if (!supportedTypes.includes(type)) {\n console.warn(`Invalid swatch type ${type}`);\n }\n\n if (multiple) {\n console.warn(\n 'Multiple selection swatches are not currently supported.'\n );\n }\n\n return (\n <div\n key={`swatch-item-${id}`}\n id={`swatch-item-${id}`}\n data-slot-key={`product-swatch--${id}`}\n className=\"pdp-swatches__field\"\n >\n <div className=\"pdp-swatches__field__label\">\n {selections[id]\n ? hideSelectedValue\n ? `${label}`\n : `${label}: ${selections[id].label}`\n : label}\n </div>\n\n <Swatches\n id={id}\n type={type}\n required={required}\n items={items}\n label={label} //label referring to the name of the swatchGroup\n selected={selections[id]?.value}\n />\n </div>\n );\n })}\n </div>\n );\n};\n"],"names":["supportedTypes","mapToPickerOptions","items","item","optionUIDsToSelection","optionUIDs","options","accum","optionUID","option","Swatches","hideSelectedValue","disablePreselections","selectedUIDs","onValues","onErrors","defaultOptions","selectionsToUpdate","className","children","imageSwatchNode","props","RequiredLabel","useText","ChooseOptionLabel","selections","setSelections","useState","defaultSelection","selected","useEffect","selection","prev","next","selectionToUpdate","selectedItem","_a","useMemo","errors","valueSelected","handleOnSelection","useCallback","id","label","optionId","handlePickerSelect","required","type","jsx","classes","Picker","event","common","TextSwatch","ImageSwatch","ColorSwatch","multiple","jsxs"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Swatches.js","sources":["/@dropins/storefront-pdp/src/components/Swatches/Swatches.tsx"],"sourcesContent":["/**\n * ADOBE CONFIDENTIAL\n * __________________\n * Copyright 2023 Adobe\n * All Rights Reserved.\n * __________________\n * NOTICE: All information contained herein is, and remains\n * the property of Adobe and its suppliers, if any. The intellectual\n * and technical concepts contained herein are proprietary to Adobe\n * and its suppliers and are protected by all applicable intellectual\n * property laws, including trade secret and copyright laws.\n * Dissemination of this information or reproduction of this material\n * is strictly forbidden unless prior written permission is obtained\n * from Adobe.\n */\n\nimport { FunctionComponent, VNode } from 'preact';\nimport {\n HTMLAttributes,\n useState,\n useMemo,\n useCallback,\n useEffect,\n JSX,\n} from 'preact/compat';\nimport { classes } from '@adobe-commerce/elsie/lib';\nimport { useText } from '@adobe-commerce/elsie/i18n';\nimport {\n ColorSwatch,\n ImageSwatch,\n TextSwatch,\n Picker,\n PickerOption,\n ImageNodeRenderProps,\n} from '@adobe-commerce/elsie/components';\n\nimport '@/pdp/components/Swatches/Swatches.css';\n\nconst supportedTypes = ['text', 'image', 'color', 'dropdown'];\n\nconst mapToPickerOptions = (items: OptionValue[]): PickerOption[] => {\n return items.map((item: OptionValue) => ({\n ...item,\n text: item.label,\n disabled: !item.inStock,\n }));\n};\n\ntype OptionValue = {\n id: string;\n label: string;\n inStock: boolean;\n value: string;\n selected?: boolean;\n};\n\nexport type Option = {\n id: string;\n type: (typeof supportedTypes)[number];\n label: string;\n required?: boolean;\n multiple?: boolean;\n items: OptionValue[];\n};\n\ntype Selection = { [id: string]: { label: string; value: string } };\n\nfunction optionUIDsToSelection(\n optionUIDs: string[],\n options: Array<Option>\n): Selection {\n return optionUIDs.reduce((accum, optionUID) => {\n const option = options?.find((option) =>\n option.items.find((item) => item.id === optionUID)\n );\n if (!option) return accum;\n\n const item = option.items.find((item) => item.id === optionUID);\n\n return {\n ...accum,\n [option.id]: {\n label: item!.label,\n value: item!.id,\n },\n };\n }, {});\n}\n\nexport interface SwatchesProps extends HTMLAttributes<HTMLDivElement> {\n options: Array<Option>;\n hideSelectedValue?: boolean;\n disablePreselections?: boolean;\n defaultOptions?: string[];\n selectionsToUpdate?: Option[];\n onValues?: (uids: Selection, current: string) => void;\n onErrors?: (errors: { [id: string]: string }) => void;\n selectedUIDs?: string[];\n imageSwatchNode?: VNode | ((props: ImageNodeRenderProps) => JSX.Element);\n}\n\nexport const Swatches: FunctionComponent<SwatchesProps> = ({\n options,\n hideSelectedValue,\n disablePreselections,\n selectedUIDs,\n onValues,\n onErrors,\n defaultOptions,\n selectionsToUpdate,\n className,\n children,\n imageSwatchNode,\n ...props\n}) => {\n // i18n\n const RequiredLabel = useText('PDP.Swatches.Required.label').label;\n const ChooseOptionLabel = useText('PDP.Swatches.ChooseOption.label').label;\n\n const [selections, setSelections] = useState<Selection>(() => {\n const initial = options?.reduce((accum, option) => {\n const { items } = option;\n const defaultSelection = items?.find((item) =>\n defaultOptions?.includes(item.id)\n );\n const selected = items?.find((item) => item.selected);\n if (defaultSelection) {\n return {\n ...accum,\n [option.id]: {\n label: defaultSelection.label,\n value: defaultSelection.id,\n },\n };\n } else if (selected) {\n return {\n ...accum,\n [option.id]: { label: selected.label, value: selected.id },\n };\n }\n return accum;\n }, {} as Selection);\n\n return initial;\n });\n\n // set selected options from props\n useEffect(() => {\n if (selectedUIDs) {\n const selection = optionUIDsToSelection(selectedUIDs, options);\n // if the internal state is already the same as the props, do nothing\n if (JSON.stringify(selection) === JSON.stringify(selections)) return;\n\n setSelections((prev) => {\n let next = {\n ...prev,\n ...selection,\n };\n onValues?.(next);\n return next;\n });\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [selectedUIDs]);\n\n // this only applies for the case with anchor options\n // update selections in the swatches if they are updated in the parent component\n useEffect(() => {\n selectionsToUpdate?.forEach((selectionToUpdate) => {\n setSelections((prev) => {\n const selectedItem = selectionToUpdate?.items?.find(\n (item) => item.selected\n );\n if (!selectedItem) return prev;\n\n const next = {\n ...prev,\n [selectionToUpdate.id]: {\n label: selectedItem?.label,\n value: selectedItem?.id,\n },\n };\n return next;\n });\n });\n }, [selectionsToUpdate, setSelections]);\n\n // Update invalid options\n useMemo(() => {\n const errors = options?.reduce((accum, option) => {\n let valueSelected = false;\n option?.items?.forEach((item) => {\n const selected = selections[option.id]?.value === item.id;\n if (selected) {\n valueSelected = true;\n }\n });\n\n // Validate required\n if (option.required && !valueSelected) {\n accum[option.id] = RequiredLabel;\n }\n return accum;\n }, {} as { [id: string]: string });\n\n // Call the callback\n onErrors?.(errors);\n\n return errors;\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [selections]);\n\n const handleOnSelection = useCallback(\n (id: string, label: string, optionId: string) => {\n setSelections((prev) => {\n let next = {\n ...prev,\n ...(id && { [id]: { label, value: optionId } }),\n };\n\n if (label === ChooseOptionLabel) {\n delete next[id];\n }\n\n // Call the callback\n onValues?.(next, optionId);\n\n // Return the next state\n return next;\n });\n },\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [onValues]\n );\n\n // Function to handle the picker selection\n const handlePickerSelect = useCallback(\n (optionId: string, selection: any) => {\n const label = selection.selectedOptions[0]?.label ?? '';\n handleOnSelection(optionId, label, selection.value);\n },\n [handleOnSelection]\n );\n\n const Swatches = useCallback(\n ({ items, id, required, type, selected, label }: any) => {\n const uniqueId = `pdp-swatch-${id}=${Math.random().toString(36)}`;\n\n return (\n items?.length > 0 && (\n <div className={classes(['pdp-swatches__options'])}>\n {type?.toLowerCase() === 'dropdown' ? (\n <Picker\n id={uniqueId}\n name={id}\n aria-label={label}\n placeholder={\n disablePreselections ? ChooseOptionLabel : undefined\n }\n handleSelect={(event) => handlePickerSelect(id, event.target)}\n options={mapToPickerOptions(items)}\n value={selected}\n />\n ) : (\n items?.map((option: any) => {\n const common = {\n key: option.id,\n id: `${uniqueId}-${option.id}`,\n name: id,\n value: option.value,\n label: option.label,\n groupAriaLabel: label,\n selected: selected === option.id,\n outOfStock: !option.inStock,\n // API may return null, we default to true as all swatches are required.\n // we still comply to this in case the api return \"false\".\n required: required === null ? true : required,\n onValue: () => {\n handleOnSelection(id, option.label, option.id);\n },\n };\n\n switch (type) {\n case 'text':\n return <TextSwatch {...common} label={option.label} />;\n\n case 'image':\n return (\n <ImageSwatch\n {...common}\n src={option.value}\n alt={option.label}\n imageNode={imageSwatchNode}\n />\n );\n\n case 'color':\n return (\n <ColorSwatch\n {...common}\n size=\"large\"\n color={option.value}\n />\n );\n\n default:\n console.warn(`Invalid swatch type ${type}`);\n return null;\n }\n })\n )}\n </div>\n )\n );\n },\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [ChooseOptionLabel, handleOnSelection, handlePickerSelect]\n );\n\n return (\n <div {...props} className={classes(['pdp-swatches', className])}>\n {options?.map(({ type, label, id, multiple, required, items }) => {\n // Only render supported types\n if (!supportedTypes.includes(type)) {\n console.warn(`Invalid swatch type ${type}`);\n }\n\n if (multiple) {\n console.warn(\n 'Multiple selection swatches are not currently supported.'\n );\n }\n\n return (\n <div\n key={`swatch-item-${id}`}\n id={`swatch-item-${id}`}\n data-slot-key={`product-swatch--${id}`}\n className=\"pdp-swatches__field\"\n >\n <div className=\"pdp-swatches__field__label\">\n {selections[id]\n ? hideSelectedValue\n ? `${label}`\n : `${label}: ${selections[id].label}`\n : label}\n </div>\n\n <Swatches\n id={id}\n type={type}\n required={required}\n items={items}\n label={label} //label referring to the name of the swatchGroup\n selected={selections[id]?.value}\n />\n </div>\n );\n })}\n </div>\n );\n};\n"],"names":["supportedTypes","mapToPickerOptions","items","item","optionUIDsToSelection","optionUIDs","options","accum","optionUID","option","Swatches","hideSelectedValue","disablePreselections","selectedUIDs","onValues","onErrors","defaultOptions","selectionsToUpdate","className","children","imageSwatchNode","props","RequiredLabel","useText","ChooseOptionLabel","selections","setSelections","useState","defaultSelection","selected","useEffect","selection","prev","next","selectionToUpdate","selectedItem","_a","useMemo","errors","valueSelected","handleOnSelection","useCallback","id","label","optionId","handlePickerSelect","required","type","uniqueId","jsx","classes","Picker","event","common","TextSwatch","ImageSwatch","ColorSwatch","multiple","jsxs"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"name": "@dropins/storefront-pdp", "version": "1.3.1-
|
|
1
|
+
{"name": "@dropins/storefront-pdp", "version": "1.3.1-alpha101", "@dropins/tools": "1.4.1-alpha101", "license": "SEE LICENSE IN LICENSE.md"}
|