@adminlte/react 0.1.0

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 (83) hide show
  1. package/CHANGELOG.md +161 -0
  2. package/README.md +454 -0
  3. package/dist/context/accessibility.js +141 -0
  4. package/dist/context/body-class-sync.js +22 -0
  5. package/dist/context/color-mode-context.js +61 -0
  6. package/dist/context/command-palette-context.js +28 -0
  7. package/dist/context/html-dir.js +17 -0
  8. package/dist/context/link-context.js +18 -0
  9. package/dist/context/lte-behaviors.js +52 -0
  10. package/dist/context/sidebar-context.js +87 -0
  11. package/dist/css/adminlte.css +17259 -0
  12. package/dist/form/button.js +21 -0
  13. package/dist/form/input-color.js +30 -0
  14. package/dist/form/input-file.js +29 -0
  15. package/dist/form/input-flatpickr.js +45 -0
  16. package/dist/form/input-switch.js +26 -0
  17. package/dist/form/input-tom-select.js +59 -0
  18. package/dist/form/input.js +23 -0
  19. package/dist/form/select.js +25 -0
  20. package/dist/form/textarea.js +22 -0
  21. package/dist/hooks/use-card-widget.js +44 -0
  22. package/dist/hooks/use-direct-chat.js +16 -0
  23. package/dist/hooks/use-fullscreen.js +44 -0
  24. package/dist/hooks/use-push-menu.js +54 -0
  25. package/dist/hooks/use-sortable.js +26 -0
  26. package/dist/hooks/use-treeview-animation.js +27 -0
  27. package/dist/index.d.ts +1010 -0
  28. package/dist/index.js +145 -0
  29. package/dist/layout/app-content.js +18 -0
  30. package/dist/layout/auth-layout.js +25 -0
  31. package/dist/layout/color-mode-toggle.js +67 -0
  32. package/dist/layout/dashboard-layout.js +101 -0
  33. package/dist/layout/footer.js +19 -0
  34. package/dist/layout/sidebar-brand.js +16 -0
  35. package/dist/layout/sidebar-nav-item.js +46 -0
  36. package/dist/layout/sidebar-nav.js +43 -0
  37. package/dist/layout/sidebar-overlay.js +18 -0
  38. package/dist/layout/sidebar.js +48 -0
  39. package/dist/layout/topbar.js +128 -0
  40. package/dist/lib/class-name.js +6 -0
  41. package/dist/lib/flatten-menu.js +23 -0
  42. package/dist/tool/datatable.js +45 -0
  43. package/dist/tool/editor.js +72 -0
  44. package/dist/tool/modal.js +28 -0
  45. package/dist/types/direct-chat.js +0 -0
  46. package/dist/types/layout.js +0 -0
  47. package/dist/types/menu.js +0 -0
  48. package/dist/types/theme.js +0 -0
  49. package/dist/widget/accordion.js +35 -0
  50. package/dist/widget/alert.js +18 -0
  51. package/dist/widget/apex-chart.js +40 -0
  52. package/dist/widget/avatar.js +72 -0
  53. package/dist/widget/badge.js +20 -0
  54. package/dist/widget/breadcrumb.js +26 -0
  55. package/dist/widget/callout.js +11 -0
  56. package/dist/widget/card.js +84 -0
  57. package/dist/widget/carousel.js +56 -0
  58. package/dist/widget/command-palette.js +137 -0
  59. package/dist/widget/description-block.js +19 -0
  60. package/dist/widget/direct-chat.js +96 -0
  61. package/dist/widget/dropdown.js +63 -0
  62. package/dist/widget/info-box.js +24 -0
  63. package/dist/widget/list-group.js +47 -0
  64. package/dist/widget/nav-messages.js +48 -0
  65. package/dist/widget/nav-notifications.js +40 -0
  66. package/dist/widget/nav-tasks.js +60 -0
  67. package/dist/widget/offcanvas.js +61 -0
  68. package/dist/widget/pagination.js +93 -0
  69. package/dist/widget/profile-card.js +32 -0
  70. package/dist/widget/progress-group.js +23 -0
  71. package/dist/widget/progress.js +25 -0
  72. package/dist/widget/ratings.js +20 -0
  73. package/dist/widget/small-box.js +34 -0
  74. package/dist/widget/sparkline-chart.js +43 -0
  75. package/dist/widget/spinner.js +26 -0
  76. package/dist/widget/stepper.js +57 -0
  77. package/dist/widget/table.js +50 -0
  78. package/dist/widget/tabs.js +46 -0
  79. package/dist/widget/timeline.js +15 -0
  80. package/dist/widget/toast.js +41 -0
  81. package/dist/widget/tooltip.js +30 -0
  82. package/dist/widget/world-map.js +42 -0
  83. package/package.json +116 -0
@@ -0,0 +1,141 @@
1
+ "use client";
2
+ import { useEffect } from "react";
3
+ function Accessibility() {
4
+ useEffect(() => {
5
+ if (typeof document === "undefined") return;
6
+ const created = [];
7
+ const cleanups = [];
8
+ let liveRegion = document.getElementById("live-region");
9
+ if (!liveRegion) {
10
+ liveRegion = document.createElement("div");
11
+ liveRegion.id = "live-region";
12
+ liveRegion.className = "live-region";
13
+ liveRegion.setAttribute("aria-live", "polite");
14
+ liveRegion.setAttribute("aria-atomic", "true");
15
+ liveRegion.setAttribute("role", "status");
16
+ document.body.append(liveRegion);
17
+ created.push(liveRegion);
18
+ }
19
+ const announce = (message, priority = "polite") => {
20
+ if (!liveRegion) return;
21
+ liveRegion.setAttribute("aria-live", priority);
22
+ liveRegion.textContent = message;
23
+ window.setTimeout(() => {
24
+ if (liveRegion) liveRegion.textContent = "";
25
+ }, 1e3);
26
+ };
27
+ if (!document.querySelector(".skip-links")) {
28
+ const container = document.createElement("div");
29
+ container.className = "skip-links";
30
+ const mk = (href, text) => {
31
+ const a = document.createElement("a");
32
+ a.href = href;
33
+ a.className = "skip-link";
34
+ a.textContent = text;
35
+ return a;
36
+ };
37
+ container.append(mk("#main", "Skip to main content"));
38
+ container.append(mk("#navigation", "Skip to navigation"));
39
+ document.body.insertBefore(container, document.body.firstChild);
40
+ created.push(container);
41
+ const main = document.querySelector('#main, main, [role="main"]');
42
+ if (main) {
43
+ if (!main.id) main.id = "main";
44
+ if (!main.hasAttribute("tabindex")) main.setAttribute("tabindex", "-1");
45
+ }
46
+ const nav = document.querySelector('#navigation, nav, [role="navigation"]');
47
+ if (nav) {
48
+ if (!nav.id) nav.id = "navigation";
49
+ if (!nav.hasAttribute("tabindex")) nav.setAttribute("tabindex", "-1");
50
+ }
51
+ }
52
+ const onKeyDown = (event) => {
53
+ if (event.key !== "Escape") return;
54
+ if (document.querySelector(".modal.show")) return;
55
+ if (document.querySelector(".dropdown-menu.show")) {
56
+ const toggleButton = document.querySelector(
57
+ '[data-bs-toggle="dropdown"][aria-expanded="true"]'
58
+ );
59
+ toggleButton?.click();
60
+ event.preventDefault();
61
+ }
62
+ };
63
+ document.addEventListener("keydown", onKeyDown);
64
+ cleanups.push(() => document.removeEventListener("keydown", onKeyDown));
65
+ if (window.matchMedia("(prefers-reduced-motion: reduce)").matches) {
66
+ document.body.classList.add("reduce-motion");
67
+ document.documentElement.style.scrollBehavior = "auto";
68
+ const style = document.createElement("style");
69
+ style.textContent = "*, *::before, *::after { animation-duration: 0.01ms !important; animation-iteration-count: 1 !important; transition-duration: 0.01ms !important; }";
70
+ document.head.append(style);
71
+ created.push(style);
72
+ cleanups.push(() => document.body.classList.remove("reduce-motion"));
73
+ }
74
+ const appMain = document.querySelector(".app-main");
75
+ if (appMain) {
76
+ if (!appMain.getAttribute("role")) appMain.setAttribute("role", "main");
77
+ if (!appMain.id) appMain.id = "main";
78
+ }
79
+ document.querySelectorAll(".navbar-nav, .nav").forEach((nav, index) => {
80
+ if (nav.tagName === "UL" || nav.tagName === "OL") return;
81
+ if (!nav.hasAttribute("role")) nav.setAttribute("role", "navigation");
82
+ if (!nav.hasAttribute("aria-label")) nav.setAttribute("aria-label", `Navigation ${index + 1}`);
83
+ });
84
+ document.querySelectorAll("table").forEach((table) => {
85
+ if (!table.hasAttribute("role")) table.setAttribute("role", "table");
86
+ table.querySelectorAll("th").forEach((th) => {
87
+ if (!th.hasAttribute("scope")) {
88
+ if (th.closest("thead")) th.setAttribute("scope", "col");
89
+ else if (th.cellIndex === 0) th.setAttribute("scope", "row");
90
+ }
91
+ });
92
+ });
93
+ document.querySelectorAll("input, select, textarea").forEach((input) => {
94
+ if (!input.labels?.length && !input.hasAttribute("aria-label") && !input.hasAttribute("aria-labelledby")) {
95
+ const placeholder = input.getAttribute("placeholder");
96
+ if (placeholder) input.setAttribute("aria-label", placeholder);
97
+ }
98
+ if (!input.classList.contains("disable-adminlte-validations")) {
99
+ const onInvalid = () => {
100
+ input.classList.add("is-invalid");
101
+ announce(
102
+ `Error in ${input.labels?.[0]?.textContent || input.name}: ${input.validationMessage}`,
103
+ "assertive"
104
+ );
105
+ };
106
+ input.addEventListener("invalid", onInvalid);
107
+ cleanups.push(() => input.removeEventListener("invalid", onInvalid));
108
+ }
109
+ });
110
+ const focusHistory = [];
111
+ const onModalShown = (e) => {
112
+ const modal = e.target;
113
+ const focusable = modal.querySelector(
114
+ 'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
115
+ );
116
+ focusHistory.push(document.activeElement);
117
+ focusable?.focus();
118
+ };
119
+ const onModalHidden = () => focusHistory.pop()?.focus();
120
+ const onDropdownShown = (e) => {
121
+ const dropdown = e.target;
122
+ dropdown.querySelector(".dropdown-menu a, .dropdown-menu button")?.focus();
123
+ };
124
+ document.addEventListener("shown.bs.modal", onModalShown);
125
+ document.addEventListener("hidden.bs.modal", onModalHidden);
126
+ document.addEventListener("shown.bs.dropdown", onDropdownShown);
127
+ cleanups.push(() => {
128
+ document.removeEventListener("shown.bs.modal", onModalShown);
129
+ document.removeEventListener("hidden.bs.modal", onModalHidden);
130
+ document.removeEventListener("shown.bs.dropdown", onDropdownShown);
131
+ });
132
+ return () => {
133
+ cleanups.forEach((fn) => fn());
134
+ created.forEach((el) => el.remove());
135
+ };
136
+ }, []);
137
+ return null;
138
+ }
139
+ export {
140
+ Accessibility
141
+ };
@@ -0,0 +1,22 @@
1
+ "use client";
2
+ import { useEffect } from "react";
3
+ import { useSidebarContext } from "./sidebar-context.js";
4
+ function BodyClassSync({ staticClasses }) {
5
+ const { isCollapsed, isMobileOpen, isMiniMode } = useSidebarContext();
6
+ useEffect(() => {
7
+ const body = document.body;
8
+ const staticList = staticClasses.split(" ").filter(Boolean);
9
+ staticList.forEach((cls) => body.classList.add(cls));
10
+ body.classList.toggle("sidebar-collapse", isCollapsed);
11
+ body.classList.toggle("sidebar-open", isMobileOpen);
12
+ body.classList.toggle("sidebar-mini", isMiniMode);
13
+ return () => {
14
+ staticList.forEach((cls) => body.classList.remove(cls));
15
+ body.classList.remove("sidebar-collapse", "sidebar-open", "sidebar-mini");
16
+ };
17
+ }, [isCollapsed, isMobileOpen, isMiniMode, staticClasses]);
18
+ return null;
19
+ }
20
+ export {
21
+ BodyClassSync
22
+ };
@@ -0,0 +1,61 @@
1
+ "use client";
2
+ import { jsx } from "react/jsx-runtime";
3
+ import { createContext, useContext, useEffect, useMemo, useState } from "react";
4
+ const ColorModeContext = createContext(void 0);
5
+ function ColorModeProvider({
6
+ initialMode = "auto",
7
+ children
8
+ }) {
9
+ const [colorMode, setColorMode] = useState(initialMode);
10
+ const [resolvedMode, setResolvedMode] = useState("light");
11
+ useEffect(() => {
12
+ if (typeof window === "undefined") return;
13
+ const saved = localStorage.getItem("lte-theme");
14
+ if (saved && ["light", "dark", "auto"].includes(saved)) {
15
+ setColorMode(saved);
16
+ }
17
+ }, []);
18
+ useEffect(() => {
19
+ if (typeof window === "undefined") return;
20
+ let resolved;
21
+ if (colorMode === "auto") {
22
+ resolved = window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
23
+ } else {
24
+ resolved = colorMode;
25
+ }
26
+ setResolvedMode(resolved);
27
+ document.documentElement.setAttribute("data-bs-theme", resolved);
28
+ localStorage.setItem("lte-theme", colorMode);
29
+ }, [colorMode]);
30
+ useEffect(() => {
31
+ if (colorMode !== "auto" || typeof window === "undefined") return;
32
+ const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
33
+ const handleChange = () => {
34
+ const resolved = mediaQuery.matches ? "dark" : "light";
35
+ setResolvedMode(resolved);
36
+ document.documentElement.setAttribute("data-bs-theme", resolved);
37
+ };
38
+ mediaQuery.addEventListener("change", handleChange);
39
+ return () => mediaQuery.removeEventListener("change", handleChange);
40
+ }, [colorMode]);
41
+ const value = useMemo(
42
+ () => ({
43
+ colorMode,
44
+ setColorMode,
45
+ resolvedMode
46
+ }),
47
+ [colorMode, resolvedMode]
48
+ );
49
+ return /* @__PURE__ */ jsx(ColorModeContext.Provider, { value, children });
50
+ }
51
+ function useColorModeContext() {
52
+ const context = useContext(ColorModeContext);
53
+ if (!context) {
54
+ throw new Error("useColorModeContext must be used within ColorModeProvider");
55
+ }
56
+ return context;
57
+ }
58
+ export {
59
+ ColorModeProvider,
60
+ useColorModeContext
61
+ };
@@ -0,0 +1,28 @@
1
+ "use client";
2
+ import { jsx } from "react/jsx-runtime";
3
+ import { createContext, useContext, useState, useEffect, useCallback } from "react";
4
+ const CommandPaletteContext = createContext(void 0);
5
+ function CommandPaletteProvider({ children }) {
6
+ const [isOpen, setIsOpen] = useState(false);
7
+ const open = useCallback(() => setIsOpen(true), []);
8
+ const close = useCallback(() => setIsOpen(false), []);
9
+ const toggle = useCallback(() => setIsOpen((o) => !o), []);
10
+ useEffect(() => {
11
+ const onKey = (e) => {
12
+ if ((e.metaKey || e.ctrlKey) && (e.key === "k" || e.key === "K")) {
13
+ e.preventDefault();
14
+ toggle();
15
+ }
16
+ };
17
+ document.addEventListener("keydown", onKey);
18
+ return () => document.removeEventListener("keydown", onKey);
19
+ }, [toggle]);
20
+ return /* @__PURE__ */ jsx(CommandPaletteContext.Provider, { value: { isOpen, open, close, toggle }, children });
21
+ }
22
+ function useCommandPalette() {
23
+ return useContext(CommandPaletteContext);
24
+ }
25
+ export {
26
+ CommandPaletteProvider,
27
+ useCommandPalette
28
+ };
@@ -0,0 +1,17 @@
1
+ "use client";
2
+ import { useEffect } from "react";
3
+ function HtmlDir({ dir }) {
4
+ useEffect(() => {
5
+ const root = document.documentElement;
6
+ const previous = root.getAttribute("dir");
7
+ root.setAttribute("dir", dir);
8
+ return () => {
9
+ if (previous) root.setAttribute("dir", previous);
10
+ else root.removeAttribute("dir");
11
+ };
12
+ }, [dir]);
13
+ return null;
14
+ }
15
+ export {
16
+ HtmlDir
17
+ };
@@ -0,0 +1,18 @@
1
+ "use client";
2
+ import { jsx } from "react/jsx-runtime";
3
+ import { createContext, useContext } from "react";
4
+ const DefaultLink = ({ href, children, ...rest }) => /* @__PURE__ */ jsx("a", { href, ...rest, children });
5
+ const LinkContext = createContext(DefaultLink);
6
+ function LinkProvider({
7
+ component,
8
+ children
9
+ }) {
10
+ return /* @__PURE__ */ jsx(LinkContext.Provider, { value: component ?? DefaultLink, children });
11
+ }
12
+ function useLinkComponent() {
13
+ return useContext(LinkContext);
14
+ }
15
+ export {
16
+ LinkProvider,
17
+ useLinkComponent
18
+ };
@@ -0,0 +1,52 @@
1
+ "use client";
2
+ import { useEffect } from "react";
3
+ function LteBehaviors() {
4
+ useEffect(() => {
5
+ const onClick = (e) => {
6
+ const target = e.target;
7
+ const btn = target?.closest("[data-lte-toggle]");
8
+ if (!btn) return;
9
+ const action = btn.getAttribute("data-lte-toggle");
10
+ const card = btn.closest(".card");
11
+ switch (action) {
12
+ case "card-collapse":
13
+ card?.classList.toggle("collapsed-card");
14
+ break;
15
+ case "card-maximize":
16
+ card?.classList.toggle("maximized-card");
17
+ break;
18
+ case "card-remove":
19
+ card?.remove();
20
+ break;
21
+ case "chat-pane": {
22
+ const chat = btn.closest(".direct-chat") ?? card;
23
+ chat?.classList.toggle("direct-chat-contacts-open");
24
+ break;
25
+ }
26
+ default:
27
+ break;
28
+ }
29
+ };
30
+ const onSubmit = (e) => {
31
+ const form = e.target?.closest(
32
+ ".needs-validation, .needs-validation-tooltip"
33
+ );
34
+ if (!form) return;
35
+ if (!form.checkValidity()) {
36
+ e.preventDefault();
37
+ e.stopPropagation();
38
+ }
39
+ form.classList.add("was-validated");
40
+ };
41
+ document.addEventListener("click", onClick);
42
+ document.addEventListener("submit", onSubmit, true);
43
+ return () => {
44
+ document.removeEventListener("click", onClick);
45
+ document.removeEventListener("submit", onSubmit, true);
46
+ };
47
+ }, []);
48
+ return null;
49
+ }
50
+ export {
51
+ LteBehaviors
52
+ };
@@ -0,0 +1,87 @@
1
+ "use client";
2
+ import { jsx } from "react/jsx-runtime";
3
+ import { createContext, useCallback, useContext, useEffect, useMemo, useState } from "react";
4
+ const SidebarContext = createContext(void 0);
5
+ function SidebarProvider({
6
+ sidebarMini = false,
7
+ enablePersistence = false,
8
+ sidebarBreakpoint = 992,
9
+ children
10
+ }) {
11
+ const [isCollapsed, setIsCollapsed] = useState(false);
12
+ const [isMobileOpen, setIsMobileOpen] = useState(false);
13
+ const [isMiniMode] = useState(sidebarMini);
14
+ const [windowWidth, setWindowWidth] = useState(null);
15
+ useEffect(() => {
16
+ if (typeof window === "undefined") return;
17
+ setWindowWidth(window.innerWidth);
18
+ if (enablePersistence) {
19
+ const saved = localStorage.getItem("lte.sidebar.state");
20
+ if (saved) {
21
+ try {
22
+ const { collapsed } = JSON.parse(saved);
23
+ setIsCollapsed(collapsed);
24
+ } catch {
25
+ }
26
+ }
27
+ }
28
+ }, [enablePersistence]);
29
+ useEffect(() => {
30
+ if (typeof window === "undefined" || !enablePersistence) return;
31
+ localStorage.setItem("lte.sidebar.state", JSON.stringify({ collapsed: isCollapsed }));
32
+ }, [isCollapsed, enablePersistence]);
33
+ useEffect(() => {
34
+ const handleResize = () => {
35
+ setWindowWidth(window.innerWidth);
36
+ };
37
+ window.addEventListener("resize", handleResize);
38
+ return () => window.removeEventListener("resize", handleResize);
39
+ }, []);
40
+ useEffect(() => {
41
+ if (windowWidth === null) return;
42
+ const isMobileSize = windowWidth <= sidebarBreakpoint;
43
+ if (!isMobileSize && isMobileOpen) {
44
+ setIsMobileOpen(false);
45
+ }
46
+ }, [windowWidth, sidebarBreakpoint, isMobileOpen]);
47
+ const toggle = useCallback(() => {
48
+ const w = windowWidth ?? (typeof window !== "undefined" ? window.innerWidth : 9999);
49
+ if (w <= sidebarBreakpoint) {
50
+ setIsMobileOpen((v) => !v);
51
+ } else {
52
+ setIsCollapsed((v) => !v);
53
+ }
54
+ }, [windowWidth, sidebarBreakpoint]);
55
+ const collapse = useCallback(() => {
56
+ setIsCollapsed(true);
57
+ setIsMobileOpen(false);
58
+ }, []);
59
+ const expand = useCallback(() => {
60
+ setIsCollapsed(false);
61
+ setIsMobileOpen(false);
62
+ }, []);
63
+ const value = useMemo(
64
+ () => ({
65
+ isCollapsed,
66
+ isMobileOpen,
67
+ isMiniMode,
68
+ toggle,
69
+ collapse,
70
+ expand,
71
+ sidebarBreakpoint
72
+ }),
73
+ [isCollapsed, isMobileOpen, isMiniMode, toggle, collapse, expand, sidebarBreakpoint]
74
+ );
75
+ return /* @__PURE__ */ jsx(SidebarContext.Provider, { value, children });
76
+ }
77
+ function useSidebarContext() {
78
+ const context = useContext(SidebarContext);
79
+ if (!context) {
80
+ throw new Error("useSidebarContext must be used within SidebarProvider");
81
+ }
82
+ return context;
83
+ }
84
+ export {
85
+ SidebarProvider,
86
+ useSidebarContext
87
+ };