@thinkersteps_labs/3d-viewer-react 0.0.0-stage → 1.0.1
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/README.md +106 -2
- package/dist/index.cjs +2 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +247 -0
- package/dist/index.js +402 -0
- package/dist/index.js.map +1 -0
- package/dist/style.css +1 -0
- package/package.json +43 -3
package/README.md
CHANGED
|
@@ -1,3 +1,107 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @thinkersteps_labs/3d-viewer-react
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Official React component wrapper for `@thinkersteps_labs/3d-viewer-core`. Renders photorealistic 3D jewelry viewers, swatches, and customizers in Next.js, Remix, Vite, and standard React applications.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pnpm add @thinkersteps_labs/3d-viewer-react @thinkersteps_labs/3d-viewer-core three
|
|
11
|
+
# or with npm
|
|
12
|
+
npm install @thinkersteps_labs/3d-viewer-react @thinkersteps_labs/3d-viewer-core three
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## 1. Turnkey Customizer (5-Line Embed)
|
|
18
|
+
|
|
19
|
+
The `<JewelryCustomizer />` provides a complete, responsive 3D canvas and luxury swatch controls out of the box:
|
|
20
|
+
|
|
21
|
+
```tsx
|
|
22
|
+
import { JewelryCustomizer } from '@thinkersteps_labs/3d-viewer-react'
|
|
23
|
+
|
|
24
|
+
export function ProductPage() {
|
|
25
|
+
return (
|
|
26
|
+
<JewelryCustomizer
|
|
27
|
+
src="https://cdn.example.com/models/solitaire-ring.glb"
|
|
28
|
+
defaultMetal="yellow-gold-18k"
|
|
29
|
+
defaultStone="diamond-d"
|
|
30
|
+
height={520}
|
|
31
|
+
autoRotate
|
|
32
|
+
onMetalChange={(metal) => console.log('Selected metal:', metal)}
|
|
33
|
+
onStoneChange={(stone) => console.log('Selected stone:', stone)}
|
|
34
|
+
/>
|
|
35
|
+
)
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## 2. Composable Primitives (`<Viewer />` + Swatches)
|
|
42
|
+
|
|
43
|
+
Combine `<Viewer />` with pre-built `<MetalSwatches />` and `<StoneSwatches />` for custom layouts:
|
|
44
|
+
|
|
45
|
+
```tsx
|
|
46
|
+
import { useState } from 'react'
|
|
47
|
+
import {
|
|
48
|
+
Viewer,
|
|
49
|
+
MetalSwatches,
|
|
50
|
+
StoneSwatches,
|
|
51
|
+
type MetalColorProp,
|
|
52
|
+
type StoneColorProp,
|
|
53
|
+
} from '@thinkersteps_labs/3d-viewer-react'
|
|
54
|
+
|
|
55
|
+
export function Customizer() {
|
|
56
|
+
const [metal, setMetal] = useState<MetalColorProp>('yellow-gold-18k')
|
|
57
|
+
const [stone, setStone] = useState<StoneColorProp>('diamond-d')
|
|
58
|
+
|
|
59
|
+
return (
|
|
60
|
+
<div style={{ maxWidth: '840px', margin: '0 auto' }}>
|
|
61
|
+
<Viewer
|
|
62
|
+
src="https://cdn.example.com/models/solitaire-ring.glb"
|
|
63
|
+
metalColor={metal}
|
|
64
|
+
stoneColor={stone}
|
|
65
|
+
height={500}
|
|
66
|
+
autoRotate
|
|
67
|
+
/>
|
|
68
|
+
|
|
69
|
+
<div style={{ marginTop: '16px', display: 'flex', flexDirection: 'column', gap: '14px' }}>
|
|
70
|
+
<MetalSwatches value={metal} onChange={setMetal} variant="pills" />
|
|
71
|
+
<StoneSwatches value={stone} onChange={setStone} variant="pills" />
|
|
72
|
+
</div>
|
|
73
|
+
</div>
|
|
74
|
+
)
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## 3. Headless Hook (`useJewelryCustomizer`)
|
|
81
|
+
|
|
82
|
+
For custom UI layouts with pre-wired state and preset lookup:
|
|
83
|
+
|
|
84
|
+
```tsx
|
|
85
|
+
import { Viewer, useJewelryCustomizer } from '@thinkersteps_labs/3d-viewer-react'
|
|
86
|
+
|
|
87
|
+
export function HeadlessCustomizer() {
|
|
88
|
+
const { metal, setMetal, stone, setStone, metalOptions, stoneOptions, viewerProps } =
|
|
89
|
+
useJewelryCustomizer({
|
|
90
|
+
defaultMetal: 'yellow-gold-18k',
|
|
91
|
+
defaultStone: 'diamond-d',
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
return (
|
|
95
|
+
<div>
|
|
96
|
+
<Viewer src="/models/ring.glb" {...viewerProps} height={480} />
|
|
97
|
+
{/* Build your bespoke buttons, dropdowns, or swatches */}
|
|
98
|
+
</div>
|
|
99
|
+
)
|
|
100
|
+
}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
## License
|
|
106
|
+
|
|
107
|
+
MIT
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const e=require("react/jsx-runtime"),u=require("react"),l=require("@thinkersteps_labs/3d-viewer-core"),k=u.forwardRef(function(i,c){const{src:N,source:P,metalColor:S,stoneColor:f,materialColors:m,partColors:b,background:r,metalEnvUrl:p,gemEnvUrl:t,options:j,fov:y,shadows:M,autoRotate:x,quality:v,height:T,minHeight:_,aspectRatio:L,className:I,style:$}=i,A=u.useRef(null),E=u.useRef(null),h=u.useRef(i);h.current=i,u.useImperativeHandle(c,()=>E.current,[]),u.useEffect(()=>{if(!A.current)return;const o=l.createViewer(A.current,{...j,...r!==void 0&&{background:r},...y!==void 0&&{fov:y},...M!==void 0&&{shadows:M},...x!==void 0&&{autoRotate:x},...v!==void 0&&{quality:v},...p!==void 0&&{metalEnvUrl:p},...t!==void 0&&{gemEnvUrl:t}});return E.current=o,c&&(typeof c=="function"?c(o):c.current=o),o.on("loaded",({parts:d,materials:s})=>{var n,g;return(g=(n=h.current).onLoaded)==null?void 0:g.call(n,d,s)}),o.on("partSelected",d=>{var s,n;return(n=(s=h.current).onPartSelected)==null?void 0:n.call(s,d)}),o.on("change",d=>{var s,n;return(n=(s=h.current).onChange)==null?void 0:n.call(s,d)}),o.on("error",d=>{var s,n;return(n=(s=h.current).onError)==null?void 0:n.call(s,d)}),o.on("loading",({progress:d})=>{var s,n;return(n=(s=h.current).onProgress)==null?void 0:n.call(s,d)}),()=>{o.dispose(),c&&(typeof c=="function"?c(null):c.current=null)}},[]),u.useEffect(()=>{if(!E.current)return;const o=l.normalizeModelSource(N??P);if(!o){E.current.unload();return}const d=new AbortController;return E.current.load(o,{signal:d.signal}),()=>d.abort()},[N,P]),u.useEffect(()=>{var o;S&&((o=E.current)==null||o.setMetalColor(S))},[S]),u.useEffect(()=>{var o;f&&((o=E.current)==null||o.setStoneColor(f))},[f]);const w=u.useRef({});u.useEffect(()=>{if(!E.current)return;const o=w.current,d=m??{};for(const s of Object.keys(o))s in d||E.current.clearMaterialColor(s);for(const[s,n]of Object.entries(d))o[s]!==n&&E.current.setMaterialColor(s,n);w.current={...d}},[m]);const O=u.useRef({});u.useEffect(()=>{if(!E.current)return;const o=O.current,d=b??{};for(const s of Object.keys(o))if(!(s in d))if(s.includes(":")){const[n,g]=s.split(":"),C=parseInt(g??"",10);E.current.clearPartColor(n??"",isNaN(C)?void 0:C)}else E.current.clearPartColor(s);for(const[s,n]of Object.entries(d))if(o[s]!==n)if(s.includes(":")){const[g,C]=s.split(":"),z=parseInt(C??"",10);E.current.setPartColor(g??"",n,isNaN(z)?void 0:z)}else E.current.setPartColor(s,n);O.current={...d}},[b]),u.useEffect(()=>{E.current&&(x?E.current.startRotation():E.current.stopRotation())},[x]),u.useEffect(()=>{var o;v&&((o=E.current)==null||o.setQuality(v))},[v]);const R={width:"100%",height:T!==void 0?typeof T=="number"?`${T}px`:T:"100%",minHeight:_!==void 0?typeof _=="number"?`${_}px`:_:void 0,aspectRatio:L,position:"relative",...$};return e.jsx("div",{ref:A,className:I,style:R})});function D({value:a,onChange:i,options:c=l.CANONICAL_METAL_PRESETS,category:N="all",variant:P="pills",showLabel:S=!0,className:f="",style:m}){const b=N==="all"?c:c.filter(t=>t.category===N),r=a?l.getMetalPreset(a):void 0,p=(r==null?void 0:r.id)??a;return e.jsxs("div",{className:`td-swatch-group ${f}`,style:m,children:[S&&e.jsxs("div",{className:"td-swatch-header",children:[e.jsx("span",{className:"td-swatch-title",children:"Metal"}),r&&e.jsx("span",{className:"td-swatch-selected-name",children:r.label})]}),e.jsx("div",{className:"td-swatch-row",role:"radiogroup","aria-label":"Metal Selection",children:b.map(t=>{const j=p===t.id||a===t.hex;return e.jsxs("button",{type:"button",role:"radio","aria-checked":j,title:t.label,className:`td-swatch-${P==="dots"?"dot":"pill"} ${j?"active":""}`,onClick:()=>i==null?void 0:i(t.id,t),children:[e.jsx("span",{className:"td-swatch-color-circle",style:{backgroundColor:t.hex}}),P==="pills"&&e.jsx("span",{children:t.label})]},t.id)})})]})}function F({value:a,onChange:i,options:c=l.CANONICAL_METAL_PRESETS,label:N="Select Metal",className:P="",style:S}){var b;const f=a?l.getMetalPreset(a):void 0,m=(f==null?void 0:f.id)??a??((b=c[0])==null?void 0:b.id);return e.jsxs("div",{className:`td-select-wrapper ${P}`,style:S,children:[N&&e.jsx("label",{className:"td-swatch-title",children:N}),e.jsx("select",{className:"td-select",value:m,onChange:r=>{const p=r.target.value,t=l.getMetalPreset(p);i==null||i(p,t)},children:c.map(r=>e.jsx("option",{value:r.id,children:r.label},r.id))})]})}function H({value:a,onChange:i,options:c=l.CANONICAL_STONE_PRESETS,category:N="all",variant:P="pills",showLabel:S=!0,className:f="",style:m}){const b=N==="all"?c:c.filter(t=>t.category===N),r=a?l.getStonePreset(a):void 0,p=(r==null?void 0:r.id)??a;return e.jsxs("div",{className:`td-swatch-group ${f}`,style:m,children:[S&&e.jsxs("div",{className:"td-swatch-header",children:[e.jsx("span",{className:"td-swatch-title",children:"Gemstone"}),r&&e.jsxs("span",{className:"td-swatch-selected-name",children:[r.label,r.grade?` (${r.grade})`:""]})]}),e.jsx("div",{className:"td-swatch-row",role:"radiogroup","aria-label":"Gemstone Selection",children:b.map(t=>{const j=p===t.id||a===t.hex;return e.jsxs("button",{type:"button",role:"radio","aria-checked":j,title:`${t.label}${t.grade?` - ${t.grade}`:""}`,className:`td-swatch-${P==="dots"?"dot":"pill"} ${j?"active":""}`,onClick:()=>i==null?void 0:i(t.id,t),children:[e.jsx("span",{className:"td-swatch-color-circle",style:{backgroundColor:t.hex}}),P==="pills"&&e.jsx("span",{children:t.label})]},t.id)})})]})}function G({value:a,onChange:i,options:c=l.CANONICAL_STONE_PRESETS,label:N="Select Gemstone",className:P="",style:S}){var b;const f=a?l.getStonePreset(a):void 0,m=(f==null?void 0:f.id)??a??((b=c[0])==null?void 0:b.id);return e.jsxs("div",{className:`td-select-wrapper ${P}`,style:S,children:[N&&e.jsx("label",{className:"td-swatch-title",children:N}),e.jsx("select",{className:"td-select",value:m,onChange:r=>{const p=r.target.value,t=l.getStonePreset(p);i==null||i(p,t)},children:c.map(r=>e.jsxs("option",{value:r.id,children:[r.label," ",r.grade?`(${r.grade})`:""]},r.id))})]})}function q({src:a,source:i,defaultMetal:c="yellow-gold-18k",defaultStone:N="diamond-d",metal:P,onMetalChange:S,stone:f,onStoneChange:m,metalOptions:b,stoneOptions:r,controlsVariant:p="pills",height:t=520,autoRotate:j=!0,quality:y="high",fov:M,shadows:x,onLoaded:v,onPartSelected:T,className:_="",style:L,viewerRef:I}){const[$,A]=u.useState(c),[E,h]=u.useState(N),w=P!==void 0?P:$,O=f!==void 0?f:E,R=(s,n)=>{P===void 0&&A(s),S==null||S(s,n)},o=(s,n)=>{f===void 0&&h(s),m==null||m(s,n)},d=typeof t=="number"?`${t}px`:t;return e.jsxs("div",{className:`td-customizer-card ${_}`,style:L,children:[e.jsx("div",{className:"td-customizer-viewport",style:{height:d},children:e.jsx(k,{ref:I,src:a,source:i,metalColor:w,stoneColor:O,autoRotate:j,quality:y,fov:M,shadows:x,onLoaded:v,onPartSelected:T})}),p!=="none"&&e.jsx("div",{className:"td-customizer-controls",children:p==="select"?e.jsxs(e.Fragment,{children:[e.jsx(F,{value:w,onChange:R,options:b}),e.jsx(G,{value:O,onChange:o,options:r})]}):e.jsxs(e.Fragment,{children:[e.jsx(D,{value:w,onChange:R,options:b,variant:p}),e.jsx(H,{value:O,onChange:o,options:r,variant:p})]})})]})}function J(a={}){const{defaultMetal:i="yellow-gold-18k",defaultStone:c="diamond-d",metalOptions:N=l.CANONICAL_METAL_PRESETS,stoneOptions:P=l.CANONICAL_STONE_PRESETS}=a,[S,f]=u.useState(i),[m,b]=u.useState(c),r=u.useMemo(()=>l.getMetalPreset(S),[S]),p=u.useMemo(()=>l.getStonePreset(m),[m]),t=u.useMemo(()=>({metalColor:S,stoneColor:m}),[S,m]);return{metal:S,setMetal:f,stone:m,setStone:b,metalPreset:r,stonePreset:p,metalOptions:N,stoneOptions:P,viewerProps:t}}Object.defineProperty(exports,"ALL_METAL_PRESETS",{enumerable:!0,get:()=>l.ALL_METAL_PRESETS});Object.defineProperty(exports,"ALL_STONE_PRESETS",{enumerable:!0,get:()=>l.ALL_STONE_PRESETS});Object.defineProperty(exports,"CANONICAL_METAL_PRESETS",{enumerable:!0,get:()=>l.CANONICAL_METAL_PRESETS});Object.defineProperty(exports,"CANONICAL_STONE_PRESETS",{enumerable:!0,get:()=>l.CANONICAL_STONE_PRESETS});Object.defineProperty(exports,"DIAMOND_PRESETS",{enumerable:!0,get:()=>l.DIAMOND_PRESETS});Object.defineProperty(exports,"GEMSTONE_PRESETS",{enumerable:!0,get:()=>l.GEMSTONE_PRESETS});Object.defineProperty(exports,"METAL_PRESETS",{enumerable:!0,get:()=>l.METAL_PRESETS});Object.defineProperty(exports,"PHYSICALLY_BASED_METAL_PRESETS",{enumerable:!0,get:()=>l.PHYSICALLY_BASED_METAL_PRESETS});Object.defineProperty(exports,"STONE_PRESETS",{enumerable:!0,get:()=>l.STONE_PRESETS});Object.defineProperty(exports,"getMetalPreset",{enumerable:!0,get:()=>l.getMetalPreset});Object.defineProperty(exports,"getStonePreset",{enumerable:!0,get:()=>l.getStonePreset});Object.defineProperty(exports,"inferFormatFromUrl",{enumerable:!0,get:()=>l.inferFormatFromUrl});Object.defineProperty(exports,"normalizeModelSource",{enumerable:!0,get:()=>l.normalizeModelSource});exports.JewelryCustomizer=q;exports.MetalSelect=F;exports.MetalSwatches=D;exports.StoneSelect=G;exports.StoneSwatches=H;exports.Viewer=k;exports.default=k;exports.useJewelryCustomizer=J;
|
|
2
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs","sources":["../src/Viewer.tsx","../src/swatches/MetalSwatches.tsx","../src/swatches/StoneSwatches.tsx","../src/swatches/JewelryCustomizer.tsx","../src/swatches/useJewelryCustomizer.ts"],"sourcesContent":["/// <reference types=\"vite/client\" />\nimport { useRef, useEffect, forwardRef, useImperativeHandle, type CSSProperties } from 'react'\nimport {\n createViewer,\n normalizeModelSource,\n type Viewer as CoreViewer,\n type ModelSource,\n type ViewerSourceInput,\n type MetalColorProp,\n type StoneColorProp,\n type ViewerOptions,\n type ViewerState,\n type PartInfo,\n type MaterialSlotInfo,\n type PartType,\n} from '@thinkersteps_labs/3d-viewer-core'\n\nexport interface ViewerRef extends CoreViewer { }\n\nexport interface ViewerProps {\n /** 3D model URL or source object. Takes precedence over `source` if both provided. */\n src?: string\n /** 3D model source (URL string, ModelSource payload, or null). */\n source?: ViewerSourceInput\n /** Metal preset ID or hex code. IDE autocompletes standard presets. */\n metalColor?: MetalColorProp\n /** Stone preset ID or hex code. IDE autocompletes standard presets. */\n stoneColor?: StoneColorProp\n /** Bulk material name or slot ID color overrides. */\n materialColors?: Record<string, string>\n /** Part color overrides keyed by partId or partId:slotIndex. */\n partColors?: Record<string, string>\n background?: string | number\n metalEnvUrl?: string | ArrayBuffer\n gemEnvUrl?: string | ArrayBuffer\n options?: ViewerOptions\n fov?: number\n shadows?: boolean\n autoRotate?: boolean\n quality?: 'low' | 'medium' | 'high'\n /** Explicit container height (e.g. 520 or '520px'). Prevents zero-height collapse. */\n height?: number | string\n /** Explicit container min-height. */\n minHeight?: number | string\n /** Aspect ratio for responsive sizing (e.g. '16/9' or '4/3'). */\n aspectRatio?: string\n onLoaded?: (parts: PartInfo[], materials?: MaterialSlotInfo[]) => void\n onPartSelected?: (info: {\n meshId: string\n partId?: string\n type: PartType\n slotIndex?: number\n slotId?: string\n materialName?: string\n }) => void\n onChange?: (state: ViewerState) => void\n onError?: (err: Error) => void\n onProgress?: (progress: number) => void\n className?: string\n style?: CSSProperties\n}\n\nexport const Viewer = forwardRef<ViewerRef, ViewerProps>(function Viewer(props, ref) {\n const {\n src,\n source,\n metalColor,\n stoneColor,\n materialColors,\n partColors,\n background,\n metalEnvUrl,\n gemEnvUrl,\n options,\n fov,\n shadows,\n autoRotate,\n quality,\n height,\n minHeight,\n aspectRatio,\n className,\n style,\n } = props\n const containerRef = useRef<HTMLDivElement>(null)\n const viewerRef = useRef<ViewerRef | null>(null)\n const cb = useRef(props)\n cb.current = props\n\n useImperativeHandle(ref, () => viewerRef.current!, [])\n\n useEffect(() => {\n if (!containerRef.current) return\n const viewer = createViewer(containerRef.current, {\n ...options,\n ...(background !== undefined && { background }),\n ...(fov !== undefined && { fov }),\n ...(shadows !== undefined && { shadows }),\n ...(autoRotate !== undefined && { autoRotate }),\n ...(quality !== undefined && { quality }),\n ...(metalEnvUrl !== undefined && { metalEnvUrl }),\n ...(gemEnvUrl !== undefined && { gemEnvUrl }),\n })\n viewerRef.current = viewer\n if (import.meta.env.DEV && typeof window !== 'undefined') (window as any).__viewer = viewer\n if (ref) {\n if (typeof ref === 'function') ref(viewer)\n else (ref as any).current = viewer\n }\n viewer.on('loaded', ({ parts, materials }) => cb.current.onLoaded?.(parts, materials))\n viewer.on('partSelected', (info) => cb.current.onPartSelected?.(info))\n viewer.on('change', (state) => cb.current.onChange?.(state))\n viewer.on('error', (err) => cb.current.onError?.(err))\n viewer.on('loading', ({ progress }) => cb.current.onProgress?.(progress))\n return () => {\n viewer.dispose()\n if (ref) {\n if (typeof ref === 'function') ref(null)\n else (ref as any).current = null\n }\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [])\n\n useEffect(() => {\n if (!viewerRef.current) return\n const resolved = normalizeModelSource(src ?? source)\n if (!resolved) {\n viewerRef.current.unload()\n return\n }\n const ac = new AbortController()\n viewerRef.current.load(resolved, { signal: ac.signal })\n return () => ac.abort()\n }, [src, source])\n\n useEffect(() => {\n if (metalColor) viewerRef.current?.setMetalColor(metalColor)\n }, [metalColor])\n\n useEffect(() => {\n if (stoneColor) viewerRef.current?.setStoneColor(stoneColor)\n }, [stoneColor])\n\n const prevMaterialColorsRef = useRef<Record<string, string>>({})\n useEffect(() => {\n if (!viewerRef.current) return\n const prev = prevMaterialColorsRef.current\n const next = materialColors ?? {}\n\n for (const key of Object.keys(prev)) {\n if (!(key in next)) {\n viewerRef.current.clearMaterialColor(key)\n }\n }\n for (const [key, color] of Object.entries(next)) {\n if (prev[key] !== color) {\n viewerRef.current.setMaterialColor(key, color)\n }\n }\n prevMaterialColorsRef.current = { ...next }\n }, [materialColors])\n\n const prevPartColorsRef = useRef<Record<string, string>>({})\n useEffect(() => {\n if (!viewerRef.current) return\n const prev = prevPartColorsRef.current\n const next = partColors ?? {}\n\n for (const key of Object.keys(prev)) {\n if (!(key in next)) {\n if (key.includes(':')) {\n const [partId, slotIdxStr] = key.split(':')\n const slotIndex = parseInt(slotIdxStr ?? '', 10)\n viewerRef.current.clearPartColor(partId ?? '', isNaN(slotIndex) ? undefined : slotIndex)\n } else {\n viewerRef.current.clearPartColor(key)\n }\n }\n }\n for (const [key, color] of Object.entries(next)) {\n if (prev[key] !== color) {\n if (key.includes(':')) {\n const [partId, slotIdxStr] = key.split(':')\n const slotIndex = parseInt(slotIdxStr ?? '', 10)\n viewerRef.current.setPartColor(partId ?? '', color, isNaN(slotIndex) ? undefined : slotIndex)\n } else {\n viewerRef.current.setPartColor(key, color)\n }\n }\n }\n prevPartColorsRef.current = { ...next }\n }, [partColors])\n\n useEffect(() => {\n if (!viewerRef.current) return\n if (autoRotate) viewerRef.current.startRotation()\n else viewerRef.current.stopRotation()\n }, [autoRotate])\n\n useEffect(() => {\n if (quality) viewerRef.current?.setQuality(quality)\n }, [quality])\n\n const containerStyle: CSSProperties = {\n width: '100%',\n height: height !== undefined ? (typeof height === 'number' ? `${height}px` : height) : '100%',\n minHeight: minHeight !== undefined ? (typeof minHeight === 'number' ? `${minHeight}px` : minHeight) : undefined,\n aspectRatio,\n position: 'relative',\n ...style,\n }\n\n return (\n <div\n ref={containerRef}\n className={className}\n style={containerStyle}\n />\n )\n})\n\nexport default Viewer\n","import React, { type CSSProperties } from 'react'\nimport {\n CANONICAL_METAL_PRESETS,\n getMetalPreset,\n type MetalPreset,\n type MetalColorProp,\n} from '@thinkersteps_labs/3d-viewer-core'\nimport './swatches.css'\n\nexport interface MetalSwatchesProps {\n value?: MetalColorProp\n onChange?: (metalId: string, preset?: MetalPreset) => void\n options?: MetalPreset[]\n category?: 'all' | 'gold' | 'platinum-silver' | 'alternative'\n variant?: 'pills' | 'dots'\n showLabel?: boolean\n className?: string\n style?: CSSProperties\n}\n\nexport function MetalSwatches({\n value,\n onChange,\n options = CANONICAL_METAL_PRESETS,\n category = 'all',\n variant = 'pills',\n showLabel = true,\n className = '',\n style,\n}: MetalSwatchesProps) {\n const filteredOptions = category === 'all'\n ? options\n : options.filter((m) => m.category === category)\n\n const activePreset = value ? getMetalPreset(value) : undefined\n const activeId = activePreset?.id ?? value\n\n return (\n <div className={`td-swatch-group ${className}`} style={style}>\n {showLabel && (\n <div className=\"td-swatch-header\">\n <span className=\"td-swatch-title\">Metal</span>\n {activePreset && (\n <span className=\"td-swatch-selected-name\">{activePreset.label}</span>\n )}\n </div>\n )}\n <div className=\"td-swatch-row\" role=\"radiogroup\" aria-label=\"Metal Selection\">\n {filteredOptions.map((m) => {\n const isSelected = activeId === m.id || value === m.hex\n return (\n <button\n key={m.id}\n type=\"button\"\n role=\"radio\"\n aria-checked={isSelected}\n title={m.label}\n className={`td-swatch-${variant === 'dots' ? 'dot' : 'pill'} ${isSelected ? 'active' : ''}`}\n onClick={() => onChange?.(m.id, m)}\n >\n <span\n className=\"td-swatch-color-circle\"\n style={{ backgroundColor: m.hex }}\n />\n {variant === 'pills' && <span>{m.label}</span>}\n </button>\n )\n })}\n </div>\n </div>\n )\n}\n\nexport interface MetalSelectProps {\n value?: MetalColorProp\n onChange?: (metalId: string, preset?: MetalPreset) => void\n options?: MetalPreset[]\n label?: string\n className?: string\n style?: CSSProperties\n}\n\nexport function MetalSelect({\n value,\n onChange,\n options = CANONICAL_METAL_PRESETS,\n label = 'Select Metal',\n className = '',\n style,\n}: MetalSelectProps) {\n const activePreset = value ? getMetalPreset(value) : undefined\n const activeValue = activePreset?.id ?? value ?? options[0]?.id\n\n return (\n <div className={`td-select-wrapper ${className}`} style={style}>\n {label && <label className=\"td-swatch-title\">{label}</label>}\n <select\n className=\"td-select\"\n value={activeValue}\n onChange={(e) => {\n const val = e.target.value\n const preset = getMetalPreset(val)\n onChange?.(val, preset)\n }}\n >\n {options.map((m) => (\n <option key={m.id} value={m.id}>\n {m.label}\n </option>\n ))}\n </select>\n </div>\n )\n}\n","import React, { type CSSProperties } from 'react'\nimport {\n CANONICAL_STONE_PRESETS,\n getStonePreset,\n type StonePreset,\n type StoneColorProp,\n} from '@thinkersteps_labs/3d-viewer-core'\nimport './swatches.css'\n\nexport interface StoneSwatchesProps {\n value?: StoneColorProp\n onChange?: (stoneId: string, preset?: StonePreset) => void\n options?: StonePreset[]\n category?: 'all' | 'diamond' | 'gemstone'\n variant?: 'pills' | 'dots'\n showLabel?: boolean\n className?: string\n style?: CSSProperties\n}\n\nexport function StoneSwatches({\n value,\n onChange,\n options = CANONICAL_STONE_PRESETS,\n category = 'all',\n variant = 'pills',\n showLabel = true,\n className = '',\n style,\n}: StoneSwatchesProps) {\n const filteredOptions = category === 'all'\n ? options\n : options.filter((s) => s.category === category)\n\n const activePreset = value ? getStonePreset(value) : undefined\n const activeId = activePreset?.id ?? value\n\n return (\n <div className={`td-swatch-group ${className}`} style={style}>\n {showLabel && (\n <div className=\"td-swatch-header\">\n <span className=\"td-swatch-title\">Gemstone</span>\n {activePreset && (\n <span className=\"td-swatch-selected-name\">\n {activePreset.label}\n {activePreset.grade ? ` (${activePreset.grade})` : ''}\n </span>\n )}\n </div>\n )}\n <div className=\"td-swatch-row\" role=\"radiogroup\" aria-label=\"Gemstone Selection\">\n {filteredOptions.map((s) => {\n const isSelected = activeId === s.id || value === s.hex\n return (\n <button\n key={s.id}\n type=\"button\"\n role=\"radio\"\n aria-checked={isSelected}\n title={`${s.label}${s.grade ? ` - ${s.grade}` : ''}`}\n className={`td-swatch-${variant === 'dots' ? 'dot' : 'pill'} ${isSelected ? 'active' : ''}`}\n onClick={() => onChange?.(s.id, s)}\n >\n <span\n className=\"td-swatch-color-circle\"\n style={{ backgroundColor: s.hex }}\n />\n {variant === 'pills' && <span>{s.label}</span>}\n </button>\n )\n })}\n </div>\n </div>\n )\n}\n\nexport interface StoneSelectProps {\n value?: StoneColorProp\n onChange?: (stoneId: string, preset?: StonePreset) => void\n options?: StonePreset[]\n label?: string\n className?: string\n style?: CSSProperties\n}\n\nexport function StoneSelect({\n value,\n onChange,\n options = CANONICAL_STONE_PRESETS,\n label = 'Select Gemstone',\n className = '',\n style,\n}: StoneSelectProps) {\n const activePreset = value ? getStonePreset(value) : undefined\n const activeValue = activePreset?.id ?? value ?? options[0]?.id\n\n return (\n <div className={`td-select-wrapper ${className}`} style={style}>\n {label && <label className=\"td-swatch-title\">{label}</label>}\n <select\n className=\"td-select\"\n value={activeValue}\n onChange={(e) => {\n const val = e.target.value\n const preset = getStonePreset(val)\n onChange?.(val, preset)\n }}\n >\n {options.map((s) => (\n <option key={s.id} value={s.id}>\n {s.label} {s.grade ? `(${s.grade})` : ''}\n </option>\n ))}\n </select>\n </div>\n )\n}\n","import React, { useState, type CSSProperties } from 'react'\nimport {\n type MetalColorProp,\n type StoneColorProp,\n type ViewerSourceInput,\n type MetalPreset,\n type StonePreset,\n type PartInfo,\n type PartType,\n} from '@thinkersteps_labs/3d-viewer-core'\nimport { Viewer, type ViewerRef } from '../Viewer'\nimport { MetalSwatches, MetalSelect } from './MetalSwatches'\nimport { StoneSwatches, StoneSelect } from './StoneSwatches'\nimport './swatches.css'\n\nexport interface JewelryCustomizerProps {\n src?: string\n source?: ViewerSourceInput\n defaultMetal?: MetalColorProp\n defaultStone?: StoneColorProp\n metal?: MetalColorProp\n onMetalChange?: (metal: string, preset?: MetalPreset) => void\n stone?: StoneColorProp\n onStoneChange?: (stone: string, preset?: StonePreset) => void\n metalOptions?: MetalPreset[]\n stoneOptions?: StonePreset[]\n controlsVariant?: 'pills' | 'dots' | 'select' | 'none'\n height?: number | string\n autoRotate?: boolean\n quality?: 'low' | 'medium' | 'high'\n fov?: number\n shadows?: boolean\n onLoaded?: (parts: PartInfo[]) => void\n onPartSelected?: (info: { meshId: string; type: PartType }) => void\n className?: string\n style?: CSSProperties\n viewerRef?: React.Ref<ViewerRef>\n}\n\nexport function JewelryCustomizer({\n src,\n source,\n defaultMetal = 'yellow-gold-18k',\n defaultStone = 'diamond-d',\n metal: controlledMetal,\n onMetalChange,\n stone: controlledStone,\n onStoneChange,\n metalOptions,\n stoneOptions,\n controlsVariant = 'pills',\n height = 520,\n autoRotate = true,\n quality = 'high',\n fov,\n shadows,\n onLoaded,\n onPartSelected,\n className = '',\n style,\n viewerRef,\n}: JewelryCustomizerProps) {\n const [internalMetal, setInternalMetal] = useState<MetalColorProp>(defaultMetal)\n const [internalStone, setInternalStone] = useState<StoneColorProp>(defaultStone)\n\n const currentMetal = controlledMetal !== undefined ? controlledMetal : internalMetal\n const currentStone = controlledStone !== undefined ? controlledStone : internalStone\n\n const handleMetalChange = (val: string, preset?: MetalPreset) => {\n if (controlledMetal === undefined) setInternalMetal(val)\n onMetalChange?.(val, preset)\n }\n\n const handleStoneChange = (val: string, preset?: StonePreset) => {\n if (controlledStone === undefined) setInternalStone(val)\n onStoneChange?.(val, preset)\n }\n\n const viewportHeight = typeof height === 'number' ? `${height}px` : height\n\n return (\n <div className={`td-customizer-card ${className}`} style={style}>\n <div className=\"td-customizer-viewport\" style={{ height: viewportHeight }}>\n <Viewer\n ref={viewerRef}\n src={src}\n source={source}\n metalColor={currentMetal}\n stoneColor={currentStone}\n autoRotate={autoRotate}\n quality={quality}\n fov={fov}\n shadows={shadows}\n onLoaded={onLoaded}\n onPartSelected={onPartSelected}\n />\n </div>\n\n {controlsVariant !== 'none' && (\n <div className=\"td-customizer-controls\">\n {controlsVariant === 'select' ? (\n <>\n <MetalSelect\n value={currentMetal}\n onChange={handleMetalChange}\n options={metalOptions}\n />\n <StoneSelect\n value={currentStone}\n onChange={handleStoneChange}\n options={stoneOptions}\n />\n </>\n ) : (\n <>\n <MetalSwatches\n value={currentMetal}\n onChange={handleMetalChange}\n options={metalOptions}\n variant={controlsVariant}\n />\n <StoneSwatches\n value={currentStone}\n onChange={handleStoneChange}\n options={stoneOptions}\n variant={controlsVariant}\n />\n </>\n )}\n </div>\n )}\n </div>\n )\n}\n","import { useState, useMemo } from 'react'\nimport {\n CANONICAL_METAL_PRESETS,\n CANONICAL_STONE_PRESETS,\n getMetalPreset,\n getStonePreset,\n type MetalColorProp,\n type StoneColorProp,\n type MetalPreset,\n type StonePreset,\n} from '@thinkersteps_labs/3d-viewer-core'\n\nexport interface UseJewelryCustomizerOptions {\n defaultMetal?: MetalColorProp\n defaultStone?: StoneColorProp\n metalOptions?: MetalPreset[]\n stoneOptions?: StonePreset[]\n}\n\nexport interface UseJewelryCustomizerReturn {\n metal: MetalColorProp\n setMetal: (val: MetalColorProp) => void\n stone: StoneColorProp\n setStone: (val: StoneColorProp) => void\n metalPreset?: MetalPreset\n stonePreset?: StonePreset\n metalOptions: MetalPreset[]\n stoneOptions: StonePreset[]\n viewerProps: {\n metalColor: MetalColorProp\n stoneColor: StoneColorProp\n }\n}\n\nexport function useJewelryCustomizer(\n options: UseJewelryCustomizerOptions = {}\n): UseJewelryCustomizerReturn {\n const {\n defaultMetal = 'yellow-gold-18k',\n defaultStone = 'diamond-d',\n metalOptions = CANONICAL_METAL_PRESETS,\n stoneOptions = CANONICAL_STONE_PRESETS,\n } = options\n\n const [metal, setMetal] = useState<MetalColorProp>(defaultMetal)\n const [stone, setStone] = useState<StoneColorProp>(defaultStone)\n\n const metalPreset = useMemo(() => getMetalPreset(metal), [metal])\n const stonePreset = useMemo(() => getStonePreset(stone), [stone])\n\n const viewerProps = useMemo(\n () => ({\n metalColor: metal,\n stoneColor: stone,\n }),\n [metal, stone]\n )\n\n return {\n metal,\n setMetal,\n stone,\n setStone,\n metalPreset,\n stonePreset,\n metalOptions,\n stoneOptions,\n viewerProps,\n }\n}\n"],"names":["Viewer","forwardRef","props","ref","src","source","metalColor","stoneColor","materialColors","partColors","background","metalEnvUrl","gemEnvUrl","options","fov","shadows","autoRotate","quality","height","minHeight","aspectRatio","className","style","containerRef","useRef","viewerRef","cb","useImperativeHandle","useEffect","viewer","createViewer","parts","materials","_b","_a","info","state","err","progress","resolved","normalizeModelSource","ac","prevMaterialColorsRef","prev","next","key","color","prevPartColorsRef","partId","slotIdxStr","slotIndex","containerStyle","jsx","MetalSwatches","value","onChange","CANONICAL_METAL_PRESETS","category","variant","showLabel","filteredOptions","m","activePreset","getMetalPreset","activeId","jsxs","isSelected","MetalSelect","label","activeValue","e","val","preset","StoneSwatches","CANONICAL_STONE_PRESETS","s","getStonePreset","StoneSelect","JewelryCustomizer","defaultMetal","defaultStone","controlledMetal","onMetalChange","controlledStone","onStoneChange","metalOptions","stoneOptions","controlsVariant","onLoaded","onPartSelected","internalMetal","setInternalMetal","useState","internalStone","setInternalStone","currentMetal","currentStone","handleMetalChange","handleStoneChange","viewportHeight","Fragment","useJewelryCustomizer","metal","setMetal","stone","setStone","metalPreset","useMemo","stonePreset","viewerProps"],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
import { ALL_METAL_PRESETS } from '@thinkersteps_labs/3d-viewer-core';
|
|
2
|
+
import { ALL_STONE_PRESETS } from '@thinkersteps_labs/3d-viewer-core';
|
|
3
|
+
import { CANONICAL_METAL_PRESETS } from '@thinkersteps_labs/3d-viewer-core';
|
|
4
|
+
import { CANONICAL_STONE_PRESETS } from '@thinkersteps_labs/3d-viewer-core';
|
|
5
|
+
import { Viewer as CoreViewer } from '@thinkersteps_labs/3d-viewer-core';
|
|
6
|
+
import { CSSProperties } from 'react';
|
|
7
|
+
import { default as default_2 } from 'react';
|
|
8
|
+
import { DIAMOND_PRESETS } from '@thinkersteps_labs/3d-viewer-core';
|
|
9
|
+
import { DiamondQuality } from '@thinkersteps_labs/3d-viewer-core';
|
|
10
|
+
import { ForwardRefExoticComponent } from 'react';
|
|
11
|
+
import { GEMSTONE_PRESETS } from '@thinkersteps_labs/3d-viewer-core';
|
|
12
|
+
import { getMetalPreset } from '@thinkersteps_labs/3d-viewer-core';
|
|
13
|
+
import { getStonePreset } from '@thinkersteps_labs/3d-viewer-core';
|
|
14
|
+
import { inferFormatFromUrl } from '@thinkersteps_labs/3d-viewer-core';
|
|
15
|
+
import { MaterialSlotInfo } from '@thinkersteps_labs/3d-viewer-core';
|
|
16
|
+
import { MeshMaterialSlot } from '@thinkersteps_labs/3d-viewer-core';
|
|
17
|
+
import { METAL_PRESETS } from '@thinkersteps_labs/3d-viewer-core';
|
|
18
|
+
import { MetalColorProp } from '@thinkersteps_labs/3d-viewer-core';
|
|
19
|
+
import { MetalPreset } from '@thinkersteps_labs/3d-viewer-core';
|
|
20
|
+
import { ModelSource } from '@thinkersteps_labs/3d-viewer-core';
|
|
21
|
+
import { normalizeModelSource } from '@thinkersteps_labs/3d-viewer-core';
|
|
22
|
+
import { PartInfo } from '@thinkersteps_labs/3d-viewer-core';
|
|
23
|
+
import { PartType } from '@thinkersteps_labs/3d-viewer-core';
|
|
24
|
+
import { PHYSICALLY_BASED_METAL_PRESETS } from '@thinkersteps_labs/3d-viewer-core';
|
|
25
|
+
import { RefAttributes } from 'react';
|
|
26
|
+
import { StandardMetalId } from '@thinkersteps_labs/3d-viewer-core';
|
|
27
|
+
import { StandardStoneId } from '@thinkersteps_labs/3d-viewer-core';
|
|
28
|
+
import { StateRestoreResult } from '@thinkersteps_labs/3d-viewer-core';
|
|
29
|
+
import { STONE_PRESETS } from '@thinkersteps_labs/3d-viewer-core';
|
|
30
|
+
import { StoneColorProp } from '@thinkersteps_labs/3d-viewer-core';
|
|
31
|
+
import { StonePreset } from '@thinkersteps_labs/3d-viewer-core';
|
|
32
|
+
import { ViewerOptions } from '@thinkersteps_labs/3d-viewer-core';
|
|
33
|
+
import { ViewerSourceInput } from '@thinkersteps_labs/3d-viewer-core';
|
|
34
|
+
import { ViewerState } from '@thinkersteps_labs/3d-viewer-core';
|
|
35
|
+
|
|
36
|
+
export { ALL_METAL_PRESETS }
|
|
37
|
+
|
|
38
|
+
export { ALL_STONE_PRESETS }
|
|
39
|
+
|
|
40
|
+
export { CANONICAL_METAL_PRESETS }
|
|
41
|
+
|
|
42
|
+
export { CANONICAL_STONE_PRESETS }
|
|
43
|
+
|
|
44
|
+
export { CoreViewer }
|
|
45
|
+
|
|
46
|
+
export { DIAMOND_PRESETS }
|
|
47
|
+
|
|
48
|
+
export { DiamondQuality }
|
|
49
|
+
|
|
50
|
+
export { GEMSTONE_PRESETS }
|
|
51
|
+
|
|
52
|
+
export { getMetalPreset }
|
|
53
|
+
|
|
54
|
+
export { getStonePreset }
|
|
55
|
+
|
|
56
|
+
export { inferFormatFromUrl }
|
|
57
|
+
|
|
58
|
+
export declare function JewelryCustomizer({ src, source, defaultMetal, defaultStone, metal: controlledMetal, onMetalChange, stone: controlledStone, onStoneChange, metalOptions, stoneOptions, controlsVariant, height, autoRotate, quality, fov, shadows, onLoaded, onPartSelected, className, style, viewerRef, }: JewelryCustomizerProps): default_2.JSX.Element;
|
|
59
|
+
|
|
60
|
+
export declare interface JewelryCustomizerProps {
|
|
61
|
+
src?: string;
|
|
62
|
+
source?: ViewerSourceInput;
|
|
63
|
+
defaultMetal?: MetalColorProp;
|
|
64
|
+
defaultStone?: StoneColorProp;
|
|
65
|
+
metal?: MetalColorProp;
|
|
66
|
+
onMetalChange?: (metal: string, preset?: MetalPreset) => void;
|
|
67
|
+
stone?: StoneColorProp;
|
|
68
|
+
onStoneChange?: (stone: string, preset?: StonePreset) => void;
|
|
69
|
+
metalOptions?: MetalPreset[];
|
|
70
|
+
stoneOptions?: StonePreset[];
|
|
71
|
+
controlsVariant?: 'pills' | 'dots' | 'select' | 'none';
|
|
72
|
+
height?: number | string;
|
|
73
|
+
autoRotate?: boolean;
|
|
74
|
+
quality?: 'low' | 'medium' | 'high';
|
|
75
|
+
fov?: number;
|
|
76
|
+
shadows?: boolean;
|
|
77
|
+
onLoaded?: (parts: PartInfo[]) => void;
|
|
78
|
+
onPartSelected?: (info: {
|
|
79
|
+
meshId: string;
|
|
80
|
+
type: PartType;
|
|
81
|
+
}) => void;
|
|
82
|
+
className?: string;
|
|
83
|
+
style?: CSSProperties;
|
|
84
|
+
viewerRef?: default_2.Ref<ViewerRef>;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export { MaterialSlotInfo }
|
|
88
|
+
|
|
89
|
+
export { MeshMaterialSlot }
|
|
90
|
+
|
|
91
|
+
export { METAL_PRESETS }
|
|
92
|
+
|
|
93
|
+
export { MetalColorProp }
|
|
94
|
+
|
|
95
|
+
export { MetalPreset }
|
|
96
|
+
|
|
97
|
+
export declare function MetalSelect({ value, onChange, options, label, className, style, }: MetalSelectProps): default_2.JSX.Element;
|
|
98
|
+
|
|
99
|
+
export declare interface MetalSelectProps {
|
|
100
|
+
value?: MetalColorProp;
|
|
101
|
+
onChange?: (metalId: string, preset?: MetalPreset) => void;
|
|
102
|
+
options?: MetalPreset[];
|
|
103
|
+
label?: string;
|
|
104
|
+
className?: string;
|
|
105
|
+
style?: CSSProperties;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export declare function MetalSwatches({ value, onChange, options, category, variant, showLabel, className, style, }: MetalSwatchesProps): default_2.JSX.Element;
|
|
109
|
+
|
|
110
|
+
export declare interface MetalSwatchesProps {
|
|
111
|
+
value?: MetalColorProp;
|
|
112
|
+
onChange?: (metalId: string, preset?: MetalPreset) => void;
|
|
113
|
+
options?: MetalPreset[];
|
|
114
|
+
category?: 'all' | 'gold' | 'platinum-silver' | 'alternative';
|
|
115
|
+
variant?: 'pills' | 'dots';
|
|
116
|
+
showLabel?: boolean;
|
|
117
|
+
className?: string;
|
|
118
|
+
style?: CSSProperties;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export { ModelSource }
|
|
122
|
+
|
|
123
|
+
export { normalizeModelSource }
|
|
124
|
+
|
|
125
|
+
export { PartInfo }
|
|
126
|
+
|
|
127
|
+
export { PartType }
|
|
128
|
+
|
|
129
|
+
export { PHYSICALLY_BASED_METAL_PRESETS }
|
|
130
|
+
|
|
131
|
+
export { StandardMetalId }
|
|
132
|
+
|
|
133
|
+
export { StandardStoneId }
|
|
134
|
+
|
|
135
|
+
export { StateRestoreResult }
|
|
136
|
+
|
|
137
|
+
export { STONE_PRESETS }
|
|
138
|
+
|
|
139
|
+
export { StoneColorProp }
|
|
140
|
+
|
|
141
|
+
export { StonePreset }
|
|
142
|
+
|
|
143
|
+
export declare function StoneSelect({ value, onChange, options, label, className, style, }: StoneSelectProps): default_2.JSX.Element;
|
|
144
|
+
|
|
145
|
+
export declare interface StoneSelectProps {
|
|
146
|
+
value?: StoneColorProp;
|
|
147
|
+
onChange?: (stoneId: string, preset?: StonePreset) => void;
|
|
148
|
+
options?: StonePreset[];
|
|
149
|
+
label?: string;
|
|
150
|
+
className?: string;
|
|
151
|
+
style?: CSSProperties;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export declare function StoneSwatches({ value, onChange, options, category, variant, showLabel, className, style, }: StoneSwatchesProps): default_2.JSX.Element;
|
|
155
|
+
|
|
156
|
+
export declare interface StoneSwatchesProps {
|
|
157
|
+
value?: StoneColorProp;
|
|
158
|
+
onChange?: (stoneId: string, preset?: StonePreset) => void;
|
|
159
|
+
options?: StonePreset[];
|
|
160
|
+
category?: 'all' | 'diamond' | 'gemstone';
|
|
161
|
+
variant?: 'pills' | 'dots';
|
|
162
|
+
showLabel?: boolean;
|
|
163
|
+
className?: string;
|
|
164
|
+
style?: CSSProperties;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
export declare function useJewelryCustomizer(options?: UseJewelryCustomizerOptions): UseJewelryCustomizerReturn;
|
|
168
|
+
|
|
169
|
+
export declare interface UseJewelryCustomizerOptions {
|
|
170
|
+
defaultMetal?: MetalColorProp;
|
|
171
|
+
defaultStone?: StoneColorProp;
|
|
172
|
+
metalOptions?: MetalPreset[];
|
|
173
|
+
stoneOptions?: StonePreset[];
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
export declare interface UseJewelryCustomizerReturn {
|
|
177
|
+
metal: MetalColorProp;
|
|
178
|
+
setMetal: (val: MetalColorProp) => void;
|
|
179
|
+
stone: StoneColorProp;
|
|
180
|
+
setStone: (val: StoneColorProp) => void;
|
|
181
|
+
metalPreset?: MetalPreset;
|
|
182
|
+
stonePreset?: StonePreset;
|
|
183
|
+
metalOptions: MetalPreset[];
|
|
184
|
+
stoneOptions: StonePreset[];
|
|
185
|
+
viewerProps: {
|
|
186
|
+
metalColor: MetalColorProp;
|
|
187
|
+
stoneColor: StoneColorProp;
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
declare const Viewer: ForwardRefExoticComponent<ViewerProps & RefAttributes<ViewerRef>>;
|
|
192
|
+
export { Viewer }
|
|
193
|
+
export default Viewer;
|
|
194
|
+
|
|
195
|
+
export { ViewerOptions }
|
|
196
|
+
|
|
197
|
+
export declare interface ViewerProps {
|
|
198
|
+
/** 3D model URL or source object. Takes precedence over `source` if both provided. */
|
|
199
|
+
src?: string;
|
|
200
|
+
/** 3D model source (URL string, ModelSource payload, or null). */
|
|
201
|
+
source?: ViewerSourceInput;
|
|
202
|
+
/** Metal preset ID or hex code. IDE autocompletes standard presets. */
|
|
203
|
+
metalColor?: MetalColorProp;
|
|
204
|
+
/** Stone preset ID or hex code. IDE autocompletes standard presets. */
|
|
205
|
+
stoneColor?: StoneColorProp;
|
|
206
|
+
/** Bulk material name or slot ID color overrides. */
|
|
207
|
+
materialColors?: Record<string, string>;
|
|
208
|
+
/** Part color overrides keyed by partId or partId:slotIndex. */
|
|
209
|
+
partColors?: Record<string, string>;
|
|
210
|
+
background?: string | number;
|
|
211
|
+
metalEnvUrl?: string | ArrayBuffer;
|
|
212
|
+
gemEnvUrl?: string | ArrayBuffer;
|
|
213
|
+
options?: ViewerOptions;
|
|
214
|
+
fov?: number;
|
|
215
|
+
shadows?: boolean;
|
|
216
|
+
autoRotate?: boolean;
|
|
217
|
+
quality?: 'low' | 'medium' | 'high';
|
|
218
|
+
/** Explicit container height (e.g. 520 or '520px'). Prevents zero-height collapse. */
|
|
219
|
+
height?: number | string;
|
|
220
|
+
/** Explicit container min-height. */
|
|
221
|
+
minHeight?: number | string;
|
|
222
|
+
/** Aspect ratio for responsive sizing (e.g. '16/9' or '4/3'). */
|
|
223
|
+
aspectRatio?: string;
|
|
224
|
+
onLoaded?: (parts: PartInfo[], materials?: MaterialSlotInfo[]) => void;
|
|
225
|
+
onPartSelected?: (info: {
|
|
226
|
+
meshId: string;
|
|
227
|
+
partId?: string;
|
|
228
|
+
type: PartType;
|
|
229
|
+
slotIndex?: number;
|
|
230
|
+
slotId?: string;
|
|
231
|
+
materialName?: string;
|
|
232
|
+
}) => void;
|
|
233
|
+
onChange?: (state: ViewerState) => void;
|
|
234
|
+
onError?: (err: Error) => void;
|
|
235
|
+
onProgress?: (progress: number) => void;
|
|
236
|
+
className?: string;
|
|
237
|
+
style?: CSSProperties;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
export declare interface ViewerRef extends CoreViewer {
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
export { ViewerSourceInput }
|
|
244
|
+
|
|
245
|
+
export { ViewerState }
|
|
246
|
+
|
|
247
|
+
export { }
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,402 @@
|
|
|
1
|
+
import { jsx as a, jsxs as N, Fragment as V } from "react/jsx-runtime";
|
|
2
|
+
import { forwardRef as Y, useRef as _, useImperativeHandle as q, useEffect as b, useState as O, useMemo as D } from "react";
|
|
3
|
+
import { createViewer as B, normalizeModelSource as Q, getMetalPreset as k, CANONICAL_METAL_PRESETS as F, getStonePreset as z, CANONICAL_STONE_PRESETS as U } from "@thinkersteps_labs/3d-viewer-core";
|
|
4
|
+
import { ALL_METAL_PRESETS as ie, ALL_STONE_PRESETS as ae, CANONICAL_METAL_PRESETS as de, CANONICAL_STONE_PRESETS as ue, DIAMOND_PRESETS as pe, GEMSTONE_PRESETS as fe, METAL_PRESETS as me, PHYSICALLY_BASED_METAL_PRESETS as Se, STONE_PRESETS as he, getMetalPreset as ve, getStonePreset as Ne, inferFormatFromUrl as we, normalizeModelSource as Ee } from "@thinkersteps_labs/3d-viewer-core";
|
|
5
|
+
const K = Y(function(s, c) {
|
|
6
|
+
const {
|
|
7
|
+
src: S,
|
|
8
|
+
source: h,
|
|
9
|
+
metalColor: d,
|
|
10
|
+
stoneColor: u,
|
|
11
|
+
materialColors: f,
|
|
12
|
+
partColors: v,
|
|
13
|
+
background: t,
|
|
14
|
+
metalEnvUrl: m,
|
|
15
|
+
gemEnvUrl: e,
|
|
16
|
+
options: w,
|
|
17
|
+
fov: g,
|
|
18
|
+
shadows: x,
|
|
19
|
+
autoRotate: P,
|
|
20
|
+
quality: y,
|
|
21
|
+
height: M,
|
|
22
|
+
minHeight: R,
|
|
23
|
+
aspectRatio: j,
|
|
24
|
+
className: H,
|
|
25
|
+
style: G
|
|
26
|
+
} = s, I = _(null), p = _(null), E = _(s);
|
|
27
|
+
E.current = s, q(c, () => p.current, []), b(() => {
|
|
28
|
+
if (!I.current) return;
|
|
29
|
+
const o = B(I.current, {
|
|
30
|
+
...w,
|
|
31
|
+
...t !== void 0 && { background: t },
|
|
32
|
+
...g !== void 0 && { fov: g },
|
|
33
|
+
...x !== void 0 && { shadows: x },
|
|
34
|
+
...P !== void 0 && { autoRotate: P },
|
|
35
|
+
...y !== void 0 && { quality: y },
|
|
36
|
+
...m !== void 0 && { metalEnvUrl: m },
|
|
37
|
+
...e !== void 0 && { gemEnvUrl: e }
|
|
38
|
+
});
|
|
39
|
+
return p.current = o, c && (typeof c == "function" ? c(o) : c.current = o), o.on("loaded", ({ parts: i, materials: r }) => {
|
|
40
|
+
var l, C;
|
|
41
|
+
return (C = (l = E.current).onLoaded) == null ? void 0 : C.call(l, i, r);
|
|
42
|
+
}), o.on("partSelected", (i) => {
|
|
43
|
+
var r, l;
|
|
44
|
+
return (l = (r = E.current).onPartSelected) == null ? void 0 : l.call(r, i);
|
|
45
|
+
}), o.on("change", (i) => {
|
|
46
|
+
var r, l;
|
|
47
|
+
return (l = (r = E.current).onChange) == null ? void 0 : l.call(r, i);
|
|
48
|
+
}), o.on("error", (i) => {
|
|
49
|
+
var r, l;
|
|
50
|
+
return (l = (r = E.current).onError) == null ? void 0 : l.call(r, i);
|
|
51
|
+
}), o.on("loading", ({ progress: i }) => {
|
|
52
|
+
var r, l;
|
|
53
|
+
return (l = (r = E.current).onProgress) == null ? void 0 : l.call(r, i);
|
|
54
|
+
}), () => {
|
|
55
|
+
o.dispose(), c && (typeof c == "function" ? c(null) : c.current = null);
|
|
56
|
+
};
|
|
57
|
+
}, []), b(() => {
|
|
58
|
+
if (!p.current) return;
|
|
59
|
+
const o = Q(S ?? h);
|
|
60
|
+
if (!o) {
|
|
61
|
+
p.current.unload();
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
const i = new AbortController();
|
|
65
|
+
return p.current.load(o, { signal: i.signal }), () => i.abort();
|
|
66
|
+
}, [S, h]), b(() => {
|
|
67
|
+
var o;
|
|
68
|
+
d && ((o = p.current) == null || o.setMetalColor(d));
|
|
69
|
+
}, [d]), b(() => {
|
|
70
|
+
var o;
|
|
71
|
+
u && ((o = p.current) == null || o.setStoneColor(u));
|
|
72
|
+
}, [u]);
|
|
73
|
+
const T = _({});
|
|
74
|
+
b(() => {
|
|
75
|
+
if (!p.current) return;
|
|
76
|
+
const o = T.current, i = f ?? {};
|
|
77
|
+
for (const r of Object.keys(o))
|
|
78
|
+
r in i || p.current.clearMaterialColor(r);
|
|
79
|
+
for (const [r, l] of Object.entries(i))
|
|
80
|
+
o[r] !== l && p.current.setMaterialColor(r, l);
|
|
81
|
+
T.current = { ...i };
|
|
82
|
+
}, [f]);
|
|
83
|
+
const A = _({});
|
|
84
|
+
b(() => {
|
|
85
|
+
if (!p.current) return;
|
|
86
|
+
const o = A.current, i = v ?? {};
|
|
87
|
+
for (const r of Object.keys(o))
|
|
88
|
+
if (!(r in i))
|
|
89
|
+
if (r.includes(":")) {
|
|
90
|
+
const [l, C] = r.split(":"), L = parseInt(C ?? "", 10);
|
|
91
|
+
p.current.clearPartColor(l ?? "", isNaN(L) ? void 0 : L);
|
|
92
|
+
} else
|
|
93
|
+
p.current.clearPartColor(r);
|
|
94
|
+
for (const [r, l] of Object.entries(i))
|
|
95
|
+
if (o[r] !== l)
|
|
96
|
+
if (r.includes(":")) {
|
|
97
|
+
const [C, L] = r.split(":"), J = parseInt(L ?? "", 10);
|
|
98
|
+
p.current.setPartColor(C ?? "", l, isNaN(J) ? void 0 : J);
|
|
99
|
+
} else
|
|
100
|
+
p.current.setPartColor(r, l);
|
|
101
|
+
A.current = { ...i };
|
|
102
|
+
}, [v]), b(() => {
|
|
103
|
+
p.current && (P ? p.current.startRotation() : p.current.stopRotation());
|
|
104
|
+
}, [P]), b(() => {
|
|
105
|
+
var o;
|
|
106
|
+
y && ((o = p.current) == null || o.setQuality(y));
|
|
107
|
+
}, [y]);
|
|
108
|
+
const $ = {
|
|
109
|
+
width: "100%",
|
|
110
|
+
height: M !== void 0 ? typeof M == "number" ? `${M}px` : M : "100%",
|
|
111
|
+
minHeight: R !== void 0 ? typeof R == "number" ? `${R}px` : R : void 0,
|
|
112
|
+
aspectRatio: j,
|
|
113
|
+
position: "relative",
|
|
114
|
+
...G
|
|
115
|
+
};
|
|
116
|
+
return /* @__PURE__ */ a(
|
|
117
|
+
"div",
|
|
118
|
+
{
|
|
119
|
+
ref: I,
|
|
120
|
+
className: H,
|
|
121
|
+
style: $
|
|
122
|
+
}
|
|
123
|
+
);
|
|
124
|
+
});
|
|
125
|
+
function W({
|
|
126
|
+
value: n,
|
|
127
|
+
onChange: s,
|
|
128
|
+
options: c = F,
|
|
129
|
+
category: S = "all",
|
|
130
|
+
variant: h = "pills",
|
|
131
|
+
showLabel: d = !0,
|
|
132
|
+
className: u = "",
|
|
133
|
+
style: f
|
|
134
|
+
}) {
|
|
135
|
+
const v = S === "all" ? c : c.filter((e) => e.category === S), t = n ? k(n) : void 0, m = (t == null ? void 0 : t.id) ?? n;
|
|
136
|
+
return /* @__PURE__ */ N("div", { className: `td-swatch-group ${u}`, style: f, children: [
|
|
137
|
+
d && /* @__PURE__ */ N("div", { className: "td-swatch-header", children: [
|
|
138
|
+
/* @__PURE__ */ a("span", { className: "td-swatch-title", children: "Metal" }),
|
|
139
|
+
t && /* @__PURE__ */ a("span", { className: "td-swatch-selected-name", children: t.label })
|
|
140
|
+
] }),
|
|
141
|
+
/* @__PURE__ */ a("div", { className: "td-swatch-row", role: "radiogroup", "aria-label": "Metal Selection", children: v.map((e) => {
|
|
142
|
+
const w = m === e.id || n === e.hex;
|
|
143
|
+
return /* @__PURE__ */ N(
|
|
144
|
+
"button",
|
|
145
|
+
{
|
|
146
|
+
type: "button",
|
|
147
|
+
role: "radio",
|
|
148
|
+
"aria-checked": w,
|
|
149
|
+
title: e.label,
|
|
150
|
+
className: `td-swatch-${h === "dots" ? "dot" : "pill"} ${w ? "active" : ""}`,
|
|
151
|
+
onClick: () => s == null ? void 0 : s(e.id, e),
|
|
152
|
+
children: [
|
|
153
|
+
/* @__PURE__ */ a(
|
|
154
|
+
"span",
|
|
155
|
+
{
|
|
156
|
+
className: "td-swatch-color-circle",
|
|
157
|
+
style: { backgroundColor: e.hex }
|
|
158
|
+
}
|
|
159
|
+
),
|
|
160
|
+
h === "pills" && /* @__PURE__ */ a("span", { children: e.label })
|
|
161
|
+
]
|
|
162
|
+
},
|
|
163
|
+
e.id
|
|
164
|
+
);
|
|
165
|
+
}) })
|
|
166
|
+
] });
|
|
167
|
+
}
|
|
168
|
+
function X({
|
|
169
|
+
value: n,
|
|
170
|
+
onChange: s,
|
|
171
|
+
options: c = F,
|
|
172
|
+
label: S = "Select Metal",
|
|
173
|
+
className: h = "",
|
|
174
|
+
style: d
|
|
175
|
+
}) {
|
|
176
|
+
var v;
|
|
177
|
+
const u = n ? k(n) : void 0, f = (u == null ? void 0 : u.id) ?? n ?? ((v = c[0]) == null ? void 0 : v.id);
|
|
178
|
+
return /* @__PURE__ */ N("div", { className: `td-select-wrapper ${h}`, style: d, children: [
|
|
179
|
+
S && /* @__PURE__ */ a("label", { className: "td-swatch-title", children: S }),
|
|
180
|
+
/* @__PURE__ */ a(
|
|
181
|
+
"select",
|
|
182
|
+
{
|
|
183
|
+
className: "td-select",
|
|
184
|
+
value: f,
|
|
185
|
+
onChange: (t) => {
|
|
186
|
+
const m = t.target.value, e = k(m);
|
|
187
|
+
s == null || s(m, e);
|
|
188
|
+
},
|
|
189
|
+
children: c.map((t) => /* @__PURE__ */ a("option", { value: t.id, children: t.label }, t.id))
|
|
190
|
+
}
|
|
191
|
+
)
|
|
192
|
+
] });
|
|
193
|
+
}
|
|
194
|
+
function Z({
|
|
195
|
+
value: n,
|
|
196
|
+
onChange: s,
|
|
197
|
+
options: c = U,
|
|
198
|
+
category: S = "all",
|
|
199
|
+
variant: h = "pills",
|
|
200
|
+
showLabel: d = !0,
|
|
201
|
+
className: u = "",
|
|
202
|
+
style: f
|
|
203
|
+
}) {
|
|
204
|
+
const v = S === "all" ? c : c.filter((e) => e.category === S), t = n ? z(n) : void 0, m = (t == null ? void 0 : t.id) ?? n;
|
|
205
|
+
return /* @__PURE__ */ N("div", { className: `td-swatch-group ${u}`, style: f, children: [
|
|
206
|
+
d && /* @__PURE__ */ N("div", { className: "td-swatch-header", children: [
|
|
207
|
+
/* @__PURE__ */ a("span", { className: "td-swatch-title", children: "Gemstone" }),
|
|
208
|
+
t && /* @__PURE__ */ N("span", { className: "td-swatch-selected-name", children: [
|
|
209
|
+
t.label,
|
|
210
|
+
t.grade ? ` (${t.grade})` : ""
|
|
211
|
+
] })
|
|
212
|
+
] }),
|
|
213
|
+
/* @__PURE__ */ a("div", { className: "td-swatch-row", role: "radiogroup", "aria-label": "Gemstone Selection", children: v.map((e) => {
|
|
214
|
+
const w = m === e.id || n === e.hex;
|
|
215
|
+
return /* @__PURE__ */ N(
|
|
216
|
+
"button",
|
|
217
|
+
{
|
|
218
|
+
type: "button",
|
|
219
|
+
role: "radio",
|
|
220
|
+
"aria-checked": w,
|
|
221
|
+
title: `${e.label}${e.grade ? ` - ${e.grade}` : ""}`,
|
|
222
|
+
className: `td-swatch-${h === "dots" ? "dot" : "pill"} ${w ? "active" : ""}`,
|
|
223
|
+
onClick: () => s == null ? void 0 : s(e.id, e),
|
|
224
|
+
children: [
|
|
225
|
+
/* @__PURE__ */ a(
|
|
226
|
+
"span",
|
|
227
|
+
{
|
|
228
|
+
className: "td-swatch-color-circle",
|
|
229
|
+
style: { backgroundColor: e.hex }
|
|
230
|
+
}
|
|
231
|
+
),
|
|
232
|
+
h === "pills" && /* @__PURE__ */ a("span", { children: e.label })
|
|
233
|
+
]
|
|
234
|
+
},
|
|
235
|
+
e.id
|
|
236
|
+
);
|
|
237
|
+
}) })
|
|
238
|
+
] });
|
|
239
|
+
}
|
|
240
|
+
function ee({
|
|
241
|
+
value: n,
|
|
242
|
+
onChange: s,
|
|
243
|
+
options: c = U,
|
|
244
|
+
label: S = "Select Gemstone",
|
|
245
|
+
className: h = "",
|
|
246
|
+
style: d
|
|
247
|
+
}) {
|
|
248
|
+
var v;
|
|
249
|
+
const u = n ? z(n) : void 0, f = (u == null ? void 0 : u.id) ?? n ?? ((v = c[0]) == null ? void 0 : v.id);
|
|
250
|
+
return /* @__PURE__ */ N("div", { className: `td-select-wrapper ${h}`, style: d, children: [
|
|
251
|
+
S && /* @__PURE__ */ a("label", { className: "td-swatch-title", children: S }),
|
|
252
|
+
/* @__PURE__ */ a(
|
|
253
|
+
"select",
|
|
254
|
+
{
|
|
255
|
+
className: "td-select",
|
|
256
|
+
value: f,
|
|
257
|
+
onChange: (t) => {
|
|
258
|
+
const m = t.target.value, e = z(m);
|
|
259
|
+
s == null || s(m, e);
|
|
260
|
+
},
|
|
261
|
+
children: c.map((t) => /* @__PURE__ */ N("option", { value: t.id, children: [
|
|
262
|
+
t.label,
|
|
263
|
+
" ",
|
|
264
|
+
t.grade ? `(${t.grade})` : ""
|
|
265
|
+
] }, t.id))
|
|
266
|
+
}
|
|
267
|
+
)
|
|
268
|
+
] });
|
|
269
|
+
}
|
|
270
|
+
function le({
|
|
271
|
+
src: n,
|
|
272
|
+
source: s,
|
|
273
|
+
defaultMetal: c = "yellow-gold-18k",
|
|
274
|
+
defaultStone: S = "diamond-d",
|
|
275
|
+
metal: h,
|
|
276
|
+
onMetalChange: d,
|
|
277
|
+
stone: u,
|
|
278
|
+
onStoneChange: f,
|
|
279
|
+
metalOptions: v,
|
|
280
|
+
stoneOptions: t,
|
|
281
|
+
controlsVariant: m = "pills",
|
|
282
|
+
height: e = 520,
|
|
283
|
+
autoRotate: w = !0,
|
|
284
|
+
quality: g = "high",
|
|
285
|
+
fov: x,
|
|
286
|
+
shadows: P,
|
|
287
|
+
onLoaded: y,
|
|
288
|
+
onPartSelected: M,
|
|
289
|
+
className: R = "",
|
|
290
|
+
style: j,
|
|
291
|
+
viewerRef: H
|
|
292
|
+
}) {
|
|
293
|
+
const [G, I] = O(c), [p, E] = O(S), T = h !== void 0 ? h : G, A = u !== void 0 ? u : p, $ = (r, l) => {
|
|
294
|
+
h === void 0 && I(r), d == null || d(r, l);
|
|
295
|
+
}, o = (r, l) => {
|
|
296
|
+
u === void 0 && E(r), f == null || f(r, l);
|
|
297
|
+
}, i = typeof e == "number" ? `${e}px` : e;
|
|
298
|
+
return /* @__PURE__ */ N("div", { className: `td-customizer-card ${R}`, style: j, children: [
|
|
299
|
+
/* @__PURE__ */ a("div", { className: "td-customizer-viewport", style: { height: i }, children: /* @__PURE__ */ a(
|
|
300
|
+
K,
|
|
301
|
+
{
|
|
302
|
+
ref: H,
|
|
303
|
+
src: n,
|
|
304
|
+
source: s,
|
|
305
|
+
metalColor: T,
|
|
306
|
+
stoneColor: A,
|
|
307
|
+
autoRotate: w,
|
|
308
|
+
quality: g,
|
|
309
|
+
fov: x,
|
|
310
|
+
shadows: P,
|
|
311
|
+
onLoaded: y,
|
|
312
|
+
onPartSelected: M
|
|
313
|
+
}
|
|
314
|
+
) }),
|
|
315
|
+
m !== "none" && /* @__PURE__ */ a("div", { className: "td-customizer-controls", children: m === "select" ? /* @__PURE__ */ N(V, { children: [
|
|
316
|
+
/* @__PURE__ */ a(
|
|
317
|
+
X,
|
|
318
|
+
{
|
|
319
|
+
value: T,
|
|
320
|
+
onChange: $,
|
|
321
|
+
options: v
|
|
322
|
+
}
|
|
323
|
+
),
|
|
324
|
+
/* @__PURE__ */ a(
|
|
325
|
+
ee,
|
|
326
|
+
{
|
|
327
|
+
value: A,
|
|
328
|
+
onChange: o,
|
|
329
|
+
options: t
|
|
330
|
+
}
|
|
331
|
+
)
|
|
332
|
+
] }) : /* @__PURE__ */ N(V, { children: [
|
|
333
|
+
/* @__PURE__ */ a(
|
|
334
|
+
W,
|
|
335
|
+
{
|
|
336
|
+
value: T,
|
|
337
|
+
onChange: $,
|
|
338
|
+
options: v,
|
|
339
|
+
variant: m
|
|
340
|
+
}
|
|
341
|
+
),
|
|
342
|
+
/* @__PURE__ */ a(
|
|
343
|
+
Z,
|
|
344
|
+
{
|
|
345
|
+
value: A,
|
|
346
|
+
onChange: o,
|
|
347
|
+
options: t,
|
|
348
|
+
variant: m
|
|
349
|
+
}
|
|
350
|
+
)
|
|
351
|
+
] }) })
|
|
352
|
+
] });
|
|
353
|
+
}
|
|
354
|
+
function ce(n = {}) {
|
|
355
|
+
const {
|
|
356
|
+
defaultMetal: s = "yellow-gold-18k",
|
|
357
|
+
defaultStone: c = "diamond-d",
|
|
358
|
+
metalOptions: S = F,
|
|
359
|
+
stoneOptions: h = U
|
|
360
|
+
} = n, [d, u] = O(s), [f, v] = O(c), t = D(() => k(d), [d]), m = D(() => z(f), [f]), e = D(
|
|
361
|
+
() => ({
|
|
362
|
+
metalColor: d,
|
|
363
|
+
stoneColor: f
|
|
364
|
+
}),
|
|
365
|
+
[d, f]
|
|
366
|
+
);
|
|
367
|
+
return {
|
|
368
|
+
metal: d,
|
|
369
|
+
setMetal: u,
|
|
370
|
+
stone: f,
|
|
371
|
+
setStone: v,
|
|
372
|
+
metalPreset: t,
|
|
373
|
+
stonePreset: m,
|
|
374
|
+
metalOptions: S,
|
|
375
|
+
stoneOptions: h,
|
|
376
|
+
viewerProps: e
|
|
377
|
+
};
|
|
378
|
+
}
|
|
379
|
+
export {
|
|
380
|
+
ie as ALL_METAL_PRESETS,
|
|
381
|
+
ae as ALL_STONE_PRESETS,
|
|
382
|
+
de as CANONICAL_METAL_PRESETS,
|
|
383
|
+
ue as CANONICAL_STONE_PRESETS,
|
|
384
|
+
pe as DIAMOND_PRESETS,
|
|
385
|
+
fe as GEMSTONE_PRESETS,
|
|
386
|
+
le as JewelryCustomizer,
|
|
387
|
+
me as METAL_PRESETS,
|
|
388
|
+
X as MetalSelect,
|
|
389
|
+
W as MetalSwatches,
|
|
390
|
+
Se as PHYSICALLY_BASED_METAL_PRESETS,
|
|
391
|
+
he as STONE_PRESETS,
|
|
392
|
+
ee as StoneSelect,
|
|
393
|
+
Z as StoneSwatches,
|
|
394
|
+
K as Viewer,
|
|
395
|
+
K as default,
|
|
396
|
+
ve as getMetalPreset,
|
|
397
|
+
Ne as getStonePreset,
|
|
398
|
+
we as inferFormatFromUrl,
|
|
399
|
+
Ee as normalizeModelSource,
|
|
400
|
+
ce as useJewelryCustomizer
|
|
401
|
+
};
|
|
402
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../src/Viewer.tsx","../src/swatches/MetalSwatches.tsx","../src/swatches/StoneSwatches.tsx","../src/swatches/JewelryCustomizer.tsx","../src/swatches/useJewelryCustomizer.ts"],"sourcesContent":["/// <reference types=\"vite/client\" />\nimport { useRef, useEffect, forwardRef, useImperativeHandle, type CSSProperties } from 'react'\nimport {\n createViewer,\n normalizeModelSource,\n type Viewer as CoreViewer,\n type ModelSource,\n type ViewerSourceInput,\n type MetalColorProp,\n type StoneColorProp,\n type ViewerOptions,\n type ViewerState,\n type PartInfo,\n type MaterialSlotInfo,\n type PartType,\n} from '@thinkersteps_labs/3d-viewer-core'\n\nexport interface ViewerRef extends CoreViewer { }\n\nexport interface ViewerProps {\n /** 3D model URL or source object. Takes precedence over `source` if both provided. */\n src?: string\n /** 3D model source (URL string, ModelSource payload, or null). */\n source?: ViewerSourceInput\n /** Metal preset ID or hex code. IDE autocompletes standard presets. */\n metalColor?: MetalColorProp\n /** Stone preset ID or hex code. IDE autocompletes standard presets. */\n stoneColor?: StoneColorProp\n /** Bulk material name or slot ID color overrides. */\n materialColors?: Record<string, string>\n /** Part color overrides keyed by partId or partId:slotIndex. */\n partColors?: Record<string, string>\n background?: string | number\n metalEnvUrl?: string | ArrayBuffer\n gemEnvUrl?: string | ArrayBuffer\n options?: ViewerOptions\n fov?: number\n shadows?: boolean\n autoRotate?: boolean\n quality?: 'low' | 'medium' | 'high'\n /** Explicit container height (e.g. 520 or '520px'). Prevents zero-height collapse. */\n height?: number | string\n /** Explicit container min-height. */\n minHeight?: number | string\n /** Aspect ratio for responsive sizing (e.g. '16/9' or '4/3'). */\n aspectRatio?: string\n onLoaded?: (parts: PartInfo[], materials?: MaterialSlotInfo[]) => void\n onPartSelected?: (info: {\n meshId: string\n partId?: string\n type: PartType\n slotIndex?: number\n slotId?: string\n materialName?: string\n }) => void\n onChange?: (state: ViewerState) => void\n onError?: (err: Error) => void\n onProgress?: (progress: number) => void\n className?: string\n style?: CSSProperties\n}\n\nexport const Viewer = forwardRef<ViewerRef, ViewerProps>(function Viewer(props, ref) {\n const {\n src,\n source,\n metalColor,\n stoneColor,\n materialColors,\n partColors,\n background,\n metalEnvUrl,\n gemEnvUrl,\n options,\n fov,\n shadows,\n autoRotate,\n quality,\n height,\n minHeight,\n aspectRatio,\n className,\n style,\n } = props\n const containerRef = useRef<HTMLDivElement>(null)\n const viewerRef = useRef<ViewerRef | null>(null)\n const cb = useRef(props)\n cb.current = props\n\n useImperativeHandle(ref, () => viewerRef.current!, [])\n\n useEffect(() => {\n if (!containerRef.current) return\n const viewer = createViewer(containerRef.current, {\n ...options,\n ...(background !== undefined && { background }),\n ...(fov !== undefined && { fov }),\n ...(shadows !== undefined && { shadows }),\n ...(autoRotate !== undefined && { autoRotate }),\n ...(quality !== undefined && { quality }),\n ...(metalEnvUrl !== undefined && { metalEnvUrl }),\n ...(gemEnvUrl !== undefined && { gemEnvUrl }),\n })\n viewerRef.current = viewer\n if (import.meta.env.DEV && typeof window !== 'undefined') (window as any).__viewer = viewer\n if (ref) {\n if (typeof ref === 'function') ref(viewer)\n else (ref as any).current = viewer\n }\n viewer.on('loaded', ({ parts, materials }) => cb.current.onLoaded?.(parts, materials))\n viewer.on('partSelected', (info) => cb.current.onPartSelected?.(info))\n viewer.on('change', (state) => cb.current.onChange?.(state))\n viewer.on('error', (err) => cb.current.onError?.(err))\n viewer.on('loading', ({ progress }) => cb.current.onProgress?.(progress))\n return () => {\n viewer.dispose()\n if (ref) {\n if (typeof ref === 'function') ref(null)\n else (ref as any).current = null\n }\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [])\n\n useEffect(() => {\n if (!viewerRef.current) return\n const resolved = normalizeModelSource(src ?? source)\n if (!resolved) {\n viewerRef.current.unload()\n return\n }\n const ac = new AbortController()\n viewerRef.current.load(resolved, { signal: ac.signal })\n return () => ac.abort()\n }, [src, source])\n\n useEffect(() => {\n if (metalColor) viewerRef.current?.setMetalColor(metalColor)\n }, [metalColor])\n\n useEffect(() => {\n if (stoneColor) viewerRef.current?.setStoneColor(stoneColor)\n }, [stoneColor])\n\n const prevMaterialColorsRef = useRef<Record<string, string>>({})\n useEffect(() => {\n if (!viewerRef.current) return\n const prev = prevMaterialColorsRef.current\n const next = materialColors ?? {}\n\n for (const key of Object.keys(prev)) {\n if (!(key in next)) {\n viewerRef.current.clearMaterialColor(key)\n }\n }\n for (const [key, color] of Object.entries(next)) {\n if (prev[key] !== color) {\n viewerRef.current.setMaterialColor(key, color)\n }\n }\n prevMaterialColorsRef.current = { ...next }\n }, [materialColors])\n\n const prevPartColorsRef = useRef<Record<string, string>>({})\n useEffect(() => {\n if (!viewerRef.current) return\n const prev = prevPartColorsRef.current\n const next = partColors ?? {}\n\n for (const key of Object.keys(prev)) {\n if (!(key in next)) {\n if (key.includes(':')) {\n const [partId, slotIdxStr] = key.split(':')\n const slotIndex = parseInt(slotIdxStr ?? '', 10)\n viewerRef.current.clearPartColor(partId ?? '', isNaN(slotIndex) ? undefined : slotIndex)\n } else {\n viewerRef.current.clearPartColor(key)\n }\n }\n }\n for (const [key, color] of Object.entries(next)) {\n if (prev[key] !== color) {\n if (key.includes(':')) {\n const [partId, slotIdxStr] = key.split(':')\n const slotIndex = parseInt(slotIdxStr ?? '', 10)\n viewerRef.current.setPartColor(partId ?? '', color, isNaN(slotIndex) ? undefined : slotIndex)\n } else {\n viewerRef.current.setPartColor(key, color)\n }\n }\n }\n prevPartColorsRef.current = { ...next }\n }, [partColors])\n\n useEffect(() => {\n if (!viewerRef.current) return\n if (autoRotate) viewerRef.current.startRotation()\n else viewerRef.current.stopRotation()\n }, [autoRotate])\n\n useEffect(() => {\n if (quality) viewerRef.current?.setQuality(quality)\n }, [quality])\n\n const containerStyle: CSSProperties = {\n width: '100%',\n height: height !== undefined ? (typeof height === 'number' ? `${height}px` : height) : '100%',\n minHeight: minHeight !== undefined ? (typeof minHeight === 'number' ? `${minHeight}px` : minHeight) : undefined,\n aspectRatio,\n position: 'relative',\n ...style,\n }\n\n return (\n <div\n ref={containerRef}\n className={className}\n style={containerStyle}\n />\n )\n})\n\nexport default Viewer\n","import React, { type CSSProperties } from 'react'\nimport {\n CANONICAL_METAL_PRESETS,\n getMetalPreset,\n type MetalPreset,\n type MetalColorProp,\n} from '@thinkersteps_labs/3d-viewer-core'\nimport './swatches.css'\n\nexport interface MetalSwatchesProps {\n value?: MetalColorProp\n onChange?: (metalId: string, preset?: MetalPreset) => void\n options?: MetalPreset[]\n category?: 'all' | 'gold' | 'platinum-silver' | 'alternative'\n variant?: 'pills' | 'dots'\n showLabel?: boolean\n className?: string\n style?: CSSProperties\n}\n\nexport function MetalSwatches({\n value,\n onChange,\n options = CANONICAL_METAL_PRESETS,\n category = 'all',\n variant = 'pills',\n showLabel = true,\n className = '',\n style,\n}: MetalSwatchesProps) {\n const filteredOptions = category === 'all'\n ? options\n : options.filter((m) => m.category === category)\n\n const activePreset = value ? getMetalPreset(value) : undefined\n const activeId = activePreset?.id ?? value\n\n return (\n <div className={`td-swatch-group ${className}`} style={style}>\n {showLabel && (\n <div className=\"td-swatch-header\">\n <span className=\"td-swatch-title\">Metal</span>\n {activePreset && (\n <span className=\"td-swatch-selected-name\">{activePreset.label}</span>\n )}\n </div>\n )}\n <div className=\"td-swatch-row\" role=\"radiogroup\" aria-label=\"Metal Selection\">\n {filteredOptions.map((m) => {\n const isSelected = activeId === m.id || value === m.hex\n return (\n <button\n key={m.id}\n type=\"button\"\n role=\"radio\"\n aria-checked={isSelected}\n title={m.label}\n className={`td-swatch-${variant === 'dots' ? 'dot' : 'pill'} ${isSelected ? 'active' : ''}`}\n onClick={() => onChange?.(m.id, m)}\n >\n <span\n className=\"td-swatch-color-circle\"\n style={{ backgroundColor: m.hex }}\n />\n {variant === 'pills' && <span>{m.label}</span>}\n </button>\n )\n })}\n </div>\n </div>\n )\n}\n\nexport interface MetalSelectProps {\n value?: MetalColorProp\n onChange?: (metalId: string, preset?: MetalPreset) => void\n options?: MetalPreset[]\n label?: string\n className?: string\n style?: CSSProperties\n}\n\nexport function MetalSelect({\n value,\n onChange,\n options = CANONICAL_METAL_PRESETS,\n label = 'Select Metal',\n className = '',\n style,\n}: MetalSelectProps) {\n const activePreset = value ? getMetalPreset(value) : undefined\n const activeValue = activePreset?.id ?? value ?? options[0]?.id\n\n return (\n <div className={`td-select-wrapper ${className}`} style={style}>\n {label && <label className=\"td-swatch-title\">{label}</label>}\n <select\n className=\"td-select\"\n value={activeValue}\n onChange={(e) => {\n const val = e.target.value\n const preset = getMetalPreset(val)\n onChange?.(val, preset)\n }}\n >\n {options.map((m) => (\n <option key={m.id} value={m.id}>\n {m.label}\n </option>\n ))}\n </select>\n </div>\n )\n}\n","import React, { type CSSProperties } from 'react'\nimport {\n CANONICAL_STONE_PRESETS,\n getStonePreset,\n type StonePreset,\n type StoneColorProp,\n} from '@thinkersteps_labs/3d-viewer-core'\nimport './swatches.css'\n\nexport interface StoneSwatchesProps {\n value?: StoneColorProp\n onChange?: (stoneId: string, preset?: StonePreset) => void\n options?: StonePreset[]\n category?: 'all' | 'diamond' | 'gemstone'\n variant?: 'pills' | 'dots'\n showLabel?: boolean\n className?: string\n style?: CSSProperties\n}\n\nexport function StoneSwatches({\n value,\n onChange,\n options = CANONICAL_STONE_PRESETS,\n category = 'all',\n variant = 'pills',\n showLabel = true,\n className = '',\n style,\n}: StoneSwatchesProps) {\n const filteredOptions = category === 'all'\n ? options\n : options.filter((s) => s.category === category)\n\n const activePreset = value ? getStonePreset(value) : undefined\n const activeId = activePreset?.id ?? value\n\n return (\n <div className={`td-swatch-group ${className}`} style={style}>\n {showLabel && (\n <div className=\"td-swatch-header\">\n <span className=\"td-swatch-title\">Gemstone</span>\n {activePreset && (\n <span className=\"td-swatch-selected-name\">\n {activePreset.label}\n {activePreset.grade ? ` (${activePreset.grade})` : ''}\n </span>\n )}\n </div>\n )}\n <div className=\"td-swatch-row\" role=\"radiogroup\" aria-label=\"Gemstone Selection\">\n {filteredOptions.map((s) => {\n const isSelected = activeId === s.id || value === s.hex\n return (\n <button\n key={s.id}\n type=\"button\"\n role=\"radio\"\n aria-checked={isSelected}\n title={`${s.label}${s.grade ? ` - ${s.grade}` : ''}`}\n className={`td-swatch-${variant === 'dots' ? 'dot' : 'pill'} ${isSelected ? 'active' : ''}`}\n onClick={() => onChange?.(s.id, s)}\n >\n <span\n className=\"td-swatch-color-circle\"\n style={{ backgroundColor: s.hex }}\n />\n {variant === 'pills' && <span>{s.label}</span>}\n </button>\n )\n })}\n </div>\n </div>\n )\n}\n\nexport interface StoneSelectProps {\n value?: StoneColorProp\n onChange?: (stoneId: string, preset?: StonePreset) => void\n options?: StonePreset[]\n label?: string\n className?: string\n style?: CSSProperties\n}\n\nexport function StoneSelect({\n value,\n onChange,\n options = CANONICAL_STONE_PRESETS,\n label = 'Select Gemstone',\n className = '',\n style,\n}: StoneSelectProps) {\n const activePreset = value ? getStonePreset(value) : undefined\n const activeValue = activePreset?.id ?? value ?? options[0]?.id\n\n return (\n <div className={`td-select-wrapper ${className}`} style={style}>\n {label && <label className=\"td-swatch-title\">{label}</label>}\n <select\n className=\"td-select\"\n value={activeValue}\n onChange={(e) => {\n const val = e.target.value\n const preset = getStonePreset(val)\n onChange?.(val, preset)\n }}\n >\n {options.map((s) => (\n <option key={s.id} value={s.id}>\n {s.label} {s.grade ? `(${s.grade})` : ''}\n </option>\n ))}\n </select>\n </div>\n )\n}\n","import React, { useState, type CSSProperties } from 'react'\nimport {\n type MetalColorProp,\n type StoneColorProp,\n type ViewerSourceInput,\n type MetalPreset,\n type StonePreset,\n type PartInfo,\n type PartType,\n} from '@thinkersteps_labs/3d-viewer-core'\nimport { Viewer, type ViewerRef } from '../Viewer'\nimport { MetalSwatches, MetalSelect } from './MetalSwatches'\nimport { StoneSwatches, StoneSelect } from './StoneSwatches'\nimport './swatches.css'\n\nexport interface JewelryCustomizerProps {\n src?: string\n source?: ViewerSourceInput\n defaultMetal?: MetalColorProp\n defaultStone?: StoneColorProp\n metal?: MetalColorProp\n onMetalChange?: (metal: string, preset?: MetalPreset) => void\n stone?: StoneColorProp\n onStoneChange?: (stone: string, preset?: StonePreset) => void\n metalOptions?: MetalPreset[]\n stoneOptions?: StonePreset[]\n controlsVariant?: 'pills' | 'dots' | 'select' | 'none'\n height?: number | string\n autoRotate?: boolean\n quality?: 'low' | 'medium' | 'high'\n fov?: number\n shadows?: boolean\n onLoaded?: (parts: PartInfo[]) => void\n onPartSelected?: (info: { meshId: string; type: PartType }) => void\n className?: string\n style?: CSSProperties\n viewerRef?: React.Ref<ViewerRef>\n}\n\nexport function JewelryCustomizer({\n src,\n source,\n defaultMetal = 'yellow-gold-18k',\n defaultStone = 'diamond-d',\n metal: controlledMetal,\n onMetalChange,\n stone: controlledStone,\n onStoneChange,\n metalOptions,\n stoneOptions,\n controlsVariant = 'pills',\n height = 520,\n autoRotate = true,\n quality = 'high',\n fov,\n shadows,\n onLoaded,\n onPartSelected,\n className = '',\n style,\n viewerRef,\n}: JewelryCustomizerProps) {\n const [internalMetal, setInternalMetal] = useState<MetalColorProp>(defaultMetal)\n const [internalStone, setInternalStone] = useState<StoneColorProp>(defaultStone)\n\n const currentMetal = controlledMetal !== undefined ? controlledMetal : internalMetal\n const currentStone = controlledStone !== undefined ? controlledStone : internalStone\n\n const handleMetalChange = (val: string, preset?: MetalPreset) => {\n if (controlledMetal === undefined) setInternalMetal(val)\n onMetalChange?.(val, preset)\n }\n\n const handleStoneChange = (val: string, preset?: StonePreset) => {\n if (controlledStone === undefined) setInternalStone(val)\n onStoneChange?.(val, preset)\n }\n\n const viewportHeight = typeof height === 'number' ? `${height}px` : height\n\n return (\n <div className={`td-customizer-card ${className}`} style={style}>\n <div className=\"td-customizer-viewport\" style={{ height: viewportHeight }}>\n <Viewer\n ref={viewerRef}\n src={src}\n source={source}\n metalColor={currentMetal}\n stoneColor={currentStone}\n autoRotate={autoRotate}\n quality={quality}\n fov={fov}\n shadows={shadows}\n onLoaded={onLoaded}\n onPartSelected={onPartSelected}\n />\n </div>\n\n {controlsVariant !== 'none' && (\n <div className=\"td-customizer-controls\">\n {controlsVariant === 'select' ? (\n <>\n <MetalSelect\n value={currentMetal}\n onChange={handleMetalChange}\n options={metalOptions}\n />\n <StoneSelect\n value={currentStone}\n onChange={handleStoneChange}\n options={stoneOptions}\n />\n </>\n ) : (\n <>\n <MetalSwatches\n value={currentMetal}\n onChange={handleMetalChange}\n options={metalOptions}\n variant={controlsVariant}\n />\n <StoneSwatches\n value={currentStone}\n onChange={handleStoneChange}\n options={stoneOptions}\n variant={controlsVariant}\n />\n </>\n )}\n </div>\n )}\n </div>\n )\n}\n","import { useState, useMemo } from 'react'\nimport {\n CANONICAL_METAL_PRESETS,\n CANONICAL_STONE_PRESETS,\n getMetalPreset,\n getStonePreset,\n type MetalColorProp,\n type StoneColorProp,\n type MetalPreset,\n type StonePreset,\n} from '@thinkersteps_labs/3d-viewer-core'\n\nexport interface UseJewelryCustomizerOptions {\n defaultMetal?: MetalColorProp\n defaultStone?: StoneColorProp\n metalOptions?: MetalPreset[]\n stoneOptions?: StonePreset[]\n}\n\nexport interface UseJewelryCustomizerReturn {\n metal: MetalColorProp\n setMetal: (val: MetalColorProp) => void\n stone: StoneColorProp\n setStone: (val: StoneColorProp) => void\n metalPreset?: MetalPreset\n stonePreset?: StonePreset\n metalOptions: MetalPreset[]\n stoneOptions: StonePreset[]\n viewerProps: {\n metalColor: MetalColorProp\n stoneColor: StoneColorProp\n }\n}\n\nexport function useJewelryCustomizer(\n options: UseJewelryCustomizerOptions = {}\n): UseJewelryCustomizerReturn {\n const {\n defaultMetal = 'yellow-gold-18k',\n defaultStone = 'diamond-d',\n metalOptions = CANONICAL_METAL_PRESETS,\n stoneOptions = CANONICAL_STONE_PRESETS,\n } = options\n\n const [metal, setMetal] = useState<MetalColorProp>(defaultMetal)\n const [stone, setStone] = useState<StoneColorProp>(defaultStone)\n\n const metalPreset = useMemo(() => getMetalPreset(metal), [metal])\n const stonePreset = useMemo(() => getStonePreset(stone), [stone])\n\n const viewerProps = useMemo(\n () => ({\n metalColor: metal,\n stoneColor: stone,\n }),\n [metal, stone]\n )\n\n return {\n metal,\n setMetal,\n stone,\n setStone,\n metalPreset,\n stonePreset,\n metalOptions,\n stoneOptions,\n viewerProps,\n }\n}\n"],"names":["Viewer","forwardRef","props","ref","src","source","metalColor","stoneColor","materialColors","partColors","background","metalEnvUrl","gemEnvUrl","options","fov","shadows","autoRotate","quality","height","minHeight","aspectRatio","className","style","containerRef","useRef","viewerRef","cb","useImperativeHandle","useEffect","viewer","createViewer","parts","materials","_b","_a","info","state","err","progress","resolved","normalizeModelSource","ac","prevMaterialColorsRef","prev","next","key","color","prevPartColorsRef","partId","slotIdxStr","slotIndex","containerStyle","jsx","MetalSwatches","value","onChange","CANONICAL_METAL_PRESETS","category","variant","showLabel","filteredOptions","m","activePreset","getMetalPreset","activeId","jsxs","isSelected","MetalSelect","label","activeValue","e","val","preset","StoneSwatches","CANONICAL_STONE_PRESETS","s","getStonePreset","StoneSelect","JewelryCustomizer","defaultMetal","defaultStone","controlledMetal","onMetalChange","controlledStone","onStoneChange","metalOptions","stoneOptions","controlsVariant","onLoaded","onPartSelected","internalMetal","setInternalMetal","useState","internalStone","setInternalStone","currentMetal","currentStone","handleMetalChange","handleStoneChange","viewportHeight","Fragment","useJewelryCustomizer","metal","setMetal","stone","setStone","metalPreset","useMemo","stonePreset","viewerProps"],"mappings":"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"}
|
package/dist/style.css
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
.td-swatch-group{display:flex;flex-direction:column;gap:8px;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,sans-serif}.td-swatch-header{display:flex;justify-content:space-between;align-items:baseline;font-size:13px;font-weight:500;color:#333}.td-swatch-title{text-transform:uppercase;letter-spacing:.05em;font-size:11px;font-weight:600;color:#666}.td-swatch-selected-name{font-weight:600;color:#111}.td-swatch-row{display:flex;flex-wrap:wrap;gap:8px;align-items:center}.td-swatch-pill{display:inline-flex;align-items:center;gap:8px;padding:6px 12px;border-radius:9999px;border:1px solid #e2e8f0;background:#fff;color:#1e293b;font-size:13px;font-weight:500;cursor:pointer;transition:all .15s ease-in-out;outline:none;box-shadow:0 1px 2px #0000000a}.td-swatch-pill:hover{border-color:#cbd5e1;background:#f8fafc;transform:translateY(-1px)}.td-swatch-pill.active{border-color:#0f172a;background:#0f172a;color:#fff;box-shadow:0 2px 4px #0f172a33}.td-swatch-dot{position:relative;width:32px;height:32px;border-radius:50%;border:2px solid transparent;padding:2px;background:transparent;cursor:pointer;transition:all .15s ease-in-out;outline:none;display:inline-flex;align-items:center;justify-content:center}.td-swatch-dot:hover{transform:scale(1.1)}.td-swatch-dot.active{border-color:#0f172a;transform:scale(1.08)}.td-swatch-color-circle{width:100%;height:100%;border-radius:50%;border:1px solid rgba(0,0,0,.12);box-shadow:inset 0 1px 2px #fff6,0 1px 2px #00000014;display:inline-block;flex-shrink:0}.td-swatch-pill .td-swatch-color-circle{width:14px;height:14px}.td-select-wrapper{display:flex;flex-direction:column;gap:6px;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,sans-serif}.td-select{padding:8px 12px;border-radius:8px;border:1px solid #cbd5e1;background-color:#fff;font-size:14px;color:#1e293b;outline:none;cursor:pointer;transition:border-color .15s}.td-select:focus{border-color:#0f172a;box-shadow:0 0 0 2px #0f172a1a}.td-customizer-card{display:flex;flex-direction:column;gap:16px;background:#fff;border-radius:16px;border:1px solid #e2e8f0;padding:16px;box-shadow:0 4px 6px -1px #0000000d,0 2px 4px -2px #0000000d}.td-customizer-viewport{position:relative;width:100%;border-radius:12px;overflow:hidden;background:#f8fafc}.td-customizer-controls{display:flex;flex-direction:column;gap:14px}
|
package/package.json
CHANGED
|
@@ -1,6 +1,46 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@thinkersteps_labs/3d-viewer-react",
|
|
3
|
-
"version": "
|
|
4
|
-
"
|
|
5
|
-
"
|
|
3
|
+
"version": "1.0.1",
|
|
4
|
+
"license": "MIT",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "git+https://github.com/lalitthinker/3d-jewelry-viewer.git",
|
|
8
|
+
"directory": "packages/react"
|
|
9
|
+
},
|
|
10
|
+
"publishConfig": {
|
|
11
|
+
"access": "public"
|
|
12
|
+
},
|
|
13
|
+
"type": "module",
|
|
14
|
+
"main": "./dist/index.cjs",
|
|
15
|
+
"module": "./dist/index.js",
|
|
16
|
+
"types": "./dist/index.d.ts",
|
|
17
|
+
"exports": {
|
|
18
|
+
".": {
|
|
19
|
+
"types": "./dist/index.d.ts",
|
|
20
|
+
"import": "./dist/index.js",
|
|
21
|
+
"require": "./dist/index.cjs"
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
"files": [
|
|
25
|
+
"dist"
|
|
26
|
+
],
|
|
27
|
+
"peerDependencies": {
|
|
28
|
+
"react": ">=18.0.0",
|
|
29
|
+
"three": ">=0.150.0",
|
|
30
|
+
"@thinkersteps_labs/3d-viewer-core": "1.0.1"
|
|
31
|
+
},
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"@types/node": "^20.11.0",
|
|
34
|
+
"@types/react": "^18.2.0",
|
|
35
|
+
"@vitejs/plugin-react": "^4.2.0",
|
|
36
|
+
"react": "^18.2.0",
|
|
37
|
+
"three": "^0.160.0",
|
|
38
|
+
"vite": "^5.0.0",
|
|
39
|
+
"vite-plugin-dts": "^3.7.0",
|
|
40
|
+
"@thinkersteps_labs/3d-viewer-core": "1.0.1"
|
|
41
|
+
},
|
|
42
|
+
"scripts": {
|
|
43
|
+
"build": "vite build",
|
|
44
|
+
"typecheck": "tsc --noEmit"
|
|
45
|
+
}
|
|
6
46
|
}
|