@vuu-ui/vuu-shell 0.6.25 → 0.6.26-debug

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/esm/index.js CHANGED
@@ -1,2 +1,714 @@
1
- import ge,{useEffect as fe,useState as ye}from"react";import ve from"classnames";import{Fragment as xe,jsx as Se,jsxs as E}from"react/jsx-runtime";var bt=({connectionStatus:t,className:e,element:o="span",...r})=>{let[a,s]=ye("vuuConnectingStatus");fe(()=>{switch(t){case"connected":case"reconnected":s("vuuActiveStatus");break;case"connecting":s("vuuConnectingStatus");break;case"disconnected":s("vuuDisconnectedStatus");break;default:break}},[t]);let n=ge.createElement(o,{...r,className:ve("vuuStatus vuuIcon",a,e)});return Se(xe,{children:E("div",{className:"vuuStatus-container salt-theme",children:[n,E("div",{className:"vuuStatus-text",children:["Status: ",t.toUpperCase()]})]})})};import B,{Suspense as we}from"react";import{registerComponent as De}from"@vuu-ui/vuu-layout";import Ce from"react";import{Fragment as Le,jsx as U,jsxs as Pe}from"react/jsx-runtime";var x=class extends Ce.Component{constructor(e){super(e),this.state={errorMessage:null}}static getDerivedStateFromError(e){return{errorMessage:e.message}}componentDidCatch(e,o){console.log(e,o)}render(){return this.state.errorMessage?Pe(Le,{children:[U("h1",{children:"Something went wrong."}),U("p",{children:this.state.errorMessage})]}):this.props.children}};import{jsx as Te}from"react/jsx-runtime";var I=()=>Te("div",{className:"hwLoader",children:"loading"});var R=async t=>{let e=new CSSStyleSheet;return fetch(t).then(o=>o.text()).then(o=>e.replace(o))};import{jsx as S}from"react/jsx-runtime";function He({url:t,css:e,params:o,...r}){e&&R(e).then(s=>{document.adoptedStyleSheets=[...document.adoptedStyleSheets,s]});let a=B.lazy(()=>import(t));return S(x,{children:S(we,{fallback:S(I,{}),children:S(a,{...r,...o})})})}var A=B.memo(He);A.displayName="Feature";De("Feature",A,"view");import{useState as F}from"react";import{Button as be}from"@salt-ds/core";import{FormField as V,Input as O}from"@heswell/salt-lab";import{jsx as y,jsxs as Me}from"react/jsx-runtime";var $="vuuLoginPanel",oo=({onSubmit:t})=>{let[e,o]=F(""),[r,a]=F(""),s=()=>{t(e,r)},n=(l,u)=>{o(u)},c=(l,u)=>{a(u)},i=e.trim()!==""&&r.trim()!=="";return Me("div",{className:$,children:[y(V,{label:"Username",style:{width:200},children:y(O,{value:e,id:"text-username",onChange:n})}),y(V,{label:"Password",style:{width:200},children:y(O,{type:"password",value:r,id:"text-password",onChange:c})}),y(be,{className:`${$}-login`,disabled:!i,onClick:s,variant:"cta",children:"Login"})]})};import{getCookieValue as G}from"@vuu-ui/vuu-utils";var ao=()=>{let t=G("vuu-username"),e=G("vuu-auth-token");return[t,e]},Ne=(t="/login.html")=>{window.location.href=t},_=t=>{document.cookie="vuu-username= ; expires = Thu, 01 Jan 1970 00:00:00 GMT",document.cookie="vuu-auth-token= ; expires = Thu, 01 Jan 1970 00:00:00 GMT",Ne(t)};import{connectToServer as ht}from"@vuu-ui/vuu-data";import{useCallback as L,useEffect as gt,useRef as b,useState as ne}from"react";import{useCallback as P,useEffect as ke,useState as Ee}from"react";var Ue=(t,e)=>{let[o,r]=Ee(e),a=i=>{r(i)},s=P(async(i="latest")=>{fetch(`api/vui/${t.username}/${i}`,{}).then(l=>l.ok?l.json():e).then(a).catch(()=>{a(e)})},[e,t.username]);ke(()=>{s()},[s]);let n=P(i=>{fetch(`api/vui/${t.username}`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(i)}).then(l=>l.ok?l.json():e)},[e,t]),c=P(i=>{s(i)},[s]);return[o,n,c]},J=Ue;import{createContext as Ie,useContext as Re}from"react";import{jsx as T}from"react/jsx-runtime";var Be={},w=Ie(Be),Ae=({children:t,context:e,inheritedContext:o})=>{let r={...o,...e};return T(w.Provider,{value:r,children:t})},z=({children:t,value:e})=>T(w.Consumer,{children:o=>T(Ae,{context:e,inheritedContext:o,children:t})}),yo=()=>Re(w);import ft from"classnames";import{Chest as yt,DraggableLayout as se,Drawer as vt,Flexbox as xt,LayoutProvider as St,View as Ct}from"@vuu-ui/vuu-layout";import{useCallback as oe}from"react";import{Button as Ke}from"@salt-ds/core";import{DropdownBase as Qe}from"@heswell/salt-lab";import{UserSolidIcon as We}from"@salt-ds/icons";import{formatDate as Fe}from"@vuu-ui/vuu-utils";import{List as Ve,ListItem as Oe}from"@heswell/salt-lab";import{Button as $e}from"@salt-ds/core";import{ExportIcon as Ge}from"@salt-ds/icons";import{forwardRef as _e,useCallback as Y,useEffect as Je,useState as ze}from"react";var q=async t=>await fetch(`api/vui/${t.username}`,{}).then(o=>o.ok?o.json():null).catch(()=>{console.log("error getting history")});import{jsx as C,jsxs as K}from"react/jsx-runtime";var qe=({lastUpdate:t},{lastUpdate:e})=>e===t?0:e<t?-1:1,Ye=t=>C(Oe,{...t}),Q=_e(function({loginUrl:e,onNavigate:o,user:r,layoutId:a="latest"},s){let[n,c]=ze([]);Je(()=>{async function d(){let h=(await q(r)).filter(f=>f.id!=="latest").sort(qe).map(({id:f,lastUpdate:v})=>({lastUpdate:v,id:f,label:`Saved at ${Fe(new Date(v),"kk:mm:ss")}`}));console.log({sortedHistory:h}),c(h)}d()},[r]);let i=Y((d,p)=>{p&&o(p.id)},[o]),l=Y(()=>{_(e)},[e]),u=n.length===0?null:a==="latest"?n[0]:n.find(d=>d.id===a);return K("div",{className:"vuuUserPanel",ref:s,children:[C(Ve,{ListItem:Ye,className:"vuuUserPanel-history",onSelect:i,selected:u,source:n}),C("div",{className:"vuuUserPanel-buttonBar",children:K($e,{"aria-label":"logout",onClick:l,children:[C(Ge,{})," Logout"]})})]})});import{jsx as D,jsxs as Xe}from"react/jsx-runtime";var W=({layoutId:t,loginUrl:e,onNavigate:o,user:r})=>Xe(Qe,{className:"vuuUserProfile",placement:"bottom-end",children:[D(Ke,{variant:"secondary",children:D(We,{})}),D(Q,{layoutId:t,loginUrl:e,onNavigate:s=>{o(s)},user:r})]});import{ToggleButton as X,ToggleButtonGroup as Ze}from"@heswell/salt-lab";import je from"classnames";import{useControlled as et}from"@salt-ds/core";import{useCallback as tt}from"react";import{jsx as j,jsxs as rt}from"react/jsx-runtime";var ot="vuuThemeSwitch",Z=["light","dark"],ee=({className:t,defaultMode:e,mode:o,onChange:r,...a})=>{let[s,n]=et({controlled:o,default:e!=null?e:"light",name:"ThemeSwitch",state:"mode"}),c=Z.indexOf(s),i=tt((u,d)=>{let p=Z[d];n(p),r(p)},[r,n]),l=je(ot,t);return rt(Ze,{className:l,...a,onChange:i,selectedIndex:c,children:[j(X,{"aria-label":"alert",tooltipText:"Light Theme","data-icon":"light"}),j(X,{"aria-label":"home",tooltipText:"Dark Theme","data-icon":"dark"})]})};import ut from"classnames";import{Dropdown as nt}from"@heswell/salt-lab";import{DEFAULT_DENSITY as st}from"@salt-ds/core";import{useCallback as at}from"react";import it from"classnames";import{jsx as ct}from"react/jsx-runtime";var lt="vuuDensitySwitch",mt=["high","medium","low","touch"],te=({className:t,defaultDensity:e=st,onDensityChange:o})=>{let r=at((s,n)=>{o(n)},[o]),a=it(lt,t);return ct(nt,{className:a,source:mt,defaultSelected:e,onSelectionChange:r})};import{jsx as H,jsxs as pt}from"react/jsx-runtime";var dt="vuuAppHeader",re=({className:t,layoutId:e,loginUrl:o,onNavigate:r,onSwitchTheme:a,themeMode:s="light",onDensitySwitch:n,density:c="medium",user:i,...l})=>{let u=ut(dt,t,`salt-density-${c}`),d=oe(h=>a==null?void 0:a(h),[a]),p=oe(h=>n==null?void 0:n(h),[n]);return pt("header",{className:u,...l,children:[H(ee,{defaultMode:s,onChange:d}),H(te,{defaultDensity:c,onDensityChange:p}),H(W,{layoutId:e,loginUrl:o,onNavigate:r,user:i})]})};import{jsx as g,jsxs as ae}from"react/jsx-runtime";var Lt={type:"View",props:{style:{height:"calc(100% - 6px)"}},children:[{props:{className:"vuuShell-warningPlaceholder"},type:"Placeholder"}]},qr=({children:t,className:e,defaultLayout:o=Lt,leftSidePanel:r,loginUrl:a,serverUrl:s,user:n,...c})=>{let i=b(null),[l,u]=ne("medium"),d=b(null),[p,h]=ne(!1),f=b("latest"),[v,M,N]=J(n,o),ie=L(m=>{M(m)},[M]),le=L(m=>{i.current&&(i.current.dataset.mode=m)},[]),me=L(m=>{u(m)},[u]),ce=m=>{var k;let he=m.target;(k=d.current)!=null&&k.contains(he)||h(!p)},ue=L(m=>{f.current=m,N(m)},[N]);gt(()=>{s&&n.token&&ht(s,n.token)},[s,n.token]);let de=()=>{let m=[];return r&&m.push(g(vt,{onClick:ce,open:p,position:"left",inline:!0,peekaboo:!0,sizeOpen:200,toggleButton:"end",children:g(Ct,{className:"vuuShell-palette",id:"vw-app-palette",ref:d,style:{height:"100%"},children:r},"app-palette")},"left-panel")),m},pe=ft("vuuShell",e,"salt-theme",`salt-density-${l}`);return ae(z,{value:void 0,children:[g(St,{layout:v,onLayoutChange:ie,children:g(se,{className:pe,"data-mode":"light",ref:i,...c,children:ae(xt,{className:"App",style:{flexDirection:"column",height:"100%",width:"100%"},children:[g(re,{layoutId:f.current,loginUrl:a,user:n,onNavigate:ue,onSwitchTheme:le,onDensitySwitch:me}),g(yt,{style:{flex:1},children:de().concat(g(se,{dropTarget:!0,style:{width:"100%",height:"100%"}},"main-content"))})]})})}),t]})};export{bt as ConnectionStatusIcon,A as Feature,oo as LoginPanel,qr as Shell,z as ShellContextProvider,ee as ThemeSwitch,ao as getAuthDetailsFromCookies,_ as logout,Ne as redirectToLogin,yo as useShellContext};
1
+ // src/connection-status/ConnectionStatusIcon.tsx
2
+ import React, { useEffect, useState } from "react";
3
+ import cx from "classnames";
4
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
5
+ var ConnectionStatusIcon = ({ connectionStatus, className, element = "span", ...props }) => {
6
+ const [classBase5, setClassBase] = useState("vuuConnectingStatus");
7
+ useEffect(() => {
8
+ switch (connectionStatus) {
9
+ case "connected":
10
+ case "reconnected":
11
+ setClassBase("vuuActiveStatus");
12
+ break;
13
+ case "connecting":
14
+ setClassBase("vuuConnectingStatus");
15
+ break;
16
+ case "disconnected":
17
+ setClassBase("vuuDisconnectedStatus");
18
+ break;
19
+ default:
20
+ break;
21
+ }
22
+ }, [connectionStatus]);
23
+ const statusIcon = React.createElement(
24
+ element,
25
+ {
26
+ ...props,
27
+ className: cx("vuuStatus vuuIcon", classBase5, className)
28
+ }
29
+ );
30
+ return /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsxs("div", { className: "vuuStatus-container salt-theme", children: [
31
+ statusIcon,
32
+ /* @__PURE__ */ jsxs("div", { className: "vuuStatus-text", children: [
33
+ "Status: ",
34
+ connectionStatus.toUpperCase()
35
+ ] })
36
+ ] }) });
37
+ };
38
+
39
+ // src/density-switch/DensitySwitch.tsx
40
+ import { Dropdown } from "@heswell/salt-lab";
41
+ import { useCallback } from "react";
42
+ import cx2 from "classnames";
43
+ import { jsx as jsx2 } from "react/jsx-runtime";
44
+ var classBase = "vuuDensitySwitch";
45
+ var densities = ["high", "medium", "low", "touch"];
46
+ var DEFAULT_DENSITY = "high";
47
+ var DensitySwitch = ({
48
+ className: classNameProp,
49
+ defaultDensity = DEFAULT_DENSITY,
50
+ onDensityChange
51
+ }) => {
52
+ const handleSelectionChange = useCallback((_event, selectedItem) => {
53
+ onDensityChange(selectedItem);
54
+ }, [onDensityChange]);
55
+ const className = cx2(classBase, classNameProp);
56
+ return /* @__PURE__ */ jsx2(
57
+ Dropdown,
58
+ {
59
+ className,
60
+ source: densities,
61
+ defaultSelected: defaultDensity,
62
+ onSelectionChange: handleSelectionChange
63
+ }
64
+ );
65
+ };
66
+
67
+ // src/feature/Feature.tsx
68
+ import React3, { Suspense } from "react";
69
+ import { registerComponent } from "@vuu-ui/vuu-layout";
70
+
71
+ // src/feature/ErrorBoundary.jsx
72
+ import React2 from "react";
73
+ import { Fragment as Fragment2, jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
74
+ var ErrorBoundary = class extends React2.Component {
75
+ constructor(props) {
76
+ super(props);
77
+ this.state = { errorMessage: null };
78
+ }
79
+ static getDerivedStateFromError(error) {
80
+ return { errorMessage: error.message };
81
+ }
82
+ componentDidCatch(error, errorInfo) {
83
+ console.log(error, errorInfo);
84
+ }
85
+ render() {
86
+ if (this.state.errorMessage) {
87
+ return /* @__PURE__ */ jsxs2(Fragment2, { children: [
88
+ /* @__PURE__ */ jsx3("h1", { children: "Something went wrong." }),
89
+ /* @__PURE__ */ jsx3("p", { children: this.state.errorMessage })
90
+ ] });
91
+ }
92
+ return this.props.children;
93
+ }
94
+ };
95
+
96
+ // src/feature/Loader.tsx
97
+ import { jsx as jsx4 } from "react/jsx-runtime";
98
+ var Loader = () => /* @__PURE__ */ jsx4("div", { className: "hwLoader", children: "loading" });
99
+
100
+ // src/feature/Feature.tsx
101
+ import { jsx as jsx5 } from "react/jsx-runtime";
102
+ function RawFeature({
103
+ url,
104
+ css,
105
+ params,
106
+ ...props
107
+ }) {
108
+ if (css) {
109
+ import(
110
+ /* @vite-ignore */
111
+ css
112
+ ).then(
113
+ (cssModule) => {
114
+ document.adoptedStyleSheets = [
115
+ ...document.adoptedStyleSheets,
116
+ cssModule.default
117
+ ];
118
+ }
119
+ );
120
+ }
121
+ const LazyFeature = React3.lazy(() => import(
122
+ /* @vite-ignore */
123
+ url
124
+ ));
125
+ return /* @__PURE__ */ jsx5(ErrorBoundary, { children: /* @__PURE__ */ jsx5(Suspense, { fallback: /* @__PURE__ */ jsx5(Loader, {}), children: /* @__PURE__ */ jsx5(LazyFeature, { ...props, ...params }) }) });
126
+ }
127
+ var Feature = React3.memo(RawFeature);
128
+ Feature.displayName = "Feature";
129
+ registerComponent("Feature", Feature, "view");
130
+
131
+ // src/login/LoginPanel.tsx
132
+ import { useState as useState2 } from "react";
133
+ import { Button } from "@salt-ds/core";
134
+ import { FormField, Input } from "@heswell/salt-lab";
135
+ import { jsx as jsx6, jsxs as jsxs3 } from "react/jsx-runtime";
136
+ var classBase2 = "vuuLoginPanel";
137
+ var LoginPanel = ({ onSubmit }) => {
138
+ const [username, setUserName] = useState2("");
139
+ const [password, setPassword] = useState2("");
140
+ const login = () => {
141
+ onSubmit(username, password);
142
+ };
143
+ const handleUsername = (_event, value) => {
144
+ setUserName(value);
145
+ };
146
+ const handlePassword = (_event, value) => {
147
+ setPassword(value);
148
+ };
149
+ const dataIsValid = username.trim() !== "" && password.trim() !== "";
150
+ return /* @__PURE__ */ jsxs3("div", { className: classBase2, children: [
151
+ /* @__PURE__ */ jsx6(FormField, { label: "Username", style: { width: 200 }, children: /* @__PURE__ */ jsx6(Input, { value: username, id: "text-username", onChange: handleUsername }) }),
152
+ /* @__PURE__ */ jsx6(FormField, { label: "Password", style: { width: 200 }, children: /* @__PURE__ */ jsx6(
153
+ Input,
154
+ {
155
+ type: "password",
156
+ value: password,
157
+ id: "text-password",
158
+ onChange: handlePassword
159
+ }
160
+ ) }),
161
+ /* @__PURE__ */ jsx6(
162
+ Button,
163
+ {
164
+ className: `${classBase2}-login`,
165
+ disabled: !dataIsValid,
166
+ onClick: login,
167
+ variant: "cta",
168
+ children: "Login"
169
+ }
170
+ )
171
+ ] });
172
+ };
173
+
174
+ // src/login/login-utils.ts
175
+ import { getCookieValue } from "@vuu-ui/vuu-utils";
176
+ var getAuthDetailsFromCookies = () => {
177
+ const username = getCookieValue("vuu-username");
178
+ const token = getCookieValue("vuu-auth-token");
179
+ return [username, token];
180
+ };
181
+ var redirectToLogin = (loginUrl = "/login.html") => {
182
+ window.location.href = loginUrl;
183
+ };
184
+ var logout = (loginUrl) => {
185
+ document.cookie = "vuu-username= ; expires = Thu, 01 Jan 1970 00:00:00 GMT";
186
+ document.cookie = "vuu-auth-token= ; expires = Thu, 01 Jan 1970 00:00:00 GMT";
187
+ redirectToLogin(loginUrl);
188
+ };
189
+
190
+ // src/shell.tsx
191
+ import { connectToServer } from "@vuu-ui/vuu-data";
192
+ import cx5 from "classnames";
193
+ import {
194
+ useCallback as useCallback6,
195
+ useEffect as useEffect4,
196
+ useRef,
197
+ useState as useState5
198
+ } from "react";
199
+
200
+ // src/ShellContextProvider.tsx
201
+ import { createContext, useContext } from "react";
202
+ import { jsx as jsx7 } from "react/jsx-runtime";
203
+ var defaultConfig = {};
204
+ var ShellContext = createContext(defaultConfig);
205
+ var Provider = ({
206
+ children,
207
+ context,
208
+ inheritedContext
209
+ }) => {
210
+ const mergedContext = {
211
+ ...inheritedContext,
212
+ ...context
213
+ };
214
+ return /* @__PURE__ */ jsx7(ShellContext.Provider, { value: mergedContext, children });
215
+ };
216
+ var ShellContextProvider = ({
217
+ children,
218
+ value
219
+ }) => {
220
+ return /* @__PURE__ */ jsx7(ShellContext.Consumer, { children: (context) => /* @__PURE__ */ jsx7(Provider, { context: value, inheritedContext: context, children }) });
221
+ };
222
+ var useShellContext = () => {
223
+ return useContext(ShellContext);
224
+ };
225
+
226
+ // src/use-layout-config.js
227
+ import { useCallback as useCallback2, useEffect as useEffect2, useState as useState3 } from "react";
228
+ var useLayoutConfig = (user, defaultLayout) => {
229
+ const [layout, _setLayout] = useState3(defaultLayout);
230
+ const setLayout = (layout2) => {
231
+ _setLayout(layout2);
232
+ };
233
+ const load = useCallback2(
234
+ async (id = "latest") => {
235
+ fetch(`api/vui/${user.username}/${id}`, {}).then((response) => {
236
+ return response.ok ? response.json() : defaultLayout;
237
+ }).then(setLayout).catch(() => {
238
+ setLayout(defaultLayout);
239
+ });
240
+ },
241
+ [defaultLayout, user.username]
242
+ );
243
+ useEffect2(() => {
244
+ load();
245
+ }, [load]);
246
+ const saveData = useCallback2(
247
+ (data) => {
248
+ fetch(`api/vui/${user.username}`, {
249
+ method: "POST",
250
+ headers: {
251
+ "Content-Type": "application/json"
252
+ },
253
+ body: JSON.stringify(data)
254
+ }).then((response) => {
255
+ return response.ok ? response.json() : defaultLayout;
256
+ });
257
+ },
258
+ [defaultLayout, user]
259
+ );
260
+ const loadLayoutById = useCallback2(
261
+ (id) => {
262
+ load(id);
263
+ },
264
+ [load]
265
+ );
266
+ return [layout, saveData, loadLayoutById];
267
+ };
268
+ var use_layout_config_default = useLayoutConfig;
269
+
270
+ // src/shell.tsx
271
+ import {
272
+ DockLayout,
273
+ DraggableLayout,
274
+ Drawer,
275
+ Flexbox,
276
+ LayoutProvider,
277
+ View
278
+ } from "@vuu-ui/vuu-layout";
279
+
280
+ // src/app-header/AppHeader.tsx
281
+ import { useCallback as useCallback5 } from "react";
282
+
283
+ // src/user-profile/UserProfile.tsx
284
+ import { Button as Button3 } from "@salt-ds/core";
285
+ import { DropdownBase } from "@heswell/salt-lab";
286
+ import { UserSolidIcon } from "@salt-ds/icons";
287
+
288
+ // src/user-profile/UserPanel.tsx
289
+ import { formatDate } from "@vuu-ui/vuu-utils";
290
+ import { List, ListItem } from "@heswell/salt-lab";
291
+ import { Button as Button2 } from "@salt-ds/core";
292
+ import { ExportIcon } from "@salt-ds/icons";
293
+ import {
294
+ forwardRef,
295
+ useCallback as useCallback3,
296
+ useEffect as useEffect3,
297
+ useState as useState4
298
+ } from "react";
299
+
300
+ // src/get-layout-history.ts
301
+ var getLayoutHistory = async (user) => {
302
+ const history = await fetch(`api/vui/${user.username}`, {}).then((response) => {
303
+ return response.ok ? response.json() : null;
304
+ }).catch(() => {
305
+ console.log("error getting history");
306
+ });
307
+ return history;
308
+ };
309
+
310
+ // src/user-profile/UserPanel.tsx
311
+ import { jsx as jsx8, jsxs as jsxs4 } from "react/jsx-runtime";
312
+ var byLastUpdate = ({ lastUpdate: l1 }, { lastUpdate: l2 }) => {
313
+ return l2 === l1 ? 0 : l2 < l1 ? -1 : 1;
314
+ };
315
+ var HistoryListItem = (props) => {
316
+ return /* @__PURE__ */ jsx8(ListItem, { ...props });
317
+ };
318
+ var UserPanel = forwardRef(function UserPanel2({ loginUrl, onNavigate, user, layoutId = "latest" }, forwardedRef) {
319
+ const [history, setHistory] = useState4([]);
320
+ useEffect3(() => {
321
+ async function getHistory() {
322
+ const history2 = await getLayoutHistory(user);
323
+ const sortedHistory = history2.filter((item) => item.id !== "latest").sort(byLastUpdate).map(({ id, lastUpdate }) => ({
324
+ lastUpdate,
325
+ id,
326
+ label: `Saved at ${formatDate(new Date(lastUpdate), "kk:mm:ss")}`
327
+ }));
328
+ console.log({ sortedHistory });
329
+ setHistory(sortedHistory);
330
+ }
331
+ getHistory();
332
+ }, [user]);
333
+ const handleHisorySelected = useCallback3(
334
+ (evt, selected2) => {
335
+ if (selected2) {
336
+ onNavigate(selected2.id);
337
+ }
338
+ },
339
+ [onNavigate]
340
+ );
341
+ const handleLogout = useCallback3(() => {
342
+ logout(loginUrl);
343
+ }, [loginUrl]);
344
+ const selected = history.length === 0 ? null : layoutId === "latest" ? history[0] : history.find((i) => i.id === layoutId);
345
+ return /* @__PURE__ */ jsxs4("div", { className: "vuuUserPanel", ref: forwardedRef, children: [
346
+ /* @__PURE__ */ jsx8(
347
+ List,
348
+ {
349
+ ListItem: HistoryListItem,
350
+ className: "vuuUserPanel-history",
351
+ onSelect: handleHisorySelected,
352
+ selected,
353
+ source: history
354
+ }
355
+ ),
356
+ /* @__PURE__ */ jsx8("div", { className: "vuuUserPanel-buttonBar", children: /* @__PURE__ */ jsxs4(Button2, { "aria-label": "logout", onClick: handleLogout, children: [
357
+ /* @__PURE__ */ jsx8(ExportIcon, {}),
358
+ " Logout"
359
+ ] }) })
360
+ ] });
361
+ });
362
+
363
+ // src/user-profile/UserProfile.tsx
364
+ import { jsx as jsx9, jsxs as jsxs5 } from "react/jsx-runtime";
365
+ var UserProfile = ({
366
+ layoutId,
367
+ loginUrl,
368
+ onNavigate,
369
+ user
370
+ }) => {
371
+ const handleNavigate = (id) => {
372
+ onNavigate(id);
373
+ };
374
+ return /* @__PURE__ */ jsxs5(DropdownBase, { className: "vuuUserProfile", placement: "bottom-end", children: [
375
+ /* @__PURE__ */ jsx9(Button3, { variant: "secondary", children: /* @__PURE__ */ jsx9(UserSolidIcon, {}) }),
376
+ /* @__PURE__ */ jsx9(
377
+ UserPanel,
378
+ {
379
+ layoutId,
380
+ loginUrl,
381
+ onNavigate: handleNavigate,
382
+ user
383
+ }
384
+ )
385
+ ] });
386
+ };
387
+
388
+ // src/theme-switch/ThemeSwitch.tsx
389
+ import {
390
+ ToggleButton,
391
+ ToggleButtonGroup
392
+ } from "@heswell/salt-lab";
393
+ import cx3 from "classnames";
394
+ import { useControlled } from "@salt-ds/core";
395
+ import { useCallback as useCallback4 } from "react";
396
+ import { jsx as jsx10, jsxs as jsxs6 } from "react/jsx-runtime";
397
+ var classBase3 = "vuuThemeSwitch";
398
+ var modes = ["light", "dark"];
399
+ var ThemeSwitch = ({
400
+ className: classNameProp,
401
+ defaultMode: defaultModeProp,
402
+ mode: modeProp,
403
+ onChange,
404
+ ...htmlAttributes
405
+ }) => {
406
+ const [mode, setMode] = useControlled({
407
+ controlled: modeProp,
408
+ default: defaultModeProp != null ? defaultModeProp : "light",
409
+ name: "ThemeSwitch",
410
+ state: "mode"
411
+ });
412
+ const selectedIndex = modes.indexOf(mode);
413
+ const handleChangeSecondary = useCallback4(
414
+ (_evt, index) => {
415
+ const mode2 = modes[index];
416
+ setMode(mode2);
417
+ onChange(mode2);
418
+ },
419
+ [onChange, setMode]
420
+ );
421
+ const className = cx3(classBase3, classNameProp);
422
+ return /* @__PURE__ */ jsxs6(
423
+ ToggleButtonGroup,
424
+ {
425
+ className,
426
+ ...htmlAttributes,
427
+ onChange: handleChangeSecondary,
428
+ selectedIndex,
429
+ children: [
430
+ /* @__PURE__ */ jsx10(
431
+ ToggleButton,
432
+ {
433
+ "aria-label": "alert",
434
+ tooltipText: "Light Theme",
435
+ "data-icon": "light"
436
+ }
437
+ ),
438
+ /* @__PURE__ */ jsx10(
439
+ ToggleButton,
440
+ {
441
+ "aria-label": "home",
442
+ tooltipText: "Dark Theme",
443
+ "data-icon": "dark"
444
+ }
445
+ )
446
+ ]
447
+ }
448
+ );
449
+ };
450
+
451
+ // src/app-header/AppHeader.tsx
452
+ import cx4 from "classnames";
453
+ import { jsx as jsx11, jsxs as jsxs7 } from "react/jsx-runtime";
454
+ var classBase4 = "vuuAppHeader";
455
+ var AppHeader = ({
456
+ className: classNameProp,
457
+ layoutId,
458
+ loginUrl,
459
+ onNavigate,
460
+ onSwitchTheme,
461
+ themeMode = "light",
462
+ user,
463
+ ...htmlAttributes
464
+ }) => {
465
+ const className = cx4(classBase4, classNameProp);
466
+ const handleSwitchTheme = useCallback5(
467
+ (mode) => onSwitchTheme == null ? void 0 : onSwitchTheme(mode),
468
+ [onSwitchTheme]
469
+ );
470
+ return /* @__PURE__ */ jsxs7("header", { className, ...htmlAttributes, children: [
471
+ /* @__PURE__ */ jsx11(ThemeSwitch, { defaultMode: themeMode, onChange: handleSwitchTheme }),
472
+ /* @__PURE__ */ jsx11(
473
+ UserProfile,
474
+ {
475
+ layoutId,
476
+ loginUrl,
477
+ onNavigate,
478
+ user
479
+ }
480
+ )
481
+ ] });
482
+ };
483
+
484
+ // src/shell.tsx
485
+ import { jsx as jsx12, jsxs as jsxs8 } from "react/jsx-runtime";
486
+ var warningLayout = {
487
+ type: "View",
488
+ props: {
489
+ style: { height: "calc(100% - 6px)" }
490
+ },
491
+ children: [
492
+ {
493
+ props: {
494
+ className: "vuuShell-warningPlaceholder"
495
+ },
496
+ type: "Placeholder"
497
+ }
498
+ ]
499
+ };
500
+ var Shell = ({
501
+ children,
502
+ className: classNameProp,
503
+ defaultLayout = warningLayout,
504
+ leftSidePanel,
505
+ loginUrl,
506
+ serverUrl,
507
+ user,
508
+ ...htmlAttributes
509
+ }) => {
510
+ const rootRef = useRef(null);
511
+ const paletteView = useRef(null);
512
+ const [open, setOpen] = useState5(false);
513
+ const layoutId = useRef("latest");
514
+ const [layout, setLayoutConfig, loadLayoutById] = use_layout_config_default(
515
+ user,
516
+ defaultLayout
517
+ );
518
+ const handleLayoutChange = useCallback6(
519
+ (layout2) => {
520
+ setLayoutConfig(layout2);
521
+ },
522
+ [setLayoutConfig]
523
+ );
524
+ const handleSwitchTheme = useCallback6((mode) => {
525
+ if (rootRef.current) {
526
+ rootRef.current.dataset.mode = mode;
527
+ }
528
+ }, []);
529
+ const handleDrawerClick = (e) => {
530
+ var _a;
531
+ const target = e.target;
532
+ if (!((_a = paletteView.current) == null ? void 0 : _a.contains(target))) {
533
+ setOpen(!open);
534
+ }
535
+ };
536
+ const handleNavigate = useCallback6(
537
+ (id) => {
538
+ layoutId.current = id;
539
+ loadLayoutById(id);
540
+ },
541
+ [loadLayoutById]
542
+ );
543
+ useEffect4(() => {
544
+ if (serverUrl && user.token) {
545
+ connectToServer(serverUrl, user.token);
546
+ }
547
+ }, [serverUrl, user.token]);
548
+ const getDrawers = () => {
549
+ const drawers = [];
550
+ if (leftSidePanel) {
551
+ drawers.push(
552
+ /* @__PURE__ */ jsx12(
553
+ Drawer,
554
+ {
555
+ onClick: handleDrawerClick,
556
+ open,
557
+ position: "left",
558
+ inline: true,
559
+ peekaboo: true,
560
+ sizeOpen: 200,
561
+ toggleButton: "end",
562
+ children: /* @__PURE__ */ jsx12(
563
+ View,
564
+ {
565
+ className: "vuuShell-palette",
566
+ id: "vw-app-palette",
567
+ ref: paletteView,
568
+ style: { height: "100%" },
569
+ children: leftSidePanel
570
+ },
571
+ "app-palette"
572
+ )
573
+ },
574
+ "left-panel"
575
+ )
576
+ );
577
+ }
578
+ return drawers;
579
+ };
580
+ const className = cx5(
581
+ "vuuShell",
582
+ classNameProp,
583
+ "salt-theme",
584
+ "salt-density-high"
585
+ );
586
+ return (
587
+ // ShellContext TBD
588
+ /* @__PURE__ */ jsxs8(ShellContextProvider, { value: void 0, children: [
589
+ /* @__PURE__ */ jsx12(LayoutProvider, { layout, onLayoutChange: handleLayoutChange, children: /* @__PURE__ */ jsx12(
590
+ DraggableLayout,
591
+ {
592
+ className,
593
+ "data-mode": "light",
594
+ ref: rootRef,
595
+ ...htmlAttributes,
596
+ children: /* @__PURE__ */ jsxs8(
597
+ Flexbox,
598
+ {
599
+ className: "App",
600
+ style: { flexDirection: "column", height: "100%", width: "100%" },
601
+ children: [
602
+ /* @__PURE__ */ jsx12(
603
+ AppHeader,
604
+ {
605
+ layoutId: layoutId.current,
606
+ loginUrl,
607
+ user,
608
+ onNavigate: handleNavigate,
609
+ onSwitchTheme: handleSwitchTheme
610
+ }
611
+ ),
612
+ /* @__PURE__ */ jsx12(DockLayout, { style: { flex: 1 }, children: getDrawers().concat(
613
+ /* @__PURE__ */ jsx12(
614
+ DraggableLayout,
615
+ {
616
+ dropTarget: true,
617
+ style: { width: "100%", height: "100%" }
618
+ },
619
+ "main-content"
620
+ )
621
+ ) })
622
+ ]
623
+ }
624
+ )
625
+ }
626
+ ) }),
627
+ children
628
+ ] })
629
+ );
630
+ };
631
+
632
+ // src/theme-provider/ThemeProvider.tsx
633
+ import {
634
+ createContext as createContext2,
635
+ isValidElement,
636
+ cloneElement,
637
+ useContext as useContext2
638
+ } from "react";
639
+ import cx6 from "classnames";
640
+ import { jsx as jsx13 } from "react/jsx-runtime";
641
+ var DEFAULT_DENSITY2 = "medium";
642
+ var DEFAULT_THEME = "salt-theme";
643
+ var DEFAULT_THEME_MODE = "light";
644
+ var ThemeContext = createContext2({
645
+ density: "high",
646
+ theme: "salt-theme",
647
+ themeMode: "light"
648
+ });
649
+ var createThemedChildren = (children, theme, themeMode, density) => {
650
+ var _a;
651
+ if (isValidElement(children)) {
652
+ return cloneElement(children, {
653
+ className: cx6(
654
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
655
+ (_a = children.props) == null ? void 0 : _a.className,
656
+ theme,
657
+ `salt-density-${density}`
658
+ ),
659
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
660
+ // @ts-expect-error
661
+ "data-mode": themeMode
662
+ });
663
+ } else {
664
+ console.warn(
665
+ `
666
+ ThemeProvider can only apply CSS classes for theming to a single nested child element of the ThemeProvider.
667
+ Wrap elements with a single container`
668
+ );
669
+ return children;
670
+ }
671
+ };
672
+ var ThemeProvider = ({
673
+ children,
674
+ theme: themeProp,
675
+ themeMode: themeModeProp,
676
+ density: densityProp
677
+ }) => {
678
+ var _a, _b, _c;
679
+ const {
680
+ density: inheritedDensity,
681
+ themeMode: inheritedThemeMode,
682
+ theme: inheritedTheme
683
+ } = useContext2(ThemeContext);
684
+ const density = (_a = densityProp != null ? densityProp : inheritedDensity) != null ? _a : DEFAULT_DENSITY2;
685
+ const themeMode = (_b = themeModeProp != null ? themeModeProp : inheritedThemeMode) != null ? _b : DEFAULT_THEME_MODE;
686
+ const theme = (_c = themeProp != null ? themeProp : inheritedTheme) != null ? _c : DEFAULT_THEME;
687
+ const themedChildren = createThemedChildren(
688
+ children,
689
+ theme,
690
+ themeMode,
691
+ density
692
+ );
693
+ return /* @__PURE__ */ jsx13(ThemeContext.Provider, { value: { themeMode, density, theme }, children: themedChildren });
694
+ };
695
+ ThemeProvider.displayName = "ThemeProvider";
696
+ export {
697
+ ConnectionStatusIcon,
698
+ DEFAULT_DENSITY2 as DEFAULT_DENSITY,
699
+ DEFAULT_THEME,
700
+ DEFAULT_THEME_MODE,
701
+ DensitySwitch,
702
+ Feature,
703
+ LoginPanel,
704
+ Shell,
705
+ ShellContextProvider,
706
+ ThemeContext,
707
+ ThemeProvider,
708
+ ThemeSwitch,
709
+ getAuthDetailsFromCookies,
710
+ logout,
711
+ redirectToLogin,
712
+ useShellContext
713
+ };
2
714
  //# sourceMappingURL=index.js.map