nexus-shared 1.1.5 → 1.1.7
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/package.json +8 -4
- package/src/api-services/preference-service.tsx +5 -0
- package/src/api-services/system-service.tsx +322 -0
- package/src/components/documents/button.tsx +136 -0
- package/src/components/documents/icon-box.tsx +92 -0
- package/src/components/documents/page-title.tsx +7 -0
- package/src/components/documents/tab-button.tsx +169 -0
- package/src/components/index.js +0 -0
- package/src/components/inputs/checkbox-input.tsx +66 -0
- package/src/components/inputs/input-box.tsx +45 -0
- package/src/components/inputs/input-element.tsx +65 -0
- package/src/components/inputs/input-form.tsx +50 -0
- package/src/components/inputs/input.tsx +181 -0
- package/src/components/inputs/number-input.tsx +108 -0
- package/src/components/inputs/radiobox-input.tsx +53 -0
- package/src/components/inputs/textarea-input.tsx +47 -0
- package/src/components/inputs/textbox-input.tsx +45 -0
- package/src/components/layouts/global-dialogbox.tsx +433 -0
- package/src/components/layouts/global-layout.tsx +63 -0
- package/src/components/layouts/layout-helpers.tsx +21 -0
- package/src/components/layouts/utility-menu.tsx +69 -0
- package/src/components/panels/theme-panel.tsx +44 -0
- package/src/helpers/bitwise-helpers.tsx +11 -0
- package/src/helpers/browser-helpers.tsx +71 -0
- package/src/helpers/datasource-helpers.tsx +99 -0
- package/src/helpers/element-helpers.tsx +57 -0
- package/src/helpers/input-helpers.tsx +24 -0
- package/src/helpers/string-helpers.tsx +28 -0
- package/src/helpers/utility-helpers.tsx +44 -0
- package/src/index.ts +67 -11
- package/src/interfaces/browser-interfaces.tsx +23 -0
- package/src/interfaces/button-interfaces.tsx +63 -0
- package/src/interfaces/datasource-interfaces.tsx +22 -0
- package/src/interfaces/datatable-interfaces.tsx +25 -0
- package/src/interfaces/dialogbox-interfaces.tsx +5 -0
- package/src/interfaces/http-interfaces.tsx +15 -0
- package/src/interfaces/icon-interfaces.tsx +126 -0
- package/src/interfaces/input-interfaces.tsx +360 -0
- package/src/interfaces/layout-interfaces.tsx +191 -0
- package/src/interfaces/menu-interfaces.tsx +36 -0
- package/src/interfaces/permission-interfaces.tsx +9 -0
- package/src/interfaces/storage-interfaces.tsx +3 -0
- package/src/interfaces/system-interfaces.tsx +22 -0
- package/src/interfaces/theme-interfaces.tsx +209 -0
- package/src/interfaces/type-interfaces.tsx +22 -0
- package/src/nexus-client.tsx +21 -0
- package/src/nexus.environments.tsx +34 -0
- package/src/services/loader-service.tsx +168 -0
- package/src/services/localstorage-service.tsx +43 -0
- package/src/services/theme-service.tsx +147 -0
- package/src/styles/nexus.animation.css +269 -0
- package/src/styles/nexus.core.css +119 -0
- package/src/styles/nexus.dialog.css +141 -0
- package/src/styles/nexus.icon.css +50 -0
- package/src/styles/nexus.input.css +207 -0
- package/src/styles/nexus.loader.css +11 -0
- package/src/styles/nexus.logic.css +18 -0
- package/src/styles/nexus.utility.css +347 -0
- package/src/client/index.ts +0 -1
- package/src/client/nexus-selectable-list.css +0 -131
- package/src/client/nexus-selectable-list.tsx +0 -111
- package/src/client.ts +0 -7
- package/src/interface.ts +0 -5
- package/src/interfaces/index.ts +0 -6
- package/src/interfaces/nexus-base.ts +0 -5
- package/src/interfaces/nexus-list.ts +0 -24
- package/src/server/index.ts +0 -1
- package/src/server/nexus-stat-list.css +0 -92
- package/src/server/nexus-stat-list.tsx +0 -46
- package/src/server.ts +0 -7
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import Script from "next/script";
|
|
2
|
+
import React from "react";
|
|
3
|
+
import {
|
|
4
|
+
IGlobalLayout,
|
|
5
|
+
ROOT_LOADER_IDENTITY,
|
|
6
|
+
} from "../../interfaces/layout-interfaces";
|
|
7
|
+
import { FILES } from "../../nexus.environments";
|
|
8
|
+
import { LayoutHelpers } from "./layout-helpers";
|
|
9
|
+
|
|
10
|
+
import "./../../styles/nexus.animation.css";
|
|
11
|
+
import "./../../styles/nexus.core.css";
|
|
12
|
+
import "./../../styles/nexus.dialog.css";
|
|
13
|
+
import "./../../styles/nexus.icon.css";
|
|
14
|
+
import "./../../styles/nexus.input.css";
|
|
15
|
+
import "./../../styles/nexus.loader.css";
|
|
16
|
+
import "./../../styles/nexus.logic.css";
|
|
17
|
+
import "./../../styles/nexus.utility.css";
|
|
18
|
+
|
|
19
|
+
export const GlobalLayout = async ({
|
|
20
|
+
children,
|
|
21
|
+
globalLayout,
|
|
22
|
+
}: Readonly<{ children: React.ReactNode; globalLayout: IGlobalLayout }>) => {
|
|
23
|
+
return (
|
|
24
|
+
<React.Fragment>
|
|
25
|
+
<LayoutHelpers globalLayout={globalLayout} />
|
|
26
|
+
<div
|
|
27
|
+
style={{
|
|
28
|
+
zIndex: "1000",
|
|
29
|
+
width: "100vw",
|
|
30
|
+
height: "100vh",
|
|
31
|
+
position: "fixed",
|
|
32
|
+
display: "flex",
|
|
33
|
+
justifyContent: "center",
|
|
34
|
+
alignItems: "center",
|
|
35
|
+
backgroundColor: "rgb(40, 40, 40)",
|
|
36
|
+
}}
|
|
37
|
+
id={ROOT_LOADER_IDENTITY}
|
|
38
|
+
>
|
|
39
|
+
<img
|
|
40
|
+
src={FILES.LOGO.ICON}
|
|
41
|
+
alt={"logo"}
|
|
42
|
+
style={{
|
|
43
|
+
minHeight: "3rem",
|
|
44
|
+
minWidth: "3rem",
|
|
45
|
+
width: "3rem",
|
|
46
|
+
height: "3rem",
|
|
47
|
+
}}
|
|
48
|
+
/>
|
|
49
|
+
</div>
|
|
50
|
+
{children}
|
|
51
|
+
<Script
|
|
52
|
+
type="module"
|
|
53
|
+
src="https://cdn.jsdelivr.net/npm/ionicons@5.5.2/dist/ionicons/ionicons.esm.js"
|
|
54
|
+
strategy="lazyOnload"
|
|
55
|
+
></Script>
|
|
56
|
+
<Script
|
|
57
|
+
noModule
|
|
58
|
+
src="https://cdn.jsdelivr.net/npm/ionicons@5.5.2/dist/ionicons/ionicons.js"
|
|
59
|
+
strategy="lazyOnload"
|
|
60
|
+
></Script>
|
|
61
|
+
</React.Fragment>
|
|
62
|
+
);
|
|
63
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { useEffect } from "react";
|
|
2
|
+
import { RemoveElement } from "../../helpers/browser-helpers";
|
|
3
|
+
import { IGlobalLayout, ROOT_LOADER_IDENTITY } from "../../interfaces/layout-interfaces";
|
|
4
|
+
import { DEFAULT_THEME_INFORMATIONS } from "../../interfaces/theme-interfaces";
|
|
5
|
+
import { O } from "../../nexus-client";
|
|
6
|
+
import { InitializeStyles } from "../../services/theme-service";
|
|
7
|
+
|
|
8
|
+
export const LayoutHelpers = ({ globalLayout }: Readonly<{ globalLayout: IGlobalLayout }>) => {
|
|
9
|
+
useEffect(() => {
|
|
10
|
+
globalLayout.systemThemes = DEFAULT_THEME_INFORMATIONS;
|
|
11
|
+
O.systemThemes = DEFAULT_THEME_INFORMATIONS;
|
|
12
|
+
|
|
13
|
+
const timeout = setTimeout(() => {
|
|
14
|
+
clearTimeout(timeout);
|
|
15
|
+
RemoveElement(ROOT_LOADER_IDENTITY, 500);
|
|
16
|
+
InitializeStyles();
|
|
17
|
+
}, 50);
|
|
18
|
+
}, []);
|
|
19
|
+
|
|
20
|
+
return <div className="nexus-popup-container"></div>;
|
|
21
|
+
};
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import React, { JSX } from "react";
|
|
2
|
+
import { EIconTypes } from "../../interfaces/icon-interfaces";
|
|
3
|
+
import { EPositions, ESizes, IGlobalLayout } from "../../interfaces/layout-interfaces";
|
|
4
|
+
import { GetUtilityMenuCode, IPanelMenu, IUtilityMenu, UTILITIES_BUTTON_PREFIX } from "../../interfaces/menu-interfaces";
|
|
5
|
+
import { EBackgrounds } from "../../interfaces/theme-interfaces";
|
|
6
|
+
import { Iconbox } from "../documents/icon-box";
|
|
7
|
+
import { PageTitle } from "../documents/page-title";
|
|
8
|
+
import { ThemePanel } from "../panels/theme-panel";
|
|
9
|
+
import { GlobalDialogbox } from "./global-dialogbox";
|
|
10
|
+
|
|
11
|
+
export const BUTTON_IDENTITY = (isneedPrefix: boolean) => {
|
|
12
|
+
const _ = isneedPrefix ? UTILITIES_BUTTON_PREFIX : "";
|
|
13
|
+
return {
|
|
14
|
+
PROFILE_BOX: `${_}profile`,
|
|
15
|
+
SEARCH_BOX: `${_}root-search`,
|
|
16
|
+
FAVORITE_BOX: `${_}favorite-menu`,
|
|
17
|
+
CARD_BOX: `${_}cart-menu`,
|
|
18
|
+
THEME_BOX: `${_}switch-theme`,
|
|
19
|
+
MEGA_BOX: `${_}mega-menu`,
|
|
20
|
+
SIGN_IN_BUTTON: `${_}sign-in`,
|
|
21
|
+
SIGN_OUT_BUTTON: `${_}sign-out`,
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
export const UtilityMenu = ({ utilityMenus, userPanels, column, paddingRight, globalLayout, iconBoxBackground }: Readonly<{ utilityMenus: IUtilityMenu[]; userPanels: IPanelMenu[]; column?: number; paddingRight?: number; globalLayout: IGlobalLayout; iconBoxBackground: EBackgrounds }>) => {
|
|
25
|
+
return (
|
|
26
|
+
<div style={{ paddingRight: paddingRight ?? 0, zIndex: 3 }} className={`utilities df fr ac jr h100p col-${column ?? 12}`}>
|
|
27
|
+
{utilityMenus.map((utilityMenu, index) => (
|
|
28
|
+
<UtilityIcon key={index} utilityMenu={utilityMenu} boxBackground={iconBoxBackground} globalLayout={globalLayout} />
|
|
29
|
+
))}
|
|
30
|
+
<ProfilePanel globalLayout={globalLayout} boxBackground={iconBoxBackground} userPanels={userPanels} />
|
|
31
|
+
</div>
|
|
32
|
+
);
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const UtilityIcon = ({ utilityMenu, globalLayout, boxBackground }: Readonly<{ utilityMenu: IUtilityMenu; globalLayout: IGlobalLayout; boxBackground?: EBackgrounds }>) => {
|
|
36
|
+
return (
|
|
37
|
+
<Iconbox id={GetUtilityMenuCode(utilityMenu.menuCode)} icon={utilityMenu.menuIcon} iconType={EIconTypes.FILLED} iconSize={ESizes.Small} boxSize={ESizes.Small} background={boxBackground} defaultClass="mr2">
|
|
38
|
+
<UtilityDialogBox utilityMenu={utilityMenu} globalLayout={globalLayout} />
|
|
39
|
+
</Iconbox>
|
|
40
|
+
);
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export const ProfilePanel = ({ globalLayout, userPanels, boxBackground }: Readonly<{ globalLayout: IGlobalLayout; userPanels: IPanelMenu[]; boxBackground?: EBackgrounds }>): JSX.Element => {
|
|
44
|
+
return (
|
|
45
|
+
<div className={`pr ${ESizes.Small} ib ${boxBackground} h p2 r`}>
|
|
46
|
+
<h6>BA</h6>
|
|
47
|
+
</div>
|
|
48
|
+
);
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
const UtilityDialogBox = ({ utilityMenu, globalLayout }: Readonly<{ utilityMenu: IUtilityMenu; globalLayout: IGlobalLayout }>) => {
|
|
52
|
+
return (
|
|
53
|
+
<GlobalDialogbox hoverEffectDelay={true} defaultPadding={5} position={EPositions.Left} buttonIdentity={GetUtilityMenuCode(utilityMenu.menuCode)} defaultWidth={30}>
|
|
54
|
+
<div>
|
|
55
|
+
<PageTitle marginBottom={5} borderBottom={1} title={utilityMenu.menuName} />
|
|
56
|
+
<UtilityPanel utilityMenu={utilityMenu} globalLayout={globalLayout} />
|
|
57
|
+
</div>
|
|
58
|
+
</GlobalDialogbox>
|
|
59
|
+
);
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
const UtilityPanel = ({ utilityMenu, globalLayout }: Readonly<{ utilityMenu: IUtilityMenu; globalLayout: IGlobalLayout }>) => {
|
|
63
|
+
switch (utilityMenu.menuCode) {
|
|
64
|
+
case BUTTON_IDENTITY(false).THEME_BOX:
|
|
65
|
+
return <ThemePanel />;
|
|
66
|
+
default:
|
|
67
|
+
return <div>Unknown Panel: {utilityMenu.menuName}</div>;
|
|
68
|
+
}
|
|
69
|
+
};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import React, { useEffect } from "react";
|
|
2
|
+
import { GetButton, IButton } from "../../interfaces/button-interfaces";
|
|
3
|
+
import { EIconTypes } from "../../interfaces/icon-interfaces";
|
|
4
|
+
import { ClickHandler } from "../../interfaces/type-interfaces";
|
|
5
|
+
import { O } from "../../nexus-client";
|
|
6
|
+
import { GetCurrentThemeName, SetCurrentTheme } from "../../services/localstorage-service";
|
|
7
|
+
import { SwitchTheme } from "../../services/theme-service";
|
|
8
|
+
import { CreateTabButtons } from "../documents/tab-button";
|
|
9
|
+
|
|
10
|
+
const onClicked: ClickHandler = (event, element, button: IButton) => {
|
|
11
|
+
if (button.id === GetCurrentThemeName()) return;
|
|
12
|
+
const themeCode = button.id;
|
|
13
|
+
if (!themeCode) return;
|
|
14
|
+
SwitchTheme(themeCode);
|
|
15
|
+
SetCurrentTheme(themeCode);
|
|
16
|
+
};
|
|
17
|
+
const RenderSwitchTheme = (baseElement: HTMLElement) => {
|
|
18
|
+
if (!baseElement || baseElement.classList.contains("ddcc")) return;
|
|
19
|
+
baseElement.classList.add("ddcc");
|
|
20
|
+
|
|
21
|
+
const currentTheme = GetCurrentThemeName();
|
|
22
|
+
const themes = O.systemThemes;
|
|
23
|
+
|
|
24
|
+
if (!themes || themes.length === 0) {
|
|
25
|
+
const p = document.createElement("p");
|
|
26
|
+
p.textContent = "No theme available!";
|
|
27
|
+
p.className = "o08 p5 bg3 tc";
|
|
28
|
+
baseElement.appendChild(p);
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
const themeButtons: IButton[] = themes.map((theme, index) => GetButton(theme.displayName, theme.systemName, null, theme.icon, onClicked, theme, null, null, theme.displayOrder, EIconTypes.FILLED, null));
|
|
32
|
+
const activeButton = themeButtons.find((button) => button.id === currentTheme);
|
|
33
|
+
CreateTabButtons(themeButtons, baseElement, activeButton, onClicked);
|
|
34
|
+
|
|
35
|
+
return "Theme Settings";
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export const ThemePanel = () => {
|
|
39
|
+
const containerRef = React.useRef<HTMLDivElement>(null);
|
|
40
|
+
useEffect(() => {
|
|
41
|
+
if (containerRef.current) RenderSwitchTheme(containerRef.current);
|
|
42
|
+
}, [containerRef.current]);
|
|
43
|
+
return <div ref={containerRef}></div>;
|
|
44
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export function HasFlag(state: number, flag: number): boolean {
|
|
2
|
+
return (state & flag) === flag;
|
|
3
|
+
}
|
|
4
|
+
export function BitwiseToList<T>(enumType: any, bitwiseValue: number): T[] {
|
|
5
|
+
return Object.values(enumType)
|
|
6
|
+
.filter((v) => typeof v === "number")
|
|
7
|
+
.filter((v: number) => (bitwiseValue & v) === v && v !== 0) as T[];
|
|
8
|
+
}
|
|
9
|
+
export function ListToBitwise(values: number[]): number {
|
|
10
|
+
return values.reduce((acc, curr) => acc | curr, 0);
|
|
11
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { EAnimationClasses } from "../interfaces/layout-interfaces";
|
|
2
|
+
import { NEXUS_INFO } from "../nexus.environments";
|
|
3
|
+
import { EKeyModifier, EKeys } from "./../interfaces/browser-interfaces";
|
|
4
|
+
import { HasFlag } from "./bitwise-helpers";
|
|
5
|
+
import { Debounce } from "./utility-helpers";
|
|
6
|
+
|
|
7
|
+
export const IsBrowser = (): boolean => typeof window !== "undefined" && typeof document !== "undefined";
|
|
8
|
+
|
|
9
|
+
export const RemoveElement = async (elementIdentity: string | HTMLElement, timeout?: number, animation?: EAnimationClasses): Promise<boolean> => {
|
|
10
|
+
return new Promise(async (resolve) => {
|
|
11
|
+
if (!IsBrowser() || !elementIdentity) return resolve(false);
|
|
12
|
+
else if (typeof elementIdentity === "string") {
|
|
13
|
+
const element = document.getElementById(elementIdentity);
|
|
14
|
+
if (element) return await RemoveElement(element, timeout);
|
|
15
|
+
} else if (elementIdentity instanceof HTMLElement || (elementIdentity as HTMLElement)) {
|
|
16
|
+
const timeoutIdentifier = setTimeout(() => {
|
|
17
|
+
(elementIdentity as HTMLElement).remove();
|
|
18
|
+
clearTimeout(timeoutIdentifier);
|
|
19
|
+
elementIdentity.remove();
|
|
20
|
+
return resolve(true);
|
|
21
|
+
}, timeout ?? 0);
|
|
22
|
+
elementIdentity.classList.add(animation ?? EAnimationClasses.FADE_OUT);
|
|
23
|
+
return resolve(true);
|
|
24
|
+
} else return resolve(false);
|
|
25
|
+
});
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const setDocumentTitle = (title?: string) => IsBrowser() && (document.title = `Nexus - ${title ?? NEXUS_INFO.CURRENT_MODULE_SHORT_NAME ?? "Solutions"}`);
|
|
29
|
+
export const SetDocumentTitleDebounce = Debounce(setDocumentTitle, 100);
|
|
30
|
+
|
|
31
|
+
export const ConvertRemToPixels = (rem: number): number => {
|
|
32
|
+
const fontSize = parseFloat(getComputedStyle(document.documentElement).fontSize) || 16;
|
|
33
|
+
return Math.round(rem * fontSize * 1000) / 1000;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export const ConvertPixelsToRem = (px: number): number => {
|
|
37
|
+
const fontSize = parseFloat(getComputedStyle(document.documentElement).fontSize) || 16;
|
|
38
|
+
return Math.round((px / fontSize) * 1000) / 1000;
|
|
39
|
+
};
|
|
40
|
+
export const IsKeyPressed = (event: any, key: EKeys | string, modifier?: EKeyModifier): boolean => {
|
|
41
|
+
const isPressed = (event?.key ?? event?.nativeEvent?.data) === key;
|
|
42
|
+
if (!isPressed) return isPressed;
|
|
43
|
+
|
|
44
|
+
if (!modifier) return isPressed;
|
|
45
|
+
|
|
46
|
+
if (HasFlag(modifier, EKeyModifier.Shift) && !event.shiftKey) return false;
|
|
47
|
+
if (HasFlag(modifier, EKeyModifier.Ctrl) && !event.ctrlKey) return false;
|
|
48
|
+
if (HasFlag(modifier, EKeyModifier.Alt) && !event.altKey) return false;
|
|
49
|
+
|
|
50
|
+
return isPressed;
|
|
51
|
+
};
|
|
52
|
+
export const IsValidURL = (url?: string | null) => url !== undefined && url !== null && url !== "#" && url.length > 0;
|
|
53
|
+
|
|
54
|
+
export const FindChildElement = (parent: HTMLElement, childSelector: string, shouldScanAllChildren: boolean = false) => {
|
|
55
|
+
if (!parent || !childSelector) return null;
|
|
56
|
+
if (shouldScanAllChildren) {
|
|
57
|
+
const children = parent.querySelectorAll(childSelector);
|
|
58
|
+
return children.length > 0 ? children[0] : null;
|
|
59
|
+
} else return parent.querySelector(childSelector);
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
export const FindChildElements = (parent: HTMLElement, childSelector: string, shouldScanAllChildren: boolean = false) => {
|
|
63
|
+
if (!parent || !childSelector) return [];
|
|
64
|
+
if (shouldScanAllChildren) {
|
|
65
|
+
const children = parent.querySelectorAll(childSelector);
|
|
66
|
+
return children.length > 0 ? children : [];
|
|
67
|
+
} else {
|
|
68
|
+
const children = parent.querySelectorAll(childSelector);
|
|
69
|
+
return children.length > 0 ? [children[0]] : [];
|
|
70
|
+
}
|
|
71
|
+
};
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { IColumn } from "../interfaces/datatable-interfaces";
|
|
2
|
+
import { IsNullOrEmpty } from "./string-helpers";
|
|
3
|
+
|
|
4
|
+
export function GetVisibleAndHiddenItems<T>(allItems: T[], visibleRef: T[], hiddenRef: T[], activeItem: T | undefined, maxVisibleCount: number): { visibleItems: T[]; hiddenItems: T[] } {
|
|
5
|
+
let visibleItems: T[] = [];
|
|
6
|
+
let hiddenItems: T[] = [];
|
|
7
|
+
visibleRef.length = 0;
|
|
8
|
+
hiddenRef.length = 0;
|
|
9
|
+
|
|
10
|
+
if (allItems.length <= maxVisibleCount) {
|
|
11
|
+
const _ = {
|
|
12
|
+
visibleItems: allItems,
|
|
13
|
+
hiddenItems: [],
|
|
14
|
+
};
|
|
15
|
+
visibleRef.push(..._.visibleItems);
|
|
16
|
+
hiddenRef.push(..._.hiddenItems);
|
|
17
|
+
return _;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if (!activeItem || !allItems.includes(activeItem)) {
|
|
21
|
+
visibleItems = allItems.slice(0, maxVisibleCount);
|
|
22
|
+
hiddenItems = allItems.slice(maxVisibleCount);
|
|
23
|
+
} else {
|
|
24
|
+
const index = allItems.indexOf(activeItem);
|
|
25
|
+
// It means the active item is within the visible range
|
|
26
|
+
const selectedItem = allItems[index];
|
|
27
|
+
// 0 to maxVisibleCount - 1
|
|
28
|
+
visibleItems = allItems.slice(0, maxVisibleCount - 1);
|
|
29
|
+
visibleItems.push(selectedItem);
|
|
30
|
+
hiddenItems = allItems.slice(maxVisibleCount - 1);
|
|
31
|
+
// remove the hidden but active item from the hidden items
|
|
32
|
+
hiddenItems = hiddenItems.filter((item) => item !== selectedItem);
|
|
33
|
+
if (index > maxVisibleCount - 1) {
|
|
34
|
+
} else {
|
|
35
|
+
visibleItems = allItems.slice(0, maxVisibleCount);
|
|
36
|
+
hiddenItems = allItems.slice(maxVisibleCount);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
visibleRef.push(...visibleItems);
|
|
40
|
+
hiddenRef.push(...hiddenItems);
|
|
41
|
+
return { visibleItems, hiddenItems };
|
|
42
|
+
}
|
|
43
|
+
export function DynamicSorting<T>(data: T[], key: keyof T, isAsc: boolean) {
|
|
44
|
+
return [...data].sort((a, b) => {
|
|
45
|
+
const aValue = a[key];
|
|
46
|
+
const bValue = b[key];
|
|
47
|
+
let result = 0;
|
|
48
|
+
|
|
49
|
+
// **Handle null & undefined values**
|
|
50
|
+
if (aValue == null && bValue == null) return 0;
|
|
51
|
+
if (aValue == null) return isAsc ? -1 : 1;
|
|
52
|
+
if (bValue == null) return isAsc ? 1 : -1;
|
|
53
|
+
|
|
54
|
+
// **Handle numbers**
|
|
55
|
+
if (typeof aValue === "number" && typeof bValue === "number") result = aValue - bValue;
|
|
56
|
+
// **Handle strings**
|
|
57
|
+
else if (typeof aValue === "string" && typeof bValue === "string") result = aValue.localeCompare(bValue);
|
|
58
|
+
// **Handle dates**
|
|
59
|
+
else if (aValue instanceof Date && bValue instanceof Date) result = aValue.getTime() - bValue.getTime();
|
|
60
|
+
// **Handle objects (fallback)**
|
|
61
|
+
else if (typeof aValue === "object" && typeof bValue === "object") result = JSON.stringify(aValue).localeCompare(JSON.stringify(bValue));
|
|
62
|
+
// **Handle mixed types (fallback)**
|
|
63
|
+
else result = String(aValue).localeCompare(String(bValue));
|
|
64
|
+
|
|
65
|
+
return isAsc ? result : -result;
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
export function CreateClone<T>(data: T | T[], index?: number, object?: T): T | T[] {
|
|
69
|
+
// Check if the input is an array
|
|
70
|
+
if (Array.isArray(data)) {
|
|
71
|
+
// Clone each element in the array
|
|
72
|
+
let clonedArray = data.map((item) => ({ ...item }));
|
|
73
|
+
|
|
74
|
+
// If both index and object are provided, add the object at the specified index
|
|
75
|
+
if (index !== undefined && object !== undefined) {
|
|
76
|
+
// Insert object at the specified index
|
|
77
|
+
clonedArray.splice(index, 0, { ...object });
|
|
78
|
+
}
|
|
79
|
+
return clonedArray;
|
|
80
|
+
} else if (typeof data === "object" && data !== null)
|
|
81
|
+
// Clone a single object
|
|
82
|
+
return { ...data };
|
|
83
|
+
else throw new Error("Input must be an object or an array of objects");
|
|
84
|
+
}
|
|
85
|
+
export const SearchDatasourceUsingColumns = (dataSource: any[], searchText: string | null, columns: IColumn[]) => {
|
|
86
|
+
if (!dataSource || !Array.isArray(dataSource) || dataSource.length === 0 || !columns || columns.length === 0 || IsNullOrEmpty(searchText)) return dataSource;
|
|
87
|
+
const searchableColumns = columns.filter((column) => column.isSearchable);
|
|
88
|
+
if (searchableColumns.length === 0) return dataSource;
|
|
89
|
+
const searchLower = searchText?.toLowerCase().trim();
|
|
90
|
+
return dataSource.filter((data) => {
|
|
91
|
+
return searchableColumns.some((column) => {
|
|
92
|
+
if (column.systemName) {
|
|
93
|
+
const value = data[column.systemName];
|
|
94
|
+
return value && value.toString().toLowerCase().includes(searchLower);
|
|
95
|
+
}
|
|
96
|
+
return false;
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
};
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { UN } from "../interfaces/type-interfaces";
|
|
2
|
+
|
|
3
|
+
export function RenderChildren<T>(parentContainer: HTMLElement, elementList: HTMLElement[], toggleButton: HTMLElement, activeItem: T | UN, visibleItems: T[], hiddenItems: T[], createItem: (item: T) => HTMLElement, refreshElementClass: (element: HTMLElement, activeItem: T | UN) => void, isInit: boolean, isHiddenItemClicked: boolean, dataUniqueKey: string, dataAttributeKey: string) {
|
|
4
|
+
if (!isInit) {
|
|
5
|
+
// Update classes for all item links based on activeItem
|
|
6
|
+
for (const element of elementList) refreshElementClass(element, activeItem);
|
|
7
|
+
if (isHiddenItemClicked && activeItem) {
|
|
8
|
+
// A hidden item was clicked: replace last visible item in DOM with the active one
|
|
9
|
+
const newActiveItem = createItem(activeItem);
|
|
10
|
+
const lastItemElement = elementList[elementList.length - 1];
|
|
11
|
+
|
|
12
|
+
if (lastItemElement) {
|
|
13
|
+
lastItemElement.replaceWith(newActiveItem);
|
|
14
|
+
elementList[elementList.length - 1].remove();
|
|
15
|
+
elementList[elementList.length - 1] = newActiveItem;
|
|
16
|
+
}
|
|
17
|
+
} else {
|
|
18
|
+
// Ensure last visible DOM element matches last item in visibleItems
|
|
19
|
+
const lastVisible = visibleItems[visibleItems.length - 1];
|
|
20
|
+
const lastDomItem = elementList[elementList.length - 1];
|
|
21
|
+
|
|
22
|
+
const currentItemCode = lastDomItem?.getAttribute(dataAttributeKey);
|
|
23
|
+
if (lastVisible && lastDomItem && currentItemCode !== (lastVisible as any)[dataUniqueKey]) {
|
|
24
|
+
const correctedItem = createItem(lastVisible);
|
|
25
|
+
lastDomItem.replaceWith(correctedItem);
|
|
26
|
+
lastDomItem.remove();
|
|
27
|
+
elementList[elementList.length - 1] = correctedItem;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Initial render: clear and create full visible item
|
|
34
|
+
elementList.length = 0;
|
|
35
|
+
parentContainer.innerHTML = "";
|
|
36
|
+
|
|
37
|
+
for (const item of visibleItems) {
|
|
38
|
+
const itemItem = createItem(item);
|
|
39
|
+
parentContainer.appendChild(itemItem);
|
|
40
|
+
elementList.push(itemItem);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Append toggle icon if hidden items exist
|
|
44
|
+
if (hiddenItems.length > 0) {
|
|
45
|
+
parentContainer.appendChild(toggleButton);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
export const SetElementStyles = (element: HTMLElement, styles: React.CSSProperties | UN) => {
|
|
49
|
+
if (!element || !styles) return;
|
|
50
|
+
if (typeof styles === "object") {
|
|
51
|
+
Object.keys(styles).forEach((key) => {
|
|
52
|
+
const value = styles[key as keyof typeof styles];
|
|
53
|
+
if (value === undefined) return;
|
|
54
|
+
element.style.setProperty(key, value === null ? null : String(value));
|
|
55
|
+
});
|
|
56
|
+
} else element.style.setProperty(styles as string, styles as string);
|
|
57
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { EValueChangeTypes, IInputCreateResults, IInputRootParameters } from "../interfaces/input-interfaces";
|
|
2
|
+
import { ESizes } from "../interfaces/layout-interfaces";
|
|
3
|
+
import { UN } from "../interfaces/type-interfaces";
|
|
4
|
+
|
|
5
|
+
export const GetParentKey = (parentKey?: string | null) => {
|
|
6
|
+
if (parentKey) return parentKey.split("|")[0];
|
|
7
|
+
return undefined;
|
|
8
|
+
};
|
|
9
|
+
export const GetInputId = (param: IInputRootParameters<any>) => param.id.split("-")[0];
|
|
10
|
+
export const GetInputClasses = (size?: ESizes | UN, cls?: string | UN) => `ipt pr sn ${size ?? ""} ${cls ?? ""}`;
|
|
11
|
+
export const SetHaveValueClass = (input: HTMLElement, isHaveValue: boolean) => {
|
|
12
|
+
if (!input) return;
|
|
13
|
+
input.classList.toggle("txhv", isHaveValue);
|
|
14
|
+
};
|
|
15
|
+
export const ForceSetValues = (inputs: IInputCreateResults[] | UN, keys: string[] | UN, value: any | null, timeout?: number | UN, invokeOnChanged?: boolean | UN) => {
|
|
16
|
+
if (!inputs || inputs.length === 0) return;
|
|
17
|
+
for (const input of inputs) if (!keys || keys.length === 0 || keys.includes(GetInputId(input.input))) ForceSetValue(input, value, timeout, invokeOnChanged);
|
|
18
|
+
};
|
|
19
|
+
export const ForceSetValue = (input?: IInputCreateResults | null, value?: any | null, timeout?: number | UN, invokeOnChanged?: boolean | UN) => {
|
|
20
|
+
const timeoutValue = setTimeout(() => {
|
|
21
|
+
input?.forceChangeDefaultValue && input.forceChangeDefaultValue(value, EValueChangeTypes.ForceChanged, invokeOnChanged);
|
|
22
|
+
clearTimeout(timeoutValue);
|
|
23
|
+
}, timeout ?? 0);
|
|
24
|
+
};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { UN } from "../interfaces/type-interfaces";
|
|
2
|
+
|
|
3
|
+
export const ConvertToCode = (text: string | UN) => text?.toString().toLowerCase().replace(/\s+/g, "-") ?? null;
|
|
4
|
+
|
|
5
|
+
export const IsNullOrEmpty = (value?: string | null) => !(value !== null && value !== undefined && value.toString().trim().length > 0);
|
|
6
|
+
export function MakeFirstLetterUpperCase(str?: string) {
|
|
7
|
+
if (!str) return str;
|
|
8
|
+
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
9
|
+
}
|
|
10
|
+
export const GetRandomNumber = (min = 0, max = 100) => Math.floor(Math.random() * (max - min + 1)) + min;
|
|
11
|
+
export const GetRandomString = (length: number = 10, includeNumbers: boolean = true, includeSpecialChars: boolean = false): string => {
|
|
12
|
+
const characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" + (includeNumbers ? "0123456789" : "") + (includeSpecialChars ? "!@#$%^&*()_+-=[]{}|;:,.<>?/" : "");
|
|
13
|
+
let result = "";
|
|
14
|
+
|
|
15
|
+
for (let i = 0; i < length; i++) {
|
|
16
|
+
const randomIndex = Math.floor(Math.random() * characters.length);
|
|
17
|
+
result += characters[randomIndex];
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return result;
|
|
21
|
+
};
|
|
22
|
+
export function PadStart(value: string | number | null | undefined, targetLength: number, padString: string = "0"): string {
|
|
23
|
+
if (value == null || value === undefined) return "";
|
|
24
|
+
|
|
25
|
+
const str = value?.toString();
|
|
26
|
+
if (str.length >= targetLength) return str;
|
|
27
|
+
return padString.repeat(targetLength - str.length) + str;
|
|
28
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
const DEFAULT_DELAY = 500;
|
|
2
|
+
|
|
3
|
+
export type DebouncedFunction<T extends (...args: any[]) => void> = ((...args: Parameters<T>) => void) & {
|
|
4
|
+
cancel: () => void;
|
|
5
|
+
executeImmediately: (...args: Parameters<T>) => void;
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
export function Debounce<T extends (...args: any[]) => void>(func: T, delay?: number): DebouncedFunction<T> {
|
|
9
|
+
let timer: ReturnType<typeof setTimeout> | undefined;
|
|
10
|
+
let lastArgs: Parameters<T> | undefined;
|
|
11
|
+
let isPending = false;
|
|
12
|
+
|
|
13
|
+
const debounced = (...args: Parameters<T>) => {
|
|
14
|
+
lastArgs = args;
|
|
15
|
+
isPending = true;
|
|
16
|
+
clearTimeout(timer);
|
|
17
|
+
timer = setTimeout(() => {
|
|
18
|
+
timer = undefined;
|
|
19
|
+
isPending = false;
|
|
20
|
+
lastArgs = undefined;
|
|
21
|
+
func(...args);
|
|
22
|
+
}, delay ?? DEFAULT_DELAY);
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
/** Cancel the debounced function */
|
|
26
|
+
debounced.cancel = () => {
|
|
27
|
+
clearTimeout(timer);
|
|
28
|
+
timer = undefined;
|
|
29
|
+
isPending = false;
|
|
30
|
+
lastArgs = undefined;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
/** Execute the debounced function immediately */
|
|
34
|
+
debounced.executeImmediately = (...args: Parameters<T>) => {
|
|
35
|
+
clearTimeout(timer);
|
|
36
|
+
timer = undefined;
|
|
37
|
+
const invokeArgs = args.length > 0 ? args : isPending ? lastArgs : undefined;
|
|
38
|
+
isPending = false;
|
|
39
|
+
lastArgs = undefined;
|
|
40
|
+
if (invokeArgs !== undefined) func(...invokeArgs);
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
return debounced;
|
|
44
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1,11 +1,67 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
*
|
|
5
|
-
* -
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
export * from "./
|
|
10
|
-
export * from "./
|
|
11
|
-
export * from "./
|
|
1
|
+
import "./load-env";
|
|
2
|
+
|
|
3
|
+
// API services
|
|
4
|
+
export * from "./api-services/preference-service";
|
|
5
|
+
export * from "./api-services/system-service";
|
|
6
|
+
|
|
7
|
+
// Components — documents
|
|
8
|
+
export * from "./components/documents/button";
|
|
9
|
+
export * from "./components/documents/icon-box";
|
|
10
|
+
export * from "./components/documents/page-title";
|
|
11
|
+
export * from "./components/documents/tab-button";
|
|
12
|
+
|
|
13
|
+
// Components — inputs
|
|
14
|
+
export * from "./components/inputs/checkbox-input";
|
|
15
|
+
export * from "./components/inputs/input";
|
|
16
|
+
export * from "./components/inputs/input-box";
|
|
17
|
+
export * from "./components/inputs/input-element";
|
|
18
|
+
export * from "./components/inputs/input-form";
|
|
19
|
+
export * from "./components/inputs/number-input";
|
|
20
|
+
export * from "./components/inputs/radiobox-input";
|
|
21
|
+
export * from "./components/inputs/textarea-input";
|
|
22
|
+
export * from "./components/inputs/textbox-input";
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
// Components — layouts
|
|
26
|
+
export * from "./components/layouts/global-layout";
|
|
27
|
+
export * from "./components/layouts/global-dialogbox";
|
|
28
|
+
export * from "./components/layouts/layout-helpers";
|
|
29
|
+
export * from "./components/layouts/utility-menu";
|
|
30
|
+
|
|
31
|
+
// Components — panels
|
|
32
|
+
export * from "./components/panels/theme-panel";
|
|
33
|
+
|
|
34
|
+
// Helpers
|
|
35
|
+
export * from "./helpers/bitwise-helpers";
|
|
36
|
+
export * from "./helpers/browser-helpers";
|
|
37
|
+
export * from "./helpers/datasource-helpers";
|
|
38
|
+
export * from "./helpers/element-helpers";
|
|
39
|
+
export * from "./helpers/input-helpers";
|
|
40
|
+
export * from "./helpers/string-helpers";
|
|
41
|
+
export * from "./helpers/utility-helpers";
|
|
42
|
+
|
|
43
|
+
// Interfaces
|
|
44
|
+
export * from "./interfaces/browser-interfaces";
|
|
45
|
+
export * from "./interfaces/button-interfaces";
|
|
46
|
+
export * from "./interfaces/datatable-interfaces";
|
|
47
|
+
export * from "./interfaces/datasource-interfaces";
|
|
48
|
+
export * from "./interfaces/dialogbox-interfaces";
|
|
49
|
+
export * from "./interfaces/http-interfaces";
|
|
50
|
+
export * from "./interfaces/icon-interfaces";
|
|
51
|
+
export * from "./interfaces/input-interfaces";
|
|
52
|
+
export * from "./interfaces/layout-interfaces";
|
|
53
|
+
export * from "./interfaces/menu-interfaces";
|
|
54
|
+
export * from "./interfaces/permission-interfaces";
|
|
55
|
+
export * from "./interfaces/storage-interfaces";
|
|
56
|
+
export * from "./interfaces/system-interfaces";
|
|
57
|
+
export * from "./interfaces/theme-interfaces";
|
|
58
|
+
export * from "./interfaces/type-interfaces";
|
|
59
|
+
|
|
60
|
+
// Services
|
|
61
|
+
export * from "./services/loader-service";
|
|
62
|
+
export * from "./services/localstorage-service";
|
|
63
|
+
export * from "./services/theme-service";
|
|
64
|
+
|
|
65
|
+
// Core
|
|
66
|
+
export * from "./nexus-client";
|
|
67
|
+
export * from "./nexus.environments";
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export enum EKeys {
|
|
2
|
+
TAB = "Tab",
|
|
3
|
+
DELETE = "Delete",
|
|
4
|
+
ENTER = "Enter",
|
|
5
|
+
ESCAPE = "Escape",
|
|
6
|
+
SPACE = " ",
|
|
7
|
+
BACKSPACE = "Backspace",
|
|
8
|
+
ARROW_UP = "ArrowUp",
|
|
9
|
+
ARROW_DOWN = "ArrowDown",
|
|
10
|
+
ARROW_LEFT = "ArrowLeft",
|
|
11
|
+
ARROW_RIGHT = "ArrowRight",
|
|
12
|
+
A = "a",
|
|
13
|
+
B = "b",
|
|
14
|
+
C = "c",
|
|
15
|
+
D = "d",
|
|
16
|
+
DOT = ".",
|
|
17
|
+
}
|
|
18
|
+
export enum EKeyModifier {
|
|
19
|
+
None = 0,
|
|
20
|
+
Shift = 1 << 0, // 1
|
|
21
|
+
Ctrl = 1 << 1, // 2
|
|
22
|
+
Alt = 1 << 2, // 4
|
|
23
|
+
}
|