@xh/hoist 79.0.0-SNAPSHOT.1766020485210 → 79.0.0-SNAPSHOT.1766094533168

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/admin/AppComponent.ts +9 -1
  3. package/admin/AppModel.ts +0 -4
  4. package/admin/tabs/cluster/instances/InstancesTab.ts +1 -1
  5. package/admin/tabs/cluster/instances/InstancesTabModel.ts +0 -1
  6. package/admin/tabs/userData/roles/details/RoleDetailsModel.ts +0 -1
  7. package/build/types/cmp/tab/TabContainer.d.ts +19 -4
  8. package/build/types/cmp/tab/TabContainerModel.d.ts +18 -19
  9. package/build/types/cmp/tab/Types.d.ts +61 -0
  10. package/build/types/cmp/tab/index.d.ts +1 -1
  11. package/build/types/data/RecordAction.d.ts +4 -1
  12. package/build/types/desktop/cmp/tab/TabSwitcher.d.ts +1 -1
  13. package/build/types/desktop/cmp/tab/dynamic/DynamicTabSwitcher.d.ts +7 -0
  14. package/build/types/desktop/cmp/tab/dynamic/DynamicTabSwitcherModel.d.ts +30 -0
  15. package/build/types/desktop/cmp/tab/dynamic/scroller/Scroller.d.ts +19 -0
  16. package/build/types/desktop/cmp/tab/dynamic/scroller/ScrollerModel.d.ts +23 -0
  17. package/build/types/desktop/cmp/tab/impl/Tab.d.ts +7 -2
  18. package/build/types/desktop/cmp/tab/impl/TabContainer.d.ts +1 -1
  19. package/build/types/desktop/cmp/tab/impl/TabContextMenuItems.d.ts +4 -0
  20. package/build/types/desktop/cmp/tab/index.d.ts +1 -0
  21. package/build/types/dynamics/desktop.d.ts +1 -0
  22. package/build/types/mobile/cmp/tab/impl/TabContainer.d.ts +1 -1
  23. package/cmp/tab/TabContainer.ts +19 -4
  24. package/cmp/tab/TabContainerModel.ts +113 -54
  25. package/cmp/tab/TabModel.ts +1 -2
  26. package/cmp/tab/Types.ts +80 -0
  27. package/cmp/tab/index.ts +1 -1
  28. package/data/RecordAction.ts +4 -1
  29. package/desktop/appcontainer/AppContainer.ts +3 -2
  30. package/desktop/cmp/grid/impl/filter/headerfilter/HeaderFilter.ts +1 -1
  31. package/desktop/cmp/grid/impl/filter/headerfilter/HeaderFilterModel.ts +0 -1
  32. package/desktop/cmp/tab/TabSwitcher.ts +18 -3
  33. package/desktop/cmp/tab/Tabs.scss +1 -0
  34. package/desktop/cmp/tab/dynamic/DynamicTabSwitcher.scss +53 -0
  35. package/desktop/cmp/tab/dynamic/DynamicTabSwitcher.ts +237 -0
  36. package/desktop/cmp/tab/dynamic/DynamicTabSwitcherModel.ts +167 -0
  37. package/desktop/cmp/tab/dynamic/scroller/Scroller.ts +69 -0
  38. package/desktop/cmp/tab/dynamic/scroller/ScrollerModel.ts +92 -0
  39. package/desktop/cmp/tab/impl/Tab.ts +30 -6
  40. package/desktop/cmp/tab/impl/TabContainer.ts +34 -9
  41. package/desktop/cmp/tab/impl/TabContextMenuItems.ts +21 -0
  42. package/desktop/cmp/tab/index.ts +1 -0
  43. package/dynamics/desktop.ts +2 -0
  44. package/mobile/cmp/tab/impl/TabContainer.ts +16 -9
  45. package/package.json +1 -1
  46. package/tsconfig.tsbuildinfo +1 -1
  47. package/build/types/cmp/tab/TabSwitcherProps.d.ts +0 -16
  48. package/cmp/tab/TabSwitcherProps.ts +0 -28
@@ -6,20 +6,29 @@
6
6
  */
7
7
  import {div, hbox, placeholder, vbox} from '@xh/hoist/cmp/layout';
8
8
  import {TabContainerModel, TabContainerProps} from '@xh/hoist/cmp/tab';
9
+ import {TabSwitcherProps} from '@xh/hoist/cmp/tab/Types';
9
10
  import {getTestId} from '@xh/hoist/utils/js';
10
11
  import {getLayoutProps} from '@xh/hoist/utils/react';
11
- import {isEmpty} from 'lodash';
12
+ import {isEmpty, isNull, isObject} from 'lodash';
12
13
  import '../Tabs.scss';
13
14
  import {tabSwitcher} from '../TabSwitcher';
15
+ import {dynamicTabSwitcher} from '../dynamic/DynamicTabSwitcher';
14
16
  import {tab} from './Tab';
15
17
 
16
18
  /**
17
19
  * Desktop implementation of TabContainer.
18
20
  * @internal
19
21
  */
20
- export function tabContainerImpl({model, className, testId, ...props}: TabContainerProps) {
21
- const layoutProps = getLayoutProps(props),
22
- vertical = ['left', 'right'].includes(model.switcher?.orientation),
22
+ export function tabContainerImpl({
23
+ model,
24
+ childContainerProps,
25
+ className,
26
+ testId,
27
+ ...props
28
+ }: TabContainerProps) {
29
+ const switcherProps = getSwitcherProps(props),
30
+ layoutProps = getLayoutProps(props),
31
+ vertical = ['left', 'right'].includes(switcherProps?.orientation),
23
32
  container = vertical ? hbox : vbox;
24
33
 
25
34
  // Default flex = 'auto' if no dimensions / flex specified.
@@ -31,21 +40,33 @@ export function tabContainerImpl({model, className, testId, ...props}: TabContai
31
40
  ...layoutProps,
32
41
  className,
33
42
  testId,
34
- item: getChildren(model, testId)
43
+ item: getChildren(model, switcherProps, testId, childContainerProps)
35
44
  });
36
45
  }
37
46
 
38
- function getChildren(model: TabContainerModel, testId: string) {
47
+ function getSwitcherProps(tabContainerProps: TabContainerProps): TabSwitcherProps {
48
+ const {switcher} = tabContainerProps;
49
+ if (isObject(switcher)) return switcher;
50
+ return switcher === false || isNull(switcher) ? null : {orientation: 'top'};
51
+ }
52
+
53
+ function getChildren(
54
+ model: TabContainerModel,
55
+ switcher: TabSwitcherProps,
56
+ testId: string,
57
+ childContainerProps: TabContainerProps['childContainerProps']
58
+ ) {
39
59
  const {tabs} = model;
40
60
  if (isEmpty(tabs)) {
41
61
  return div({className: 'xh-tab-wrapper', item: placeholder(model.emptyText)});
42
62
  }
43
63
 
44
- const {activeTabId, switcher} = model,
64
+ const {activeTabId, dynamicTabSwitcherModel} = model,
45
65
  switcherBefore = ['left', 'top'].includes(switcher?.orientation),
46
66
  switcherAfter = ['right', 'bottom'].includes(switcher?.orientation),
67
+ switcherImpl = dynamicTabSwitcherModel ? dynamicTabSwitcher : tabSwitcher,
47
68
  switcherCmp = switcher
48
- ? tabSwitcher({key: 'switcher', testId: getTestId(testId, 'switcher'), ...switcher})
69
+ ? switcherImpl({key: 'switcher', testId: getTestId(testId, 'switcher'), ...switcher})
49
70
  : null;
50
71
 
51
72
  return [
@@ -58,7 +79,11 @@ function getChildren(model: TabContainerModel, testId: string) {
58
79
  className: 'xh-tab-wrapper',
59
80
  style,
60
81
  key: tabId,
61
- item: tab({model: tabModel, testId: getTestId(testId, tabId)})
82
+ item: tab({
83
+ childContainerProps,
84
+ model: tabModel,
85
+ testId: getTestId(testId, tabId)
86
+ })
62
87
  });
63
88
  }),
64
89
  switcherAfter ? switcherCmp : null
@@ -0,0 +1,21 @@
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 {TabSwitcherMenuContext} from '@xh/hoist/cmp/tab';
8
+ import {isMenuItem, type MenuItemLike, MenuToken} from '@xh/hoist/core';
9
+
10
+ /** @internal */
11
+ export function getContextMenuItem(
12
+ item: MenuItemLike<MenuToken, TabSwitcherMenuContext>,
13
+ context: TabSwitcherMenuContext
14
+ ): MenuItemLike<MenuToken, TabSwitcherMenuContext> {
15
+ if (!isMenuItem(item)) return item;
16
+ const ret = {...item};
17
+ if (item.actionFn) ret.actionFn = e => item.actionFn(e, context);
18
+ if (item.prepareFn) ret.prepareFn = e => item.prepareFn(e, context);
19
+ if (item.items) ret.items = item.items.map(it => this.buildMenuItem(it, context));
20
+ return ret;
21
+ }
@@ -5,3 +5,4 @@
5
5
  * Copyright © 2025 Extremely Heavy Industries Inc.
6
6
  */
7
7
  export * from './TabSwitcher';
8
+ export * from './dynamic/DynamicTabSwitcher';
@@ -29,6 +29,7 @@ export let tabContainerImpl = null;
29
29
  export let useContextMenu = null;
30
30
  export let errorMessageImpl = null;
31
31
  export let maskImpl = null;
32
+ export let DynamicTabSwitcherModel = null;
32
33
 
33
34
  /**
34
35
  * Provide implementations of functions and classes exported in this file.
@@ -50,4 +51,5 @@ export function installDesktopImpls(impls) {
50
51
  useContextMenu = impls.useContextMenu;
51
52
  errorMessageImpl = impls.errorMessageImpl;
52
53
  maskImpl = impls.maskImpl;
54
+ DynamicTabSwitcherModel = impls.DynamicTabSwitcherModel;
53
55
  }
@@ -10,23 +10,24 @@ import {page, tab as onsenTab, tabbar as onsenTabbar} from '@xh/hoist/kit/onsen'
10
10
  import '@xh/hoist/mobile/register';
11
11
  import {debounced, throwIf} from '@xh/hoist/utils/js';
12
12
  import classNames from 'classnames';
13
- import {isEmpty} from 'lodash';
13
+ import {isEmpty, isNull, isObject} from 'lodash';
14
14
  import {tab} from './Tab';
15
15
  import './Tabs.scss';
16
- import {TabContainerProps, TabModel} from '@xh/hoist/cmp/tab';
16
+ import {TabContainerProps, TabModel, TabSwitcherProps} from '@xh/hoist/cmp/tab';
17
17
 
18
18
  /**
19
19
  * Mobile Implementation of TabContainer.
20
20
  *
21
21
  * @internal
22
22
  */
23
- export function tabContainerImpl({model, className}: TabContainerProps) {
24
- const {activeTab, switcher} = model,
23
+ export function tabContainerImpl({model, className, ...props}: TabContainerProps) {
24
+ const switcherProps = getSwitcherProps(props),
25
+ {activeTab} = model,
25
26
  tabs = model.tabs.filter(it => !it.excludeFromSwitcher),
26
27
  impl = useLocalModel(TabContainerLocalModel);
27
28
 
28
29
  throwIf(
29
- switcher && !['top', 'bottom'].includes(switcher.orientation),
30
+ switcherProps && !['top', 'bottom'].includes(switcherProps.orientation),
30
31
  "Mobile TabContainer tab switcher orientation must be 'top', or 'bottom'"
31
32
  );
32
33
 
@@ -38,19 +39,25 @@ export function tabContainerImpl({model, className}: TabContainerProps) {
38
39
  }
39
40
 
40
41
  return onsenTabbar({
41
- className: classNames(className, `xh-tab-container--${switcher?.orientation}`),
42
- position: switcher?.orientation,
42
+ className: classNames(className, `xh-tab-container--${switcherProps?.orientation}`),
43
+ position: switcherProps?.orientation,
43
44
  activeIndex: activeTab ? tabs.indexOf(activeTab) : 0,
44
45
  renderTabs: (idx, ref) => {
45
46
  impl.setSwiper(ref);
46
47
  return tabs.map(renderTabModel);
47
48
  },
48
49
  onPreChange: e => model.activateTab(tabs[e.index].id),
49
- hideTabs: !switcher,
50
- ...switcher
50
+ hideTabs: !switcherProps,
51
+ ...switcherProps
51
52
  });
52
53
  }
53
54
 
55
+ function getSwitcherProps(tabContainerProps: TabContainerProps): TabSwitcherProps {
56
+ const {switcher} = tabContainerProps;
57
+ if (isObject(switcher)) return switcher;
58
+ return switcher === false || isNull(switcher) ? null : {orientation: 'bottom'};
59
+ }
60
+
54
61
  function renderTabModel(tabModel: TabModel) {
55
62
  const {id, title, icon} = tabModel;
56
63
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xh/hoist",
3
- "version": "79.0.0-SNAPSHOT.1766020485210",
3
+ "version": "79.0.0-SNAPSHOT.1766094533168",
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",