@xh/hoist 80.0.0-SNAPSHOT.1768251023007 → 80.0.0-SNAPSHOT.1768251400948
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/CHANGELOG.md +14 -9
- package/build/types/cmp/grid/GridModel.d.ts +2 -2
- package/build/types/cmp/layout/CollapsibleSet.d.ts +14 -0
- package/build/types/cmp/layout/Tags.d.ts +2 -0
- package/build/types/cmp/tab/TabContainerModel.d.ts +1 -1
- package/build/types/core/XH.d.ts +1 -3
- package/build/types/core/enums/RenderMode.d.ts +1 -1
- package/build/types/desktop/cmp/button/AppMenuButton.d.ts +1 -10
- package/build/types/desktop/cmp/button/CollapsibleSetButton.d.ts +12 -0
- package/build/types/desktop/cmp/dash/canvas/DashCanvasModel.d.ts +46 -6
- package/build/types/desktop/cmp/dash/canvas/widgetwell/DashCanvasWidgetWell.d.ts +19 -0
- package/build/types/desktop/cmp/dash/canvas/widgetwell/DashCanvasWidgetWellModel.d.ts +11 -0
- package/build/types/dynamics/desktop.d.ts +1 -0
- package/build/types/dynamics/mobile.d.ts +1 -0
- package/build/types/mobile/cmp/button/CollapsibleSetButton.d.ts +12 -0
- package/build/types/mobile/cmp/header/AppMenuButton.d.ts +1 -10
- package/build/types/svc/IdentityService.d.ts +2 -4
- package/cmp/grid/GridModel.ts +2 -2
- package/cmp/layout/CollapsibleSet.scss +49 -0
- package/cmp/layout/CollapsibleSet.ts +135 -0
- package/cmp/layout/Tags.ts +2 -0
- package/cmp/tab/TabContainerModel.ts +1 -1
- package/core/XH.ts +4 -9
- package/core/enums/RenderMode.ts +1 -1
- package/desktop/appcontainer/AppContainer.ts +2 -0
- package/desktop/cmp/appbar/AppBar.scss +5 -24
- package/desktop/cmp/button/AppMenuButton.ts +2 -30
- package/desktop/cmp/button/CollapsibleSetButton.ts +57 -0
- package/desktop/cmp/dash/canvas/DashCanvas.ts +21 -4
- package/desktop/cmp/dash/canvas/DashCanvasModel.ts +140 -24
- package/desktop/cmp/dash/canvas/widgetwell/DashCanvasWidgetWell.scss +34 -0
- package/desktop/cmp/dash/canvas/widgetwell/DashCanvasWidgetWell.ts +135 -0
- package/desktop/cmp/dash/canvas/widgetwell/DashCanvasWidgetWellModel.ts +65 -0
- package/dynamics/desktop.ts +2 -0
- package/dynamics/mobile.ts +2 -0
- package/mobile/appcontainer/AppContainer.ts +2 -0
- package/mobile/cmp/button/CollapsibleSetButton.ts +57 -0
- package/mobile/cmp/header/AppBar.scss +0 -11
- package/mobile/cmp/header/AppMenuButton.ts +1 -29
- package/package.json +3 -3
- package/styles/vars.scss +1 -2
- package/svc/IdentityService.ts +2 -14
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* This file belongs to Hoist, an application development toolkit
|
|
3
|
+
* developed by Extremely Heavy Industries (www.xh.io | info@xh.io)
|
|
4
|
+
*
|
|
5
|
+
* Copyright © 2025 Extremely Heavy Industries Inc.
|
|
6
|
+
*/
|
|
7
|
+
import {DragEvent} from 'react';
|
|
8
|
+
import {DashCanvasModel} from '@xh/hoist/desktop/cmp/dash';
|
|
9
|
+
import {HoistModel, managed} from '@xh/hoist/core';
|
|
10
|
+
import '@xh/hoist/desktop/register';
|
|
11
|
+
import {makeObservable, observable} from '@xh/hoist/mobx';
|
|
12
|
+
import {runInAction} from 'mobx';
|
|
13
|
+
|
|
14
|
+
export class DashCanvasWidgetWellModel extends HoistModel {
|
|
15
|
+
@managed
|
|
16
|
+
@observable.ref
|
|
17
|
+
dashCanvasModel: DashCanvasModel;
|
|
18
|
+
|
|
19
|
+
constructor() {
|
|
20
|
+
super();
|
|
21
|
+
makeObservable(this);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
override onLinked() {
|
|
25
|
+
this.addReaction({
|
|
26
|
+
track: () => this.componentProps,
|
|
27
|
+
run: () =>
|
|
28
|
+
runInAction(() => (this.dashCanvasModel = this.componentProps.dashCanvasModel)),
|
|
29
|
+
fireImmediately: true
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
onDragStart(evt: DragEvent<HTMLDivElement>) {
|
|
34
|
+
const target = evt.target as HTMLElement;
|
|
35
|
+
if (!target) return;
|
|
36
|
+
|
|
37
|
+
this.dashCanvasModel.showAddViewButtonWhenEmpty = false;
|
|
38
|
+
evt.dataTransfer.effectAllowed = 'move';
|
|
39
|
+
target.classList.add('is-dragging');
|
|
40
|
+
|
|
41
|
+
const viewSpecId: string = target.getAttribute('id').split('draggableFor-')[1],
|
|
42
|
+
viewSpec = this.dashCanvasModel.viewSpecs.find(it => it.id === viewSpecId),
|
|
43
|
+
{width, height} = viewSpec,
|
|
44
|
+
widget = {
|
|
45
|
+
viewSpecId,
|
|
46
|
+
layout: {
|
|
47
|
+
x: 0,
|
|
48
|
+
y: 0,
|
|
49
|
+
w: width,
|
|
50
|
+
h: height
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
this.dashCanvasModel.setDraggedInView(widget);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
onDragEnd(evt: DragEvent<HTMLDivElement>) {
|
|
58
|
+
this.dashCanvasModel.showAddViewButtonWhenEmpty = true;
|
|
59
|
+
|
|
60
|
+
const target = evt.target as HTMLElement;
|
|
61
|
+
if (!target) return;
|
|
62
|
+
|
|
63
|
+
target.classList.remove('is-dragging');
|
|
64
|
+
}
|
|
65
|
+
}
|
package/dynamics/desktop.ts
CHANGED
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
*
|
|
16
16
|
* See the platform specific AppContainer where these implementations are actually provided.
|
|
17
17
|
*/
|
|
18
|
+
export let collapsibleSetButton = null;
|
|
18
19
|
export let ColChooserModel = null;
|
|
19
20
|
export let ColumnHeaderFilterModel = null;
|
|
20
21
|
export let ModalSupportModel = null;
|
|
@@ -37,6 +38,7 @@ export let DynamicTabSwitcherModel = null;
|
|
|
37
38
|
* Not for Application use.
|
|
38
39
|
*/
|
|
39
40
|
export function installDesktopImpls(impls) {
|
|
41
|
+
collapsibleSetButton = impls.collapsibleSetButton;
|
|
40
42
|
ColChooserModel = impls.ColChooserModel;
|
|
41
43
|
ColumnHeaderFilterModel = impls.ColumnHeaderFilterModel;
|
|
42
44
|
ModalSupportModel = impls.ModalSupportModel;
|
package/dynamics/mobile.ts
CHANGED
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
*
|
|
16
16
|
* See the platform specific AppContainer where these implementations are actually provided.
|
|
17
17
|
*/
|
|
18
|
+
export let collapsibleSetButton = null;
|
|
18
19
|
export let ColChooserModel = null;
|
|
19
20
|
export let colChooser = null;
|
|
20
21
|
export let zoneMapper = null;
|
|
@@ -30,6 +31,7 @@ export let maskImpl = null;
|
|
|
30
31
|
* Not for Application use.
|
|
31
32
|
*/
|
|
32
33
|
export function installMobileImpls(impls) {
|
|
34
|
+
collapsibleSetButton = impls.collapsibleSetButton;
|
|
33
35
|
ColChooserModel = impls.ColChooserModel;
|
|
34
36
|
colChooser = impls.colChooser;
|
|
35
37
|
zoneMapper = impls.zoneMapper;
|
|
@@ -18,6 +18,7 @@ import {pinPadImpl} from '@xh/hoist/mobile/cmp/pinpad/impl/PinPad';
|
|
|
18
18
|
import {storeFilterFieldImpl} from '@xh/hoist/mobile/cmp/store/impl/StoreFilterField';
|
|
19
19
|
import {tabContainerImpl} from '@xh/hoist/mobile/cmp/tab/impl/TabContainer';
|
|
20
20
|
import {zoneMapper} from '@xh/hoist/mobile/cmp/zoneGrid/impl/ZoneMapper';
|
|
21
|
+
import {collapsibleSetButton} from '@xh/hoist/mobile/cmp/button/CollapsibleSetButton';
|
|
21
22
|
import {elementFromContent, useOnMount} from '@xh/hoist/utils/react';
|
|
22
23
|
import {isEmpty} from 'lodash';
|
|
23
24
|
import {aboutDialog} from './AboutDialog';
|
|
@@ -34,6 +35,7 @@ import {toastSource} from './ToastSource';
|
|
|
34
35
|
import {versionBar} from './VersionBar';
|
|
35
36
|
|
|
36
37
|
installMobileImpls({
|
|
38
|
+
collapsibleSetButton,
|
|
37
39
|
tabContainerImpl,
|
|
38
40
|
storeFilterFieldImpl,
|
|
39
41
|
pinPadImpl,
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* This file belongs to Hoist, an application development toolkit
|
|
3
|
+
* developed by Extremely Heavy Industries (www.xh.io | info@xh.io)
|
|
4
|
+
*
|
|
5
|
+
* Copyright © 2026 Extremely Heavy Industries Inc.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import {type ReactElement, type ReactNode, type JSX, useState} from 'react';
|
|
9
|
+
import {tooltip as bpTooltip} from '@xh/hoist/kit/blueprint';
|
|
10
|
+
import {fragment} from '@xh/hoist/cmp/layout';
|
|
11
|
+
import {hoistCmp} from '@xh/hoist/core';
|
|
12
|
+
import type {Intent, HoistProps} from '@xh/hoist/core';
|
|
13
|
+
import {button} from '@xh/hoist/mobile/cmp/button';
|
|
14
|
+
import {legend} from '@xh/hoist/cmp/layout';
|
|
15
|
+
import {Icon} from '@xh/hoist/icon/Icon';
|
|
16
|
+
|
|
17
|
+
export interface CollapsibleSetButtonProps extends HoistProps {
|
|
18
|
+
icon?: ReactElement;
|
|
19
|
+
text: ReactNode;
|
|
20
|
+
tooltip?: JSX.Element | string;
|
|
21
|
+
clickHandler?: (boolean) => void;
|
|
22
|
+
intent?: Intent;
|
|
23
|
+
collapsed?: boolean;
|
|
24
|
+
disabled?: boolean;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export const [CollapsibleSetButton, collapsibleSetButton] =
|
|
28
|
+
hoistCmp.withFactory<CollapsibleSetButtonProps>({
|
|
29
|
+
displayName: 'CollapsibleSetButton',
|
|
30
|
+
model: false,
|
|
31
|
+
render({icon, text, tooltip, intent, clickHandler, collapsed, disabled}) {
|
|
32
|
+
const [isCollapsed, setIsCollapsed] = useState<boolean>(collapsed === true),
|
|
33
|
+
btn = button({
|
|
34
|
+
text: fragment(text, isCollapsed ? Icon.angleDown() : Icon.angleUp()),
|
|
35
|
+
icon,
|
|
36
|
+
outlined: isCollapsed && !intent,
|
|
37
|
+
minimal: !intent || (intent && !isCollapsed),
|
|
38
|
+
intent,
|
|
39
|
+
disabled,
|
|
40
|
+
onClick: () => {
|
|
41
|
+
const val = !isCollapsed;
|
|
42
|
+
setIsCollapsed(val);
|
|
43
|
+
clickHandler?.(val);
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
return legend(
|
|
48
|
+
tooltip
|
|
49
|
+
? bpTooltip({
|
|
50
|
+
item: btn,
|
|
51
|
+
content: tooltip,
|
|
52
|
+
intent
|
|
53
|
+
})
|
|
54
|
+
: btn
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
});
|
|
@@ -18,17 +18,6 @@
|
|
|
18
18
|
display: flex;
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
.xh-app-menu-button__user-profile {
|
|
22
|
-
border-radius: 50%;
|
|
23
|
-
border: 1px solid var(--xh-appbar-title-color);
|
|
24
|
-
cursor: pointer;
|
|
25
|
-
height: 28px;
|
|
26
|
-
font-size: var(--xh-font-size-small-em);
|
|
27
|
-
line-height: 27px;
|
|
28
|
-
text-align: center;
|
|
29
|
-
width: 28px;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
21
|
.xh-button {
|
|
33
22
|
background: transparent !important;
|
|
34
23
|
color: var(--xh-appbar-title-color) !important;
|
|
@@ -4,14 +4,11 @@
|
|
|
4
4
|
*
|
|
5
5
|
* Copyright © 2026 Extremely Heavy Industries Inc.
|
|
6
6
|
*/
|
|
7
|
-
import {
|
|
8
|
-
import {hoistCmp, HoistProps, HoistUser, MenuItemLike, XH} from '@xh/hoist/core';
|
|
7
|
+
import {hoistCmp, MenuItemLike, XH} from '@xh/hoist/core';
|
|
9
8
|
import {Icon} from '@xh/hoist/icon';
|
|
10
9
|
import {menuButton, MenuButtonProps} from '@xh/hoist/mobile/cmp/menu';
|
|
11
10
|
import '@xh/hoist/mobile/register';
|
|
12
11
|
import {withDefault} from '@xh/hoist/utils/js';
|
|
13
|
-
import {isFunction} from 'lodash';
|
|
14
|
-
import {ReactNode} from 'react';
|
|
15
12
|
|
|
16
13
|
export interface AppMenuButtonProps extends MenuButtonProps {
|
|
17
14
|
/** Array of app-specific MenuItems or configs to create them. */
|
|
@@ -40,17 +37,8 @@ export interface AppMenuButtonProps extends MenuButtonProps {
|
|
|
40
37
|
|
|
41
38
|
/** True to hide the About button */
|
|
42
39
|
hideAboutItem?: boolean;
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* Replace the default hamburger icon with a user profile representation. Set to true to render
|
|
46
|
-
* the user's initials from their `HoistUser.displayName`. Alternately, provide a custom
|
|
47
|
-
* function to render an alternate compact string or element for the current user.
|
|
48
|
-
*/
|
|
49
|
-
renderWithUserProfile?: boolean | RenderWithUserProfileCustomFn;
|
|
50
40
|
}
|
|
51
41
|
|
|
52
|
-
type RenderWithUserProfileCustomFn = (user: HoistUser) => ReactNode;
|
|
53
|
-
|
|
54
42
|
/**
|
|
55
43
|
* A top-level application drop down menu, which installs a standard set of menu items for common
|
|
56
44
|
* application actions. Application specific items can be displayed before these standard items.
|
|
@@ -74,13 +62,11 @@ export const [AppMenuButton, appMenuButton] = hoistCmp.withFactory<AppMenuButton
|
|
|
74
62
|
hideOptionsItem,
|
|
75
63
|
hideThemeItem,
|
|
76
64
|
hideAboutItem,
|
|
77
|
-
renderWithUserProfile,
|
|
78
65
|
...rest
|
|
79
66
|
} = props;
|
|
80
67
|
|
|
81
68
|
return menuButton({
|
|
82
69
|
className,
|
|
83
|
-
icon: renderWithUserProfile ? userProfile({renderWithUserProfile}) : Icon.menu(),
|
|
84
70
|
menuItems: buildMenuItems(props),
|
|
85
71
|
menuClassName: 'xh-app-menu',
|
|
86
72
|
popoverProps: {popoverClassName: 'xh-app-menu-popover'},
|
|
@@ -92,20 +78,6 @@ export const [AppMenuButton, appMenuButton] = hoistCmp.withFactory<AppMenuButton
|
|
|
92
78
|
//---------------------------
|
|
93
79
|
// Implementation
|
|
94
80
|
//---------------------------
|
|
95
|
-
const userProfile = hoistCmp.factory<
|
|
96
|
-
HoistProps & {renderWithUserProfile: true | RenderWithUserProfileCustomFn}
|
|
97
|
-
>({
|
|
98
|
-
model: false,
|
|
99
|
-
render({renderWithUserProfile}) {
|
|
100
|
-
return div({
|
|
101
|
-
className: 'xh-app-menu-button__user-profile',
|
|
102
|
-
item: isFunction(renderWithUserProfile)
|
|
103
|
-
? renderWithUserProfile(XH.getUser())
|
|
104
|
-
: XH.getUserInitials()
|
|
105
|
-
});
|
|
106
|
-
}
|
|
107
|
-
});
|
|
108
|
-
|
|
109
81
|
function buildMenuItems({
|
|
110
82
|
hideOptionsItem,
|
|
111
83
|
hideFeedbackItem,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xh/hoist",
|
|
3
|
-
"version": "80.0.0-SNAPSHOT.
|
|
3
|
+
"version": "80.0.0-SNAPSHOT.1768251400948",
|
|
4
4
|
"description": "Hoist add-on for building and deploying React Applications.",
|
|
5
5
|
"repository": "github:xh/hoist-react",
|
|
6
6
|
"homepage": "https://xh.io",
|
|
@@ -62,11 +62,11 @@
|
|
|
62
62
|
"moment": "~2.30.1",
|
|
63
63
|
"numbro": "~2.5.0",
|
|
64
64
|
"onsenui": "~2.12.8",
|
|
65
|
-
"qs": "~6.14.
|
|
65
|
+
"qs": "~6.14.1",
|
|
66
66
|
"react-beautiful-dnd": "~13.1.0",
|
|
67
67
|
"react-dates": "~21.8.0",
|
|
68
68
|
"react-dropzone": "~10.2.2",
|
|
69
|
-
"react-grid-layout": "2.
|
|
69
|
+
"react-grid-layout": "2.2.2",
|
|
70
70
|
"react-markdown": "~10.1.0",
|
|
71
71
|
"react-onsenui": "~1.13.2",
|
|
72
72
|
"react-popper": "~2.3.0",
|
package/styles/vars.scss
CHANGED
|
@@ -205,14 +205,13 @@ body {
|
|
|
205
205
|
//---------
|
|
206
206
|
--xh-appbar-bg: var(--appbar-bg, var(--xh-bg-alt));
|
|
207
207
|
--xh-appbar-border-color: var(--appbar-border-color, transparent);
|
|
208
|
-
--xh-appbar-box-shadow: var(--appbar-box-shadow, #{0 0 0 1px rgb(17 20 24 / 10%), 0 1px 1px rgb(17 20 24 / 20%)});
|
|
209
208
|
--xh-appbar-color: var(--appbar-color, var(--xh-text-color));
|
|
210
209
|
--xh-appbar-height: var(--appbar-height, 42);
|
|
211
210
|
--xh-appbar-height-px: calc(var(--xh-appbar-height) * 1px);
|
|
212
211
|
--xh-appbar-title-color: var(--appbar-title-color, #{mc('blue-grey', '700')});
|
|
213
212
|
--xh-appbar-title-font-size: var(--appbar-title-font-size, calc(var(--xh-font-size) * 1.9));
|
|
214
213
|
--xh-appbar-title-font-size-px: calc(var(--xh-appbar-title-font-size) * 1px);
|
|
215
|
-
--xh-appbar-
|
|
214
|
+
--xh-appbar-box-shadow: var(--appbar-box-shadow, #{0 0 0 1px rgb(17 20 24 / 10%), 0 1px 1px rgb(17 20 24 / 20%)});
|
|
216
215
|
|
|
217
216
|
&.xh-dark {
|
|
218
217
|
--xh-appbar-border-color: var(--appbar-border-color, #{mc('blue-grey', '700')});
|
package/svc/IdentityService.ts
CHANGED
|
@@ -30,28 +30,16 @@ export class IdentityService extends HoistService {
|
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
/**
|
|
33
|
+
/** Current acting user (see authUser for notes on impersonation) */
|
|
34
34
|
get user(): HoistUser {
|
|
35
35
|
return this._apparentUser;
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
/**
|
|
38
|
+
/** Current acting user's username. */
|
|
39
39
|
get username(): string {
|
|
40
40
|
return this.user?.username ?? null;
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
-
/** @returns current acting user's initials, based on displayName. */
|
|
44
|
-
get userInitials(): string {
|
|
45
|
-
// Handle common case of displayName being left as an email address.
|
|
46
|
-
const [displayName] = this.user.displayName.split('@'),
|
|
47
|
-
nameParts = displayName.split(/[\s.]+/);
|
|
48
|
-
|
|
49
|
-
return nameParts
|
|
50
|
-
.map(part => part.charAt(0).toUpperCase())
|
|
51
|
-
.join('')
|
|
52
|
-
.substring(0, XH.isMobileApp ? 2 : 3);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
43
|
/**
|
|
56
44
|
* Actual user who authenticated to the web application.
|
|
57
45
|
* This will be the same as the user except when an administrator is impersonation another
|