@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,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,50 @@
1
+ import "./AppLayoutMobile.css";
2
+
3
+ import { useEffect, useState } from "react";
4
+ import { useLocation } from "react-router";
5
+
6
+ import { AppMenu } from "./AppMenu.js";
7
+ import type { AppLayoutProps } from "./index.js";
8
+ import { PartnerToggle } from "./PartnerToggle.js";
9
+
10
+ function Toggle({ onToggle }: { onToggle: () => void }) {
11
+ return (
12
+ <button type="button" className="LayoutSmall-toggle" onClick={onToggle} aria-label="Toggle menu">
13
+
14
+ </button>
15
+ );
16
+ }
17
+
18
+ export function AppLayoutMobile({ AppMenuProps, children, menu, partner }: AppLayoutProps) {
19
+ let [drawerOpen, setDrawerOpen] = useState(false);
20
+ let location = useLocation();
21
+
22
+ // oxlint-disable-next-line react-hooks/exhaustive-deps -- close drawer on navigation
23
+ useEffect(() => {
24
+ setDrawerOpen(false);
25
+ }, [location]);
26
+
27
+ return (
28
+ <div className="LayoutSmall-root">
29
+ {partner && menu && <PartnerToggle open={drawerOpen} onClick={() => setDrawerOpen((c) => !c)} />}
30
+ {!partner && menu && (
31
+ <div className="LayoutSmall-menuBar">
32
+ <Toggle onToggle={() => setDrawerOpen((c) => !c)} />
33
+ </div>
34
+ )}
35
+ {menu && (
36
+ <>
37
+ <div
38
+ className={`LayoutSmall-drawerOverlay${drawerOpen ? " open" : ""}`}
39
+ onClick={() => setDrawerOpen(false)}
40
+ aria-hidden="true"
41
+ />
42
+ <div className={`LayoutSmall-drawer AppMenu-drawer${drawerOpen ? " open" : ""}`}>
43
+ <AppMenu {...AppMenuProps}>{menu}</AppMenu>
44
+ </div>
45
+ </>
46
+ )}
47
+ {children}
48
+ </div>
49
+ );
50
+ }
@@ -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,75 @@
1
+ import "./AppMenu.css";
2
+
3
+ import { getLocalizedString } from "@olenbetong/appframe-core";
4
+
5
+ import clsx from "clsx";
6
+ import type React from "react";
7
+
8
+ type MenuHeaderProps = {
9
+ children?: React.ReactNode[] | React.ReactNode;
10
+ primary: string;
11
+ secondary?: string;
12
+ };
13
+
14
+ function MenuHeader({ primary, secondary }: MenuHeaderProps) {
15
+ return (
16
+ <>
17
+ <div className="AppMenu-header">
18
+ <h1 className="AppMenu-title" id="NavigationHeader">
19
+ {primary}
20
+ </h1>
21
+ {secondary && <p className="AppMenu-subTitle">{secondary}</p>}
22
+ </div>
23
+ <hr className="AppMenu-divider" />
24
+ </>
25
+ );
26
+ }
27
+
28
+ function handleKeyDown(evt: React.KeyboardEvent) {
29
+ let nextElement: Element | null | undefined = null;
30
+ let appMenu = evt.currentTarget;
31
+
32
+ if (!document.activeElement || !(appMenu instanceof HTMLElement) || !appMenu.contains(document.activeElement)) return;
33
+
34
+ let links = Array.from(appMenu.querySelectorAll<HTMLElement>("a, button"));
35
+ let currentIndex = links.indexOf(document.activeElement as HTMLElement);
36
+
37
+ if (evt.key === "ArrowDown" || evt.key === "ArrowRight") {
38
+ if (currentIndex < links.length) {
39
+ nextElement = links[currentIndex + 1];
40
+ }
41
+ } else if (evt.key === "ArrowUp" || evt.key === "ArrowLeft") {
42
+ if (currentIndex > 0) {
43
+ nextElement = links[currentIndex - 1];
44
+ }
45
+ } else if (evt.key === "Home" || evt.key === "End") {
46
+ nextElement = links.at(evt.key === "Home" ? 0 : -1);
47
+ }
48
+
49
+ if (nextElement instanceof HTMLElement) {
50
+ evt.preventDefault();
51
+ nextElement.scrollIntoView({ block: "nearest" });
52
+ nextElement.focus();
53
+ }
54
+ }
55
+
56
+ export type AppMenuProps = Pick<React.HTMLProps<HTMLElement>, "aria-label" | "aria-labelledby" | "className" | "id"> & {
57
+ children?: React.ReactNode[] | React.ReactNode;
58
+ headerPrimary?: string;
59
+ headerSecondary?: string;
60
+ };
61
+
62
+ export function AppMenu({ children, className, headerPrimary, headerSecondary, ...props }: AppMenuProps) {
63
+ return (
64
+ <nav
65
+ aria-labelledby={headerPrimary ? "NavigationHeader" : undefined}
66
+ aria-label={headerPrimary ? undefined : getLocalizedString("Application pages")}
67
+ className={clsx(className, "MenuItems-root")}
68
+ onKeyDown={handleKeyDown}
69
+ {...props}
70
+ >
71
+ {headerPrimary && <MenuHeader primary={headerPrimary} secondary={headerSecondary} />}
72
+ {children}
73
+ </nav>
74
+ );
75
+ }
@@ -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,80 @@
1
+ import "./AppMenuItem.css";
2
+
3
+ import clsx from "clsx";
4
+ import type { To } from "react-router";
5
+ import { forwardRef } from "react";
6
+ import { NavLink, type NavLinkProps } from "react-router";
7
+ import type React from "react";
8
+
9
+ export type AppMenuItemProps = Omit<NavLinkProps, "className"> & {
10
+ children: React.ReactNode | React.ReactNode[];
11
+ info?: React.ReactNode | React.ReactNode[];
12
+ icon?: React.ReactNode;
13
+ onClick?: React.MouseEventHandler<HTMLAnchorElement>;
14
+ to: To;
15
+ end?: boolean;
16
+ className?: string;
17
+ };
18
+
19
+ export const AppMenuItem = forwardRef<HTMLAnchorElement, AppMenuItemProps>(function AppMenuItem(
20
+ { children, className, end = true, info, to, icon, ...props }: AppMenuItemProps,
21
+ ref,
22
+ ) {
23
+ return (
24
+ <NavLink viewTransition to={to} className={clsx("AppMenuItem-root", className)} end={end} {...props} ref={ref}>
25
+ {icon && <span className="AppMenuItem-icon">{icon}</span>}
26
+ <span className="AppMenuItem-text">{children}</span>
27
+ {info && <span className="AppMenuItem-info">{info}</span>}
28
+ </NavLink>
29
+ );
30
+ });
31
+
32
+ export type AppMenuItemExternalLinkProps = Omit<React.AnchorHTMLAttributes<HTMLAnchorElement>, "href"> & {
33
+ children: React.ReactNode | React.ReactNode[];
34
+ info?: React.ReactNode | React.ReactNode[];
35
+ icon?: React.ReactNode;
36
+ href: string;
37
+ target?: string;
38
+ };
39
+
40
+ export const AppMenuItemExternalLink = forwardRef<HTMLAnchorElement, AppMenuItemExternalLinkProps>(
41
+ function AppMenuItemExternalLink(
42
+ { children, className, href, info, icon, target, ...props }: AppMenuItemExternalLinkProps,
43
+ ref,
44
+ ) {
45
+ return (
46
+ <a href={href} className={clsx("AppMenuItem-root", className)} target={target} {...props} ref={ref}>
47
+ {icon && <span className="AppMenuItem-icon">{icon}</span>}
48
+ <span className="AppMenuItem-text">{children}</span>
49
+ {info && <span className="AppMenuItem-info">{info}</span>}
50
+ </a>
51
+ );
52
+ },
53
+ );
54
+
55
+ export type AppMenuItemButtonProps = Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, "onClick"> & {
56
+ active?: boolean;
57
+ children: React.ReactNode | React.ReactNode[];
58
+ info?: React.ReactNode | React.ReactNode[];
59
+ icon?: React.ReactNode;
60
+ onClick?: React.MouseEventHandler<HTMLButtonElement>;
61
+ };
62
+
63
+ export const AppMenuItemButton = forwardRef<HTMLButtonElement, AppMenuItemButtonProps>(function AppMenuItemButton(
64
+ { children, className, active = false, info, onClick, icon, ...props }: AppMenuItemButtonProps,
65
+ ref,
66
+ ) {
67
+ return (
68
+ <button
69
+ type="button"
70
+ onClick={onClick}
71
+ className={clsx("AppMenuItem-root", className, active && "active")}
72
+ {...props}
73
+ ref={ref}
74
+ >
75
+ {icon && <span className="AppMenuItem-icon">{icon}</span>}
76
+ <span className="AppMenuItem-text">{children}</span>
77
+ {info && <span className="AppMenuItem-info">{info}</span>}
78
+ </button>
79
+ );
80
+ });
@@ -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,14 @@
1
+ import "./AppMenuSubheader.css";
2
+
3
+ import clsx from "clsx";
4
+ import type React from "react";
5
+
6
+ export type AppMenuSubheaderProps = React.HTMLAttributes<HTMLDivElement>;
7
+
8
+ export function AppMenuSubheader({ children, className, ...props }: AppMenuSubheaderProps) {
9
+ return (
10
+ <div className={clsx("AppMenuSubheader-root", className)} {...props}>
11
+ {children}
12
+ </div>
13
+ );
14
+ }
@@ -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
+ }