@salsita-ai/sdk 0.50.0-develop.abef6d86a1 → 0.50.0-develop.ae52227c7e

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/README.md +2 -2
  2. package/dist/application-spec/errors/diagnostic-codes.d.ts +1 -0
  3. package/dist/application-spec/errors/diagnostic-codes.js +1 -1
  4. package/dist/application-spec/errors/diagnostic-messages.d.ts +1 -0
  5. package/dist/application-spec/errors/diagnostic-messages.js +1 -1
  6. package/dist/application-spec/generate-application/code/project-scaffolding.d.ts +7 -0
  7. package/dist/application-spec/generate-application/code/project-scaffolding.js +1 -1
  8. package/dist/application-spec/generate-application/code/templates/domain-spec/generate-domain-block.js +25 -23
  9. package/dist/application-spec/generate-application/code/templates/domain.js +3 -3
  10. package/dist/application-spec/generate-application/code/templates/package-json.js +1 -1
  11. package/dist/application-spec/generate-application/code/templates/skills/sdk-content.d.ts +1 -0
  12. package/dist/application-spec/generate-application/code/templates/skills/sdk-content.js +1 -1
  13. package/dist/application-spec/parse-application-files/spec/model/defaults.d.ts +5 -0
  14. package/dist/application-spec/parse-application-files/spec/model/defaults.js +1 -1
  15. package/dist/configurator/pages/DefaultConfiguratorLayout.d.ts +6 -0
  16. package/dist/configurator/pages/DefaultConfiguratorLayout.js +1 -0
  17. package/dist/configurator/pages/LoadedConfiguratorDetailPage.js +1 -1
  18. package/dist/configurator/ui/configurator-layout/universal/DesktopLayout.js +4 -4
  19. package/dist/configurator/ui/configurator-layout/universal/DesktopPreview.js +1 -1
  20. package/dist/configurator/ui/configurator-layout/universal/MobileLayout.js +4 -4
  21. package/dist/configurator/ui/configurator-layout/universal/MobilePreview.js +1 -1
  22. package/dist/configurator/ui/configurator-layout/universal/use-layout-scene-safe-area.d.ts +47 -0
  23. package/dist/configurator/ui/configurator-layout/universal/use-layout-scene-safe-area.js +1 -0
  24. package/dist/configurator/ui/configurator-layout/universal/use-scene-safe-area.d.ts +11 -26
  25. package/dist/configurator/ui/configurator-layout/universal/use-scene-safe-area.js +1 -1
  26. package/dist/docs/complex-use-cases/filtered-controls-with-fix-dialog.mdx +16 -19
  27. package/dist/docs/complex-use-cases/sketching.mdx +0 -38
  28. package/dist/docs/controls/select-attribute/cardselect.mdx +9 -13
  29. package/dist/docs/index.json +1 -1
  30. package/dist/docs/integrations/woocommerce/local-development.mdx +1 -1
  31. package/dist/docs/other-features/side-effects.mdx +8 -11
  32. package/dist/docs/other-features/violation-messages.mdx +52 -56
  33. package/dist/docs/phoenix/configurator-interface.mdx +100 -65
  34. package/dist/docs/phoenix/phoenix-cli.mdx +19 -26
  35. package/dist/docs/phoenix/project-structure.mdx +8 -6
  36. package/dist/docs/phoenix/quickstart.mdx +2 -2
  37. package/dist/docs/phoenix/sdk-builder-workflow.mdx +2 -2
  38. package/dist/docs/phoenix/webhooks.mdx +1 -1
  39. package/dist/domain/core/component/domain-component-optic.d.ts +10 -17
  40. package/dist/domain/core/component/domain-component-optic.js +2 -2
  41. package/dist/domain/core/component/legacy-filter.d.ts +2 -17
  42. package/dist/domain/core/component/system-component-filter.d.ts +21 -16
  43. package/dist/domain/core/invariant/custom-invariants.d.ts +6 -14
  44. package/dist/domain/core/invariant/invariants.d.ts +1 -4
  45. package/dist/domain/core/state/migrations.d.ts +14 -45
  46. package/dist/domain/core/state/migrations.js +1 -1
  47. package/dist/domain/domain-builder.js +1 -1
  48. package/dist/domain/domain-runtime/spec/create-violation-expressions.d.ts +24 -0
  49. package/dist/domain/domain-runtime/spec/create-violation-expressions.js +1 -0
  50. package/dist/domain/domain-runtime/spec/index.d.ts +1 -1
  51. package/dist/domain/domain-runtime/spec/index.js +1 -1
  52. package/dist/domain/domain-runtime/spec/module-checks/index.d.ts +1 -1
  53. package/dist/domain/domain-runtime/spec/module-checks/resolve-invariant-modules.d.ts +2 -2
  54. package/dist/legacy/domain-cli/gen/invariants.js +3 -4
  55. package/dist/legacy/domain-cli/utils/cache.d.ts +1 -1
  56. package/dist/legacy/domain-cli/utils/cache.js +1 -1
  57. package/dist/legacy/phoenix-cli/project-gen/generators/file-templates/agents/claude-md.d.ts +1 -1
  58. package/dist/legacy/phoenix-cli/project-gen/generators/file-templates/agents/cursor-rules.d.ts +1 -1
  59. package/dist/legacy/phoenix-cli/project-gen/generators/file-templates/agents/shared-sdk-content.d.ts +1 -1
  60. package/dist/legacy/phoenix-cli/project-gen/generators/file-templates/agents/shared-sdk-content.js +1 -0
  61. package/dist/legacy/phoenix-cli/project-gen/generators/file-templates/domain-index.js +17 -15
  62. package/dist/phoenix/application-spec/application-spec-builder.js +1 -1
  63. package/dist/phoenix/commands/init.d.ts +4 -4
  64. package/dist/phoenix/commands/init.js +1 -1
  65. package/dist/phoenix/commands/prettier.js +1 -1
  66. package/dist/phoenix/utils/git/index.d.ts +1 -0
  67. package/dist/phoenix/utils/git/index.js +1 -0
  68. package/dist/phoenix/utils/git/is-inside-git-repository.d.ts +6 -0
  69. package/dist/phoenix/utils/git/is-inside-git-repository.js +1 -0
  70. package/dist/phoenix/utils/index.d.ts +1 -0
  71. package/dist/phoenix/utils/index.js +1 -1
  72. package/package.json +3 -3
  73. package/dist/domain/domain-runtime/spec/invariant-builder.d.ts +0 -26
  74. package/dist/domain/domain-runtime/spec/invariant-builder.js +0 -1
@@ -1 +1 @@
1
- import{jsx as e,jsxs as o,Fragment as i}from"react/jsx-runtime";import r from"mui-modal-provider";import{memo as n,useCallback as t,useEffect as a,useMemo as d}from"react";import{match as s}from"ts-pattern";import{InvalidAccessKeyError as l}from"#package/client";import{BuiltInLoadingPhase as u,CommonAnalyticsFactory as m,DomainLifecycleBoundary as c,LoadedDataProvider as f,useAccessService as p,useAnalyticsService as g,useAuthorizedClient as v,useConfiguratorDomainFactory as w,useConfiguratorLoadStatus as y,useConfiguratorRawLoadedData as h,useExpectPhase as I,useLoadedDataActions as j,useLoadingError as x,useLoadingPhase as C,useLogger as b,useRoutingService as k,useSpecAssistant as L}from"#package/react-sdk";import{useConfigurator as U}from"../application-runtime/index.js";import{IntegrationSubscription as M,OnConfiguratorReadyProvider as S,ViewportStateSync as E,useLayoutSystemConfig as F}from"../configurator-context/index.js";import{Layout as R,Legacy as D}from"../ui/index.js";import{LayoutCustomOwnerUi as T,LayoutCustomReadUi as P,LayoutDialog as A}from"../ui/phoenix-layout-elements/index.js";import{ConfiguratorNotFoundPage as O}from"./ConfiguratorNotFoundPage.js";import{DevContextFallback as V}from"./error-boundaries/DevContextFallback.js";import{DevLoadingFallback as q}from"./error-boundaries/DevLoadingFallback.js";import{LoadingErrorBoundary as z}from"./error-boundaries/LoadingErrorBoundary.js";import{useLoad as B}from"./use-load.js";let G=n(n=>{let{viewMode:t}=n,l=F();(()=>{let{assistantSystem:e}=U(),o=null!=L();a(()=>{if(o)return e.activate()},[e,o])})();let{ownerUi:u,readUi:m}=d(()=>s(l.layout).with("simple",()=>({ownerUi:e(D.SimpleOwnerLayout,{}),readUi:e(D.SummaryReadLayout,{})})).with("tabs",()=>({ownerUi:e(D.TabsOwnerLayout,{}),readUi:e(D.SummaryReadLayout,{})})).with("steps",()=>({ownerUi:e(D.StepsOwnerLayout,{}),readUi:e(D.SummaryReadLayout,{})})).with("universal",()=>({ownerUi:e(R,{}),readUi:e(R,{})})).with("custom",()=>({ownerUi:e(T,{}),readUi:e(P,{})})).exhaustive(),[l.layout]);return e(r,{children:o(S,{children:[t?m:u,"universal"===l.layout&&o(i,{children:[e(D.CommonFinalizePage,{}),e(A,{})]})]})})});export const LoadedConfiguratorDetailPage=()=>{I(u.SceneAssets);let{configurationId:i,accessInfo:r}=p(),n=v(),a=k(),d=b(),s=g(),{startConfiguratorLoad:L,completeConfiguratorLoad:U,failConfiguratorLoad:S,resetConfiguratorLoad:F}=j(),{isLoading:R,isError:D}=y(),T=h(),P=w(),A=t(()=>r.viewMode&&void 0!==r.revisionId?n.getConfigurationRevision(i,r.revisionId):n.getConfiguration(i),[r.revisionId,r.viewMode,n,i]),N=t(()=>{L()},[L]),H=t(e=>{U({initialRevisionId:e.revisionId,initialEntities:e.data,modelVersion:e.modelVersion,rootEntityType:e.rootEntityType,schemaIdentity:P}),s.push(m.ConfigurationLoaded(e.configurationId,e.revisionId,r.viewMode?"read":"owner")),d.appendToGlobalContext({configurationId:e.configurationId,revisionId:e.revisionId,mode:r.viewMode}),d.info("Configuration loaded.")},[r.viewMode,s,U,P,d]),J=t(e=>{if(S(e),e instanceof l)return void a.rejectAccessToken(i,r.raw);let o=e instanceof Error?e:Error("Configuration loading failed with an unknown error.",{cause:e});d.error("Configuration loading failed because the API request did not succeed. Verify the configuration ID and access token.",{configurationId:i},o)},[r.raw,i,S,d,a]),K=t(()=>{F()},[F]);return(B({key:[n,i,r.revisionId,r.viewMode],load:A,onStart:N,onSuccess:H,onError:J,onCleanup:K}),C({id:u.DataFetch,label:"Loading configuration…"},R),x(D),D)?e(O,{}):null===T?null:e(f,{value:T,children:e(z,{fallbackRender:o=>e(q,{...o}),children:e(c,{type:"configurator",children:e(z,{FallbackComponent:V,children:o(M,{children:[e(E,{}),e(G,{viewMode:r.viewMode})]})})})})})};
1
+ import{jsx as o,jsxs as r}from"react/jsx-runtime";import e from"mui-modal-provider";import{memo as i,useCallback as n,useEffect as t}from"react";import{InvalidAccessKeyError as a}from"#package/client";import{BuiltInLoadingPhase as d,CommonAnalyticsFactory as s,DomainLifecycleBoundary as l,LoadedDataProvider as u,PhoenixLayoutElement as c,useAccessService as f,useAnalyticsService as m,useAuthorizedClient as g,useConfiguratorDomainFactory as p,useConfiguratorLoadStatus as v,useConfiguratorRawLoadedData as I,useExpectPhase as C,useLoadedDataActions as h,useLoadingError as j,useLoadingPhase as k,useLogger as w,useRoutingService as y,useSpecAssistant as b}from"#package/react-sdk";import{useConfigurator as x}from"../application-runtime/index.js";import{IntegrationSubscription as E,OnConfiguratorReadyProvider as L,ViewportStateSync as D}from"../configurator-context/index.js";import{ConfiguratorNotFoundPage as M}from"./ConfiguratorNotFoundPage.js";import{DefaultConfiguratorLayout as F}from"./DefaultConfiguratorLayout.js";import{DevContextFallback as S}from"./error-boundaries/DevContextFallback.js";import{DevLoadingFallback as T}from"./error-boundaries/DevLoadingFallback.js";import{LoadingErrorBoundary as A}from"./error-boundaries/LoadingErrorBoundary.js";import{useLoad as P}from"./use-load.js";let R=i(()=>((()=>{let{assistantSystem:o}=x(),r=null!=b();t(()=>{if(r)return o.activate()},[o,r])})(),o(e,{children:o(L,{children:o(c,{name:"ConfiguratorLayout",defaultSlot:F})})})));export const LoadedConfiguratorDetailPage=()=>{C(d.SceneAssets);let{configurationId:e,accessInfo:i}=f(),t=g(),c=y(),b=w(),x=m(),{startConfiguratorLoad:L,completeConfiguratorLoad:F,failConfiguratorLoad:V,resetConfiguratorLoad:q}=h(),{isLoading:B,isError:G}=v(),N=I(),z=p(),H=n(()=>i.viewMode&&void 0!==i.revisionId?t.getConfigurationRevision(e,i.revisionId):t.getConfiguration(e),[i.revisionId,i.viewMode,t,e]),J=n(()=>{L()},[L]),K=n(o=>{F({initialRevisionId:o.revisionId,initialEntities:o.data,modelVersion:o.modelVersion,rootEntityType:o.rootEntityType,schemaIdentity:z}),x.push(s.ConfigurationLoaded(o.configurationId,o.revisionId,i.viewMode?"read":"owner")),b.appendToGlobalContext({configurationId:o.configurationId,revisionId:o.revisionId,mode:i.viewMode}),b.info("Configuration loaded.")},[i.viewMode,x,F,z,b]),O=n(o=>{if(V(o),o instanceof a)return void c.rejectAccessToken(e,i.raw);let r=o instanceof Error?o:Error("Configuration loading failed with an unknown error.",{cause:o});b.error("Configuration loading failed because the API request did not succeed. Verify the configuration ID and access token.",{configurationId:e},r)},[i.raw,e,V,b,c]),Q=n(()=>{q()},[q]);return(P({key:[t,e,i.revisionId,i.viewMode],load:H,onStart:J,onSuccess:K,onError:O,onCleanup:Q}),k({id:d.DataFetch,label:"Loading configuration…"},B),j(G),G)?o(M,{}):null===N?null:o(u,{value:N,children:o(A,{fallbackRender:r=>o(T,{...r}),children:o(l,{type:"configurator",children:o(A,{FallbackComponent:S,children:r(E,{children:[o(D,{}),o(R,{})]})})})})})};
@@ -1,4 +1,4 @@
1
- import{jsx as a,jsxs as t,Fragment as o}from"react/jsx-runtime";import{keyframes as e,paperClasses as r,snackbarClasses as d,styled as i,useTheme as n,useThemeProps as s}from"@mui/material";import{AnimatePresence as l,motion as p}from"motion/react";import{useCallback as b,useRef as u}from"react";import{useAccessService as c,useIsFullscreenActive as m}from"#package/react-sdk";import{attrf as h,commonStyles as y,numToPx as g,useInvalidateScrollTimeline as f,useIsEmpty as x,useResponsive as k}from"#package/ui-sdk";import{usePreview as v}from"../../../configurator-context/index.js";import{ASSISTANT_PANEL_SLOT as S,AssistantPanel as E,useIsAssistantPanelOpen as w}from"../../assistant/index.js";import{LayoutSlots as R}from"../slots/index.js";import{DesktopPreview as $}from"./DesktopPreview.js";import{useSceneSafeArea as B}from"./use-scene-safe-area.js";let C="PhxDesktopSidebar",D="minimalist",T="split",I="visible",A="hidden",P="assistant",F={Root:i("div",{name:C,slot:"root",shouldForwardProp:a=>"ownerState"!==a})(({ownerState:a})=>[`
1
+ import{jsx as a,jsxs as t,Fragment as o}from"react/jsx-runtime";import{keyframes as e,paperClasses as r,snackbarClasses as d,styled as i,useTheme as n,useThemeProps as s}from"@mui/material";import{AnimatePresence as l,motion as p}from"motion/react";import{useCallback as b,useRef as u}from"react";import{useAccessService as c,useIsFullscreenActive as h}from"#package/react-sdk";import{attrf as m,commonStyles as y,numToPx as g,useInvalidateScrollTimeline as f,useIsEmpty as x,useResponsive as k}from"#package/ui-sdk";import{usePreview as v}from"../../../configurator-context/index.js";import{ASSISTANT_PANEL_SLOT as S,AssistantPanel as E,useIsAssistantPanelOpen as w}from"../../assistant/index.js";import{LayoutSlots as R}from"../slots/index.js";import{DesktopPreview as $}from"./DesktopPreview.js";import{useLayoutSceneSafeArea as B}from"./use-layout-scene-safe-area.js";let C="PhxDesktopSidebar",D="minimalist",T="split",I="visible",A="hidden",P="assistant",F={Root:i("div",{name:C,slot:"root",shouldForwardProp:a=>"ownerState"!==a})(({ownerState:a})=>[`
2
2
  --phx-sidebar-background: ${a.background};
3
3
  --phx-sidebar-border: ${a.border};
4
4
  --phx-sidebar-filter: ${a.filter};
@@ -38,12 +38,12 @@ import{jsx as a,jsxs as t,Fragment as o}from"react/jsx-runtime";import{keyframes
38
38
  [bottom-start]
39
39
  min-content
40
40
  [bottom-end full-end]
41
- `,inset:0,isolation:"isolate",pointerEvents:"none",position:"absolute","@container style(--inspect: on)":{'& > *, & > * > *, [data-layout*="slot[body.footer]"] > *':{outline:"2px solid hsl(from tomato h s l / 50%)"}},'[data-layout*="interactive"]':{"& > *":{pointerEvents:"auto"}},'[data-layout*="slot[header]"]':{gridArea:"top-start / main-start / top-end / sidebar-end"},'[data-layout*="slot[body]"]':{containerType:"size",display:"grid",gridArea:"main",gridRowStart:"top-end",gridTemplateRows:"min-content 1fr min-content"},'[data-layout*="slot[body.top]"]':{gridArea:"1 / 1 / 2 / -1","& > *":{...y.transition.fadeIn}},'[data-layout*="slot[body.safeSceneArea]"]':{gridArea:"1 / 1 / 3 / -1","@container style(--inspect: on)":{background:"hsl(from lime h s l / 50%)"}},'[data-layout*="slot[body.bottom]"]':{alignItems:"end",display:"grid",gap:t(2),gridArea:"3 / 1 / 4 / -1",gridTemplateColumns:"minmax(0, auto) minmax(60px, 1fr)",justifyContent:"start",position:"relative",'&:has([data-layout="slot[body.viewControls]"]:empty)':{gap:0,gridTemplateColumns:"repeat(2, auto)"}},'[data-layout="slot[body.toolbar]"]':{animation:`${o} auto linear both`,animationTimeline:"scroll(self inline)",display:"flex",margin:t(-2),overflowX:"scroll",overscrollBehavior:"contain",padding:t(2),scrollbarWidth:"none","&::after":{content:'""'}},'[data-layout="slot[body.toolControls]"]':{insetBlockEnd:`calc(100% + ${t(6)})`,position:"absolute","& > *":{...y.transition.fadeIn,transitionDuration:"300ms"}},'[data-layout="slot[body.viewControls]"]':{},'[data-layout="slot[body.logo]"], [data-layout="slot[body.sideEffects]"]':{insetBlockEnd:`calc(100% + ${t(2)})`,position:"absolute"},'[data-layout="slot[body.sideEffects]"]':{insetInline:0,[`.${d.root}`]:{inset:"unset",insetBlockEnd:0,position:"absolute"}},'[data-layout*="slot[sidebar]"]':{display:"grid",gridArea:"top-start / sidebar-start / main-end / sidebar-end",gridTemplateRows:"minmax(0, auto)"},'[data-layout*="slot[footer]"]':{display:"grid",gap:"var(--phx-layout-gap)",gridArea:"bottom-start / full-start / bottom-end / full-end"},'&:has([data-header*="fixed"])':{'[data-layout*="slot[header]"]':{gridArea:"full-start / full-start / top-end / full-end"},'[data-layout*="slot[body]"]':{gridRowStart:"main-start"},'[data-layout*="slot[sidebar]"]':{gridRow:"main-start / main-end"}},'&:has([data-header*="floating"])':{'[data-layout*="slot[header]"]':{gridColumnEnd:"main-end"}},[`&:has([data-sidebar*="${D}"])`]:{'[data-layout*="slot[sidebar]"]':{alignContent:"end",gridRow:"main-start / main-end"}},[`&:has([data-header*="floating"]):has([data-sidebar*="${D}"])`]:{'[data-layout*="slot[header]"]':{gridColumnEnd:"sidebar-end"},'[data-layout*="slot[sidebar]"]':{gridRowStart:"top-end"}},[`&:has([data-sidebar*="${P}"])`]:{'[data-layout*="slot[sidebar]"]':{alignContent:"stretch"}},[`&:has([data-sidebar*="${A}"])`]:{"--phx-layout-gap":0,"--phx-layout-sidebar-track-size":0,'[data-layout*="slot[sidebar]"]':{overflow:"hidden"}}}]}),H=i("div")({gridArea:"1 / 1 / -1 / -1"});export const DesktopLayout=()=>{let e=u(null),r=u(null),{palette:d,shape:i,spacing:p}=n(),{sidebarWidth:y="clamp(360px, 30cqi, 400px)"}=s({props:{},name:j}),{background:g=d.background.paper,border:S=0,borderRadius:L=i.sidebarBorderRadius??i.borderRadius,filter:W=`
41
+ `,inset:0,isolation:"isolate",pointerEvents:"none",position:"absolute","@container style(--inspect: on)":{'& > *, & > * > *, [data-layout*="slot[body.footer]"] > *':{outline:"2px solid hsl(from tomato h s l / 50%)"}},'[data-layout*="interactive"]':{"& > *":{pointerEvents:"auto"}},'[data-layout*="slot[header]"]':{gridArea:"top-start / main-start / top-end / sidebar-end"},'[data-layout*="slot[body]"]':{containerType:"size",display:"grid",gridArea:"main",gridRowStart:"top-end",gridTemplateRows:"min-content 1fr min-content"},'[data-layout*="slot[body.top]"]':{gridArea:"1 / 1 / 2 / -1","& > *":{...y.transition.fadeIn}},'[data-layout*="slot[body.safeSceneArea]"]':{gridArea:"1 / 1 / 3 / -1","@container style(--inspect: on)":{background:"hsl(from lime h s l / 50%)"}},'[data-layout*="slot[body.bottom]"]':{alignItems:"end",display:"grid",gap:t(2),gridArea:"3 / 1 / 4 / -1",gridTemplateColumns:"minmax(0, auto) minmax(60px, 1fr)",justifyContent:"start",position:"relative",'&:has([data-layout="slot[body.viewControls]"]:empty)':{gap:0,gridTemplateColumns:"repeat(2, auto)"}},'[data-layout="slot[body.toolbar]"]':{animation:`${o} auto linear both`,animationTimeline:"scroll(self inline)",display:"flex",margin:t(-2),overflowX:"scroll",overscrollBehavior:"contain",padding:t(2),scrollbarWidth:"none","&::after":{content:'""'}},'[data-layout="slot[body.toolControls]"]':{insetBlockEnd:`calc(100% + ${t(6)})`,position:"absolute","& > *":{...y.transition.fadeIn,transitionDuration:"300ms"}},'[data-layout="slot[body.viewControls]"]':{},'[data-layout="slot[body.logo]"], [data-layout="slot[body.sideEffects]"]':{insetBlockEnd:`calc(100% + ${t(2)})`,position:"absolute"},'[data-layout="slot[body.sideEffects]"]':{insetInline:0,[`.${d.root}`]:{inset:"unset",insetBlockEnd:0,position:"absolute"}},'[data-layout*="slot[sidebar]"]':{display:"grid",gridArea:"top-start / sidebar-start / main-end / sidebar-end",gridTemplateRows:"minmax(0, auto)"},'[data-layout*="slot[footer]"]':{display:"grid",gap:"var(--phx-layout-gap)",gridArea:"bottom-start / full-start / bottom-end / full-end"},'&:has([data-header*="fixed"])':{'[data-layout*="slot[header]"]':{gridArea:"full-start / full-start / top-end / full-end"},'[data-layout*="slot[body]"]':{gridRowStart:"main-start"},'[data-layout*="slot[sidebar]"]':{gridRow:"main-start / main-end"}},'&:has([data-header*="floating"])':{'[data-layout*="slot[header]"]':{gridColumnEnd:"main-end"}},[`&:has([data-sidebar*="${D}"])`]:{'[data-layout*="slot[sidebar]"]':{alignContent:"end",gridRow:"main-start / main-end"}},[`&:has([data-header*="floating"]):has([data-sidebar*="${D}"])`]:{'[data-layout*="slot[header]"]':{gridColumnEnd:"sidebar-end"},'[data-layout*="slot[sidebar]"]':{gridRowStart:"top-end"}},[`&:has([data-sidebar*="${P}"])`]:{'[data-layout*="slot[sidebar]"]':{alignContent:"stretch"}},[`&:has([data-sidebar*="${A}"])`]:{"--phx-layout-gap":0,"--phx-layout-sidebar-track-size":0,'[data-layout*="slot[sidebar]"]':{overflow:"hidden"}}}]}),H=i("div")({gridArea:"1 / 1 / -1 / -1"});export const DesktopLayout=()=>{let e=u(null),r=u(null),{palette:d,shape:i,spacing:p}=n(),{sidebarWidth:y="clamp(360px, 30cqi, 400px)"}=s({props:{},name:j}),{background:g=d.background.paper,border:S=0,borderRadius:L=i.sidebarBorderRadius??i.borderRadius,filter:M=`
42
42
  drop-shadow(0 1px 1.5px hsl(from ${d.common.black} h s l / 12%))
43
43
  drop-shadow(0 1px 0.5px hsl(from ${d.common.black} h s l / 14%))
44
44
  drop-shadow(0 2px 0.5px hsl(from ${d.common.black} h s l / 20%))
45
- `,padding:q=p(2.5),scrollableIndicatorBackground:M=`linear-gradient(
45
+ `,padding:W=p(2.5),scrollableIndicatorBackground:q=`linear-gradient(
46
46
  180deg,
47
47
  hsl(from black h s l / 12%),
48
48
  hsl(from black h s l / 0%) 8px
49
- )`}=s({props:{},name:C}),{hasMiniSidebar:N,hasSplitSidebar:V}=R.useSidebarContent(),X=w(),{accessInfo:G}=c(),J=m(),{isPreview:K,isHidden:O}=v(),Q=!O&&!K,U=!J,{setCanvasPadding:Y,setAnimating:Z}=k(),{containerRef:_,safeAreaRef:aa,update:at}=B(Y,N&&!X,Q),ao=b(()=>{Z(!0)},[Z]),ae=b(()=>{Z(!1),at()},[Z,at]),ar=Q&&U,ad=x(e,{disabled:!ar}),ai=x(r,{disabled:!ar});f(r,{disabled:!ar});let an={background:g,border:S,borderRadius:L,filter:W,isHeaderEmpty:ad,isContentEmpty:ai,padding:q,scrollableIndicatorBackground:M,width:y};return a(o,{children:t(l,{mode:"wait",children:[!O&&K&&a($,{},"preview-layout"),Q&&t(z,{layoutId:"ui-layout",layout:!0,ownerState:{sidebarWidth:y},"data-layout":h({state:{initial:!J,fullscreen:J}}),onLayoutAnimationStart:ao,onLayoutAnimationComplete:ae,children:[a(H,{ref:_}),a("header",{"data-layout":"slot[header]",children:a(R.DesktopHeader,{})}),t("main",{"data-layout":"slot[body]",children:[a("div",{"data-layout":"slot[body.top] interactive",children:a(R.DesktopCallToAction,{})}),a("div",{ref:aa,"data-layout":"slot[body.safeSceneArea]"}),t("div",{"data-layout":"slot[body.bottom] interactive",children:[a("div",{"data-layout":"slot[body.toolbar]",children:a(R.DesktopToolbar,{})}),a("div",{"data-layout":"slot[body.toolControls]",children:!J&&a(R.DesktopToolControls,{})}),a("div",{"data-layout":"slot[body.viewControls]",children:a(R.DesktopViewControls,{})}),a("div",{"data-layout":"slot[body.logo]",children:a(R.DesktopPoweredBy,{})}),a("div",{"data-layout":"slot[body.sideEffects]",children:a(R.DesktopSnackbarsRoot,{})})]})]}),a("aside",{"data-layout":"slot[sidebar]",children:t(F.Root,{ownerState:an,"data-sidebar":h({variant:{[`${D}`]:N,[`${T}`]:V},state:{[`${I}`]:U,[`${A}`]:!U,[`${P}`]:X}}),inert:U?void 0:"",children:[a(F.Tabs,{ownerState:an,"data-sidebar":"slot[tabs]",children:a(R.DesktopSidebarTabs,{})}),a(F.Header,{ref:e,ownerState:an,"data-sidebar":"slot[header]",children:a(R.DesktopSidebarBackButton,{})}),a(F.Body,{ownerState:an,"data-sidebar":"slot[body]",children:a(F.Content,{ref:r,ownerState:an,"data-sidebar":"slot[content]",children:a(R.DesktopSidebarContent,{})})}),a(F.Footer,{ownerState:an,"data-sidebar":"slot[footer]",children:a(R.DesktopSidebarFooter,{})}),a(E,{})]})}),t("footer",{"data-layout":"slot[footer] interactive",children:[G.viewMode&&!J&&a(R.DesktopReadonlyBanner,{}),a(R.DesktopFooter,{})]})]},"interface-layout")]})})};
49
+ )`}=s({props:{},name:C}),{hasMiniSidebar:N,hasSplitSidebar:V}=R.useSidebarContent(),X=w(),{accessInfo:G}=c(),J=h(),{isPreview:K,isHidden:O}=v(),Q=!O&&!K,U=!J,{setAnimating:Y}=k(),{containerRef:Z,safeAreaRef:_,update:aa}=B({enabled:Q,hasMiniSidebar:N&&!X}),at=b(()=>{Y(!0)},[Y]),ao=b(()=>{Y(!1),aa()},[Y,aa]),ae=Q&&U,ar=x(e,{disabled:!ae}),ad=x(r,{disabled:!ae});f(r,{disabled:!ae});let ai={background:g,border:S,borderRadius:L,filter:M,isHeaderEmpty:ar,isContentEmpty:ad,padding:W,scrollableIndicatorBackground:q,width:y};return a(o,{children:t(l,{mode:"wait",children:[!O&&K&&a($,{},"preview-layout"),Q&&t(z,{layoutId:"ui-layout",layout:!0,ownerState:{sidebarWidth:y},"data-layout":m({state:{initial:!J,fullscreen:J}}),onLayoutAnimationStart:at,onLayoutAnimationComplete:ao,children:[a(H,{ref:Z}),a("header",{"data-layout":"slot[header]",children:a(R.DesktopHeader,{})}),t("main",{"data-layout":"slot[body]",children:[a("div",{"data-layout":"slot[body.top] interactive",children:a(R.DesktopCallToAction,{})}),a("div",{ref:_,"data-layout":"slot[body.safeSceneArea]"}),t("div",{"data-layout":"slot[body.bottom] interactive",children:[a("div",{"data-layout":"slot[body.toolbar]",children:a(R.DesktopToolbar,{})}),a("div",{"data-layout":"slot[body.toolControls]",children:!J&&a(R.DesktopToolControls,{})}),a("div",{"data-layout":"slot[body.viewControls]",children:a(R.DesktopViewControls,{})}),a("div",{"data-layout":"slot[body.logo]",children:a(R.DesktopPoweredBy,{})}),a("div",{"data-layout":"slot[body.sideEffects]",children:a(R.DesktopSnackbarsRoot,{})})]})]}),a("aside",{"data-layout":"slot[sidebar]",children:t(F.Root,{ownerState:ai,"data-sidebar":m({variant:{[`${D}`]:N,[`${T}`]:V},state:{[`${I}`]:U,[`${A}`]:!U,[`${P}`]:X}}),inert:U?void 0:"",children:[a(F.Tabs,{ownerState:ai,"data-sidebar":"slot[tabs]",children:a(R.DesktopSidebarTabs,{})}),a(F.Header,{ref:e,ownerState:ai,"data-sidebar":"slot[header]",children:a(R.DesktopSidebarBackButton,{})}),a(F.Body,{ownerState:ai,"data-sidebar":"slot[body]",children:a(F.Content,{ref:r,ownerState:ai,"data-sidebar":"slot[content]",children:a(R.DesktopSidebarContent,{})})}),a(F.Footer,{ownerState:ai,"data-sidebar":"slot[footer]",children:a(R.DesktopSidebarFooter,{})}),a(E,{})]})}),t("footer",{"data-layout":"slot[footer] interactive",children:[G.viewMode&&!J&&a(R.DesktopReadonlyBanner,{}),a(R.DesktopFooter,{})]})]},"interface-layout")]})})};
@@ -1 +1 @@
1
- import{jsx as t}from"react/jsx-runtime";import{useCallback as e,useMemo as o}from"react";import{useResolveLocalizable as a}from"#package/react-sdk";import{Preview as i,useResponsive as r}from"#package/ui-sdk";import{usePresetSelection as n,usePreview as s}from"../../../configurator-context/index.js";import{useSceneSafeArea as p}from"./use-scene-safe-area.js";let m={id:"sdk.preview.customize.title",message:"Customize product"},u={id:"sdk.preview.start.button.label",message:"Start configuring"},c={layoutId:"ui-layout",initial:{opacity:0},animate:{opacity:1},exit:{opacity:0},transition:{layout:{type:"spring",bounce:.2,duration:.6},opacity:{duration:.2,ease:"linear"}}};export const DesktopPreview=l=>{let{slotProps:d={},slots:f}=l,{enter:y}=s(),{hasMultiplePresets:g}=n(),{setCanvasPadding:k,setAnimating:x}=r(),{containerRef:b,safeAreaRef:j,update:w}=p(k,!1),S=a(),v=e(()=>{x(!0)},[x]),A=e(()=>{x(!1),w()},[x,w]),L=o(()=>({...d,root:{...c,onLayoutAnimationStart:v,onLayoutAnimationComplete:A,...d.root}}),[A,v,d]);return t(i,{title:S(m),buttonLabel:S(u),containerRef:b,safeAreaRef:j,withScene:!g,slots:f,slotProps:L,onStart:y})};
1
+ import{jsx as t}from"react/jsx-runtime";import{useCallback as e,useMemo as o}from"react";import{useResolveLocalizable as a}from"#package/react-sdk";import{Preview as i,useResponsive as r}from"#package/ui-sdk";import{usePresetSelection as n,usePreview as s}from"../../../configurator-context/index.js";import{useLayoutSceneSafeArea as p}from"./use-layout-scene-safe-area.js";let u={id:"sdk.preview.customize.title",message:"Customize product"},m={id:"sdk.preview.start.button.label",message:"Start configuring"},c={layoutId:"ui-layout",initial:{opacity:0},animate:{opacity:1},exit:{opacity:0},transition:{layout:{type:"spring",bounce:.2,duration:.6},opacity:{duration:.2,ease:"linear"}}};export const DesktopPreview=l=>{let{slotProps:d={},slots:f}=l,{enter:y}=s(),{hasMultiplePresets:g}=n(),{setAnimating:b}=r(),{containerRef:k,safeAreaRef:x,update:S}=p({enabled:!0,hasMiniSidebar:!1}),j=a(),w=e(()=>{b(!0)},[b]),v=e(()=>{b(!1),S()},[b,S]),A=o(()=>({...d,root:{...c,onLayoutAnimationStart:w,onLayoutAnimationComplete:v,...d.root}}),[v,w,d]);return t(i,{title:j(u),buttonLabel:j(m),containerRef:k,safeAreaRef:x,withScene:!g,slots:f,slotProps:A,onStart:y})};
@@ -1,11 +1,11 @@
1
- import{jsx as t,jsxs as a,Fragment as e}from"react/jsx-runtime";import{snackbarClasses as o,styled as i,useTheme as r,useThemeProps as n}from"@mui/material";import d from"lodash/noop.js";import{AnimatePresence as s}from"motion/react";import{useRef as l}from"react";import{useAccessService as m,useEagerObservableSelector as c,useIsFullscreenActive as p}from"#package/react-sdk";import{attrf as u,commonStyles as b,numToPx as h,useIsEmpty as g,useResponsive as f,useViewportSize as y}from"#package/ui-sdk";import{useConfigurator as x}from"../../../application-runtime/index.js";import{usePreview as v}from"../../../configurator-context/index.js";import{ASSISTANT_PANEL_SLOT as w,AssistantPanel as S,useIsAssistantPanelOpen as $}from"../../assistant/index.js";import{LayoutSlots as k}from"../slots/index.js";import{MobileHeader as C}from"../slots/slots.js";import{MobilePreview as F}from"./MobilePreview.js";import{useSceneSafeArea as M}from"./use-scene-safe-area.js";let T="visible",I="hidden",R=i("div",{name:"PhxMobileHeader",slot:"root"})(({theme:{spacing:t}})=>({...b.transition.fadeInFrom,alignItems:"center",display:"flex",gap:t(1),justifyContent:"space-between",position:"relative","@container style(--inspect: on)":{background:"hsl(from tomato h s l / 50%)"},'[data-header*="slot"]':{display:"flex",gap:t(2),"& > *":{pointerEvents:"auto"}},'[data-header="slot[center]"]':{display:"grid",inset:0,placeItems:"center",position:"absolute"},[`&[data-header*="${T}"]`]:{opacity:1,transitionDuration:"200ms, 300ms",transitionTimingFunction:"linear, ease-out",translate:"0 0"},[`&[data-header*="${I}"]`]:{opacity:0,transitionDuration:"100ms, 100ms",transitionTimingFunction:"linear, ease-in",translate:"0 -60%"}})),B="visible",E="hidden",P=i("div",{name:"PhxMobileControls",slot:"root"})(({theme:{spacing:t}})=>({alignItems:"end",display:"flex",position:"relative","@container style(--inspect: on)":{background:"hsl(from tomato h s l / 50%)"},'[data-controls*="slot"]':{"& > *":{pointerEvents:"auto"}},'[data-controls="slot[toolControls]"]':{...b.transition.fadeInFrom,"&:not(:empty)":{marginInlineEnd:t(2)},"& > *":{...b.transition.fadeIn,transitionDelay:"300ms",transitionDuration:"300ms"}},'[data-controls="slot[viewControls]"]':{...b.transition.fadeInFrom,marginInlineStart:"auto"},'[data-controls="slot[toolbar]"]':{"&:not(:empty)":{marginInlineStart:t(2)}},[`&[data-controls*="${B}"]`]:{'[data-controls="slot[toolControls]"], [data-controls="slot[viewControls]"]':{opacity:1,transitionDuration:"200ms, 300ms",transitionTimingFunction:"linear, ease-out",translate:"0 0"}},[`&[data-controls*="${E}"]`]:{'[data-controls="slot[toolControls]"], [data-controls="slot[viewControls]"]':{opacity:0,transitionDuration:"100ms, 100ms",transitionTimingFunction:"linear, ease-in",translate:"0 60%"}}})),D="PhxMobileSidebar",j="visible",A="hidden",z="assistant",H={Root:i("div",{name:D,slot:"root",shouldForwardProp:t=>"ownerState"!==t})(({ownerState:t})=>[`
1
+ import{jsx as t,jsxs as a,Fragment as e}from"react/jsx-runtime";import{snackbarClasses as o,styled as i,useTheme as r,useThemeProps as n}from"@mui/material";import{AnimatePresence as d}from"motion/react";import{useRef as s}from"react";import{useAccessService as l,useEagerObservableSelector as m,useIsFullscreenActive as c}from"#package/react-sdk";import{attrf as p,commonStyles as u,numToPx as b,useIsEmpty as h,useViewportSize as g}from"#package/ui-sdk";import{useConfigurator as f}from"../../../application-runtime/index.js";import{usePreview as y}from"../../../configurator-context/index.js";import{ASSISTANT_PANEL_SLOT as x,AssistantPanel as v,useIsAssistantPanelOpen as w}from"../../assistant/index.js";import{LayoutSlots as S}from"../slots/index.js";import{MobileHeader as $}from"../slots/slots.js";import{MobilePreview as k}from"./MobilePreview.js";import{useLayoutSceneSafeArea as C}from"./use-layout-scene-safe-area.js";let F="visible",M="hidden",T=i("div",{name:"PhxMobileHeader",slot:"root"})(({theme:{spacing:t}})=>({...u.transition.fadeInFrom,alignItems:"center",display:"flex",gap:t(1),justifyContent:"space-between",position:"relative","@container style(--inspect: on)":{background:"hsl(from tomato h s l / 50%)"},'[data-header*="slot"]':{display:"flex",gap:t(2),"& > *":{pointerEvents:"auto"}},'[data-header="slot[center]"]':{display:"grid",inset:0,placeItems:"center",position:"absolute"},[`&[data-header*="${F}"]`]:{opacity:1,transitionDuration:"200ms, 300ms",transitionTimingFunction:"linear, ease-out",translate:"0 0"},[`&[data-header*="${M}"]`]:{opacity:0,transitionDuration:"100ms, 100ms",transitionTimingFunction:"linear, ease-in",translate:"0 -60%"}})),I="visible",R="hidden",B=i("div",{name:"PhxMobileControls",slot:"root"})(({theme:{spacing:t}})=>({alignItems:"end",display:"flex",position:"relative","@container style(--inspect: on)":{background:"hsl(from tomato h s l / 50%)"},'[data-controls*="slot"]':{"& > *":{pointerEvents:"auto"}},'[data-controls="slot[toolControls]"]':{...u.transition.fadeInFrom,"&:not(:empty)":{marginInlineEnd:t(2)},"& > *":{...u.transition.fadeIn,transitionDelay:"300ms",transitionDuration:"300ms"}},'[data-controls="slot[viewControls]"]':{...u.transition.fadeInFrom,marginInlineStart:"auto"},'[data-controls="slot[toolbar]"]':{"&:not(:empty)":{marginInlineStart:t(2)}},[`&[data-controls*="${I}"]`]:{'[data-controls="slot[toolControls]"], [data-controls="slot[viewControls]"]':{opacity:1,transitionDuration:"200ms, 300ms",transitionTimingFunction:"linear, ease-out",translate:"0 0"}},[`&[data-controls*="${R}"]`]:{'[data-controls="slot[toolControls]"], [data-controls="slot[viewControls]"]':{opacity:0,transitionDuration:"100ms, 100ms",transitionTimingFunction:"linear, ease-in",translate:"0 60%"}}})),E="PhxMobileSidebar",P="visible",D="hidden",j="assistant",A={Root:i("div",{name:E,slot:"root",shouldForwardProp:t=>"ownerState"!==t})(({ownerState:t})=>[`
2
2
  --phx-sidebar-background: ${t.background};
3
3
  --phx-sidebar-padding: ${t.padding};
4
4
  --phx-sidebar-radius: ${t.borderRadius}px;
5
- `,{...b.transition.fadeInFrom,background:"var(--phx-sidebar-background)",borderStartStartRadius:"var(--phx-sidebar-radius)",borderStartEndRadius:"var(--phx-sidebar-radius)",display:"grid",gridTemplateColumns:"minmax(0, 1fr)",gridTemplateRows:"min-content minmax(0, 1fr) min-content",position:"relative","& > *":{pointerEvents:"auto"},"@container style(--inspect: on)":{background:"hsl(from gold h s l / 50%)"},'&:has([data-sidebar*="slot[content]"])':{...t.isContentEmpty&&{"--phx-sidebar-radius":0,'[data-sidebar*="slot[header]"]':{paddingBlock:0,"& > *":{display:"none"}}}},[`&[data-sidebar*="${j}"]`]:{opacity:1,transitionDuration:"200ms, 300ms",transitionTimingFunction:"linear, ease-out",translate:"0 0"},[`&[data-sidebar*="${A}"]`]:{opacity:0,transitionDuration:"100ms, 100ms",transitionTimingFunction:"linear, ease-in",translate:"0 60%"},[`&[data-sidebar*="${z}"] > :not([data-sidebar="${w}"])`]:{visibility:"hidden"}}]),Header:i("header",{name:D,slot:"header",shouldForwardProp:t=>"ownerState"!==t})(({theme:{spacing:t}})=>({alignItems:"center",borderStartStartRadius:"inherit",borderStartEndRadius:"inherit",display:"grid",gap:t(1),gridTemplateColumns:"repeat(2, minmax(0, 1fr))",paddingBlock:"calc(var(--phx-sidebar-padding) * 0.5)",paddingInline:"var(--phx-sidebar-padding)","& > *":{...b.transition.fadeIn,transitionDelay:"100ms",transitionDuration:"300ms"},'[data-sidebar="slot[header.start]"]':{},'[data-sidebar="slot[header.end]"]':{justifySelf:"end"}})),Body:i("div",{name:D,slot:"body",shouldForwardProp:t=>"ownerState"!==t})({display:"grid",gridTemplateRows:"minmax(0, 1fr)"}),Content:i("div",{name:D,slot:"content",shouldForwardProp:t=>"ownerState"!==t})(({theme:{spacing:t}})=>({...b.layout.normalizeScrollableContainer,display:"grid",gap:t(2),gridAutoRows:"min-content",paddingBlock:"calc(var(--phx-sidebar-padding) * 0.5)",paddingInline:"var(--phx-sidebar-padding)","&:empty":{paddingBlock:0}})),Tabs:i("div",{name:D,slot:"tabs",shouldForwardProp:t=>"ownerState"!==t})(({theme:{palette:t}})=>({borderBlockStart:`1px solid ${t.divider}`,paddingBlock:"calc(var(--phx-sidebar-padding) * 0.5)",paddingInline:"calc(var(--phx-sidebar-padding) * 0.75)","&:is(:empty)":{border:0,padding:0}})),Footer:i("footer",{name:D,slot:"footer",shouldForwardProp:t=>"ownerState"!==t})(({theme:{palette:t}})=>({borderBlockStart:`1px solid ${t.divider}`,paddingBlock:"calc(var(--phx-sidebar-padding) * 0.5)",paddingInline:"var(--phx-sidebar-padding)","&:is(:empty)":{borderColor:"transparent",paddingBlock:0}}))};export const PhxMobileLayoutName="PhxMobileLayout";let L="initial",q="fullscreen",N="min(480px, 50cqb)",V=["auto","min-content","max-content","fit-content"],G=i("div",{name:"PhxMobileLayout",slot:"root",shouldForwardProp:t=>"ownerState"!==t})(({ownerState:t,theme:{spacing:a}})=>[`
5
+ `,{...u.transition.fadeInFrom,background:"var(--phx-sidebar-background)",borderStartStartRadius:"var(--phx-sidebar-radius)",borderStartEndRadius:"var(--phx-sidebar-radius)",display:"grid",gridTemplateColumns:"minmax(0, 1fr)",gridTemplateRows:"min-content minmax(0, 1fr) min-content",position:"relative","& > *":{pointerEvents:"auto"},"@container style(--inspect: on)":{background:"hsl(from gold h s l / 50%)"},'&:has([data-sidebar*="slot[content]"])':{...t.isContentEmpty&&{"--phx-sidebar-radius":0,'[data-sidebar*="slot[header]"]':{paddingBlock:0,"& > *":{display:"none"}}}},[`&[data-sidebar*="${P}"]`]:{opacity:1,transitionDuration:"200ms, 300ms",transitionTimingFunction:"linear, ease-out",translate:"0 0"},[`&[data-sidebar*="${D}"]`]:{opacity:0,transitionDuration:"100ms, 100ms",transitionTimingFunction:"linear, ease-in",translate:"0 60%"},[`&[data-sidebar*="${j}"] > :not([data-sidebar="${x}"])`]:{visibility:"hidden"}}]),Header:i("header",{name:E,slot:"header",shouldForwardProp:t=>"ownerState"!==t})(({theme:{spacing:t}})=>({alignItems:"center",borderStartStartRadius:"inherit",borderStartEndRadius:"inherit",display:"grid",gap:t(1),gridTemplateColumns:"repeat(2, minmax(0, 1fr))",paddingBlock:"calc(var(--phx-sidebar-padding) * 0.5)",paddingInline:"var(--phx-sidebar-padding)","& > *":{...u.transition.fadeIn,transitionDelay:"100ms",transitionDuration:"300ms"},'[data-sidebar="slot[header.start]"]':{},'[data-sidebar="slot[header.end]"]':{justifySelf:"end"}})),Body:i("div",{name:E,slot:"body",shouldForwardProp:t=>"ownerState"!==t})({display:"grid",gridTemplateRows:"minmax(0, 1fr)"}),Content:i("div",{name:E,slot:"content",shouldForwardProp:t=>"ownerState"!==t})(({theme:{spacing:t}})=>({...u.layout.normalizeScrollableContainer,display:"grid",gap:t(2),gridAutoRows:"min-content",paddingBlock:"calc(var(--phx-sidebar-padding) * 0.5)",paddingInline:"var(--phx-sidebar-padding)","&:empty":{paddingBlock:0}})),Tabs:i("div",{name:E,slot:"tabs",shouldForwardProp:t=>"ownerState"!==t})(({theme:{palette:t}})=>({borderBlockStart:`1px solid ${t.divider}`,paddingBlock:"calc(var(--phx-sidebar-padding) * 0.5)",paddingInline:"calc(var(--phx-sidebar-padding) * 0.75)","&:is(:empty)":{border:0,padding:0}})),Footer:i("footer",{name:E,slot:"footer",shouldForwardProp:t=>"ownerState"!==t})(({theme:{palette:t}})=>({borderBlockStart:`1px solid ${t.divider}`,paddingBlock:"calc(var(--phx-sidebar-padding) * 0.5)",paddingInline:"var(--phx-sidebar-padding)","&:is(:empty)":{borderColor:"transparent",paddingBlock:0}}))};export const PhxMobileLayoutName="PhxMobileLayout";let z="initial",H="fullscreen",L="min(480px, 50cqb)",q=["auto","min-content","max-content","fit-content"],N=i("div",{name:"PhxMobileLayout",slot:"root",shouldForwardProp:t=>"ownerState"!==t})(({ownerState:t,theme:{spacing:a}})=>[`
6
6
  --inspect: off; // 🕹️ inspection mode toggle
7
7
 
8
- --phx-layout-sidebar-track-size: ${h(t.sidebarHeight)};
8
+ --phx-layout-sidebar-track-size: ${b(t.sidebarHeight)};
9
9
  --phx-layout-gutter: ${a(2)};
10
10
  `,{display:"grid",gridTemplateColumns:`
11
11
  [full-start]
@@ -39,4 +39,4 @@ import{jsx as t,jsxs as a,Fragment as e}from"react/jsx-runtime";import{snackbarC
39
39
  [footer-end]
40
40
  var(--phx-layout-gutter)
41
41
  [full-end]
42
- `},'[data-layout*="slot[body.header]"]':{gridArea:"header-start / main-start / header-end / main-end"},'[data-layout*="slot[body.footer]"]':{gridArea:"footer-start / main-start / footer-end / main-end",position:"relative"},'[data-layout*="slot[body.safeSceneArea]"]':{gridArea:"full","@container style(--inspect: on)":{background:"hsl(from lime h s l / 50%)"}},'[data-layout="slot[body.sideEffects]"]':{insetBlockEnd:`calc(100% + ${a(2)})`,position:"absolute"},'[data-layout*="slot[sidebar]"]':{display:"grid",gridArea:"sidebar-start / full-start / sidebar-end / full-end",gridTemplateColumns:"minmax(0, 1fr)",gridTemplateRows:"minmax(0, auto)"},'[data-layout*="slot[footer]"]':{gridArea:"footer-start / full-start / footer-end / full-end",zIndex:1},'&:has([data-sidebar*="slot[content]"])':{...t.isContentEmpty&&{"--phx-layout-sidebar-track-size":"min-content"}},[`&[data-layout*="${L}"]`]:{transitionDelay:"200ms",transitionDuration:"300ms"},[`&[data-layout*="${q}"]`]:{transitionDelay:"0ms",transitionDuration:"300ms"},[`&:has([data-sidebar*="${A}"])[class]`]:{"--phx-layout-sidebar-track-size":0}},null!=t.assistantFocusHeight&&{'[data-layout*="slot[sidebar]"]':{alignSelf:"start",blockSize:`min(100%, ${t.assistantFocusHeight}px)`,gridRow:"full-start / full-end",zIndex:2}}]),J=i("div")({gridArea:"1 / 1 / -1 / -1"}),K=t=>({inert:t?"":void 0});export const MobileLayout=()=>{let o=l(null),{palette:i,shape:b,spacing:h}=r(),{sidebarHeight:w=N}=n({props:{},name:"PhxMobileLayout"}),{background:O=i.background.paper,borderRadius:Q=b.sidebarBorderRadius??b.borderRadius,padding:U=h(2)}=n({props:{},name:D}),{accessInfo:W}=m(),X=p(),{isPreview:Y,isHidden:Z}=v(),_=!Z&&!Y,tt=!X&&_,ta=!X&&_,te=!X,{setCanvasPadding:to}=f(),{containerRef:ti,safeAreaRef:tr}=M(_?to:d,!1),tn=g(o,{disabled:!te}),{assistantSystem:td}=x(),ts=$(),tl=c(td.panel$,t=>t.isInputFocused,[]),tm=ts&&te&&tl,tc=y(tm),tp=tn&&!ts,tu={isContentEmpty:tp,sidebarHeight:ts?V.includes(w)?N:w:w,assistantFocusHeight:tm?tc?.[1]:void 0},tb={background:O,borderRadius:Q,padding:U,isContentEmpty:tp};return a(e,{children:[t(s,{initial:!1,children:!Z&&Y&&t(F,{})}),a(G,{ownerState:tu,"data-layout":u({state:{[`${L}`]:!X,[`${q}`]:X}}),...K(!_),children:[t(J,{ref:ti}),t("div",{"data-layout":"slot[sideEffects]",children:t(k.MobileSnackbarsRoot,{})}),a("main",{"data-layout":"slot[body]",children:[t("header",{"data-layout":"slot[body.header]",children:a(R,{"data-header":u({state:{[`${T}`]:tt,[`${I}`]:!tt}}),...K(!tt),children:[t("div",{"data-header":"slot[start]",children:t(C,{})}),t("div",{"data-header":"slot[center]",children:t(k.MobileCallToAction,{})}),a("div",{"data-header":"slot[end]",children:[W.viewMode&&!X&&t(k.MobileReadonlyBanner,{}),t(k.MobileHamburgerMenu,{})]})]})}),t("div",{ref:tr,"data-layout":"slot[body.safeSceneArea]"}),t("div",{"data-layout":"slot[body.footer] interactive",children:a(P,{"data-controls":u({state:{[`${B}`]:ta,[`${E}`]:!ta}}),children:[t("div",{"data-controls":"slot[toolControls]",...K(!ta),children:t(k.MobileToolControls,{})}),t("div",{"data-controls":"slot[viewControls]",...K(!ta),children:t(k.MobileViewControls,{})}),t("div",{"data-controls":"slot[toolbar]",children:_&&t(k.MobileToolbar,{})})]})})]}),t("aside",{"data-layout":"slot[sidebar]",children:a(H.Root,{ownerState:tb,"data-sidebar":u({state:{[`${j}`]:te,[`${A}`]:!te,[`${z}`]:ts}}),...K(!te),children:[a(H.Header,{ownerState:tb,"data-sidebar":"slot[header]",children:[t("div",{"data-sidebar":"slot[header.start]",children:t(k.MobileSidebarBackButton,{})}),t("div",{"data-sidebar":"slot[header.end]",children:t(k.MobilePoweredBy,{})})]}),t(H.Body,{ownerState:tb,"data-sidebar":"slot[body]",children:t(H.Content,{ref:o,ownerState:tb,"data-sidebar":"slot[content]",children:t(k.MobileSidebarContent,{})})}),t(H.Tabs,{ownerState:tb,"data-sidebar":"slot[tabs]",children:t(k.MobileTabs,{})}),t(H.Footer,{ownerState:tb,"data-sidebar":"slot[footer]",children:t(k.MobileSidebarFooter,{})}),t(S,{})]})}),t("footer",{"data-layout":"slot[footer] interactive",children:t(k.MobileFooter,{})})]})]})};
42
+ `},'[data-layout*="slot[body.header]"]':{gridArea:"header-start / main-start / header-end / main-end"},'[data-layout*="slot[body.footer]"]':{gridArea:"footer-start / main-start / footer-end / main-end",position:"relative"},'[data-layout*="slot[body.safeSceneArea]"]':{gridArea:"full","@container style(--inspect: on)":{background:"hsl(from lime h s l / 50%)"}},'[data-layout="slot[body.sideEffects]"]':{insetBlockEnd:`calc(100% + ${a(2)})`,position:"absolute"},'[data-layout*="slot[sidebar]"]':{display:"grid",gridArea:"sidebar-start / full-start / sidebar-end / full-end",gridTemplateColumns:"minmax(0, 1fr)",gridTemplateRows:"minmax(0, auto)"},'[data-layout*="slot[footer]"]':{gridArea:"footer-start / full-start / footer-end / full-end",zIndex:1},'&:has([data-sidebar*="slot[content]"])':{...t.isContentEmpty&&{"--phx-layout-sidebar-track-size":"min-content"}},[`&[data-layout*="${z}"]`]:{transitionDelay:"200ms",transitionDuration:"300ms"},[`&[data-layout*="${H}"]`]:{transitionDelay:"0ms",transitionDuration:"300ms"},[`&:has([data-sidebar*="${D}"])[class]`]:{"--phx-layout-sidebar-track-size":0}},null!=t.assistantFocusHeight&&{'[data-layout*="slot[sidebar]"]':{alignSelf:"start",blockSize:`min(100%, ${t.assistantFocusHeight}px)`,gridRow:"full-start / full-end",zIndex:2}}]),V=i("div")({gridArea:"1 / 1 / -1 / -1"}),G=t=>({inert:t?"":void 0});export const MobileLayout=()=>{let o=s(null),{palette:i,shape:u,spacing:b}=r(),{sidebarHeight:x=L}=n({props:{},name:"PhxMobileLayout"}),{background:J=i.background.paper,borderRadius:K=u.sidebarBorderRadius??u.borderRadius,padding:O=b(2)}=n({props:{},name:E}),{accessInfo:Q}=l(),U=c(),{isPreview:W,isHidden:X}=y(),Y=!X&&!W,Z=!U&&Y,_=!U&&Y,tt=!U,{containerRef:ta,safeAreaRef:te}=C({enabled:Y,hasMiniSidebar:!1}),to=h(o,{disabled:!tt}),{assistantSystem:ti}=f(),tr=w(),tn=m(ti.panel$,t=>t.isInputFocused,[]),td=tr&&tt&&tn,ts=g(td),tl=to&&!tr,tm={isContentEmpty:tl,sidebarHeight:tr?q.includes(x)?L:x:x,assistantFocusHeight:td?ts?.[1]:void 0},tc={background:J,borderRadius:K,padding:O,isContentEmpty:tl};return a(e,{children:[t(d,{initial:!1,children:!X&&W&&t(k,{})}),a(N,{ownerState:tm,"data-layout":p({state:{[`${z}`]:!U,[`${H}`]:U}}),...G(!Y),children:[t(V,{ref:ta}),t("div",{"data-layout":"slot[sideEffects]",children:t(S.MobileSnackbarsRoot,{})}),a("main",{"data-layout":"slot[body]",children:[t("header",{"data-layout":"slot[body.header]",children:a(T,{"data-header":p({state:{[`${F}`]:Z,[`${M}`]:!Z}}),...G(!Z),children:[t("div",{"data-header":"slot[start]",children:t($,{})}),t("div",{"data-header":"slot[center]",children:t(S.MobileCallToAction,{})}),a("div",{"data-header":"slot[end]",children:[Q.viewMode&&!U&&t(S.MobileReadonlyBanner,{}),t(S.MobileHamburgerMenu,{})]})]})}),t("div",{ref:te,"data-layout":"slot[body.safeSceneArea]"}),t("div",{"data-layout":"slot[body.footer] interactive",children:a(B,{"data-controls":p({state:{[`${I}`]:_,[`${R}`]:!_}}),children:[t("div",{"data-controls":"slot[toolControls]",...G(!_),children:t(S.MobileToolControls,{})}),t("div",{"data-controls":"slot[viewControls]",...G(!_),children:t(S.MobileViewControls,{})}),t("div",{"data-controls":"slot[toolbar]",children:Y&&t(S.MobileToolbar,{})})]})})]}),t("aside",{"data-layout":"slot[sidebar]",children:a(A.Root,{ownerState:tc,"data-sidebar":p({state:{[`${P}`]:tt,[`${D}`]:!tt,[`${j}`]:tr}}),...G(!tt),children:[a(A.Header,{ownerState:tc,"data-sidebar":"slot[header]",children:[t("div",{"data-sidebar":"slot[header.start]",children:t(S.MobileSidebarBackButton,{})}),t("div",{"data-sidebar":"slot[header.end]",children:t(S.MobilePoweredBy,{})})]}),t(A.Body,{ownerState:tc,"data-sidebar":"slot[body]",children:t(A.Content,{ref:o,ownerState:tc,"data-sidebar":"slot[content]",children:t(S.MobileSidebarContent,{})})}),t(A.Tabs,{ownerState:tc,"data-sidebar":"slot[tabs]",children:t(S.MobileTabs,{})}),t(A.Footer,{ownerState:tc,"data-sidebar":"slot[footer]",children:t(S.MobileSidebarFooter,{})}),t(v,{})]})}),t("footer",{"data-layout":"slot[footer] interactive",children:t(S.MobileFooter,{})})]})]})};
@@ -1 +1 @@
1
- import{jsx as t}from"react/jsx-runtime";import e from"lodash/noop.js";import{useCallback as o,useMemo as i}from"react";import{useResolveLocalizable as r}from"#package/react-sdk";import{Preview as a,useResponsive as s}from"#package/ui-sdk";import{usePresetSelection as n,usePreview as m}from"../../../configurator-context/index.js";import{useSceneSafeArea as p}from"./use-scene-safe-area.js";let c={id:"sdk.preview.customize.title",message:"Customize product"},l={id:"sdk.preview.start.button.label",message:"Start configuring"},u={initial:{opacity:0},animate:{opacity:1},exit:{opacity:0},transition:{opacity:{duration:.1,ease:"linear"}}};export const MobilePreview=f=>{let{slotProps:d={},slots:g}=f,{enter:k,isPreview:x}=m(),{hasMultiplePresets:b}=n(),{setCanvasPadding:j}=s(),{containerRef:y,safeAreaRef:w,update:v}=p(x?j:e,!1),S=r(),h=o(()=>{v()},[v]),z=i(()=>({...d,root:{...u,onLayoutAnimationComplete:h,...d.root}}),[h,d]);return t(a,{title:S(c),buttonLabel:S(l),containerRef:y,safeAreaRef:w,withScene:!b,slots:g,slotProps:z,onStart:k})};
1
+ import{jsx as t}from"react/jsx-runtime";import{useCallback as e,useMemo as o}from"react";import{useResolveLocalizable as i}from"#package/react-sdk";import{Preview as a}from"#package/ui-sdk";import{usePresetSelection as r,usePreview as s}from"../../../configurator-context/index.js";import{useLayoutSceneSafeArea as n}from"./use-layout-scene-safe-area.js";let m={id:"sdk.preview.customize.title",message:"Customize product"},p={id:"sdk.preview.start.button.label",message:"Start configuring"},c={initial:{opacity:0},animate:{opacity:1},exit:{opacity:0},transition:{opacity:{duration:.1,ease:"linear"}}};export const MobilePreview=l=>{let{slotProps:u={},slots:d}=l,{enter:f,isPreview:b}=s(),{hasMultiplePresets:g}=r(),{containerRef:k,safeAreaRef:x,update:y}=n({enabled:b,hasMiniSidebar:!1}),j=i(),w=e(()=>{y()},[y]),S=o(()=>({...u,root:{...c,onLayoutAnimationComplete:w,...u.root}}),[w,u]);return t(a,{title:j(m),buttonLabel:j(p),containerRef:k,safeAreaRef:x,withScene:!g,slots:d,slotProps:S,onStart:f})};
@@ -0,0 +1,47 @@
1
+ /** What a built-in layout tells the safe-area measurement about itself. */
2
+ export interface LayoutSceneSafeAreaOptions {
3
+ /** Whether the layout owns the canvas padding now. See `useLayoutSceneSafeArea`. */
4
+ readonly enabled: boolean;
5
+ /** Whether the sidebar is collapsed to its mini form, which the scene clears only in part. */
6
+ readonly hasMiniSidebar: boolean;
7
+ }
8
+ /**
9
+ * Measures the gap between a full-area container and an inner "safe area" element,
10
+ * and writes the resulting gaps to the responsive context as canvas padding — letting the
11
+ * 3D scene render only in the region not covered by overlay UI (preview body, sidebar, etc.).
12
+ *
13
+ * The implementation behind `useSceneSafeArea`, with the two things only the built-in
14
+ * layouts need: `enabled` and `hasMiniSidebar`.
15
+ *
16
+ * Returns:
17
+ * - `containerRef` — attach to the full-area measurement element.
18
+ * - `safeAreaRef` — attach to the region the scene should remain visible in.
19
+ * - `update` — trigger a manual re-measure on demand.
20
+ *
21
+ * `containerRef` / `safeAreaRef` are *callback* refs: the `ResizeObserver` (re)connects
22
+ * whenever a node attaches or detaches. This matters because the owning layout can mount
23
+ * late — `AnimatePresence mode="wait"` only mounts the interface after the preview has
24
+ * finished exiting, well after a one-shot mount effect would have run and bailed on null
25
+ * refs (leaving the scene stuck at the preview's padding).
26
+ *
27
+ * `enabled` is for a layout that stays mounted while another one owns the padding (e.g. the
28
+ * mobile interface while previewing, or a preview that lingers through its exit fade). While
29
+ * it is `false` the observer is disconnected, and a measurement started by the `update` of that
30
+ * render or by a pending retry writes nothing. An `update` that was created while the hook was
31
+ * enabled, such as a handler an animation already holds, still measures and writes. Turning
32
+ * `enabled` back on reconnects the observer, which measures again.
33
+ *
34
+ * `getBoundingClientRect()` returns *visually transformed* rects, so `measure` skips
35
+ * transformed frames automatically (retrying until the transform clears) to avoid feeding
36
+ * the scene a scaled gap mid layout animation.
37
+ *
38
+ * `update` exists for the complementary case: when only an ancestor's `transform` changes
39
+ * (e.g. motion FLIP settling), `ResizeObserver` doesn't fire, so nothing re-triggers
40
+ * `measure`. Call `update()` once the transform settles (e.g. from
41
+ * `onLayoutAnimationComplete`) to re-measure against the actual layout box.
42
+ */
43
+ export declare const useLayoutSceneSafeArea: (options: LayoutSceneSafeAreaOptions) => {
44
+ containerRef: (node: HTMLDivElement | null) => void;
45
+ safeAreaRef: (node: HTMLDivElement | null) => void;
46
+ update: () => void;
47
+ };
@@ -0,0 +1 @@
1
+ import{useCallback as t,useEffect as e,useRef as r}from"react";import{canvasPaddingComponent as n}from"#package/domain";import{useFirstComponent as o}from"#package/react-sdk";import{useResponsive as a}from"#package/ui-sdk";export const useLayoutSceneSafeArea=c=>{let{enabled:u,hasMiniSidebar:i}=c,{setCanvasPadding:m}=a(),l=r(null),s=r(null),f=r(null),h=r(null),p=r(0),g=r(()=>{}),b=o({componentTypes:[n]}),d=t(()=>{let t=s.current,e=f.current;if(!u||!t||!e)return;let r=t.getBoundingClientRect(),n=e.getBoundingClientRect();if(Math.abs(r.width-t.offsetWidth)>1||Math.abs(r.height-t.offsetHeight)>1){if(p.current+=1,p.current>60){p.current=0;return}l.current&&cancelAnimationFrame(l.current),l.current=requestAnimationFrame(()=>g.current());return}p.current=0;let o={bottom:Math.max(0,r.bottom-n.bottom),left:Math.max(0,n.left-r.left),right:Math.max(0,r.right-n.right),top:Math.max(0,n.top-r.top)},a=i?.3:1,c=b?.state.bottom??1,h=b?.state.left??1,d=b?.state.right??a,A=b?.state.top??1;m({bottom:o.bottom*c,left:o.left*h,right:o.right*d,top:o.top*A})},[u,i,b?.state.bottom,b?.state.left,b?.state.right,b?.state.top,m]);g.current=d;let A=t(()=>{l.current&&cancelAnimationFrame(l.current),l.current=requestAnimationFrame(d)},[d]),M=t(()=>{h.current?.disconnect(),h.current=null},[]),k=t(()=>{let t=s.current,e=f.current;if(!u||!t||!e)return void M();M();let r=new ResizeObserver(A);r.observe(t),r.observe(e),h.current=r},[M,u,A]),x=t(t=>{s.current=t,k()},[k]),F=t(t=>{f.current=t,k()},[k]);return e(()=>(k(),()=>{M(),l.current&&cancelAnimationFrame(l.current)}),[k,M]),{containerRef:x,safeAreaRef:F,update:A}};
@@ -1,33 +1,18 @@
1
- import type { CanvasPadding } from '#package/ui-sdk';
2
1
  /**
3
- * Measures the gap between a full-area container and an inner "safe area" element,
4
- * and forwards the resulting gaps as canvas padding — letting the 3D scene render
5
- * only in the region not covered by overlay UI (preview body, sidebar, etc.).
2
+ * Tells the camera which part of the canvas a layout leaves free for the scene.
6
3
  *
7
- * Returns:
8
- * - `containerRef` — attach to the full-area measurement element.
9
- * - `safeAreaRef` — attach to the region the scene should remain visible in.
10
- * - `update` — trigger a manual re-measure on demand.
11
- *
12
- * `containerRef` / `safeAreaRef` are *callback* refs: the `ResizeObserver` (re)connects
13
- * whenever a node attaches or detaches. This matters because the owning layout can mount
14
- * late — `AnimatePresence mode="wait"` only mounts the interface after the preview has
15
- * finished exiting, well after a one-shot mount effect would have run and bailed on null
16
- * refs (leaving the scene stuck at the preview's padding).
17
- *
18
- * `enabled` gates the whole thing: when `false` the observer is disconnected so an inactive
19
- * layout (e.g. the interface while previewing) neither measures nor writes padding.
4
+ * A layout attaches `containerRef` to the element that covers the whole canvas and `safeAreaRef`
5
+ * to the region the scene should stay visible in. The hook measures the gap between the two,
6
+ * again whenever either element resizes, and writes it to the responsive context as the canvas
7
+ * padding the camera frames the scene with.
20
8
  *
21
- * `getBoundingClientRect()` returns *visually transformed* rects, so `measure` skips
22
- * transformed frames automatically (retrying until the transform clears) to avoid feeding
23
- * the scene a scaled gap mid layout animation.
24
- *
25
- * `update` exists for the complementary case: when only an ancestor's `transform` changes
26
- * (e.g. motion FLIP settling), `ResizeObserver` doesn't fire, so nothing re-triggers
27
- * `measure`. Call `update()` once the transform settles (e.g. from
28
- * `onLayoutAnimationComplete`) to re-measure against the actual layout box.
9
+ * Returns:
10
+ * - `containerRef` — attach to the element that covers the whole canvas.
11
+ * - `safeAreaRef` — attach to the region the scene should stay visible in.
12
+ * - `update` — measures again on demand, for a change no resize reports, such as a `transform`
13
+ * on an ancestor settling at the end of an animation.
29
14
  */
30
- export declare const useSceneSafeArea: (setCanvasPadding: (padding: CanvasPadding) => void, hasMiniSidebar: boolean, enabled?: boolean) => {
15
+ export declare const useSceneSafeArea: () => {
31
16
  containerRef: (node: HTMLDivElement | null) => void;
32
17
  safeAreaRef: (node: HTMLDivElement | null) => void;
33
18
  update: () => void;
@@ -1 +1 @@
1
- import{useCallback as t,useEffect as e,useRef as r}from"react";import{canvasPaddingComponent as n}from"#package/domain";import{useFirstComponent as o}from"#package/react-sdk";export const useSceneSafeArea=(a,c,u=!0)=>{let i=r(null),l=r(null),m=r(null),s=r(null),f=r(0),h=r(()=>{}),g=o({componentTypes:[n]}),p=t(()=>{let t=l.current,e=m.current;if(!t||!e)return;let r=t.getBoundingClientRect(),n=e.getBoundingClientRect();if(Math.abs(r.width-t.offsetWidth)>1||Math.abs(r.height-t.offsetHeight)>1){if(f.current+=1,f.current>60){f.current=0;return}i.current&&cancelAnimationFrame(i.current),i.current=requestAnimationFrame(()=>h.current());return}f.current=0;let o={bottom:Math.max(0,r.bottom-n.bottom),left:Math.max(0,n.left-r.left),right:Math.max(0,r.right-n.right),top:Math.max(0,n.top-r.top)},u=c?.3:1,s=g?.state.bottom??1,p=g?.state.left??1,b=g?.state.right??u,d=g?.state.top??1;a({bottom:o.bottom*s,left:o.left*p,right:o.right*b,top:o.top*d})},[c,g?.state.bottom,g?.state.left,g?.state.right,g?.state.top,a]);h.current=p;let b=t(()=>{i.current&&cancelAnimationFrame(i.current),i.current=requestAnimationFrame(p)},[p]),d=t(()=>{s.current?.disconnect(),s.current=null},[]),A=t(()=>{let t=l.current,e=m.current;if(!u||!t||!e)return void d();d();let r=new ResizeObserver(b);r.observe(t),r.observe(e),s.current=r},[d,u,b]),M=t(t=>{l.current=t,A()},[A]),x=t(t=>{m.current=t,A()},[A]);return e(()=>(A(),()=>{d(),i.current&&cancelAnimationFrame(i.current)}),[A,d]),{containerRef:M,safeAreaRef:x,update:b}};
1
+ import{useLayoutSceneSafeArea as e}from"./use-layout-scene-safe-area.js";export const useSceneSafeArea=()=>e({enabled:!0,hasMiniSidebar:!1});
@@ -46,25 +46,22 @@ countersinkNotAvailable:
46
46
  ```
47
47
 
48
48
  ```ts
49
- const violationExpressions = invariantBuilder
50
- .withInvariants(
51
- implementCustomInvariants({
52
- Plate: {
53
- finishNotAvailable: s => {
54
- return availableMaterials.some(state => state.material === s.material && state.finish === s.finish)
55
- },
56
- thicknessNotAvailable: s => {
57
- return availableMaterials.some(
58
- state => state.material === s.material && state.finish === s.finish && state.thickness === s.thickness
59
- )
60
- },
61
- countersinkNotAvailable: s => {
62
- return !s.someCounterSinkAdded || counterSinkThicknesses.includes(s.thickness)
63
- },
64
- },
65
- })
66
- )
67
- .buildViolationExpressions()
49
+ // src/invariants/invariants.ts
50
+ export default phx.domain.implementCustomInvariants({
51
+ Plate: {
52
+ finishNotAvailable: s => {
53
+ return availableMaterials.some(state => state.material === s.material && state.finish === s.finish)
54
+ },
55
+ thicknessNotAvailable: s => {
56
+ return availableMaterials.some(
57
+ state => state.material === s.material && state.finish === s.finish && state.thickness === s.thickness
58
+ )
59
+ },
60
+ countersinkNotAvailable: s => {
61
+ return !s.someCounterSinkAdded || counterSinkThicknesses.includes(s.thickness)
62
+ },
63
+ },
64
+ })
68
65
  ```
69
66
 
70
67
  With following control structure. Note the hierarchy of `fixableViolations`. The top input "fixes" all violations as it should never be disabled.
@@ -669,44 +669,6 @@ import { Model, attachComponent, configuratorBuilder } from './domain/index.js'
669
669
  // ... identical to the Code section above ...
670
670
  ```
671
671
 
672
- ### Domain Setup (`domain/index.ts`)
673
-
674
- ```typescript
675
- import { memoEval } from '@salsita-ai/sdk/domain'
676
-
677
- import { adminDomainBuilder } from './__generated/admin-implementation.js'
678
- import { generatedConfiguratorBuilder } from './__generated/configurator-builder.js'
679
- import {
680
- domainBuilder,
681
- implementCustomExpressions,
682
- implementCustomInvariants,
683
- invariantBuilder,
684
- } from './__generated/implementation.js'
685
-
686
- const violationExpressions = invariantBuilder.withInvariants(implementCustomInvariants({})).buildViolationExpressions()
687
-
688
- const customExpressions = implementCustomExpressions({
689
- // ... as shown in Code section ...
690
- })
691
-
692
- const domainFactory = domainBuilder.withExpressions(violationExpressions).withExpressions(customExpressions).build()
693
- const adminDomainFactory = adminDomainBuilder.build()
694
-
695
- export const configuratorBuilder = generatedConfiguratorBuilder
696
- .withDomainFactory(domainFactory)
697
- .withAdminDomainFactory(adminDomainFactory)
698
-
699
- export * as AdminEnhancedDomain from './__generated/admin-enhanced-model.js'
700
- export * as AdminModel from './__generated/admin-model/index.js'
701
- export * as ApplicationTypes from './__generated/application-types.js'
702
- export * as EnhancedDomain from './__generated/enhanced-model.js'
703
- export * as Model from './__generated/model/index.js'
704
-
705
- export { attachAdminComponent, createAdminRecipe } from './__generated/admin-implementation.js'
706
- export { attachComponent, createRecipe } from './__generated/implementation.js'
707
- export { createPresets } from './__generated/presets.js'
708
- ```
709
-
710
672
  ### Domain Configuration (`domain/domain.yaml`)
711
673
 
712
674
  ```yaml
@@ -99,19 +99,15 @@ components:
99
99
  Optionally disable specific options using invariants. The control performs a dry run for each option and disables those that would violate your rules. Provide a clear message; if multiple violations apply, messages are concatenated.
100
100
 
101
101
  ```typescript
102
- // domain/index.ts (extract)
103
- const violationExpressions = invariantBuilder
104
- .withInvariants(
105
- implementCustomInvariants({
106
- Table: {
107
- trunkDisabled: s =>
108
- s.edgeFinish === 'TreeTrunk'
109
- ? [{ type: 'trunkDisabled', severity: 'fatal', message: 'TreeTrunk finish is disabled because stuff!' }]
110
- : [],
111
- },
112
- })
113
- )
114
- .buildViolationExpressions()
102
+ // src/invariants/trunk-disabled.ts
103
+ export default phx.domain.implementCustomInvariants({
104
+ Table: {
105
+ trunkDisabled: s =>
106
+ s.edgeFinish === 'TreeTrunk'
107
+ ? [{ type: 'trunkDisabled', severity: 'fatal', message: 'TreeTrunk finish is disabled because stuff!' }]
108
+ : [],
109
+ },
110
+ })
115
111
  ```
116
112
 
117
113
  Register the invariant type in YAML so the system knows about it.
@@ -1,5 +1,5 @@
1
1
  {
2
- "generatedAt": "2026-10-13T18:02:26.804Z",
2
+ "generatedAt": "2026-10-13T19:44:25.844Z",
3
3
  "categories": [
4
4
  {
5
5
  "name": "Phoenix",
@@ -133,7 +133,7 @@ The value of `WOOCOMMERCE_API_KEY` must correspond to the value of the 'API key'
133
133
  settings page and `WOOCOMMERCE_PRODUCT_NAME` must correspond to the name of the product template you created.
134
134
 
135
135
  - run development server (from this repo): `pnpm dev:server`
136
- - prepare local deployment (from the implementation project): `pnpm deployment:prepare-local`
136
+ - prepare local deployment (from the implementation project): `pnpm phoenix deployment:prepare-local`
137
137
  - start the dev process (from the implementation project): `pnpm dev`
138
138
  - run bundle build (from the implementation project): `pnpm build`
139
139
 
@@ -32,17 +32,14 @@ finishNotAvailable:
32
32
  ```
33
33
 
34
34
  ```ts
35
- const violationExpressions = invariantBuilder
36
- .withInvariants(
37
- implementCustomInvariants({
38
- Plate: {
39
- finishNotAvailable: s => {
40
- return availableMaterials.some(state => state.material === s.material && state.finish === s.finish)
41
- },
42
- },
43
- })
44
- )
45
- .buildViolationExpressions()
35
+ // src/invariants/invariants.ts
36
+ export default phx.domain.implementCustomInvariants({
37
+ Plate: {
38
+ finishNotAvailable: s => {
39
+ return availableMaterials.some(state => state.material === s.material && state.finish === s.finish)
40
+ },
41
+ },
42
+ })
46
43
  ```
47
44
 
48
45
  With following control structure. The top input selects the material, the bottom one selects the finish.
@@ -153,10 +153,10 @@ The `formatControlViolationMessage` function is where the magic happens. It rece
153
153
  3. **Actionable guidance**: Tell users exactly what values are valid or how to fix the problem
154
154
  4. **Consistent terminology**: Use the same terms and units throughout your application
155
155
 
156
- Implement violations with custom message formatting in your domain TypeScript file:
156
+ Implement violations with custom message formatting in a file of `src/invariants/`:
157
157
 
158
158
  ```typescript
159
- // domain/index.ts
159
+ // src/invariants/invariants.ts
160
160
 
161
161
  // Pre-define translatable labels for nested localization
162
162
  const colorLabels = {
@@ -166,60 +166,56 @@ const colorLabels = {
166
166
  yellow: msg`yellow`,
167
167
  } as const
168
168
 
169
- const violationExpressions = invariantBuilder
170
- .withInvariants(
171
- implementCustomInvariants({
172
- Scene: {
173
- itIsNotZero: s => {
174
- if (s.x !== 0) {
175
- return [
176
- {
177
- type: 'itIsNotZero',
178
- severity: 'fatal',
179
- message: 'Scene is not zero',
180
- controlViolationPriority: 1,
181
- formatControlViolationMessage: () => {
182
- return msg({
183
- message: `Scene is not zero: The position would be ${s.x} which is not equal to 0`,
184
- })
185
- },
186
- },
187
- ]
188
- }
189
- return []
190
- },
191
- // ... tooMuchRight omitted for brevity ...
192
-
193
- // Static violation: severity, message and controlViolationPriority
194
- // are declared in YAML. Implementation only returns a boolean.
195
- wayTooFarRight: s => s.x < 200,
196
-
197
- colorPositionIncompatible: s => {
198
- const compatibleColors = ['red', 'blue', 'green'] as const
199
- if (s.x >= 200 && !compatibleColors.includes(s.color)) {
200
- return [
201
- {
202
- type: 'colorPositionIncompatible',
203
- severity: 'fatal',
204
- message: 'Color is not compatible with far right position',
205
- controlViolationPriority: 3,
206
- formatControlViolationMessage: (_emission, { i18n }) => {
207
- const labels = new Intl.ListFormat(i18n.locale, {
208
- style: 'long',
209
- type: 'disjunction',
210
- }).format(compatibleColors.map(c => i18n.t(colorLabels[c])))
211
-
212
- return msg({ message: `Far right position is only available for ${labels}` })
213
- },
214
- },
215
- ]
216
- }
217
- return []
218
- },
219
- },
220
- })
221
- )
222
- .buildViolationExpressions()
169
+ export default phx.domain.implementCustomInvariants({
170
+ Buckyball: {
171
+ itIsNotZero: s => {
172
+ if (s.x !== 0) {
173
+ return [
174
+ {
175
+ type: 'itIsNotZero',
176
+ severity: 'fatal',
177
+ message: 'Scene is not zero',
178
+ controlViolationPriority: 1,
179
+ formatControlViolationMessage: () => {
180
+ return msg({
181
+ message: `Scene is not zero: The position would be ${s.x} which is not equal to 0`,
182
+ })
183
+ },
184
+ },
185
+ ]
186
+ }
187
+ return []
188
+ },
189
+ // ... tooMuchRight omitted for brevity ...
190
+
191
+ // Static violation: severity, message and controlViolationPriority
192
+ // are declared in YAML. Implementation only returns a boolean.
193
+ wayTooFarRight: s => s.x < 200,
194
+
195
+ colorPositionIncompatible: s => {
196
+ const compatibleColors = ['red', 'blue', 'green'] as const
197
+ if (s.x >= 200 && !compatibleColors.includes(s.color)) {
198
+ return [
199
+ {
200
+ type: 'colorPositionIncompatible',
201
+ severity: 'fatal',
202
+ message: 'Color is not compatible with far right position',
203
+ controlViolationPriority: 3,
204
+ formatControlViolationMessage: (_emission, { i18n }) => {
205
+ const labels = new Intl.ListFormat(i18n.locale, {
206
+ style: 'long',
207
+ type: 'disjunction',
208
+ }).format(compatibleColors.map(c => i18n.t(colorLabels[c])))
209
+
210
+ return msg({ message: `Far right position is only available for ${labels}` })
211
+ },
212
+ },
213
+ ]
214
+ }
215
+ return []
216
+ },
217
+ },
218
+ })
223
219
  ```
224
220
 
225
221
  ### Internationalization with Dynamic Content