@salsita-ai/sdk 0.50.0-develop.98e8b1502f â 0.50.0-develop.be40f0cee8
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/dist/configurator/application-runtime/extensions/systems/layout-system/layout-system.d.ts +2 -0
- package/dist/configurator/application-runtime/extensions/systems/layout-system/layout-system.js +1 -1
- package/dist/configurator/assistant/use-assistant-chat.d.ts +15 -5
- package/dist/configurator/assistant/use-assistant-chat.js +1 -1
- package/dist/configurator/ui/assistant/AssistantChips.d.ts +11 -0
- package/dist/configurator/ui/assistant/AssistantChips.js +1 -0
- package/dist/configurator/ui/assistant/AssistantComposer.d.ts +11 -0
- package/dist/configurator/ui/assistant/AssistantComposer.js +1 -0
- package/dist/configurator/ui/assistant/AssistantMarkdown.d.ts +7 -0
- package/dist/configurator/ui/assistant/AssistantMarkdown.js +1 -0
- package/dist/configurator/ui/assistant/AssistantPanel.d.ts +11 -0
- package/dist/configurator/ui/assistant/AssistantPanel.js +1 -0
- package/dist/configurator/ui/assistant/AssistantPanelProvider.d.ts +42 -0
- package/dist/configurator/ui/assistant/AssistantPanelProvider.js +1 -0
- package/dist/configurator/ui/assistant/AssistantThread.d.ts +11 -0
- package/dist/configurator/ui/assistant/AssistantThread.js +1 -0
- package/dist/configurator/ui/assistant/assistant-failure.d.ts +18 -0
- package/dist/configurator/ui/assistant/assistant-failure.js +1 -0
- package/dist/configurator/ui/assistant/index.d.ts +2 -0
- package/dist/configurator/ui/assistant/index.js +1 -0
- package/dist/configurator/ui/assistant/streamed-markdown.d.ts +6 -0
- package/dist/configurator/ui/assistant/streamed-markdown.js +2 -0
- package/dist/configurator/ui/assistant/theme.d.ts +2 -0
- package/dist/configurator/ui/assistant/theme.js +1 -0
- package/dist/configurator/ui/assistant/thread-items.d.ts +37 -0
- package/dist/configurator/ui/assistant/thread-items.js +1 -0
- package/dist/configurator/ui/assistant/tool-chip.d.ts +37 -0
- package/dist/configurator/ui/assistant/tool-chip.js +1 -0
- package/dist/configurator/ui/assistant/use-follow-stream.d.ts +17 -0
- package/dist/configurator/ui/assistant/use-follow-stream.js +1 -0
- package/dist/configurator/ui/configurator-layout/universal/DesktopLayout.js +5 -5
- package/dist/configurator/ui/configurator-layout/universal/Layout.js +1 -1
- package/dist/configurator/ui/configurator-layout/universal/MobileLayout.d.ts +2 -0
- package/dist/configurator/ui/configurator-layout/universal/MobileLayout.js +3 -3
- package/dist/configurator/ui/phoenix-layout-elements/AssistantToolbarButton.d.ts +10 -0
- package/dist/configurator/ui/phoenix-layout-elements/AssistantToolbarButton.js +1 -0
- package/dist/configurator/ui/phoenix-layout-elements/index.d.ts +1 -0
- package/dist/configurator/ui/phoenix-layout-elements/index.js +1 -1
- package/dist/docs/index.json +1 -1
- package/dist/docs/layouts/toolbar.mdx +4 -0
- package/dist/domain/system-components/phoenix-layout-elements/assistant-toolbar-button.d.ts +44 -0
- package/dist/domain/system-components/phoenix-layout-elements/assistant-toolbar-button.js +1 -0
- package/dist/domain/system-components/phoenix-layout-elements/index.d.ts +1 -0
- package/dist/domain/system-components/phoenix-layout-elements/index.js +1 -1
- package/dist/domain/system-components/phoenix-layout-elements/phoenix-layout-element.d.ts +2 -1
- package/dist/domain/system-components/phoenix-layout-elements/phoenix-layout-element.js +1 -1
- package/dist/i18n/locales/cs/messages.js +1 -1
- package/dist/i18n/locales/da/messages.js +1 -1
- package/dist/i18n/locales/de/messages.js +1 -1
- package/dist/i18n/locales/de-AT/messages.js +1 -1
- package/dist/i18n/locales/en/messages.js +1 -1
- package/dist/i18n/locales/en-AU/messages.js +1 -1
- package/dist/i18n/locales/en-GB/messages.js +1 -1
- package/dist/i18n/locales/es/messages.js +1 -1
- package/dist/i18n/locales/fr/messages.js +1 -1
- package/dist/i18n/locales/hu/messages.js +1 -1
- package/dist/i18n/locales/it/messages.js +1 -1
- package/dist/i18n/locales/nl/messages.js +1 -1
- package/dist/i18n/locales/pl/messages.js +1 -1
- package/dist/i18n/locales/pt/messages.js +1 -1
- package/dist/i18n/locales/ro/messages.js +1 -1
- package/dist/i18n/locales/sk/messages.js +1 -1
- package/dist/i18n/locales/tr/messages.js +1 -1
- package/dist/legacy/domain-spec/__generated/domain-schema.d.ts +6 -0
- package/dist/ui-sdk/theme/types.d.ts +4 -0
- package/package.json +4 -7
- package/schema/domain-spec.json +24 -0
- package/dist/extras/assistant/AssistantChat.d.ts +0 -6
- package/dist/extras/assistant/AssistantChat.js +0 -1
- package/dist/extras/assistant/index.d.ts +0 -1
- package/dist/extras/assistant/index.js +0 -1
package/dist/configurator/application-runtime/extensions/systems/layout-system/layout-system.d.ts
CHANGED
|
@@ -25,6 +25,8 @@ export declare class LayoutSystem<ENTITIES extends DomainEntity<string>> {
|
|
|
25
25
|
* whatever was true when it was created.
|
|
26
26
|
*/
|
|
27
27
|
private get _toolbarHelpExists();
|
|
28
|
+
/** Whether the application spec has an `assistant` section; read on demand for the same reason. */
|
|
29
|
+
private get _hasAssistant();
|
|
28
30
|
initialize: () => void;
|
|
29
31
|
getCleanUpPropertyPageStateUpdates: (entityId: DomainEntityId<string>, state: DomainState<ENTITIES>) => import("#package/domain").ComponentModification<import("#package/domain").SystemComponentType<"layoutStateComponent", import("./layout-state.js").LayoutStateComponentState, "propertyPageStates">>[];
|
|
30
32
|
getLayoutConfig: (state: DomainState<ENTITIES>) => {
|
package/dist/configurator/application-runtime/extensions/systems/layout-system/layout-system.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{P as t,match as e}from"ts-pattern";import{SystemState as o,applicationConfigComponent as n,customSummaryPageComponent as a,entityHeaderComponent as i,navigationStepsComponent as r,propertyPageComponent as s,sidebarTabsComponent as l,simpleSummaryComponent as d,toolbarComponent as c}from"#package/domain";import{layoutStateComponent as g}from"./layout-state.js";import{toolbarHelpElementName as u}from"./toolbar-help-element.js";export class LayoutSystem{_context;_toolbarCache=new WeakMap;state;constructor(t){this._context=t,this.state=new o({...this._context,selectors:this._context.domainContextSelectors,componentType:g,getInitialState:()=>({propertyPageStates:{}})})}get _toolbarHelpExists(){return void 0!==this._context.specSelectors.getElementSlots().layoutElements[u]}initialize=()=>{this.state.initialize()};getCleanUpPropertyPageStateUpdates=(t,e)=>this.state.getUpdates(e=>{if(!e.propertyPageStates[t])return null;let o={...e.propertyPageStates};return delete o[t],{...e,propertyPageStates:o}},e);getLayoutConfig=t=>{let e=this._context.domainContextSelectors.getComponentReader().readFirstRootComponent({componentTypes:[n]},t),o=e?.state.shareDisabled??!1,a=o||(e?.state.shareOwnerLinkDisabled??!1),i=o||(e?.state.shareReadRevisionLinkDisabled??!1);return{layout:e?.state.layout??"universal",ignoreSelectionInSidebar:e?.state.ignoreSelectionInSidebar??!1,miniSidebar:e?.state.miniSidebar??!1,splitSidebar:e?.state.splitSidebar??!1,showSelectionBackButton:e?.state.showSelectionBackButton??!0,shareDisabled:a&&i,availableLocales:e?.state.availableLocales??["en"],indicatorSwitch:e?.state.indicatorSwitch??!0}};getSidebarSummaryPage=t=>{let e=this._context.domainContextSelectors.getNavigationSystem().getActiveNavigationState(t),o=this._context.domainContextSelectors.getComponentReader().readFirstRootComponent({componentTypes:[a,d]},t),n=e===o?.state.summaryNavigationState,i=o?.state.summaryNavigationState;return{page:o,isSummaryActive:n,summaryNavigationState:i}};getEnterSidebarSummaryUpdates=t=>{let{summaryNavigationState:e}=this.getSidebarSummaryPage(t);return e?[this._context.domainContextSelectors.getNavigationSystem().getPushNavigationUpdate(e,t)]:[]};getLeaveSidebarSummaryUpdates=t=>{let e=this._context.domainContextSelectors.getNavigationSystem().getPopNavigationUpdate(t);if(e)return[e];let o=this._context.domainContextSelectors.getNavigationStates().at(0);return o?(this._context.domainServicesSelectors.getLogger().error("There is no navigation state to pop, falling back to the initial navigation state. Check whether the history stack is not broken by some custom navigation logic."),[this._context.domainContextSelectors.getNavigationSystem().getNavigationUpdate(o)]):(this._context.domainServicesSelectors.getLogger().error("There is no navigation state to pop and no initial navigation state to fallback to, this should not happen"),[])};getPushSidebarStackPageUpdates=(t,e,o,n)=>this.state.getUpdates(n=>{let a=n.propertyPageStates[t]??{customState:{},stackPages:[]};return{...n,propertyPageStates:{...n.propertyPageStates,[t]:{...a,stackPages:[...a.stackPages,{props:o,component:e}]}}}},n);getPopSidebarStackPageUpdates=(t,e)=>this.state.getUpdates(e=>{let o=e.propertyPageStates[t]??{customState:{},stackPages:[]};return{...e,propertyPageStates:{...e.propertyPageStates,[t]:{...o,stackPages:o.stackPages.slice(0,-1)}}}},e);getSidebarBackUpdates=t=>{let e=this._context.domainContextSelectors.getNavigationSystem().getHasStackToPop(t),o=this._context.domainContextSelectors.getNavigationSystem().getIsRootSelected(t),{renderedStackedPage:n,summaryPage:a,activePropertyPageId:i}=this.getSidebarContent(t);if(a)return this.getLeaveSidebarSummaryUpdates(t);if(n&&i)return this.getPopSidebarStackPageUpdates(i,t);if(e){let e=this._context.domainContextSelectors.getNavigationSystem().getPopNavigationUpdate(t);return e?[e]:[]}return o?[]:[this._context.domainContextSelectors.getNavigationSystem().getDeselectUpdate()]};getSidebarContent=t=>{let e=this._context.domainContextSelectors.getNavigationSystem().getActiveSelectionState(t),o=this.state.get(t),n=this.getLayoutConfig(t),a=this._context.domainContextSelectors.getComponentReader().readManyComponents({componentTypes:[l],entityIds:[e]},t).some(t=>t.state.tabs.length>0),r=n.miniSidebar&&!a;r&&a&&this._context.domainServicesSelectors.getLogger().warn("Mini sidebar is not active because the layout contains tabs. Only layouts without tabs can have mini sidebar.");let d=this._context.domainContextSelectors.getComponentReader().readManyComponents({componentTypes:[s]},t),{isSummaryActive:c,page:g}=this.getSidebarSummaryPage(t),u=this._context.domainContextSelectors.getComponentReader().readManyComponents({componentTypes:[i]},t),p=this._context.domainContextSelectors.getCompositionProjections().getTree(t).map.get(e);if(!p)throw Error(`Selected entity ${e} not found in composition tree`);let m=this._context.domainContextSelectors.getCompositionProjections().getTree(t).map.get(t.rootEntityId);if(!m)throw Error(`Root entity ${t.rootEntityId} not found in composition tree`);let
|
|
1
|
+
import{P as t,match as e}from"ts-pattern";import{SystemState as o,applicationConfigComponent as n,customSummaryPageComponent as a,entityHeaderComponent as i,navigationStepsComponent as r,propertyPageComponent as s,sidebarTabsComponent as l,simpleSummaryComponent as d,toolbarComponent as c}from"#package/domain";import{layoutStateComponent as g}from"./layout-state.js";import{toolbarHelpElementName as u}from"./toolbar-help-element.js";export class LayoutSystem{_context;_toolbarCache=new WeakMap;state;constructor(t){this._context=t,this.state=new o({...this._context,selectors:this._context.domainContextSelectors,componentType:g,getInitialState:()=>({propertyPageStates:{}})})}get _toolbarHelpExists(){return void 0!==this._context.specSelectors.getElementSlots().layoutElements[u]}get _hasAssistant(){return void 0!==this._context.specSelectors.getAssistant()}initialize=()=>{this.state.initialize()};getCleanUpPropertyPageStateUpdates=(t,e)=>this.state.getUpdates(e=>{if(!e.propertyPageStates[t])return null;let o={...e.propertyPageStates};return delete o[t],{...e,propertyPageStates:o}},e);getLayoutConfig=t=>{let e=this._context.domainContextSelectors.getComponentReader().readFirstRootComponent({componentTypes:[n]},t),o=e?.state.shareDisabled??!1,a=o||(e?.state.shareOwnerLinkDisabled??!1),i=o||(e?.state.shareReadRevisionLinkDisabled??!1);return{layout:e?.state.layout??"universal",ignoreSelectionInSidebar:e?.state.ignoreSelectionInSidebar??!1,miniSidebar:e?.state.miniSidebar??!1,splitSidebar:e?.state.splitSidebar??!1,showSelectionBackButton:e?.state.showSelectionBackButton??!0,shareDisabled:a&&i,availableLocales:e?.state.availableLocales??["en"],indicatorSwitch:e?.state.indicatorSwitch??!0}};getSidebarSummaryPage=t=>{let e=this._context.domainContextSelectors.getNavigationSystem().getActiveNavigationState(t),o=this._context.domainContextSelectors.getComponentReader().readFirstRootComponent({componentTypes:[a,d]},t),n=e===o?.state.summaryNavigationState,i=o?.state.summaryNavigationState;return{page:o,isSummaryActive:n,summaryNavigationState:i}};getEnterSidebarSummaryUpdates=t=>{let{summaryNavigationState:e}=this.getSidebarSummaryPage(t);return e?[this._context.domainContextSelectors.getNavigationSystem().getPushNavigationUpdate(e,t)]:[]};getLeaveSidebarSummaryUpdates=t=>{let e=this._context.domainContextSelectors.getNavigationSystem().getPopNavigationUpdate(t);if(e)return[e];let o=this._context.domainContextSelectors.getNavigationStates().at(0);return o?(this._context.domainServicesSelectors.getLogger().error("There is no navigation state to pop, falling back to the initial navigation state. Check whether the history stack is not broken by some custom navigation logic."),[this._context.domainContextSelectors.getNavigationSystem().getNavigationUpdate(o)]):(this._context.domainServicesSelectors.getLogger().error("There is no navigation state to pop and no initial navigation state to fallback to, this should not happen"),[])};getPushSidebarStackPageUpdates=(t,e,o,n)=>this.state.getUpdates(n=>{let a=n.propertyPageStates[t]??{customState:{},stackPages:[]};return{...n,propertyPageStates:{...n.propertyPageStates,[t]:{...a,stackPages:[...a.stackPages,{props:o,component:e}]}}}},n);getPopSidebarStackPageUpdates=(t,e)=>this.state.getUpdates(e=>{let o=e.propertyPageStates[t]??{customState:{},stackPages:[]};return{...e,propertyPageStates:{...e.propertyPageStates,[t]:{...o,stackPages:o.stackPages.slice(0,-1)}}}},e);getSidebarBackUpdates=t=>{let e=this._context.domainContextSelectors.getNavigationSystem().getHasStackToPop(t),o=this._context.domainContextSelectors.getNavigationSystem().getIsRootSelected(t),{renderedStackedPage:n,summaryPage:a,activePropertyPageId:i}=this.getSidebarContent(t);if(a)return this.getLeaveSidebarSummaryUpdates(t);if(n&&i)return this.getPopSidebarStackPageUpdates(i,t);if(e){let e=this._context.domainContextSelectors.getNavigationSystem().getPopNavigationUpdate(t);return e?[e]:[]}return o?[]:[this._context.domainContextSelectors.getNavigationSystem().getDeselectUpdate()]};getSidebarContent=t=>{let e=this._context.domainContextSelectors.getNavigationSystem().getActiveSelectionState(t),o=this.state.get(t),n=this.getLayoutConfig(t),a=this._context.domainContextSelectors.getComponentReader().readManyComponents({componentTypes:[l],entityIds:[e]},t).some(t=>t.state.tabs.length>0),r=n.miniSidebar&&!a;r&&a&&this._context.domainServicesSelectors.getLogger().warn("Mini sidebar is not active because the layout contains tabs. Only layouts without tabs can have mini sidebar.");let d=this._context.domainContextSelectors.getComponentReader().readManyComponents({componentTypes:[s]},t),{isSummaryActive:c,page:g}=this.getSidebarSummaryPage(t),u=this._context.domainContextSelectors.getComponentReader().readManyComponents({componentTypes:[i]},t),p=this._context.domainContextSelectors.getCompositionProjections().getTree(t).map.get(e);if(!p)throw Error(`Selected entity ${e} not found in composition tree`);let m=this._context.domainContextSelectors.getCompositionProjections().getTree(t).map.get(t.rootEntityId);if(!m)throw Error(`Root entity ${t.rootEntityId} not found in composition tree`);let h=(n.ignoreSelectionInSidebar?[m]:[p,...p.ancestors()]).map(t=>{let e=n.ignoreSelectionInSidebar?d:d.filter(e=>e.componentInstance.entityId===t.id),o=u.filter(e=>e.componentInstance.entityId===t.id);return{id:t.id,propertyPages:e,header:o[0]??null}}),S=h[0]?.id,b=(S?o.propertyPageStates[S]?.stackPages??[]:[]).at(-1)??null,k=this._context.domainContextSelectors.getNavigationSystem().getHasStackToPop(t),x=this._context.domainContextSelectors.getNavigationSystem().getIsRootSelected(t),y=c&&k||k||!!b||!x&&n.showSelectionBackButton&&!n.ignoreSelectionInSidebar;return c?{summaryPage:g,propertyPages:[],isBackAvailable:y,hasMiniSidebar:r,hasSplitSidebar:n.splitSidebar}:{summaryPage:null,propertyPages:h,renderedStackedPage:b,activePropertyPageId:S,isBackAvailable:y,hasMiniSidebar:r,hasSplitSidebar:n.splitSidebar}};getToolbarState=o=>{let n=this._toolbarHelpExists,a=this._hasAssistant,i=this._toolbarCache.get(o);if(i&&i.toolbarHelpExists===n&&i.hasAssistant===a)return i.result;let r=this._context.domainContextSelectors.getExpressionContext(),s=this._context.domainContextSelectors.getNavigationSystem().getActiveFullscreenState(o),l="read"===r.mode,d=this._context.domainContextSelectors.getComponentReader().readFirstRootComponent({componentTypes:[c]},o),g=this._context.domainContextSelectors.getDimensionSystem().getDimensionConfig(o),u=this.getLayoutConfig(o),p="read"===this._context.domainContextSelectors.getExpressionContext().mode,m=u.availableLocales.length>1,h=!p&&!u.shareDisabled,S=u.indicatorSwitch,b=g.availableDimensions.length>1||S,k=a?[{kind:"toolbarButtonGroup",children:[{kind:"assistantToolbarButton"}]}]:[],x=e(d).returnType().with(t.nonNullable,t=>t.state).with(t.nullish,()=>e([s,l]).returnType().with([!1,!1],()=>({desktop:[{kind:"toolbarButtonGroup",children:[{kind:"enterFullscreenToolbarButton"}]},{kind:"toolbarButtonGroup",children:[{kind:"resetCameraToolbarButton"}]},...m?[{kind:"toolbarButtonGroup",children:[{kind:"languageToolbarButton"}]}]:[],...h||b?[{kind:"toolbarButtonGroup",children:[...h?[{kind:"shareToolbarButton"}]:[],...b?[{kind:"measurementsToolbarButton"}]:[],...n?[{kind:"helpToolbarButton"}]:[]]}]:[],{kind:"toolbarButtonGroup",children:[{kind:"undoToolbarButton"},{kind:"redoToolbarButton"}]},...k],mobile:[{kind:"toolbarButtonGroup",children:[{kind:"undoToolbarButton"},{kind:"redoToolbarButton"}]},{kind:"toolbarButtonGroup",children:[{kind:"resetCameraToolbarButton"}]},{kind:"toolbarButtonGroup",children:[{kind:"enterFullscreenToolbarButton"}]},...k],mobileMenu:[...h?[{kind:"shareMenuAction"}]:[],...b?[{kind:"measurementsMenuAction"}]:[],...m?[{kind:"languageMenuAction"}]:[],...n?[{kind:"helpMenuAction"}]:[]]})).with([!0,!1],()=>({desktop:[{kind:"toolbarButtonGroup",children:[{kind:"exitFullscreenToolbarButton"}]}],mobile:[{kind:"toolbarButtonGroup",children:[{kind:"exitFullscreenToolbarButton"}]}],mobileMenu:[]})).with([!1,!0],()=>({desktop:[{kind:"toolbarButtonGroup",children:[{kind:"enterFullscreenToolbarButton"}]},{kind:"toolbarButtonGroup",children:[{kind:"resetCameraToolbarButton"}]},...m?[{kind:"toolbarButtonGroup",children:[{kind:"languageToolbarButton"}]}]:[],...b?[{kind:"toolbarButtonGroup",children:[...b?[{kind:"measurementsToolbarButton"}]:[]]}]:[],...n?[{kind:"helpToolbarButton"}]:[],...k],mobile:[{kind:"toolbarButtonGroup",children:[{kind:"resetCameraToolbarButton"}]},{kind:"toolbarButtonGroup",children:[{kind:"enterFullscreenToolbarButton"}]},...k],mobileMenu:[...b?[{kind:"measurementsMenuAction"}]:[],...m?[{kind:"languageMenuAction"}]:[],...n?[{kind:"helpMenuAction"}]:[]]})).with([!0,!0],()=>({desktop:[{kind:"toolbarButtonGroup",children:[{kind:"exitFullscreenToolbarButton"}]}],mobile:[{kind:"toolbarButtonGroup",children:[{kind:"exitFullscreenToolbarButton"}]}],mobileMenu:[]})).exhaustive()).exhaustive();return this._toolbarCache.set(o,{toolbarHelpExists:n,hasAssistant:a,result:x}),x};getNavigationSteps=t=>{let e=this._context.domainContextSelectors.getComponentReader().readFirstRootComponent({componentTypes:[r]},t);return e?.state.steps??[]}}
|
|
@@ -1,20 +1,30 @@
|
|
|
1
1
|
import { type UIMessage } from '@tanstack/ai-react';
|
|
2
|
-
/**
|
|
2
|
+
/** Assistant chat state and actions of the current configuration. */
|
|
3
3
|
export interface AssistantChatState {
|
|
4
4
|
/** The thread as painted: hydrated from the server, then streamed. */
|
|
5
5
|
readonly messages: ReadonlyArray<UIMessage>;
|
|
6
6
|
/** True while a reply streams or a browser tool runs. */
|
|
7
7
|
readonly isLoading: boolean;
|
|
8
8
|
readonly error: Error | undefined;
|
|
9
|
+
/**
|
|
10
|
+
* HTTP status of the latest request the server answered with a failure, for telling a refusal from
|
|
11
|
+
* a dropped connection when `error` is set. Nothing when the latest answered request succeeded or
|
|
12
|
+
* the server was never reached.
|
|
13
|
+
*/
|
|
14
|
+
readonly failedStatus: number | undefined;
|
|
15
|
+
/** False when the server said this session may read the thread but not add to it. */
|
|
16
|
+
readonly isContinuable: boolean;
|
|
17
|
+
/** False until the first request of the chat, the thread read, was answered or failed. */
|
|
18
|
+
readonly isLoaded: boolean;
|
|
9
19
|
/** Sends a user message stamped with its send time. */
|
|
10
20
|
readonly send: (content: string) => Promise<void>;
|
|
11
21
|
/** Stops the current reply in the browser and on the server. */
|
|
12
22
|
readonly stop: () => Promise<void>;
|
|
13
23
|
}
|
|
14
24
|
/**
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
* `
|
|
25
|
+
* The conversational assistant of the current configuration. The server owns the thread â the chat
|
|
26
|
+
* hydrates from it on mount and rejoins a reply still streaming â so the hook keeps nothing in
|
|
27
|
+
* browser storage. Each message carries its send time for the model. The model's `query` and
|
|
28
|
+
* `apply` calls run here, in the browser, against the configurator this hook is rendered in.
|
|
19
29
|
*/
|
|
20
30
|
export declare const useAssistantChat: () => AssistantChatState;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{fetchServerSentEvents as t,useChat as e}from"@tanstack/ai-react";import{useCallback as a,useMemo as n}from"react";import{useApplicationRuntimeSelector as s,useAuthorizedClient as
|
|
1
|
+
import{fetchServerSentEvents as t,useChat as e}from"@tanstack/ai-react";import{useCallback as a,useMemo as n,useState as r}from"react";import{useApplicationRuntimeSelector as s,useAuthorizedClient as o,useConfigurationId as i,useLogger as c}from"#package/react-sdk";import{useConfigurator as l}from"../application-runtime/index.js";export const useAssistantChat=()=>{let u=i(),h=o(),d=c(),[p,m]=r(),[f,w]=r(!0),[y,g]=r(!1),C=a(()=>h.getAssistantChatConnection(u),[h,u]),k=n(()=>{let e=async(t,e)=>{let a=await fetch(t,e).finally(()=>g(!0)),n=a.headers.get("x-assistant-thread-continuable");return m(a.ok?void 0:a.status),null!=n&&w("false"!==n),a},a=async()=>({headers:await C().headers(),fetchClient:e}),n=t(()=>C().url,a),r=t(()=>`${C().url}/runs`,a);return{...n,joinRun:r.joinRun}},[C]),{assistantSystem:S}=l(),{messages:$,isLoading:j,error:x,sendMessage:A,stop:I,runId:R}=e({threadId:`assistant:${u}`,connection:k,persistence:!0,history:{pageSize:50},tools:s(S.getTools)}),v=a(async t=>{let e={sentAt:new Date().toISOString()};await A({content:t,metadata:e})},[A]),O=a(async()=>{if(I(),null!=R)try{let t=C();await fetch(`${t.url}/runs/${encodeURIComponent(R)}/cancel`,{method:"POST",headers:await t.headers()})}catch(t){d.warn("Could not cancel the assistant run on the server",{error:t})}},[C,d,R,I]);return n(()=>({messages:$,isLoading:j,error:x,failedStatus:p,isContinuable:f,isLoaded:y,send:v,stop:O}),[$,j,x,p,f,y,v,O])};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { AssistantToolItem } from './thread-items.js';
|
|
2
|
+
export interface AssistantToolChipsProps {
|
|
3
|
+
readonly tools: readonly AssistantToolItem[];
|
|
4
|
+
/** True while the reply runs and this row is its newest block: the assistant is at work on it. */
|
|
5
|
+
readonly isActive: boolean;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* A row of notes on what the assistant did in a reply, one per tool call. A click on a note logs
|
|
9
|
+
* the input and the result of its call to the console.
|
|
10
|
+
*/
|
|
11
|
+
export declare const AssistantToolChips: import("react").MemoExoticComponent<({ tools, isActive }: AssistantToolChipsProps) => import("react/jsx-runtime").JSX.Element>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{jsx as t,jsxs as e}from"react/jsx-runtime";import{Tooltip as a,styled as i}from"@mui/material";import{memo as n,useCallback as s}from"react";import{match as o}from"ts-pattern";import{useLocalizable as r}from"#package/react-sdk";import{PhxIcon as l}from"#package/ui-sdk";import{AssistantPanelName as d}from"./theme.js";let c={id:"sdk.assistant.tool.updateDesign.label",message:"Update design"},m={id:"sdk.assistant.tool.readDesign.label",message:"Read design"},p={id:"sdk.assistant.tool.mistake.hint",message:"The assistant made a mistake."},h=i("div",{name:d,slot:"chips"})(({theme:{palette:t,spacing:e,typography:a}})=>({...a.caption,alignItems:"start",color:t.text.secondary,display:"grid",gap:e(.75),gridTemplateColumns:"min-content minmax(0, 1fr)"})),g=i("span",{name:d,slot:"activity"})(({theme:{typography:t}})=>({blockSize:`calc(${t.caption.lineHeight} * 1em)`,display:"grid",placeItems:"center"})),f=i(l,{name:d,slot:"activityIcon"})({fontSize:14,'[data-chips="active"] &':{animation:"phx-assistant-turn 2.4s linear infinite","@media (prefers-reduced-motion: reduce)":{animation:"none"}},"@keyframes phx-assistant-turn":{to:{rotate:"360deg"}}}),k=i("span",{name:d,slot:"chip"})(({theme:{palette:t,spacing:e}})=>({cursor:"default",display:"inline-block",whiteSpace:"nowrap","&:not(:last-child)::after":{color:t.text.secondary,content:'"\xb7"',display:"inline-block",marginInline:e(.75),textDecoration:"none"},'&[data-chip="failed"]':{color:t.error.main},'&[data-chip="flawed"]':{textDecoration:"line-through",textDecorationColor:t.error.main}})),u=n(({tool:e})=>{let{chip:i,input:n,result:l}=e,d=r(c),h=r(m),g=r(p),f=o(i.label).with({kind:"text"},({text:t})=>t).with({kind:"updateDesign"},()=>d).with({kind:"readDesign"},()=>h).exhaustive(),u=s(()=>{console.info(`Assistant tool call "${f}"`,{input:n,result:l})},[n,f,l]);return t(a,{title:"failed"===i.state||"flawed"===i.state?g:"",placement:"top-start",children:t(k,{onClick:u,"data-chip":i.state,children:f})})});export const AssistantToolChips=n(({tools:a,isActive:i})=>e(h,{"data-chips":i?"active":"done","aria-busy":i,children:[t(g,{children:t(f,{name:"Gear"})}),t("div",{children:a.map(e=>t(u,{tool:e},e.id))})]}));
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { AssistantChatState } from '../../assistant/index.js';
|
|
2
|
+
export interface AssistantComposerProps {
|
|
3
|
+
readonly chat: AssistantChatState | undefined;
|
|
4
|
+
readonly onFocusChange: (isFocused: boolean) => void;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* The message input of the panel. Enter sends and Shift+Enter adds a line. While a reply runs the
|
|
8
|
+
* send control is a Stop control and the input stays editable, so the next message can be written.
|
|
9
|
+
* A thread this session may not continue disables the input and says why.
|
|
10
|
+
*/
|
|
11
|
+
export declare const AssistantComposer: ({ chat, onFocusChange }: AssistantComposerProps) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{jsx as e,jsxs as a}from"react/jsx-runtime";import{Trans as r}from"@lingui/react";import{IconButton as o,InputBase as i,Tooltip as t,styled as n}from"@mui/material";import{useCallback as s,useRef as d,useState as l}from"react";import{useLocalizable as m}from"#package/react-sdk";import{PhxIcon as c,useResponsive as p}from"#package/ui-sdk";import{AssistantPanelName as u}from"./theme.js";let b={id:"sdk.assistant.composer.placeholder",message:"Ask or tell me what to changeâĻ"},g={id:"sdk.assistant.composer.send.label",message:"Send"},h={id:"sdk.assistant.composer.stop.label",message:"Stop"},k=n("form",{name:u,slot:"composer"})(({theme:{palette:e,spacing:a}})=>({borderBlockStart:`1px solid ${e.divider}`,display:"grid",gap:a(.75),paddingBlock:a(1.25),paddingInline:`var(--phx-sidebar-padding, ${a(2)})`})),f=n("div",{name:u,slot:"inputFrame"})(({theme:{palette:e,spacing:a}})=>({alignItems:"flex-end",border:`1px solid ${e.divider}`,borderRadius:12,display:"flex",gap:a(1),paddingBlock:a(.5),paddingInline:`${a(1.5)} ${a(.5)}`,"&:focus-within":{borderColor:e.primary.main},"&:has(textarea:disabled)":{background:e.action.disabledBackground}})),x=n(i,{name:u,slot:"input"})(({theme:{spacing:e,typography:a}})=>({...a.body2,flex:1,paddingBlock:e(.75)})),v=n(o,{name:u,slot:"sendButton"})(({theme:{palette:e}})=>({background:e.primary.main,borderRadius:8,color:e.primary.contrastText,"&:hover":{background:e.primary.dark},"&.Mui-disabled":{background:e.action.disabledBackground,color:e.action.disabled}})),y=n(o,{name:u,slot:"stopButton"})(({theme:{palette:e}})=>({background:e.text.primary,borderRadius:8,color:e.background.paper,"&:hover":{background:e.text.secondary}})),B=n("span")({background:"currentColor",blockSize:10,borderRadius:2,inlineSize:10,margin:5}),C=n("div",{name:u,slot:"hint"})(({theme:{palette:e,typography:a}})=>({...a.caption,color:e.text.secondary}));export const AssistantComposer=({chat:o,onFocusChange:i})=>{let[n,u]=l(""),R=d(null),{isDesktop:S}=p(),w=m(b),z=m(g),$=m(h),j=o?.isLoading??!1,I=o?.isContinuable??!0,A=n.trim(),D=null!=o&&I&&!j&&A.length>0,P=s(()=>{o&&D&&(u(""),o.send(A),S||R.current?.blur())},[D,o,A,S]),T=s(e=>{e.preventDefault(),P()},[P]),E=s(e=>{"Enter"!==e.key||e.shiftKey||e.nativeEvent.isComposing||(e.preventDefault(),P())},[P]),F=s(()=>{o?.stop()},[o]);return a(k,{onSubmit:T,children:[!I&&e(C,{role:"status",children:e(r,{id:"sdk.assistant.composer.notContinuable",message:"This conversation can be read here, but it can no longer be continued."})}),a(f,{children:[e(x,{multiline:!0,maxRows:6,placeholder:w,value:n,disabled:!I,inputRef:R,onChange:e=>u(e.target.value),onKeyDown:E,onFocus:()=>i(!0),onBlur:()=>i(!1),inputProps:{"aria-label":w}}),j?e(t,{title:$,placement:"top",children:e(y,{size:"small","aria-label":$,onClick:F,children:e(B,{})})}):e(t,{title:z,placement:"top",children:e("span",{children:e(v,{type:"submit",size:"small","aria-label":z,disabled:!D,children:e(c,{name:"PaperPlaneRightBold",fontSize:"small"})})})})]}),e(C,{children:e(r,{id:"sdk.assistant.composer.disclaimer",message:"AI can be wrong. Check the result."})})]})};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export interface AssistantMarkdownProps {
|
|
2
|
+
readonly markdown: string;
|
|
3
|
+
/** True while the text is still arriving, so markup the model has not finished is completed. */
|
|
4
|
+
readonly isStreaming: boolean;
|
|
5
|
+
}
|
|
6
|
+
/** Assistant text of the thread: Markdown with lists, tables, links and code, without a bubble. */
|
|
7
|
+
export declare const AssistantMarkdown: import("react").MemoExoticComponent<({ markdown, isStreaming }: AssistantMarkdownProps) => import("react/jsx-runtime").JSX.Element>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{jsx as r}from"react/jsx-runtime";import{styled as e}from"@mui/material";import{memo as o}from"react";import a from"react-markdown";import i from"remark-gfm";import{completeStreamedMarkdown as n}from"./streamed-markdown.js";import{AssistantPanelName as t}from"./theme.js";let l=e("div",{name:t,slot:"assistantMessage"})(({theme:{palette:r,shape:e,spacing:o,typography:a}})=>({overflowWrap:"anywhere","& > :first-child":{marginBlockStart:0},"& > :last-child":{marginBlockEnd:0},"p, ul, ol, pre, blockquote":{marginBlock:o(1)},"h1, h2, h3, h4, h5, h6":{...a.subtitle2,marginBlock:o(1.5,.5)},"ul, ol":{paddingInlineStart:o(2.5)},a:{color:r.primary.main},code:{background:r.action.hover,borderRadius:e.borderRadius/2,fontFamily:"ui-monospace, Menlo, monospace",fontSize:"0.9em",paddingInline:o(.5)},pre:{background:r.action.hover,borderRadius:e.borderRadius,overflowX:"auto",padding:o(1),code:{background:"none",padding:0}},blockquote:{borderInlineStart:`2px solid ${r.divider}`,color:r.text.secondary,marginInline:0,paddingInlineStart:o(1.5)},"th, td":{borderBlockEnd:`1px solid ${r.divider}`,padding:o(.5,1),textAlign:"start",verticalAlign:"top"}})),d=e("div")({overflowX:"auto",table:{borderCollapse:"collapse",inlineSize:"100%"}}),m={a:({node:e,children:o,...a})=>r("a",{...a,target:"_blank",rel:"noopener noreferrer",children:o}),table:({node:e,children:o,...a})=>r(d,{children:r("table",{...a,children:o})})},s=[i],c=["img"];export const AssistantMarkdown=o(({markdown:e,isStreaming:o})=>r(l,{children:r(a,{components:m,remarkPlugins:s,disallowedElements:c,children:o?n(e):e})}));
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The attribute the panel carries on its root. The layouts key their styles on it: what the panel
|
|
3
|
+
* covers is hidden, and a sidebar shorter than its slot is stretched to the height the panel needs.
|
|
4
|
+
*/
|
|
5
|
+
export declare const ASSISTANT_PANEL_SLOT = "slot[assistant]";
|
|
6
|
+
/**
|
|
7
|
+
* The built-in assistant panel: a header with the title and a close control, the thread and the
|
|
8
|
+
* composer. It covers the sidebar it is rendered in, and renders nothing while it is closed or when
|
|
9
|
+
* the application spec has no `assistant` section.
|
|
10
|
+
*/
|
|
11
|
+
export declare const AssistantPanel: () => import("react/jsx-runtime").JSX.Element | null;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{jsx as e,jsxs as t}from"react/jsx-runtime";import{IconButton as a,Tooltip as s,Typography as n,styled as r}from"@mui/material";import{useCallback as o}from"react";import{useLocalizable as i}from"#package/react-sdk";import{PhxIcon as l}from"#package/ui-sdk";import{AssistantComposer as d}from"./AssistantComposer.js";import{useAssistantPanel as m,useAssistantPanelConversation as p}from"./AssistantPanelProvider.js";import{AssistantThread as c}from"./AssistantThread.js";import{AssistantPanelName as h}from"./theme.js";let u={id:"sdk.assistant.panel.title",message:"Assistant"},g={id:"sdk.assistant.panel.close.label",message:"Close assistant"};export const ASSISTANT_PANEL_SLOT="slot[assistant]";let b=r("section",{name:h,slot:"root"})(({theme:{palette:e}})=>({background:`var(--phx-sidebar-background, ${e.background.paper})`,border:"var(--phx-sidebar-border, 0)",borderRadius:"inherit",display:"grid",gridTemplateColumns:"minmax(0, 1fr)",gridTemplateRows:"min-content minmax(0, 1fr) min-content",inset:0,overflow:"hidden",position:"absolute",zIndex:1})),f=r("header",{name:h,slot:"header"})(({theme:{palette:e,spacing:t}})=>({alignItems:"center",borderBlockEnd:`1px solid ${e.divider}`,display:"flex",gap:t(1),justifyContent:"space-between",paddingBlock:t(1),paddingInline:`var(--phx-sidebar-padding, ${t(2)}) ${t(1)}`})),x=r(n,{name:h,slot:"title"})({fontWeight:600}),k=r(a,{name:h,slot:"closeButton"})({}),j=e=>{e.target instanceof Element&&e.target.closest("button")&&e.preventDefault()};export const AssistantPanel=()=>{let a=m(),n=p(),r=i(u),h=i(g),v=a?.setOpen,A=o(()=>{v?.(!1)},[v]);return a?.open&&n?t(b,{"data-sidebar":"slot[assistant]","aria-label":r,onMouseDown:j,children:[t(f,{children:[e(x,{variant:"subtitle1",component:"h2",children:r}),e(s,{title:h,placement:"top",children:e(k,{size:"small","aria-label":h,onClick:A,children:e(l,{name:"X"})})})]}),e(c,{chat:n.chat,onRetry:n.reloadThread}),e(d,{chat:n.chat,onFocusChange:a.setInputFocused})]}):null};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { type ReactNode } from 'react';
|
|
2
|
+
import { type AssistantChatState } from '../../assistant/index.js';
|
|
3
|
+
/**
|
|
4
|
+
* The built-in assistant panel of a universal layout as the layout and the toolbar button see it:
|
|
5
|
+
* whether it is open, and the few facts about it they render. It changes only when one of those does.
|
|
6
|
+
*/
|
|
7
|
+
export interface AssistantPanelState {
|
|
8
|
+
readonly open: boolean;
|
|
9
|
+
readonly setOpen: (open: boolean) => void;
|
|
10
|
+
/** True when a reply finished while the panel was closed and the panel was not opened since. */
|
|
11
|
+
readonly hasUnreadReply: boolean;
|
|
12
|
+
/** True while the message input has focus; a phone layout gives the panel the whole screen then. */
|
|
13
|
+
readonly isInputFocused: boolean;
|
|
14
|
+
readonly setInputFocused: (isInputFocused: boolean) => void;
|
|
15
|
+
}
|
|
16
|
+
/** The conversation of the assistant panel. It changes with every chunk of a streaming reply. */
|
|
17
|
+
export interface AssistantPanelConversation {
|
|
18
|
+
/** Nothing until the chat of the current attempt has mounted. */
|
|
19
|
+
readonly chat: AssistantChatState | undefined;
|
|
20
|
+
/**
|
|
21
|
+
* Loads the thread from the server again, rejoining a reply that is still running there. It never
|
|
22
|
+
* sends a message again, because the server may already hold it; a message that did not reach the
|
|
23
|
+
* server is therefore gone from the thread and has to be written again.
|
|
24
|
+
*/
|
|
25
|
+
readonly reloadThread: () => void;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* The assistant panel of the layout this is rendered in, or nothing when the application spec has no
|
|
29
|
+
* `assistant` section or the layout does not carry the panel.
|
|
30
|
+
*/
|
|
31
|
+
export declare const useAssistantPanel: () => AssistantPanelState | undefined;
|
|
32
|
+
/** The conversation of the assistant panel, under the same conditions as {@link useAssistantPanel}. */
|
|
33
|
+
export declare const useAssistantPanelConversation: () => AssistantPanelConversation | undefined;
|
|
34
|
+
export interface AssistantPanelProviderProps {
|
|
35
|
+
readonly children: ReactNode;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Owns the open state of the assistant panel and the single chat of the layout below it. The chat
|
|
39
|
+
* lives here and not in the panel, so a reply keeps streaming while the panel is closed. Without an
|
|
40
|
+
* `assistant` section in the application spec no chat is mounted and no request reaches the server.
|
|
41
|
+
*/
|
|
42
|
+
export declare const AssistantPanelProvider: ({ children }: AssistantPanelProviderProps) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{jsx as e,jsxs as r}from"react/jsx-runtime";import{createContext as t,useCallback as s,useContext as o,useEffect as n,useMemo as a,useRef as i,useState as l}from"react";import{useLogger as d,useSpecAssistant as u}from"#package/react-sdk";import{useAssistantChat as c}from"../../assistant/index.js";let v=t(void 0),m=t(void 0);export const useAssistantPanel=()=>o(v);export const useAssistantPanelConversation=()=>o(m);let p=({onChange:e})=>{let r=c();return n(()=>{e(r)},[r,e]),n(()=>()=>{e(void 0)},[e]),null};export const AssistantPanelProvider=({children:t})=>{let o=u(),[c,x]=l(),[f,P]=l(!1),[h,j]=l(!1),[g,A]=l(0),[k,C]=l(!1),q=d(),L=s(e=>{P(e),e?j(!1):C(!1)},[]),S=c?.isLoading??!1,T=i(!1),b=s(()=>{T.current=!1,A(e=>e+1)},[]);n(()=>{!T.current||S||f||null==c||j(!0),T.current=S},[c,S,f]);let w=c?.error,y=c?.failedStatus;n(()=>{w&&q.error("The assistant request failed",{status:y},w)},[w,y,q]);let z=a(()=>o?{open:f,setOpen:L,hasUnreadReply:h,isInputFocused:k,setInputFocused:C}:void 0,[o,f,L,h,k]),B=a(()=>o?{chat:c,reloadThread:b}:void 0,[o,c,b]);return e(v.Provider,{value:z,children:r(m.Provider,{value:B,children:[o&&e(p,{onChange:x},g),t]})})};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { AssistantChatState } from '../../assistant/index.js';
|
|
2
|
+
export interface AssistantThreadProps {
|
|
3
|
+
readonly chat: AssistantChatState | undefined;
|
|
4
|
+
readonly onRetry: () => void;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* The conversation: user bubbles, assistant Markdown, tool chips, and what the panel
|
|
8
|
+
* has to say itself, which is a greeting for an empty thread, a "ThinkingâĻ" line and a failure with
|
|
9
|
+
* its way out. It follows a streaming reply until the user scrolls up.
|
|
10
|
+
*/
|
|
11
|
+
export declare const AssistantThread: ({ chat, onRetry }: AssistantThreadProps) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{jsx as e,jsxs as i}from"react/jsx-runtime";import{Trans as a}from"@lingui/react";import{Button as s,styled as t}from"@mui/material";import{useMemo as n}from"react";import{match as r}from"ts-pattern";import{PhxIcon as o}from"#package/ui-sdk";import{AssistantToolChips as l}from"./AssistantChips.js";import{AssistantMarkdown as d}from"./AssistantMarkdown.js";import{describeAssistantFailure as m}from"./assistant-failure.js";import{AssistantPanelName as p}from"./theme.js";import{buildThreadView as h}from"./thread-items.js";import{useFollowStream as c}from"./use-follow-stream.js";let g=t("div",{name:p,slot:"thread"})({display:"grid",position:"relative"}),u=t("div",{name:p,slot:"messages"})(({theme:{spacing:e,typography:i}})=>({...i.body2,display:"flex",flexDirection:"column",gap:e(1.5),overflowY:"auto",overscrollBehavior:"contain",paddingBlock:e(2),paddingInline:`var(--phx-sidebar-padding, ${e(2)})`,"& > :first-child":{marginBlockStart:"auto"}})),f=t("div",{name:p,slot:"userMessage"})(({theme:{palette:e,spacing:i}})=>({alignSelf:"flex-end",background:`hsl(from ${e.primary.main} h s l / 12%)`,borderRadius:"14px 14px 4px 14px",maxInlineSize:"85%",overflowWrap:"anywhere",paddingBlock:i(1),paddingInline:i(1.5),whiteSpace:"pre-wrap"})),k=t("div",{name:p,slot:"greeting"})({}),v=t("div",{name:p,slot:"status"})(({theme:{palette:e,typography:i}})=>({...i.caption,color:e.text.secondary})),w=t("div",{name:p,slot:"notice"})(({theme:{palette:e,shape:i,spacing:a}})=>({alignItems:"center",background:e.action.hover,borderRadius:i.borderRadius,display:"flex",flexWrap:"wrap",gap:a(1),justifyContent:"space-between",paddingBlock:a(1),paddingInline:a(1.5)})),b=t(s,{name:p,slot:"newReplyButton"})(({theme:{palette:e,spacing:i}})=>({background:e.text.primary,borderRadius:"calc(infinity * 1px)",color:e.background.paper,insetBlockEnd:i(1),insetInlineStart:"50%",position:"absolute",translate:"-50% 0","&:hover":{background:e.text.secondary}})),x=({item:i,isActive:a})=>r(i).with({kind:"user"},({text:i})=>e(f,{children:i})).with({kind:"text"},({markdown:i,isStreaming:a})=>e(d,{markdown:i,isStreaming:a})).with({kind:"tools"},({tools:i})=>e(l,{tools:i,isActive:a})).exhaustive();export const AssistantThread=({chat:t,onRetry:l})=>{let d=t?.messages,p=t?.isLoading??!1,{items:f,isThinking:y}=n(()=>h(d??[],p),[d,p]),j=n(()=>f.filter(({kind:e})=>"user"===e).length,[f]),I=t?.error?m(t.failedStatus):void 0,{scrollerRef:S,hasUnseenContent:T,handleScroll:A,scrollToEnd:B}=c(n(()=>({messages:d,isThinking:y,failure:I?.kind}),[d,y,I?.kind]),j);return i(g,{children:[i(u,{ref:S,onScroll:A,role:"log","aria-live":"polite",children:[t?.isLoaded===!0&&0===f.length&&!p&&!I&&e(k,{children:e(a,{id:"sdk.assistant.thread.greeting",message:"Hi. I can answer questions about this design and change it with you. Tell me what you need."})}),f.map(i=>e(x,{item:i,isActive:p&&i===f.at(-1)},i.id)),y&&e(v,{children:e(a,{id:"sdk.assistant.thread.thinking",message:"ThinkingâĻ"})}),I&&i(w,{role:"alert",children:[e("span",{children:r(I.kind).with("notAvailable",()=>e(a,{id:"sdk.assistant.failure.notAvailable",message:"The assistant is not available here."})).with("busy",()=>e(a,{id:"sdk.assistant.failure.busy",message:"The assistant is still working on an earlier message."})).with("unavailable",()=>e(a,{id:"sdk.assistant.failure.unavailable",message:"The assistant is unavailable right now."})).exhaustive()}),I.canRetry&&e(s,{size:"small",variant:"outlined",color:"inherit",onClick:l,children:e(a,{id:"sdk.assistant.failure.retry.label",message:"Try again"})})]})]}),T&&e(b,{size:"small",onClick:B,endIcon:e(o,{name:"CaretDown"}),children:e(a,{id:"sdk.assistant.thread.newReply.label",message:"New reply"})})]})};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What the panel tells the user when the assistant failed:
|
|
3
|
+
* - `notAvailable`: the server refuses this configuration or customer, and asking again will not help
|
|
4
|
+
* - `busy`: the server is still answering an earlier message of this thread
|
|
5
|
+
* - `unavailable`: anything else, including a dropped connection and a reply that broke off
|
|
6
|
+
*/
|
|
7
|
+
export type AssistantFailureKind = 'notAvailable' | 'busy' | 'unavailable';
|
|
8
|
+
export interface AssistantFailure {
|
|
9
|
+
readonly kind: AssistantFailureKind;
|
|
10
|
+
/** True when loading the thread again may help, so the panel offers "Try again". */
|
|
11
|
+
readonly canRetry: boolean;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Maps a failed assistant request to what the panel shows, by the HTTP status the server answered
|
|
15
|
+
* with. A failure without a status never reached the server or broke off mid-reply; it gets the same
|
|
16
|
+
* generic message as an unknown status, because the chat client does not tell those apart.
|
|
17
|
+
*/
|
|
18
|
+
export declare const describeAssistantFailure: (failedStatus: number | undefined) => AssistantFailure;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const describeAssistantFailure=a=>403===a?{kind:"notAvailable",canRetry:!1}:409===a?{kind:"busy",canRetry:!0}:{kind:"unavailable",canRetry:!0};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export{AssistantPanel,ASSISTANT_PANEL_SLOT}from"./AssistantPanel.js";export{AssistantPanelProvider,useAssistantPanel}from"./AssistantPanelProvider.js";
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Makes the Markdown of a reply that is still streaming renderable as it stands, so half-written
|
|
3
|
+
* markup does not flash as raw characters: an open code fence is closed, an inline code span, a link
|
|
4
|
+
* or a table header the model has not finished is held back, and open bold text is closed.
|
|
5
|
+
*/
|
|
6
|
+
export declare const completeStreamedMarkdown: (text: string) => string;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
let e=(e,t)=>e.split(t).length-1,t=/^\|?\s*:?-+:?\s*(\|\s*:?-+:?\s*)*\|?\s*$/;export const completeStreamedMarkdown=l=>{if(e(l,"```")%2==1)return`${l}
|
|
2
|
+
\`\`\``;let n=l.lastIndexOf("```"),s=-1===n?"":l.slice(0,n+3),r=l.slice(s.length),i=(e=>{let l=e.split("\n"),n=l.length;for(;n>0&&l[n-1]?.trimStart().startsWith("|");)n-=1;let s=l.slice(n),r=s[1],i=null!=r&&s.length>2&&t.test(r);return 0===s.length||i?e:l.slice(0,n).join("\n")})((e(r,"`")%2==1?r.slice(0,r.lastIndexOf("`")):r).replace(/!?\[([^\]\n]*)\]\([^)\n]*$/,"$1").replace(/!?\[[^\]\n]*$/,"")),c=e(i,"**")%2==1?`${i}**`:i;return`${s}${c}`};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const AssistantPanelName="PhxAssistantPanel";
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { UIMessage } from '@tanstack/ai-react';
|
|
2
|
+
import { type AssistantToolChip } from './tool-chip.js';
|
|
3
|
+
/** A tool call of the thread, with what its chip shows and what a click on the chip logs. */
|
|
4
|
+
export interface AssistantToolItem {
|
|
5
|
+
readonly id: string;
|
|
6
|
+
readonly chip: AssistantToolChip;
|
|
7
|
+
readonly input: unknown;
|
|
8
|
+
readonly result: unknown;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* One block of the thread, in reading order: a user bubble, a stretch of assistant Markdown, or a
|
|
12
|
+
* row of chips for the tool calls that follow each other without text in between.
|
|
13
|
+
*/
|
|
14
|
+
export type AssistantThreadItem = {
|
|
15
|
+
readonly kind: 'user';
|
|
16
|
+
readonly id: string;
|
|
17
|
+
readonly text: string;
|
|
18
|
+
} | {
|
|
19
|
+
readonly kind: 'text';
|
|
20
|
+
readonly id: string;
|
|
21
|
+
readonly markdown: string;
|
|
22
|
+
readonly isStreaming: boolean;
|
|
23
|
+
} | {
|
|
24
|
+
readonly kind: 'tools';
|
|
25
|
+
readonly id: string;
|
|
26
|
+
readonly tools: readonly AssistantToolItem[];
|
|
27
|
+
};
|
|
28
|
+
export interface AssistantThreadView {
|
|
29
|
+
readonly items: readonly AssistantThreadItem[];
|
|
30
|
+
/** True while a reply runs and neither streaming text nor a row of tool chips shows that it does. */
|
|
31
|
+
readonly isThinking: boolean;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Lays the messages of the chat out as the blocks the thread renders. Reasoning is left out; tool
|
|
35
|
+
* results are not shown on their own but decide the state of the chip of their call.
|
|
36
|
+
*/
|
|
37
|
+
export declare const buildThreadView: (messages: ReadonlyArray<UIMessage>, isReplying: boolean) => AssistantThreadView;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{describeToolCall as t}from"./tool-chip.js";let e=t=>{try{return JSON.parse(t)}catch{return t}},r=t=>t.map(t=>"text"===t.type?t.content:"").join("").trim();export const buildThreadView=(o,n)=>{let l=(t=>{let r=new Map;for(let o of t)for(let t of o.parts)"tool-result"===t.type&&r.set(t.toolCallId,{result:"string"==typeof t.content?e(t.content):t.content,error:"error"===t.state?t.error??"The tool call failed.":void 0});return r})(o),i=[],s=o.at(-1),a=t=>{let e=i.at(-1);e?.kind==="tools"?i[i.length-1]={...e,tools:[...e.tools,t]}:i.push({kind:"tools",id:t.id,tools:[t]})};for(let e of o){if("user"===e.role){let t=r(e.parts);t&&i.push({kind:"user",id:e.id,text:t});continue}let o=n&&e===s;e.parts.forEach((r,n)=>{let s=`${e.id}:${n}`;if("text"===r.type){if(r.content.trim()){let t=o&&n===e.parts.length-1;i.push({kind:"text",id:s,markdown:r.content,isStreaming:t})}return}if("tool-call"!==r.type)return;let p=l.get(r.id),d=r.input,u=r.output??p?.result;a({id:r.id,input:d,result:u,chip:t({name:r.name,input:d,result:u,error:p?.error,isReplyRunning:o})})})}let p=i.at(-1),d=s?.role==="assistant"&&(p?.kind==="text"&&p.isStreaming||p?.kind==="tools");return{items:i,isThinking:n&&!d}};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How a tool call of the assistant looks in the thread: still running, finished, a change that was
|
|
3
|
+
* not kept (`failed`), or a read that answered with errors (`flawed`), which matters less because
|
|
4
|
+
* the assistant usually just asks again.
|
|
5
|
+
*/
|
|
6
|
+
export type AssistantToolChipState = 'running' | 'done' | 'failed' | 'flawed';
|
|
7
|
+
/** What a tool chip is called: the operation names the model gave, a fixed text, or the tool's name. */
|
|
8
|
+
export type AssistantToolChipLabel = {
|
|
9
|
+
readonly kind: 'text';
|
|
10
|
+
readonly text: string;
|
|
11
|
+
} | {
|
|
12
|
+
readonly kind: 'updateDesign';
|
|
13
|
+
} | {
|
|
14
|
+
readonly kind: 'readDesign';
|
|
15
|
+
};
|
|
16
|
+
export interface AssistantToolChip {
|
|
17
|
+
readonly label: AssistantToolChipLabel;
|
|
18
|
+
readonly state: AssistantToolChipState;
|
|
19
|
+
}
|
|
20
|
+
/** A tool call of a message as the chip reads it. */
|
|
21
|
+
export interface AssistantToolCall {
|
|
22
|
+
readonly name: string;
|
|
23
|
+
/** The parsed input of the call; nothing while the model is still writing it. */
|
|
24
|
+
readonly input: unknown;
|
|
25
|
+
/** The result of the call, parsed from JSON; nothing while there is none. */
|
|
26
|
+
readonly result: unknown;
|
|
27
|
+
/** The error text of a call the chat client could not run. */
|
|
28
|
+
readonly error: string | undefined;
|
|
29
|
+
/** True while the reply this call belongs to is still running. */
|
|
30
|
+
readonly isReplyRunning: boolean;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Describes one tool call for its chip: the label in the order operation names, fixed text for the
|
|
34
|
+
* `apply` and `query` tools, tool name; and whether the call runs, finished, or went wrong. Why it
|
|
35
|
+
* went wrong is not part of it: the tool result words that for the model, not for the user.
|
|
36
|
+
*/
|
|
37
|
+
export declare const describeToolCall: (call: AssistantToolCall) => AssistantToolChip;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{Kind as e,parse as t}from"graphql";import{z as n}from"zod";import{applyTool as r,queryTool as a}from"@salsita-ai/contracts/assistant";let o=n.object({operations:n.array(n.object({query:n.string(),operationName:n.string().nullish()}))}),i=n.object({results:n.array(n.object({errors:n.array(n.unknown()).optional()})),committed:n.boolean()});export const describeToolCall=n=>{let s=(({name:n,input:i})=>{let s,l=(s=o.safeParse(i)).success?s.data.operations.flatMap(({query:n,operationName:r})=>r??(n=>{try{let r=t(n).definitions.find(t=>t.kind===e.OPERATION_DEFINITION);return r?.kind===e.OPERATION_DEFINITION?r.name?.value:void 0}catch{return}})(n)??[]):[];return l.length>0?{kind:"text",text:l.join(", ")}:n===r.name?{kind:"updateDesign"}:n===a.name?{kind:"readDesign"}:{kind:"text",text:n}})(n);return null==n.result&&null==n.error?{label:s,state:n.isReplyRunning?"running":"done"}:{label:s,state:(({name:e,result:t,error:n})=>{if(null!=n)return e===a.name?"flawed":"failed";let o=i.safeParse(t);if(!o.success)return"done";let{results:s,committed:l}=o.data;return e===r.name?l?"done":"failed":s.some(({errors:e})=>(e?.length??0)>0)||0===s.length?"flawed":"done"})(n)}};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type RefObject } from 'react';
|
|
2
|
+
export interface FollowStream<ELEMENT extends HTMLElement> {
|
|
3
|
+
readonly scrollerRef: RefObject<ELEMENT>;
|
|
4
|
+
/** True when content arrived while the user was reading further up. */
|
|
5
|
+
readonly hasUnseenContent: boolean;
|
|
6
|
+
readonly handleScroll: () => void;
|
|
7
|
+
readonly scrollToEnd: () => void;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Keeps a scrolling thread at its end while content arrives, until the user scrolls up; from then on
|
|
11
|
+
* it only reports that there is unseen content, and follows again once the user is back at the end.
|
|
12
|
+
*
|
|
13
|
+
* @param content changes whenever the thread's content does
|
|
14
|
+
* @param followKey changes when the thread must return to its end whatever the user did, such as
|
|
15
|
+
* when the user sends a message
|
|
16
|
+
*/
|
|
17
|
+
export declare const useFollowStream: <ELEMENT extends HTMLElement>(content: unknown, followKey: unknown) => FollowStream<ELEMENT>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{useCallback as r,useEffect as e,useLayoutEffect as t,useRef as l,useState as c}from"react";export const useFollowStream=(o,n)=>{let s=l(null),u=l(!0),[i,g]=c(!1),h=r(()=>{let r=s.current;u.current=!0,g(!1),r&&(r.scrollTop=r.scrollHeight)},[]),H=r(()=>{let r=s.current;r&&(u.current=r.scrollHeight-r.scrollTop-r.clientHeight<=24,u.current&&g(!1))},[]);return t(()=>{h()},[n,h]),t(()=>{let r=s.current;r&&(u.current?r.scrollTop=r.scrollHeight:r.scrollHeight>r.clientHeight&&g(!0))},[o]),e(()=>{let r=s.current;if(!r)return;let e=new ResizeObserver(()=>{u.current&&(r.scrollTop=r.scrollHeight)});return e.observe(r),()=>{e.disconnect()}},[]),{scrollerRef:s,hasUnseenContent:i,handleScroll:H,scrollToEnd:h}};
|
|
@@ -1,11 +1,11 @@
|
|
|
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
|
|
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,useAssistantPanel 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})=>[`
|
|
2
2
|
--phx-sidebar-background: ${a.background};
|
|
3
3
|
--phx-sidebar-border: ${a.border};
|
|
4
4
|
--phx-sidebar-filter: ${a.filter};
|
|
5
5
|
--phx-sidebar-padding: ${a.padding};
|
|
6
6
|
--phx-sidebar-radius: ${a.borderRadius}px;
|
|
7
7
|
--phx-sidebar-scrollable-indicator-background: ${a.scrollableIndicatorBackground};
|
|
8
|
-
`,{borderRadius:"var(--phx-sidebar-radius)",display:"grid",filter:"var(--phx-sidebar-filter)",gridTemplateRows:"min-content minmax(0, 1fr) min-content",inlineSize:a.width,position:"relative","& > *":{pointerEvents:"auto"},"@container style(--inspect: on)":{"--phx-sidebar-background":"hsl(from gold h s l / 50%)"},[`&[data-sidebar*="${
|
|
8
|
+
`,{borderRadius:"var(--phx-sidebar-radius)",display:"grid",filter:"var(--phx-sidebar-filter)",gridTemplateRows:"min-content minmax(0, 1fr) min-content",inlineSize:a.width,position:"relative","& > *":{pointerEvents:"auto"},"@container style(--inspect: on)":{"--phx-sidebar-background":"hsl(from gold h s l / 50%)"},[`&[data-sidebar*="${I}"]`]:{opacity:1},[`&[data-sidebar*="${A}"]`]:{opacity:0},[`&[data-sidebar*="${P}"] > :not([data-sidebar="${S}"])`]:{visibility:"hidden"}}]),Tabs:i("div",{name:C,slot:"tabs",shouldForwardProp:a=>"ownerState"!==a})(({theme:{spacing:a}})=>({insetBlockStart:0,insetInlineEnd:"100%",maxInlineSize:150,paddingInlineEnd:a(2),position:"absolute","&:is(:empty)":{padding:0},[`.${r.root}`]:{boxShadow:"none"}})),Header:i("header",{name:C,slot:"header",shouldForwardProp:a=>"ownerState"!==a})({background:"var(--phx-sidebar-background)",border:"var(--phx-sidebar-border)",borderBlockEnd:0,borderStartStartRadius:"inherit",borderStartEndRadius:"inherit",paddingBlock:"calc(0.6 * var(--phx-sidebar-padding))",paddingInline:"var(--phx-sidebar-padding)","&:is(:empty)":{border:0,paddingBlock:0}}),Body:i("div",{name:C,slot:"body",shouldForwardProp:a=>"ownerState"!==a})(({ownerState:a})=>({background:"var(--phx-sidebar-background)",border:"var(--phx-sidebar-border)",borderBlockStart:0,borderBlockEnd:0,display:"grid",position:"relative",'[data-layout*="slot[sidebar]"]:where(:has([data-sidebar="slot[header]"])) &':{...a.isHeaderEmpty&&{borderBlockStart:"var(--phx-sidebar-border)",borderStartStartRadius:"inherit",borderStartEndRadius:"inherit",paddingBlockStart:"var(--phx-sidebar-padding)"}},'&:has([data-sidebar*="slot[content]"]:empty)':{...a.isContentEmpty&&{paddingBlock:0}},[`[data-sidebar*="${D}"] &`]:{...a.isContentEmpty&&{border:0}},[`[data-sidebar*="${T}"] &`]:{borderBlockEnd:"var(--phx-sidebar-border)",borderEndStartRadius:"inherit",borderEndEndRadius:"inherit",paddingBlockEnd:"var(--phx-sidebar-padding)"}})),Content:i("div",{name:C,slot:"content",shouldForwardProp:a=>"ownerState"!==a})(({ownerState:a,theme:{spacing:t}})=>({...y.layout.normalizeScrollableContainer,alignContent:"start",borderRadius:"inherit",display:"grid",gap:t(3),padding:"var(--phx-sidebar-padding)","@supports (animation-timeline: scroll())":{"&[data-scrollable]":{scrollTimeline:"--phx-sidebar-timeline y","&::after, &::before":{animation:`${y.keyframes.fadeIn} both`,animationTimeline:"--phx-sidebar-timeline",background:"var(--phx-sidebar-scrollable-indicator-background)",backgroundRepeat:"no-repeat",content:'""',display:"block",insetInline:0,opacity:0,pointerEvents:"none",position:"absolute",zIndex:1},"&::after":{animationDirection:"reverse",animationRange:`calc(100% - ${t(4)}) 100%`,borderEndStartRadius:"inherit",borderEndEndRadius:"inherit",insetBlockStart:"50%",insetBlockEnd:0,scale:"1 -1"},"&::before":{animationRange:`0 ${t(4)}`,borderStartStartRadius:"inherit",borderStartEndRadius:"inherit",insetBlockStart:0,insetBlockEnd:"50%"}}},"&:is(:empty)":{paddingBlock:0},'[data-layout*="slot[sidebar]"] &':{...a.isHeaderEmpty&&{paddingBlockStart:0,"&::before":{borderStartStartRadius:0,borderStartEndRadius:0,insetBlockStart:"var(--phx-sidebar-padding)"}}},[`[data-sidebar*="${T}"] &`]:{paddingBlockEnd:0,"&::after":{borderEndStartRadius:0,borderEndEndRadius:0,insetBlockEnd:"var(--phx-sidebar-padding)"}}})),Footer:i("footer",{name:C,slot:"footer",shouldForwardProp:a=>"ownerState"!==a})(({ownerState:a,theme:{palette:t,spacing:o}})=>({background:"var(--phx-sidebar-background)",border:"var(--phx-sidebar-border)",borderBlockStart:`1px solid ${t.divider}`,borderEndStartRadius:"inherit",borderEndEndRadius:"inherit",padding:"var(--phx-sidebar-padding)","&:is(:empty)":{border:0,paddingBlock:0},[`[data-sidebar*="${D}"] &`]:{...a.isContentEmpty&&{borderBlockStart:"var(--phx-sidebar-border)",borderStartStartRadius:"inherit",borderStartEndRadius:"inherit"}},[`[data-sidebar*="${T}"] &`]:{borderBlockStart:"var(--phx-sidebar-border)",borderStartStartRadius:"inherit",borderStartEndRadius:"inherit",marginBlockStart:o(2)}}))};export const PhxDesktopLayoutName="PhxDesktopLayout";let j="PhxDesktopLayout",z=i(p.div,{name:j,slot:"root",shouldForwardProp:a=>"ownerState"!==a})(({ownerState:a,theme:{spacing:t}})=>{let o=e({"0%":{marginInlineEnd:0},"100%":{marginInlineEnd:t(-2)}});return[`
|
|
9
9
|
--inspect: off; // đšī¸ inspection mode toggle
|
|
10
10
|
|
|
11
11
|
--phx-layout-sidebar-track-size: ${g(a.sidebarWidth)};
|
|
@@ -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*="${
|
|
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=`
|
|
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:
|
|
45
|
+
`,padding:q=p(2.5),scrollableIndicatorBackground:M=`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:
|
|
49
|
+
)`}=s({props:{},name:C}),{hasMiniSidebar:N,hasSplitSidebar:V}=R.useSidebarContent(),X=w()?.open??!1,{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")]})})};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{jsx as r,jsxs as
|
|
1
|
+
import{jsx as r,jsxs as s,Fragment as o}from"react/jsx-runtime";import{useResponsive as t}from"#package/ui-sdk";import{AssistantPanelProvider as e}from"../../assistant/index.js";import{LayoutSlots as a}from"../slots/index.js";import{DesktopLayout as i}from"./DesktopLayout.js";import{MobileLayout as m}from"./MobileLayout.js";export const Layout=()=>{let{isDesktop:n}=t();return s(o,{children:[r(a.Services,{}),r(a.SharedCanvas,{}),r(e,{children:n?r(i,{}):r(m,{})})]})};
|
|
@@ -86,6 +86,8 @@ declare module '@mui/material/styles' {
|
|
|
86
86
|
}
|
|
87
87
|
interface LayoutOwnerState {
|
|
88
88
|
readonly isContentEmpty?: boolean;
|
|
89
|
+
/** Height of the assistant panel while its input has focus: what the on-screen keyboard leaves free. */
|
|
90
|
+
readonly assistantFocusHeight?: number;
|
|
89
91
|
}
|
|
90
92
|
export interface ThemeableMobileLayoutProps extends LayoutOwnerState {
|
|
91
93
|
/**
|