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.
Files changed (70) hide show
  1. package/package.json +8 -4
  2. package/src/api-services/preference-service.tsx +5 -0
  3. package/src/api-services/system-service.tsx +322 -0
  4. package/src/components/documents/button.tsx +136 -0
  5. package/src/components/documents/icon-box.tsx +92 -0
  6. package/src/components/documents/page-title.tsx +7 -0
  7. package/src/components/documents/tab-button.tsx +169 -0
  8. package/src/components/index.js +0 -0
  9. package/src/components/inputs/checkbox-input.tsx +66 -0
  10. package/src/components/inputs/input-box.tsx +45 -0
  11. package/src/components/inputs/input-element.tsx +65 -0
  12. package/src/components/inputs/input-form.tsx +50 -0
  13. package/src/components/inputs/input.tsx +181 -0
  14. package/src/components/inputs/number-input.tsx +108 -0
  15. package/src/components/inputs/radiobox-input.tsx +53 -0
  16. package/src/components/inputs/textarea-input.tsx +47 -0
  17. package/src/components/inputs/textbox-input.tsx +45 -0
  18. package/src/components/layouts/global-dialogbox.tsx +433 -0
  19. package/src/components/layouts/global-layout.tsx +63 -0
  20. package/src/components/layouts/layout-helpers.tsx +21 -0
  21. package/src/components/layouts/utility-menu.tsx +69 -0
  22. package/src/components/panels/theme-panel.tsx +44 -0
  23. package/src/helpers/bitwise-helpers.tsx +11 -0
  24. package/src/helpers/browser-helpers.tsx +71 -0
  25. package/src/helpers/datasource-helpers.tsx +99 -0
  26. package/src/helpers/element-helpers.tsx +57 -0
  27. package/src/helpers/input-helpers.tsx +24 -0
  28. package/src/helpers/string-helpers.tsx +28 -0
  29. package/src/helpers/utility-helpers.tsx +44 -0
  30. package/src/index.ts +67 -11
  31. package/src/interfaces/browser-interfaces.tsx +23 -0
  32. package/src/interfaces/button-interfaces.tsx +63 -0
  33. package/src/interfaces/datasource-interfaces.tsx +22 -0
  34. package/src/interfaces/datatable-interfaces.tsx +25 -0
  35. package/src/interfaces/dialogbox-interfaces.tsx +5 -0
  36. package/src/interfaces/http-interfaces.tsx +15 -0
  37. package/src/interfaces/icon-interfaces.tsx +126 -0
  38. package/src/interfaces/input-interfaces.tsx +360 -0
  39. package/src/interfaces/layout-interfaces.tsx +191 -0
  40. package/src/interfaces/menu-interfaces.tsx +36 -0
  41. package/src/interfaces/permission-interfaces.tsx +9 -0
  42. package/src/interfaces/storage-interfaces.tsx +3 -0
  43. package/src/interfaces/system-interfaces.tsx +22 -0
  44. package/src/interfaces/theme-interfaces.tsx +209 -0
  45. package/src/interfaces/type-interfaces.tsx +22 -0
  46. package/src/nexus-client.tsx +21 -0
  47. package/src/nexus.environments.tsx +34 -0
  48. package/src/services/loader-service.tsx +168 -0
  49. package/src/services/localstorage-service.tsx +43 -0
  50. package/src/services/theme-service.tsx +147 -0
  51. package/src/styles/nexus.animation.css +269 -0
  52. package/src/styles/nexus.core.css +119 -0
  53. package/src/styles/nexus.dialog.css +141 -0
  54. package/src/styles/nexus.icon.css +50 -0
  55. package/src/styles/nexus.input.css +207 -0
  56. package/src/styles/nexus.loader.css +11 -0
  57. package/src/styles/nexus.logic.css +18 -0
  58. package/src/styles/nexus.utility.css +347 -0
  59. package/src/client/index.ts +0 -1
  60. package/src/client/nexus-selectable-list.css +0 -131
  61. package/src/client/nexus-selectable-list.tsx +0 -111
  62. package/src/client.ts +0 -7
  63. package/src/interface.ts +0 -5
  64. package/src/interfaces/index.ts +0 -6
  65. package/src/interfaces/nexus-base.ts +0 -5
  66. package/src/interfaces/nexus-list.ts +0 -24
  67. package/src/server/index.ts +0 -1
  68. package/src/server/nexus-stat-list.css +0 -92
  69. package/src/server/nexus-stat-list.tsx +0 -46
  70. 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
- * Unified entry — re-exports interface, server, and client modules.
3
- *
4
- * Prefer subpath imports in client-only code:
5
- * - `@nexus/core/interface`
6
- * - `@nexus/core/server`
7
- * - `@nexus/core/client`
8
- */
9
- export * from "./interface";
10
- export * from "./server";
11
- export * from "./client";
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
+ }