@olenbetong/appframe-ds 0.2.0 → 0.4.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 (117) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/es/AfLookup/BoundLookup.d.ts +10 -0
  3. package/es/AfLookup/BoundLookup.js +16 -0
  4. package/es/AfLookup/Combobox.css +78 -0
  5. package/es/AfLookup/Combobox.d.ts +31 -0
  6. package/es/AfLookup/Combobox.js +71 -0
  7. package/es/AfLookup/Lookup.css +125 -0
  8. package/es/AfLookup/Lookup.d.ts +35 -0
  9. package/es/AfLookup/Lookup.js +42 -0
  10. package/es/AfLookup/LookupEdit.d.ts +21 -0
  11. package/es/AfLookup/LookupEdit.js +49 -0
  12. package/es/AfLookup/LookupGrid.css +57 -0
  13. package/es/AfLookup/LookupGrid.d.ts +13 -0
  14. package/es/AfLookup/LookupGrid.js +27 -0
  15. package/es/AfLookup/index.d.ts +5 -0
  16. package/es/AfLookup/index.js +5 -0
  17. package/es/binding/BoundCheckbox.d.ts +9 -0
  18. package/es/binding/BoundCheckbox.js +13 -0
  19. package/es/binding/BoundDatePicker.d.ts +7 -0
  20. package/es/binding/BoundDatePicker.js +12 -0
  21. package/es/binding/BoundDateTimePicker.d.ts +7 -0
  22. package/es/binding/BoundDateTimePicker.js +14 -0
  23. package/es/binding/BoundInput.d.ts +6 -0
  24. package/es/binding/BoundInput.js +12 -0
  25. package/es/binding/BoundNumericTextField.d.ts +20 -0
  26. package/es/binding/BoundNumericTextField.js +58 -0
  27. package/es/binding/BoundSelect.d.ts +9 -0
  28. package/es/binding/BoundSelect.js +13 -0
  29. package/es/binding/BoundSwitch.d.ts +9 -0
  30. package/es/binding/BoundSwitch.js +13 -0
  31. package/es/binding/BoundTextField.d.ts +7 -0
  32. package/es/binding/BoundTextField.js +22 -0
  33. package/es/binding/CancelButton.d.ts +3 -0
  34. package/es/binding/CancelButton.js +14 -0
  35. package/es/binding/CancelIconButton.d.ts +2 -0
  36. package/es/binding/CancelIconButton.js +15 -0
  37. package/es/binding/DataEditToolbar.d.ts +13 -0
  38. package/es/binding/DataEditToolbar.js +28 -0
  39. package/es/binding/DataObjectSelect.d.ts +50 -0
  40. package/es/binding/DataObjectSelect.js +26 -0
  41. package/es/binding/DeleteButton.d.ts +8 -0
  42. package/es/binding/DeleteButton.js +14 -0
  43. package/es/binding/DeleteIconButton.d.ts +10 -0
  44. package/es/binding/DeleteIconButton.js +15 -0
  45. package/es/binding/RefreshButton.d.ts +3 -0
  46. package/es/binding/RefreshButton.js +14 -0
  47. package/es/binding/RefreshIconButton.d.ts +2 -0
  48. package/es/binding/RefreshIconButton.js +16 -0
  49. package/es/binding/RefreshRowIconButton.d.ts +7 -0
  50. package/es/binding/RefreshRowIconButton.js +15 -0
  51. package/es/binding/SaveButton.d.ts +3 -0
  52. package/es/binding/SaveButton.js +14 -0
  53. package/es/binding/SaveIconButton.d.ts +2 -0
  54. package/es/binding/SaveIconButton.js +15 -0
  55. package/es/binding/index.d.ts +19 -0
  56. package/es/binding/index.js +19 -0
  57. package/es/index.d.ts +3 -0
  58. package/es/index.js +3 -0
  59. package/es/layout/AppLayoutDesktop.css +65 -0
  60. package/es/layout/AppLayoutDesktop.d.ts +3 -0
  61. package/es/layout/AppLayoutDesktop.js +19 -0
  62. package/es/layout/AppLayoutMobile.css +75 -0
  63. package/es/layout/AppLayoutMobile.d.ts +3 -0
  64. package/es/layout/AppLayoutMobile.js +18 -0
  65. package/es/layout/AppMenu.css +67 -0
  66. package/es/layout/AppMenu.d.ts +8 -0
  67. package/es/layout/AppMenu.js +36 -0
  68. package/es/layout/AppMenuItem.css +97 -0
  69. package/es/layout/AppMenuItem.d.ts +50 -0
  70. package/es/layout/AppMenuItem.js +14 -0
  71. package/es/layout/AppMenuSubheader.css +18 -0
  72. package/es/layout/AppMenuSubheader.d.ts +4 -0
  73. package/es/layout/AppMenuSubheader.js +6 -0
  74. package/es/layout/ErrorBoundary.css +101 -0
  75. package/es/layout/ErrorBoundary.d.ts +30 -0
  76. package/es/layout/ErrorBoundary.js +81 -0
  77. package/es/layout/PageContainer.css +29 -0
  78. package/es/layout/PageContainer.d.ts +7 -0
  79. package/es/layout/PageContainer.js +6 -0
  80. package/es/layout/PartnerToggle.d.ts +5 -0
  81. package/es/layout/PartnerToggle.js +9 -0
  82. package/es/layout/constants.d.ts +2 -0
  83. package/es/layout/constants.js +2 -0
  84. package/es/layout/index.css +65 -0
  85. package/es/layout/index.d.ts +33 -0
  86. package/es/layout/index.js +31 -0
  87. package/package.json +17 -12
  88. package/src/AfLookup/BoundLookup.tsx +4 -4
  89. package/src/AfLookup/Combobox.css +1 -1
  90. package/src/AfLookup/Combobox.tsx +79 -108
  91. package/src/AfLookup/Lookup.css +21 -0
  92. package/src/AfLookup/Lookup.tsx +25 -157
  93. package/src/AfLookup/LookupEdit.tsx +131 -0
  94. package/src/AfLookup/LookupGrid.css +57 -0
  95. package/src/AfLookup/LookupGrid.tsx +98 -0
  96. package/src/AfLookup/index.ts +2 -0
  97. package/src/binding/DataObjectSelect.tsx +1 -1
  98. package/src/index.ts +1 -0
  99. package/src/layout/AppLayoutDesktop.css +65 -0
  100. package/src/layout/AppLayoutDesktop.tsx +45 -0
  101. package/src/layout/AppLayoutMobile.css +75 -0
  102. package/src/layout/AppLayoutMobile.tsx +50 -0
  103. package/src/layout/AppMenu.css +67 -0
  104. package/src/layout/AppMenu.tsx +75 -0
  105. package/src/layout/AppMenuItem.css +97 -0
  106. package/src/layout/AppMenuItem.tsx +80 -0
  107. package/src/layout/AppMenuSubheader.css +18 -0
  108. package/src/layout/AppMenuSubheader.tsx +14 -0
  109. package/src/layout/ErrorBoundary.css +101 -0
  110. package/src/layout/ErrorBoundary.tsx +162 -0
  111. package/src/layout/PageContainer.css +29 -0
  112. package/src/layout/PageContainer.tsx +19 -0
  113. package/src/layout/PartnerToggle.tsx +23 -0
  114. package/src/layout/constants.ts +2 -0
  115. package/src/layout/index.css +65 -0
  116. package/src/layout/index.tsx +62 -0
  117. package/tsconfig.build.tsbuildinfo +1 -0
@@ -0,0 +1,65 @@
1
+ .LayoutLarge-container {
2
+ height: 100vh;
3
+ display: grid;
4
+ grid-template-rows: 1fr;
5
+ }
6
+
7
+ .LayoutLarge-root {
8
+ height: 100%;
9
+ overflow: hidden;
10
+ }
11
+
12
+ .LayoutLarge-root.LayoutLarge-withMenu {
13
+ transition: padding 300ms cubic-bezier(0.4, 0, 0.2, 1) 0ms !important;
14
+ padding-left: 0;
15
+ position: relative;
16
+ }
17
+
18
+ .LayoutLarge-root.LayoutLarge-withMenu.open {
19
+ padding-left: var(--navbar-drawer-width, 24rem);
20
+ }
21
+
22
+ .LayoutLarge-menu {
23
+ height: 100%;
24
+ width: var(--navbar-drawer-width, 24rem);
25
+ transition: left ease-in-out 200ms;
26
+ position: absolute;
27
+ top: 0;
28
+ left: calc(var(--navbar-drawer-width, 24rem) * -1);
29
+ z-index: 1200;
30
+ background-color: white;
31
+ box-shadow:
32
+ rgb(0 0 0 / 20%) 0px 2px 1px -1px,
33
+ rgb(0 0 0 / 14%) 0px 1px 1px 0px,
34
+ rgb(0 0 0 / 12%) 0px 1px 3px 0px;
35
+ }
36
+
37
+ .LayoutLarge-withMenu.open .LayoutLarge-menu {
38
+ left: 0;
39
+ }
40
+
41
+ @media screen {
42
+ .LayoutLarge-main {
43
+ height: 100%;
44
+ overflow: auto;
45
+ }
46
+
47
+ .LayoutLarge-main:has(> .app-view, > .ObPageContainer-fullHeight) {
48
+ max-height: 100%;
49
+ overflow: hidden;
50
+ }
51
+ }
52
+
53
+ @media print {
54
+ .LayoutLarge-menu {
55
+ display: none !important;
56
+ box-shadow: none !important;
57
+ overflow: hidden !important;
58
+ }
59
+
60
+ .LayoutLarge-root {
61
+ display: block;
62
+ height: auto;
63
+ overflow: visible;
64
+ }
65
+ }
@@ -0,0 +1,3 @@
1
+ import "./AppLayoutDesktop.css";
2
+ import type { AppLayoutProps } from "./index.js";
3
+ export declare function AppLayoutDesktop({ AppMenuProps, children, menu, partner }: AppLayoutProps): import("react").JSX.Element;
@@ -0,0 +1,19 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import "./AppLayoutDesktop.css";
3
+ import clsx from "clsx";
4
+ import { Suspense, useState } from "react";
5
+ import { ErrorBoundary } from "react-error-boundary";
6
+ import { AppMenu } from "./AppMenu.js";
7
+ import { ErrorAlertFallback } from "./ErrorBoundary.js";
8
+ import { PartnerToggle } from "./PartnerToggle.js";
9
+ function LoadingFallback() {
10
+ return (_jsx("div", { style: {
11
+ height: "4px",
12
+ background: "linear-gradient(90deg, var(--ds-color-brand-base-default, #0062ba) 0%, transparent 100%)",
13
+ animation: "progress-indeterminate 1.5s ease-in-out infinite",
14
+ } }));
15
+ }
16
+ export function AppLayoutDesktop({ AppMenuProps, children, menu, partner }) {
17
+ let [open, setOpen] = useState(true);
18
+ return (_jsxs("div", { className: clsx(partner ? "app-view" : "LayoutLarge-container"), children: [partner && menu && _jsx(PartnerToggle, { open: open, onClick: () => setOpen((o) => !o) }), _jsxs("div", { className: clsx("LayoutLarge-root", menu && "LayoutLarge-withMenu", open && "open"), children: [menu && (_jsx(AppMenu, { className: "LayoutLarge-menu AppMenu-drawer", ...AppMenuProps, children: menu })), _jsx("main", { className: "LayoutLarge-main", children: _jsx(Suspense, { fallback: _jsx(LoadingFallback, {}), children: _jsx(ErrorBoundary, { FallbackComponent: ErrorAlertFallback, children: children }) }) })] })] }));
19
+ }
@@ -0,0 +1,75 @@
1
+ .LayoutSmall-root:has(> .ObPageContainer-fullHeight, > .app-view) {
2
+ display: grid;
3
+ grid-template-rows: auto 1fr;
4
+ height: 100dvh;
5
+ overflow: hidden;
6
+ }
7
+
8
+ .partner-nav {
9
+ color: white;
10
+ }
11
+
12
+ /* Minimal toggle-only bar shown when there's a sidebar menu but no server AppBar */
13
+ .LayoutSmall-menuBar {
14
+ display: flex;
15
+ align-items: center;
16
+ height: var(--navbar-height, 3.5rem);
17
+ }
18
+
19
+ .LayoutSmall-toggle {
20
+ display: flex;
21
+ align-items: center;
22
+ justify-content: center;
23
+ background: transparent;
24
+ border: none;
25
+ color: inherit;
26
+ cursor: pointer;
27
+ border-radius: 50%;
28
+ height: var(--navbar-height, 3.5rem);
29
+ width: var(--navbar-height, 3.5rem);
30
+ font-size: 1.5rem;
31
+ flex-shrink: 0;
32
+ }
33
+
34
+ .LayoutSmall-toggle:hover {
35
+ background-color: rgb(0 0 0 / 0.06);
36
+ }
37
+
38
+ /* Drawer overlay */
39
+ .LayoutSmall-drawerOverlay {
40
+ position: fixed;
41
+ inset: 0;
42
+ background-color: rgb(0 0 0 / 50%);
43
+ z-index: 1199;
44
+ opacity: 0;
45
+ pointer-events: none;
46
+ transition: opacity 225ms cubic-bezier(0.4, 0, 0.2, 1);
47
+ }
48
+
49
+ .LayoutSmall-drawerOverlay.open {
50
+ opacity: 1;
51
+ pointer-events: auto;
52
+ }
53
+
54
+ /* Drawer panel */
55
+ .LayoutSmall-drawer {
56
+ position: fixed;
57
+ top: 0;
58
+ left: 0;
59
+ bottom: 0;
60
+ max-width: 90%;
61
+ width: var(--navbar-drawer-width, 20rem);
62
+ z-index: 1200;
63
+ background-color: var(--ds-color-neutral-background-default, #fff);
64
+ box-shadow:
65
+ rgb(0 0 0 / 20%) 0px 8px 10px -5px,
66
+ rgb(0 0 0 / 14%) 0px 16px 24px 2px,
67
+ rgb(0 0 0 / 12%) 0px 6px 30px 5px;
68
+ transform: translateX(-100%);
69
+ transition: transform 225ms cubic-bezier(0, 0, 0.2, 1);
70
+ overflow: hidden;
71
+ }
72
+
73
+ .LayoutSmall-drawer.open {
74
+ transform: translateX(0);
75
+ }
@@ -0,0 +1,3 @@
1
+ import "./AppLayoutMobile.css";
2
+ import type { AppLayoutProps } from "./index.js";
3
+ export declare function AppLayoutMobile({ AppMenuProps, children, menu, partner }: AppLayoutProps): import("react").JSX.Element;
@@ -0,0 +1,18 @@
1
+ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import "./AppLayoutMobile.css";
3
+ import { useEffect, useState } from "react";
4
+ import { useLocation } from "react-router";
5
+ import { AppMenu } from "./AppMenu.js";
6
+ import { PartnerToggle } from "./PartnerToggle.js";
7
+ function Toggle({ onToggle }) {
8
+ return (_jsx("button", { type: "button", className: "LayoutSmall-toggle", onClick: onToggle, "aria-label": "Toggle menu", children: "\u2630" }));
9
+ }
10
+ export function AppLayoutMobile({ AppMenuProps, children, menu, partner }) {
11
+ let [drawerOpen, setDrawerOpen] = useState(false);
12
+ let location = useLocation();
13
+ // oxlint-disable-next-line react-hooks/exhaustive-deps -- close drawer on navigation
14
+ useEffect(() => {
15
+ setDrawerOpen(false);
16
+ }, [location]);
17
+ return (_jsxs("div", { className: "LayoutSmall-root", children: [partner && menu && _jsx(PartnerToggle, { open: drawerOpen, onClick: () => setDrawerOpen((c) => !c) }), !partner && menu && (_jsx("div", { className: "LayoutSmall-menuBar", children: _jsx(Toggle, { onToggle: () => setDrawerOpen((c) => !c) }) })), menu && (_jsxs(_Fragment, { children: [_jsx("div", { className: `LayoutSmall-drawerOverlay${drawerOpen ? " open" : ""}`, onClick: () => setDrawerOpen(false), "aria-hidden": "true" }), _jsx("div", { className: `LayoutSmall-drawer AppMenu-drawer${drawerOpen ? " open" : ""}`, children: _jsx(AppMenu, { ...AppMenuProps, children: menu }) })] })), children] }));
18
+ }
@@ -0,0 +1,67 @@
1
+ .AppMenu-header {
2
+ padding: 1rem;
3
+ }
4
+
5
+ .AppMenu-header .AppMenu-title {
6
+ font-weight: 500;
7
+ letter-spacing: -0.02rem;
8
+ font-size: var(--ds-font-size-xl, 1.5rem);
9
+ margin: 0;
10
+ }
11
+
12
+ .AppMenu-header .AppMenu-subTitle {
13
+ font-size: var(--ds-font-size-sm, 1.1rem);
14
+ margin: 0;
15
+ color: var(--ds-color-neutral-text-subtle, #555);
16
+ }
17
+
18
+ .AppMenu-divider {
19
+ border: none;
20
+ border-top: 1px solid var(--ds-color-neutral-border-default, #dfdfdf);
21
+ margin: 0;
22
+ }
23
+
24
+ .AppMenu-pendingCount {
25
+ color: var(--ds-color-neutral-text-subtle, #666) !important;
26
+ font-size: 0.8em;
27
+ font-weight: 700;
28
+ padding-right: 0.5rem;
29
+ }
30
+
31
+ .MenuItems-root {
32
+ overflow-y: auto;
33
+ scrollbar-width: thin;
34
+ scrollbar-color: var(--ds-color-neutral-border-default, #dfdfdf) transparent;
35
+ }
36
+
37
+ .MenuItems-root::-webkit-scrollbar {
38
+ width: 0.4rem;
39
+ }
40
+
41
+ .MenuItems-root::-webkit-scrollbar-button {
42
+ display: none;
43
+ }
44
+
45
+ .MenuItems-root::-webkit-scrollbar-thumb {
46
+ width: 0.4rem;
47
+ background-color: var(--ds-color-neutral-border-default, #dfdfdf);
48
+ }
49
+
50
+ .MenuItems-root .AppMenuList-nested .AppMenuItem-root {
51
+ padding-left: 3rem;
52
+ padding-block: 0.25rem;
53
+ }
54
+
55
+ .MenuItems-root .AppMenuList-nested .AppMenuItem-root .AppMenuItem-text {
56
+ font-size: 0.9rem;
57
+ }
58
+
59
+ .MenuItems-collapse {
60
+ margin-bottom: -0.5rem;
61
+ margin-top: -0.5rem;
62
+ }
63
+
64
+ .MenuItem-noWrap {
65
+ overflow: hidden;
66
+ white-space: nowrap;
67
+ }
@@ -0,0 +1,8 @@
1
+ import "./AppMenu.css";
2
+ import type React from "react";
3
+ export type AppMenuProps = Pick<React.HTMLProps<HTMLElement>, "aria-label" | "aria-labelledby" | "className" | "id"> & {
4
+ children?: React.ReactNode[] | React.ReactNode;
5
+ headerPrimary?: string;
6
+ headerSecondary?: string;
7
+ };
8
+ export declare function AppMenu({ children, className, headerPrimary, headerSecondary, ...props }: AppMenuProps): React.JSX.Element;
@@ -0,0 +1,36 @@
1
+ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import "./AppMenu.css";
3
+ import { getLocalizedString } from "@olenbetong/appframe-core";
4
+ import clsx from "clsx";
5
+ function MenuHeader({ primary, secondary }) {
6
+ return (_jsxs(_Fragment, { children: [_jsxs("div", { className: "AppMenu-header", children: [_jsx("h1", { className: "AppMenu-title", id: "NavigationHeader", children: primary }), secondary && _jsx("p", { className: "AppMenu-subTitle", children: secondary })] }), _jsx("hr", { className: "AppMenu-divider" })] }));
7
+ }
8
+ function handleKeyDown(evt) {
9
+ let nextElement = null;
10
+ let appMenu = evt.currentTarget;
11
+ if (!document.activeElement || !(appMenu instanceof HTMLElement) || !appMenu.contains(document.activeElement))
12
+ return;
13
+ let links = Array.from(appMenu.querySelectorAll("a, button"));
14
+ let currentIndex = links.indexOf(document.activeElement);
15
+ if (evt.key === "ArrowDown" || evt.key === "ArrowRight") {
16
+ if (currentIndex < links.length) {
17
+ nextElement = links[currentIndex + 1];
18
+ }
19
+ }
20
+ else if (evt.key === "ArrowUp" || evt.key === "ArrowLeft") {
21
+ if (currentIndex > 0) {
22
+ nextElement = links[currentIndex - 1];
23
+ }
24
+ }
25
+ else if (evt.key === "Home" || evt.key === "End") {
26
+ nextElement = links.at(evt.key === "Home" ? 0 : -1);
27
+ }
28
+ if (nextElement instanceof HTMLElement) {
29
+ evt.preventDefault();
30
+ nextElement.scrollIntoView({ block: "nearest" });
31
+ nextElement.focus();
32
+ }
33
+ }
34
+ export function AppMenu({ children, className, headerPrimary, headerSecondary, ...props }) {
35
+ return (_jsxs("nav", { "aria-labelledby": headerPrimary ? "NavigationHeader" : undefined, "aria-label": headerPrimary ? undefined : getLocalizedString("Application pages"), className: clsx(className, "MenuItems-root"), onKeyDown: handleKeyDown, ...props, children: [headerPrimary && _jsx(MenuHeader, { primary: headerPrimary, secondary: headerSecondary }), children] }));
36
+ }
@@ -0,0 +1,97 @@
1
+ .AppMenuItem-root {
2
+ display: flex;
3
+ align-items: center;
4
+ position: relative;
5
+ border-radius: var(--ds-border-radius-md, 0.25rem);
6
+ overflow: hidden;
7
+ margin: 0.5rem;
8
+ padding: 0.5rem;
9
+ width: calc(100% - 1rem);
10
+ box-sizing: border-box;
11
+ text-decoration: none;
12
+ color: var(--ds-color-neutral-text-default, rgba(0, 0, 0, 0.87));
13
+ background: transparent;
14
+ border: none;
15
+ cursor: pointer;
16
+ font-family: inherit;
17
+ font-size: inherit;
18
+ text-align: left;
19
+ }
20
+
21
+ @media (pointer: fine) {
22
+ .AppMenuItem-root {
23
+ margin: 0.2rem 0.5rem;
24
+ }
25
+ }
26
+
27
+ .AppMenuItem-icon {
28
+ display: flex;
29
+ align-items: center;
30
+ min-width: 2.5rem;
31
+ color: inherit;
32
+ flex-shrink: 0;
33
+ }
34
+
35
+ .AppMenuItem-text {
36
+ flex: 1;
37
+ font-weight: 500;
38
+ color: var(--ds-color-neutral-text-default, rgba(0, 0, 0, 0.87));
39
+ min-width: 0;
40
+ overflow: hidden;
41
+ text-overflow: ellipsis;
42
+ white-space: nowrap;
43
+ }
44
+
45
+ .AppMenuItem-info {
46
+ margin-left: auto;
47
+ flex-shrink: 0;
48
+ }
49
+
50
+ .AppMenuItem-root::before {
51
+ background-color: #000;
52
+ opacity: 0;
53
+ transition:
54
+ opacity 30ms linear,
55
+ background-color 30ms linear;
56
+ content: "";
57
+ position: absolute;
58
+ top: 0;
59
+ left: 0;
60
+ height: 100%;
61
+ width: 100%;
62
+ pointer-events: none;
63
+ }
64
+
65
+ .AppMenuItem-root:hover,
66
+ .AppMenuItem-root:focus,
67
+ .AppMenuItem-root:active {
68
+ text-decoration: none;
69
+ outline: none;
70
+ }
71
+
72
+ .AppMenuItem-root:hover::before {
73
+ opacity: 0.04;
74
+ }
75
+
76
+ .AppMenuItem-root:active::before {
77
+ opacity: 0.16;
78
+ }
79
+
80
+ .AppMenuItem-root.active::before,
81
+ .AppMenuItem-root.active:hover::before {
82
+ background-color: var(--ds-color-brand-base-default, var(--brand-primary, #0062ba));
83
+ opacity: 0.16;
84
+ }
85
+
86
+ .AppMenuItem-root.active:hover::before {
87
+ opacity: 0.2;
88
+ }
89
+
90
+ .AppMenuItem-root.active:active::before {
91
+ opacity: 0.24;
92
+ }
93
+
94
+ .AppMenuItem-root.active .AppMenuItem-text,
95
+ .AppMenuItem-root.active .AppMenuItem-icon {
96
+ color: var(--ds-color-brand-base-default, var(--brand-primary, #0062ba));
97
+ }
@@ -0,0 +1,50 @@
1
+ import "./AppMenuItem.css";
2
+ import type { To } from "react-router";
3
+ import { type NavLinkProps } from "react-router";
4
+ import type React from "react";
5
+ export type AppMenuItemProps = Omit<NavLinkProps, "className"> & {
6
+ children: React.ReactNode | React.ReactNode[];
7
+ info?: React.ReactNode | React.ReactNode[];
8
+ icon?: React.ReactNode;
9
+ onClick?: React.MouseEventHandler<HTMLAnchorElement>;
10
+ to: To;
11
+ end?: boolean;
12
+ className?: string;
13
+ };
14
+ export declare const AppMenuItem: React.ForwardRefExoticComponent<Omit<NavLinkProps, "className"> & {
15
+ children: React.ReactNode | React.ReactNode[];
16
+ info?: React.ReactNode | React.ReactNode[];
17
+ icon?: React.ReactNode;
18
+ onClick?: React.MouseEventHandler<HTMLAnchorElement>;
19
+ to: To;
20
+ end?: boolean;
21
+ className?: string;
22
+ } & React.RefAttributes<HTMLAnchorElement>>;
23
+ export type AppMenuItemExternalLinkProps = Omit<React.AnchorHTMLAttributes<HTMLAnchorElement>, "href"> & {
24
+ children: React.ReactNode | React.ReactNode[];
25
+ info?: React.ReactNode | React.ReactNode[];
26
+ icon?: React.ReactNode;
27
+ href: string;
28
+ target?: string;
29
+ };
30
+ export declare const AppMenuItemExternalLink: React.ForwardRefExoticComponent<Omit<React.AnchorHTMLAttributes<HTMLAnchorElement>, "href"> & {
31
+ children: React.ReactNode | React.ReactNode[];
32
+ info?: React.ReactNode | React.ReactNode[];
33
+ icon?: React.ReactNode;
34
+ href: string;
35
+ target?: string;
36
+ } & React.RefAttributes<HTMLAnchorElement>>;
37
+ export type AppMenuItemButtonProps = Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, "onClick"> & {
38
+ active?: boolean;
39
+ children: React.ReactNode | React.ReactNode[];
40
+ info?: React.ReactNode | React.ReactNode[];
41
+ icon?: React.ReactNode;
42
+ onClick?: React.MouseEventHandler<HTMLButtonElement>;
43
+ };
44
+ export declare const AppMenuItemButton: React.ForwardRefExoticComponent<Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, "onClick"> & {
45
+ active?: boolean;
46
+ children: React.ReactNode | React.ReactNode[];
47
+ info?: React.ReactNode | React.ReactNode[];
48
+ icon?: React.ReactNode;
49
+ onClick?: React.MouseEventHandler<HTMLButtonElement>;
50
+ } & React.RefAttributes<HTMLButtonElement>>;
@@ -0,0 +1,14 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import "./AppMenuItem.css";
3
+ import clsx from "clsx";
4
+ import { forwardRef } from "react";
5
+ import { NavLink } from "react-router";
6
+ export const AppMenuItem = forwardRef(function AppMenuItem({ children, className, end = true, info, to, icon, ...props }, ref) {
7
+ return (_jsxs(NavLink, { viewTransition: true, to: to, className: clsx("AppMenuItem-root", className), end: end, ...props, ref: ref, children: [icon && _jsx("span", { className: "AppMenuItem-icon", children: icon }), _jsx("span", { className: "AppMenuItem-text", children: children }), info && _jsx("span", { className: "AppMenuItem-info", children: info })] }));
8
+ });
9
+ export const AppMenuItemExternalLink = forwardRef(function AppMenuItemExternalLink({ children, className, href, info, icon, target, ...props }, ref) {
10
+ return (_jsxs("a", { href: href, className: clsx("AppMenuItem-root", className), target: target, ...props, ref: ref, children: [icon && _jsx("span", { className: "AppMenuItem-icon", children: icon }), _jsx("span", { className: "AppMenuItem-text", children: children }), info && _jsx("span", { className: "AppMenuItem-info", children: info })] }));
11
+ });
12
+ export const AppMenuItemButton = forwardRef(function AppMenuItemButton({ children, className, active = false, info, onClick, icon, ...props }, ref) {
13
+ return (_jsxs("button", { type: "button", onClick: onClick, className: clsx("AppMenuItem-root", className, active && "active"), ...props, ref: ref, children: [icon && _jsx("span", { className: "AppMenuItem-icon", children: icon }), _jsx("span", { className: "AppMenuItem-text", children: children }), info && _jsx("span", { className: "AppMenuItem-info", children: info })] }));
14
+ });
@@ -0,0 +1,18 @@
1
+ .AppMenuSubheader-root {
2
+ font-size: var(--ds-font-size-xs, 0.75rem);
3
+ font-weight: 600;
4
+ letter-spacing: 0.08em;
5
+ text-transform: uppercase;
6
+ padding: 0.5rem 1rem;
7
+ color: var(--ds-color-neutral-text-subtle, #555);
8
+ background-color: var(--ds-color-neutral-background-default, transparent);
9
+ position: sticky;
10
+ top: 0;
11
+ z-index: 1;
12
+ }
13
+
14
+ @media (pointer: fine) {
15
+ .AppMenuSubheader-root {
16
+ line-height: 36px;
17
+ }
18
+ }
@@ -0,0 +1,4 @@
1
+ import "./AppMenuSubheader.css";
2
+ import type React from "react";
3
+ export type AppMenuSubheaderProps = React.HTMLAttributes<HTMLDivElement>;
4
+ export declare function AppMenuSubheader({ children, className, ...props }: AppMenuSubheaderProps): React.JSX.Element;
@@ -0,0 +1,6 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import "./AppMenuSubheader.css";
3
+ import clsx from "clsx";
4
+ export function AppMenuSubheader({ children, className, ...props }) {
5
+ return (_jsx("div", { className: clsx("AppMenuSubheader-root", className), ...props, children: children }));
6
+ }
@@ -0,0 +1,101 @@
1
+ .AppErrorBoundary-root {
2
+ height: 100vh;
3
+ display: flex;
4
+ align-items: center;
5
+ justify-content: center;
6
+ }
7
+
8
+ .AppErrorBoundary-inner {
9
+ max-width: 36rem;
10
+ width: 100%;
11
+ margin: 0 auto;
12
+ padding: 1rem;
13
+ text-align: center;
14
+ }
15
+
16
+ .AppErrorBoundary-image {
17
+ opacity: 0.6;
18
+ max-height: 30vh;
19
+ max-width: 50vw;
20
+ }
21
+
22
+ .AppErrorBoundary-title {
23
+ margin-top: var(--ds-size-6, 1.5rem);
24
+ font-size: var(--ds-font-size-6, 1.5rem);
25
+ font-weight: 700;
26
+ }
27
+
28
+ .AppErrorBoundary-alert {
29
+ margin-block: var(--ds-size-6, 1.5rem);
30
+ background: var(--ds-color-danger-surface-default, #fde8e8);
31
+ color: var(--ds-color-danger-text-default, #c01c2c);
32
+ border: 1px solid var(--ds-color-danger-border-default, #f5a6ae);
33
+ border-radius: var(--ds-border-radius-md, 0.25rem);
34
+ padding: var(--ds-size-3, 0.75rem) var(--ds-size-4, 1rem);
35
+ text-align: left;
36
+ }
37
+
38
+ .AppErrorBoundary-message {
39
+ margin-bottom: var(--ds-size-6, 1.5rem);
40
+ }
41
+
42
+ .AppErrorBoundary-reload {
43
+ appearance: none;
44
+ border: 1px solid currentColor;
45
+ border-radius: var(--ds-border-radius-md, 0.25rem);
46
+ background: transparent;
47
+ color: inherit;
48
+ cursor: pointer;
49
+ font: inherit;
50
+ font-size: var(--ds-font-size-3, 1rem);
51
+ padding: var(--ds-size-2, 0.5rem) var(--ds-size-4, 1rem);
52
+ margin-block: var(--ds-size-6, 1.5rem);
53
+ }
54
+
55
+ .AppErrorBoundary-reload:hover {
56
+ background: rgb(0 0 0 / 0.05);
57
+ }
58
+
59
+ .ErrorAlertFallback-root {
60
+ display: flex;
61
+ align-items: flex-start;
62
+ gap: var(--ds-size-2, 0.5rem);
63
+ background: var(--ds-color-danger-surface-default, #fde8e8);
64
+ color: var(--ds-color-danger-text-default, #c01c2c);
65
+ border: 1px solid var(--ds-color-danger-border-default, #f5a6ae);
66
+ border-radius: var(--ds-border-radius-md, 0.25rem);
67
+ padding: var(--ds-size-3, 0.75rem) var(--ds-size-4, 1rem);
68
+ }
69
+
70
+ .ErrorAlertFallback-content {
71
+ flex: 1;
72
+ }
73
+
74
+ .ErrorAlertFallback-title {
75
+ font-weight: 600;
76
+ margin-bottom: var(--ds-size-1, 0.25rem);
77
+ }
78
+
79
+ .ErrorAlertFallback-reload {
80
+ appearance: none;
81
+ background: transparent;
82
+ border: none;
83
+ color: inherit;
84
+ cursor: pointer;
85
+ font: inherit;
86
+ font-weight: 600;
87
+ padding: 0;
88
+ text-decoration: underline;
89
+ flex-shrink: 0;
90
+ }
91
+
92
+ .RouteErrorPage-stack {
93
+ background: rgb(0 0 0 / 0.07);
94
+ border: 2px solid rgb(0 0 0 / 0.15);
95
+ border-radius: var(--ds-border-radius-md, 0.25rem);
96
+ padding: var(--ds-size-4, 1rem);
97
+ overflow-x: auto;
98
+ white-space: pre-wrap;
99
+ word-break: break-all;
100
+ font-size: var(--ds-font-size-1, 0.75rem);
101
+ }
@@ -0,0 +1,30 @@
1
+ import "./ErrorBoundary.css";
2
+ import type { DataObject } from "@olenbetong/appframe-data";
3
+ import { Component } from "react";
4
+ export type AppErrorBoundaryProps = {
5
+ children?: React.ReactNode;
6
+ message?: string | ((error: unknown) => string);
7
+ imgSrc?: string;
8
+ image?: React.ReactNode;
9
+ };
10
+ type AppErrorBoundaryState = {
11
+ hasError: boolean;
12
+ error: unknown;
13
+ };
14
+ export declare class AppErrorBoundary extends Component<AppErrorBoundaryProps, AppErrorBoundaryState> {
15
+ constructor(props: AppErrorBoundaryProps);
16
+ static getDerivedStateFromError(error: unknown): AppErrorBoundaryState;
17
+ componentDidCatch(error: unknown, errorInfo: unknown): void;
18
+ render(): React.ReactNode;
19
+ }
20
+ export type ErrorAlertFallbackProps = {
21
+ error: unknown;
22
+ className?: string;
23
+ };
24
+ export declare function ErrorAlertFallback({ error, className }: ErrorAlertFallbackProps): import("react").JSX.Element;
25
+ export declare function RouteErrorPage(): import("react").JSX.Element;
26
+ export declare function AsyncErrorAlert(): import("react").JSX.Element;
27
+ export declare function DataObjectErrorAlert({ dataObject }: {
28
+ dataObject: DataObject<any>;
29
+ }): import("react").JSX.Element | null;
30
+ export {};