elbe-ui 2.0.10 → 2.0.12

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 (38) hide show
  1. package/dist/ui/app/app.d.ts +2 -1
  2. package/dist/ui/app/app.js +15 -7
  3. package/dist/ui/app/app_ctxt.d.ts +4 -2
  4. package/dist/ui/app/app_ctxt.js +15 -2
  5. package/dist/ui/components/base/box.js +1 -1
  6. package/dist/ui/components/base/card.js +2 -2
  7. package/dist/ui/components/base/state_builder.js +1 -1
  8. package/dist/ui/components/button/button.js +1 -1
  9. package/dist/ui/components/button/icon_button.js +1 -1
  10. package/dist/ui/components/button/toggle_button.js +1 -1
  11. package/dist/ui/components/dialog/dialog.d.ts +1 -1
  12. package/dist/ui/components/dialog/dialog.js +2 -2
  13. package/dist/ui/components/error_view.js +3 -4
  14. package/dist/ui/components/footer.js +10 -2
  15. package/dist/ui/components/input/_labeled_input.js +1 -1
  16. package/dist/ui/components/input/checkbox.js +1 -1
  17. package/dist/ui/components/input/range.js +1 -1
  18. package/dist/ui/components/input/switch.js +1 -1
  19. package/dist/ui/components/input/text/input_field.js +1 -1
  20. package/dist/ui/components/layout/header.d.ts +34 -7
  21. package/dist/ui/components/layout/header.js +76 -25
  22. package/dist/ui/components/layout/menu.js +5 -5
  23. package/dist/ui/components/layout/page.js +1 -1
  24. package/dist/ui/components/layout/toolbar.js +1 -1
  25. package/dist/ui/components/link.js +1 -1
  26. package/dist/ui/components/progress_bar.js +1 -1
  27. package/dist/ui/components/routing/route.d.ts +1 -1
  28. package/dist/ui/components/routing/route.js +8 -1
  29. package/dist/ui/components/section_card.js +2 -2
  30. package/dist/ui/components/spinner.js +1 -1
  31. package/dist/ui/components/table.js +1 -1
  32. package/dist/ui/components/text.js +1 -1
  33. package/dist/ui/components/tooltip.js +1 -1
  34. package/dist/ui/util/_util.d.ts +2 -0
  35. package/dist/ui/util/_util.js +12 -0
  36. package/dist/ui/util/toast/toast_ctx.js +1 -1
  37. package/dist/ui/util/types.d.ts +1 -0
  38. package/package.json +2 -2
@@ -23,7 +23,8 @@ type AppProps = _AppProps & {
23
23
  * - `themeSelector` (function | undefined): An optional function to further customize the theme based on the current theme configuration.
24
24
  * - `routerConfig` (object | undefined): Configuration options for the router, such as basePath.
25
25
  * - `noGlobalStyles` (boolean | undefined): If true, global styles will not be applied to the document. Useful if you have multiple Elbe apps on the same page.
26
- * - `children` (ElbeRoute | ElbeRoute[] | undefined): The route components to be rendered within the application.
26
+ * - `children` (ElbeRoute | ElbeRoute[] | undefined): The route components to be rendered within the application. Pass
27
+ * `MenuRoute` components here to define the application's routes and menu items. You may also wrap the menu routes Fragments (<></>).
27
28
  * - `globalActions` (ElbeChild[] | undefined): An array of global action components to be displayed in the application header.
28
29
  * - `footer` (ElbeChild | undefined): A footer component to be displayed at the bottom of the application.
29
30
  *
@@ -2,6 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useMemo, useState } from "react";
3
3
  import { Box, DialogsProvider, isMenuRoute, omit, ToastProvider, Wouter, } from "../..";
4
4
  import { Menu } from "../components/layout/menu";
5
+ import { unwrapFragments } from "../util/_util";
5
6
  import { AppContext } from "./app_ctxt";
6
7
  /** The main application component that sets up the application context, theme, and routing.
7
8
  * Render this component at the root of your application to initialize Elbe UI features:
@@ -17,7 +18,8 @@ import { AppContext } from "./app_ctxt";
17
18
  * - `themeSelector` (function | undefined): An optional function to further customize the theme based on the current theme configuration.
18
19
  * - `routerConfig` (object | undefined): Configuration options for the router, such as basePath.
19
20
  * - `noGlobalStyles` (boolean | undefined): If true, global styles will not be applied to the document. Useful if you have multiple Elbe apps on the same page.
20
- * - `children` (ElbeRoute | ElbeRoute[] | undefined): The route components to be rendered within the application.
21
+ * - `children` (ElbeRoute | ElbeRoute[] | undefined): The route components to be rendered within the application. Pass
22
+ * `MenuRoute` components here to define the application's routes and menu items. You may also wrap the menu routes Fragments (<></>).
21
23
  * - `globalActions` (ElbeChild[] | undefined): An array of global action components to be displayed in the application header.
22
24
  * - `footer` (ElbeChild | undefined): A footer component to be displayed at the bottom of the application.
23
25
  *
@@ -76,12 +78,19 @@ function _App(p) {
76
78
  document.documentElement.style.backgroundColor = bg;
77
79
  document.body.style.backgroundColor = bg;
78
80
  }, [themeSelected, p.config.noGlobalStyles]);
79
- const menuItems = useMemo(() => {
80
- return _extractMenuItems(p.children);
81
- }, [p.children]);
82
81
  const [location, navigate] = Wouter.useLocation();
83
82
  const [history, setHistory] = useState([_initialLocation()]);
84
83
  const [menuOpen, setMenuOpen] = useState(false);
84
+ const { children, menuItems } = useMemo(() => {
85
+ const childsOrFrags = Array.isArray(p.children)
86
+ ? p.children
87
+ : p.children
88
+ ? [p.children]
89
+ : [];
90
+ const children = unwrapFragments(childsOrFrags);
91
+ const menuItems = _extractMenuItems(children);
92
+ return { children, menuItems };
93
+ }, [p.children]);
85
94
  return (_jsx(p.themeContext.WithTheme, { theme: themeSelected, children: _jsx(AppContext.Provider, { value: {
86
95
  appConfig: p.config,
87
96
  _appThemeContext: p.themeContext,
@@ -118,14 +127,13 @@ function _App(p) {
118
127
  display: "flex",
119
128
  width: "100%",
120
129
  minHeight: "100vh",
121
- }, children: [menuItems.length > 0 && _jsx(Menu, { items: menuItems }), _jsx("div", { style: { flex: 1, width: "0px" }, children: _jsx(Wouter.Switch, { children: p.children }) })] }) }) }) }) }));
130
+ }, children: [menuItems.length > 0 && _jsx(Menu, { items: menuItems }), _jsx("div", { style: { flex: 1, width: "0px" }, children: _jsx(Wouter.Switch, { children: children }) })] }) }) }) }) }));
122
131
  }
123
132
  function _extractMenuItems(children) {
124
133
  if (!children)
125
134
  return [];
126
- const childs = Array.isArray(children) ? children : [children];
127
135
  const items = [];
128
- for (const child of childs) {
136
+ for (const child of children) {
129
137
  if (!isMenuRoute(child))
130
138
  continue;
131
139
  items.push(child.props);
@@ -3,7 +3,7 @@ import { ElbeThemeContext } from "../theme/theme_context";
3
3
  import { ElbeChild, ElbeChildren, int } from "../util/types";
4
4
  export type AppConfig = {
5
5
  title?: string;
6
- icons?: HeaderLogos;
6
+ branding?: HeaderLogos;
7
7
  globalActions?: ElbeChild[];
8
8
  footer?: ElbeChildren | null;
9
9
  routerConfig?: {
@@ -32,6 +32,8 @@ export interface AppState {
32
32
  _appThemeContext: ElbeThemeContext;
33
33
  }
34
34
  export declare const AppContext: import("react").Context<AppState | null>;
35
- export declare function useApp(): AppState;
35
+ export declare function useApp({ useFallback }?: {
36
+ useFallback?: boolean | undefined;
37
+ }): AppState;
36
38
  export declare function useMaybeApp(): AppState | null;
37
39
  export {};
@@ -1,9 +1,22 @@
1
1
  import { createContext, useContext } from "react";
2
+ import { makeThemeContext } from "../theme/theme_context";
2
3
  import { throwError, tryOrNull } from "../util/util";
3
4
  export const AppContext = createContext(null);
4
- export function useApp() {
5
+ const _fallbackAppContext = {
6
+ appConfig: {},
7
+ router: {
8
+ go: () => { },
9
+ goBack: () => { },
10
+ history: [],
11
+ location: "/",
12
+ },
13
+ _appThemeContext: makeThemeContext({}),
14
+ };
15
+ export function useApp({ useFallback = false } = {}) {
5
16
  var _a;
6
- return ((_a = tryOrNull(() => useContext(AppContext))) !== null && _a !== void 0 ? _a : throwError("useApp must be used within an ElbeApp context. try using useMaybeApp()"));
17
+ return ((_a = tryOrNull(() => useContext(AppContext))) !== null && _a !== void 0 ? _a : (useFallback
18
+ ? _fallbackAppContext
19
+ : throwError("useApp must be used within an ElbeApp context. try using useMaybeApp() or useApp({ useFallback: true }) instead.")));
7
20
  }
8
21
  export function useMaybeApp() {
9
22
  return tryOrNull(() => useContext(AppContext));
@@ -61,7 +61,7 @@ Box.inverse = (p) => createElement(Box, Object.assign(Object.assign({}, p), { sc
61
61
  * @returns
62
62
  */
63
63
  export function _Box(p) {
64
- const { _appThemeContext } = useApp();
64
+ const { _appThemeContext } = useApp({ useFallback: true });
65
65
  const usedTheme = _appThemeContext.useTheme().useWith(({ color }) => {
66
66
  var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
67
67
  return {
@@ -18,7 +18,7 @@ import { WithTooltip } from "../tooltip";
18
18
  export function Card(_a) {
19
19
  var _b, _c;
20
20
  var { mode, scheme, kind, manner, state, padding = 1, margin = 0, onTap, onLongTap, frosted, bordered, elevated, sharp, overflow, children } = _a, elbe = __rest(_a, ["mode", "scheme", "kind", "manner", "state", "padding", "margin", "onTap", "onLongTap", "frosted", "bordered", "elevated", "sharp", "overflow", "children"]);
21
- const { _appThemeContext } = useApp();
21
+ const { _appThemeContext } = useApp({ useFallback: true });
22
22
  const { theme } = _appThemeContext.useTheme();
23
23
  const isBordered = useMemo(() => {
24
24
  return (bordered !== null && bordered !== void 0 ? bordered : false) || theme.color.isContrast;
@@ -31,7 +31,7 @@ export function Card(_a) {
31
31
  ? "var(--elbe-context-color-border, transparent)"
32
32
  : undefined,
33
33
  };
34
- return (_jsx(WithTooltip, { tooltip: elbe.tooltip, children: _jsx(_Box, { mode: mode, scheme: scheme, kind: kind, manner: manner, padding: padding, margin: margin, state: state, className: elbe.className, flex: elbe.flex, elevated: elevated, frosted: frosted, style: Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({ overflow: overflow }, css.borderRadius(styles.radius)), css.borderStyle(styles.borderStyle)), css.borderWidth(styles.borderWidth)), css.borderColor(styles.borderColor)), { opacity: onTap === null ? 0.5 : 1 }), ((_b = elbe.style) !== null && _b !== void 0 ? _b : {})), native: Object.assign(Object.assign(Object.assign({}, (onTap !== undefined
34
+ return (_jsx(WithTooltip, { tooltip: elbe.tooltip, children: _jsx(_Box, { mode: mode, scheme: scheme, kind: kind, manner: manner, padding: padding, margin: margin, state: state, className: elbe.className, flex: elbe.flex, elevated: elevated, frosted: frosted, typeLabel: elbe.typeLabel, style: Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({ overflow: overflow }, css.borderRadius(styles.radius)), css.borderStyle(styles.borderStyle)), css.borderWidth(styles.borderWidth)), css.borderColor(styles.borderColor)), { opacity: onTap === null ? 0.5 : 1 }), ((_b = elbe.style) !== null && _b !== void 0 ? _b : {})), native: Object.assign(Object.assign(Object.assign({}, (onTap !== undefined
35
35
  ? {
36
36
  onClick: (e) => {
37
37
  e.preventDefault();
@@ -2,7 +2,7 @@ import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { useState } from "react";
3
3
  import { useApp } from "../../app/app_ctxt";
4
4
  export function WithStateTheme(p) {
5
- const { _appThemeContext } = useApp();
5
+ const { _appThemeContext } = useApp({ useFallback: true });
6
6
  const [elState, setElState] = useState("neutral");
7
7
  if (!p.theme) {
8
8
  console.error("WithStateTheme: No theme provided");
@@ -32,7 +32,7 @@ function _Btn(_a) {
32
32
  var _b, _c;
33
33
  var { manner, kind, onTap, icon, label, children, contentAlign } = _a, elbe = __rest(_a, ["manner", "kind", "onTap", "icon", "label", "children", "contentAlign"]);
34
34
  const toolbarCtx = useToolbar();
35
- const { _appThemeContext } = useApp();
35
+ const { _appThemeContext } = useApp({ useFallback: true });
36
36
  const baseTheme = _appThemeContext.useTheme().useWith(({ color }) => ({
37
37
  color: Object.assign(Object.assign({}, color), { selection: Object.assign(Object.assign({}, color.selection), { kind: kind !== null && kind !== void 0 ? kind : color.selection.kind, manner: manner }) }),
38
38
  }), [kind, manner]);
@@ -28,7 +28,7 @@ IconButton.plain = (p) => _jsx(_btn, Object.assign({}, p, { manner: "plain" }));
28
28
  function _btn(_a) {
29
29
  var _b;
30
30
  var { icon, onTap, manner } = _a, elbe = __rest(_a, ["icon", "onTap", "manner"]);
31
- const { _appThemeContext } = useApp();
31
+ const { _appThemeContext } = useApp({ useFallback: true });
32
32
  const baseTheme = _appThemeContext.useTheme().useWith(({ color }) => {
33
33
  var _a, _b;
34
34
  return ({
@@ -20,7 +20,7 @@ import { Icon } from "./icon_button";
20
20
  export function ToggleButton(_a) {
21
21
  var _b;
22
22
  var { value, onChange, label, icon, kind } = _a, elbe = __rest(_a, ["value", "onChange", "label", "icon", "kind"]);
23
- const { _appThemeContext } = useApp();
23
+ const { _appThemeContext } = useApp({ useFallback: true });
24
24
  const { theme } = _appThemeContext.useTheme();
25
25
  return (_jsxs(Button, Object.assign({ manner: value ? "major" : "flat", kind: kind, tooltip: elbe.tooltip, onTap: onChange && (() => onChange(!value)), ariaLabel: (_b = elbe.ariaLabel) !== null && _b !== void 0 ? _b : label, contentAlign: "space-between" }, applyProps("toggle_button", elbe, [], {
26
26
  overflow: "hidden",
@@ -18,7 +18,7 @@ export type ElbeDialogProps = {
18
18
  * - `kind` (ColorSelection.KindsAlert | undefined): An optional kind to display an alert icon next to the title.
19
19
  * - `dismissible` ("none" | "button" | "barrier" | undefined): Controls how the dialog can be dismissed.
20
20
  * - "none": The dialog cannot be dismissed by user actions.
21
- * - "button": A close button is provided in the title bar.
21
+ * - "button": A close button is provided in the title bar. (**DEFAULT**)
22
22
  * - "barrier": Clicking outside the dialog will close it.
23
23
  * Default is "button".
24
24
  * - `maxWidth` (number | undefined): The maximum width of the dialog in rem units. Defaults to 90vw if not provided.
@@ -34,7 +34,7 @@ export function elevatedBackdropStyle(open, theme, openMergeStyle) {
34
34
  * - `kind` (ColorSelection.KindsAlert | undefined): An optional kind to display an alert icon next to the title.
35
35
  * - `dismissible` ("none" | "button" | "barrier" | undefined): Controls how the dialog can be dismissed.
36
36
  * - "none": The dialog cannot be dismissed by user actions.
37
- * - "button": A close button is provided in the title bar.
37
+ * - "button": A close button is provided in the title bar. (**DEFAULT**)
38
38
  * - "barrier": Clicking outside the dialog will close it.
39
39
  * Default is "button".
40
40
  * - `maxWidth` (number | undefined): The maximum width of the dialog in rem units. Defaults to 90vw if not provided.
@@ -55,7 +55,7 @@ export function elevatedBackdropStyle(open, theme, openMergeStyle) {
55
55
  */
56
56
  export function Dialog(_a) {
57
57
  var { dismissible = "button" } = _a, p = __rest(_a, ["dismissible"]);
58
- const { _appThemeContext } = useApp();
58
+ const { _appThemeContext } = useApp({ useFallback: true });
59
59
  const theme = _appThemeContext.useTheme().useWith((c) => ({
60
60
  color: Object.assign(Object.assign({}, c.color), { selection: Object.assign(Object.assign({}, c.color.selection), { scheme: "primary", kind: "accent", manner: "plain", state: "neutral" }) }),
61
61
  }), []);
@@ -1,7 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { icons } from "lucide-react";
3
3
  import { useState } from "react";
4
- import { Card, Column, Dialog, Icon, Icons, toElbeError, Wouter, } from "../..";
4
+ import { Button, Card, Column, Dialog, Icon, Icons, Text, toElbeError, } from "../..";
5
5
  import { _maybeL10n } from "../util/l10n/_l10n_util";
6
6
  /** * A component to display error messages in a user-friendly manner.
7
7
  *
@@ -45,9 +45,8 @@ export function PrettyErrorView({ error, retry, labels = {
45
45
  pt: "detalhes do erro",
46
46
  },
47
47
  }, }) {
48
- var _a, _b, _c, _d, _e, _f;
48
+ var _a, _b, _c, _d, _e, _f, _g, _h;
49
49
  const l10n = _maybeL10n();
50
50
  const [open, setOpen] = useState(false);
51
- const [loc, navigate] = Wouter.useLocation();
52
- return (_jsxs(Column, { cross: "center", style: { margin: "1rem 0", padding: "1rem" }, children: [_jsx(Icon, { icon: (_a = error.icon) !== null && _a !== void 0 ? _a : icons.OctagonAlert }), _jsx("h4", { style: { margin: 0 }, children: (_b = l10n === null || l10n === void 0 ? void 0 : l10n.inline(error.message)) !== null && _b !== void 0 ? _b : "error" }), _jsx("span", { className: "pointer", onClick: () => setOpen(true), children: (_c = l10n === null || l10n === void 0 ? void 0 : l10n.inline(error.description)) !== null && _c !== void 0 ? _c : "" }), retry && (_jsxs("button", { className: "action", onClick: () => retry(), children: [_jsx(Icons.RotateCcw, {}), " ", (_d = l10n === null || l10n === void 0 ? void 0 : l10n.inline(labels.retry)) !== null && _d !== void 0 ? _d : "retry"] })), error.code === 404 && (_jsxs("button", { className: "action", onClick: () => navigate("/", { replace: true }), children: [_jsx(Icons.House, {}), (_e = l10n === null || l10n === void 0 ? void 0 : l10n.inline(labels.home)) !== null && _e !== void 0 ? _e : "go home"] })), _jsx(Dialog, { title: (_f = l10n === null || l10n === void 0 ? void 0 : l10n.inline(labels.details)) !== null && _f !== void 0 ? _f : "error details", open: open, onClose: () => setOpen(false), children: _jsx("pre", { className: "card inverse", children: `code: ${error.code}\n\n` + JSON.stringify(error.details, null, 2) }) })] }));
51
+ return (_jsxs(Column, { cross: "center", style: { margin: "1rem 0", padding: "1rem" }, children: [_jsx(Icon, { icon: (_a = error.icon) !== null && _a !== void 0 ? _a : icons.OctagonAlert }), _jsx(Text.h4, { v: (_b = l10n === null || l10n === void 0 ? void 0 : l10n.inline(error.message)) !== null && _b !== void 0 ? _b : "error" }), _jsx(Text, { align: "center", v: (_c = l10n === null || l10n === void 0 ? void 0 : l10n.inline(error.description)) !== null && _c !== void 0 ? _c : "", style: { cursor: "pointer" }, native: { onClick: () => setOpen(true) } }), retry && (_jsx(Button.flat, { ariaLabel: (_d = l10n === null || l10n === void 0 ? void 0 : l10n.inline(labels.retry)) !== null && _d !== void 0 ? _d : "retry", label: (_e = l10n === null || l10n === void 0 ? void 0 : l10n.inline(labels.retry)) !== null && _e !== void 0 ? _e : "retry", icon: Icons.RotateCcw, onTap: () => retry() })), error.code === 404 && (_jsx(Button.flat, { ariaLabel: (_f = l10n === null || l10n === void 0 ? void 0 : l10n.inline(labels.home)) !== null && _f !== void 0 ? _f : "go home", label: (_g = l10n === null || l10n === void 0 ? void 0 : l10n.inline(labels.home)) !== null && _g !== void 0 ? _g : "go home", icon: Icons.House, onTap: () => (window.location.href = "/") })), _jsx(Dialog, { title: (_h = l10n === null || l10n === void 0 ? void 0 : l10n.inline(labels.details)) !== null && _h !== void 0 ? _h : "error details", open: open, onClose: () => setOpen(false), children: _jsx("pre", { children: `code: ${error.code}\n\n` + JSON.stringify(error.details, null, 2) }) })] }));
53
52
  }
@@ -1,6 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { HeartIcon } from "lucide-react";
3
3
  import { Card, Column, FlexSpace, Link, Row, Text, useLayoutMode, } from "../..";
4
+ import { useApp } from "../app/app_ctxt";
4
5
  /**
5
6
  * Footer component. Can contain links, copyright info, version and legal link.
6
7
  *
@@ -13,14 +14,21 @@ import { Card, Column, FlexSpace, Link, Row, Text, useLayoutMode, } from "../.."
13
14
  * - `marginTop` (number): Margin top in rem units to add space above the footer.
14
15
  */
15
16
  export function Footer({ left, right, copyright, version, legal, marginTop, }) {
17
+ const app = useApp({ useFallback: true });
18
+ const { theme } = app._appThemeContext.useTheme();
16
19
  const layoutMode = useLayoutMode();
17
20
  return (_jsx(Card, { scheme: "secondary", sharp: true, role: "contentinfo", ariaLabel: "footer", style: {
18
21
  borderLeftStyle: "none",
19
22
  borderRightStyle: "none",
20
23
  borderBottomStyle: "none",
21
- borderTopLeftRadius: layoutMode.isWide ? "var(--g-radius)" : undefined,
22
- color: "color-mix(in srgb, var(--c-context-front) 60%, transparent)",
24
+ borderTopLeftRadius: layoutMode.isWide
25
+ ? `${theme.geometry.radius}rem`
26
+ : undefined,
27
+ /*color: theme.color.currentColor.front
28
+ .inter(theme.color.currentColor.back, 0.6)
29
+ .asCss(),*/
23
30
  marginTop: `${marginTop !== null && marginTop !== void 0 ? marginTop : 0}rem`,
31
+ marginLeft: layoutMode.isWide && !!app.menu ? "1rem" : undefined,
24
32
  }, children: _jsxs(Column, { gap: 1, children: [(left || right) && (_jsxs(Row, { main: "space-between", cross: "start", children: [left && (_jsx(Column, { gap: 0.5, flex: 1, cross: "start", children: left.map((item, i) => item.label ? _jsx(_Link, Object.assign({}, item), i) : item) })), right && (_jsx(Column, { gap: 0.5, flex: 1, cross: "end", children: right.map((item, i) => item.label ? _jsx(_Link, Object.assign({}, item), i) : item) }))] })), (left || right) && (copyright || version || legal) && _jsx("hr", {}), (copyright || version || legal) && (_jsxs(Row, { children: [copyright &&
25
33
  (typeof copyright === "string" ? (_jsx(Text, { bold: true, v: copyright })) : (copyright)), version && _jsx(_Version, { version: version }), _jsx(FlexSpace, {}), legal && _jsx(_Link, Object.assign({}, legal))] }))] }) }));
26
34
  }
@@ -11,7 +11,7 @@ import { WithTooltip } from "../tooltip";
11
11
  */
12
12
  export function LabeledInput(p) {
13
13
  var _a, _b;
14
- const { _appThemeContext } = useApp();
14
+ const { _appThemeContext } = useApp({ useFallback: true });
15
15
  const baseTheme = _appThemeContext.useTheme();
16
16
  return (_jsx(WithTooltip, { tooltip: p.tooltip, children: _jsx(WithStateTheme, { disabled: (_a = p.disabled) !== null && _a !== void 0 ? _a : false, theme: baseTheme, manner: p.manner, children: _jsxs("div", Object.assign({}, applyProps(p.typeLabel, p, [], Object.assign({ flex: p.flex ? (p.flex === true ? 1 : p.flex) : undefined, width: p.flex ? undefined : ((_b = p.width) !== null && _b !== void 0 ? _b : 12) + "rem", display: "flex", flexDirection: "column", alignItems: "stretch" }, p.style)), { children: [_jsx("label", { htmlFor: p.id, style: {
17
17
  display: p.hideLabel ? "none" : "block",
@@ -17,7 +17,7 @@ import { WithTooltip } from "../tooltip";
17
17
  * - `manner` ("flat" | "plain" | undefined): The visual style of the checkbox when it is unchecked.
18
18
  */
19
19
  export function Checkbox(p) {
20
- const { _appThemeContext } = useApp();
20
+ const { _appThemeContext } = useApp({ useFallback: true });
21
21
  const baseTheme = _appThemeContext.useTheme().useWith(({ color }) => {
22
22
  var _a;
23
23
  return ({
@@ -31,7 +31,7 @@ export function Range(p) {
31
31
  function _StyledRange(_a) {
32
32
  var _b, _c;
33
33
  var { min = 0, max = 100, step = 1, value, onChange } = _a, elbe = __rest(_a, ["min", "max", "step", "value", "onChange"]);
34
- const { _appThemeContext } = useApp();
34
+ const { _appThemeContext } = useApp({ useFallback: true });
35
35
  const { theme } = _appThemeContext.useTheme().useWith((c) => ({
36
36
  color: Object.assign(Object.assign({}, c.color), { selection: Object.assign(Object.assign({}, c.color.selection), { manner: "major" }) }),
37
37
  }), []);
@@ -17,7 +17,7 @@ import { WithTooltip } from "../tooltip";
17
17
  * - `manner` ("flat" | "plain" | undefined): The visual style of the switch when it is off.
18
18
  */
19
19
  export function Switch(p) {
20
- const { _appThemeContext } = useApp();
20
+ const { _appThemeContext } = useApp({ useFallback: true });
21
21
  const baseTheme = _appThemeContext.useTheme().useWith(({ color }) => {
22
22
  var _a;
23
23
  return ({
@@ -92,7 +92,7 @@ export var Field;
92
92
  function _Field(p) {
93
93
  var _a, _b, _c, _d;
94
94
  {
95
- const { _appThemeContext } = useApp();
95
+ const { _appThemeContext } = useApp({ useFallback: true });
96
96
  const usedTheme = _appThemeContext.useTheme();
97
97
  const id = (_a = p.id) !== null && _a !== void 0 ? _a : randomAlphaNum(8, "input_field_");
98
98
  const manner = (_b = p.manner) !== null && _b !== void 0 ? _b : "plain";
@@ -1,9 +1,12 @@
1
- import { ColorSelection, ElbeChild } from "../../..";
1
+ import { ColorSelection, ElbeChild, remSize } from "../../..";
2
+ /**
3
+ * props for the Header component. Provide logos to the application.
4
+ *
5
+ * You can provide either a custom ElbeChild component or use the AssetLogo component to display an image logo.
6
+ */
2
7
  export type HeaderLogos = {
3
- logo?: string | ElbeChild;
4
- logoDark?: string | ElbeChild;
5
- endLogo?: string | ElbeChild;
6
- endLogoDark?: string | ElbeChild;
8
+ logo?: ElbeChild;
9
+ endLogo?: ElbeChild;
7
10
  };
8
11
  export type HeaderProps = HeaderLogos & {
9
12
  leading?: ElbeChild | "back" | "close";
@@ -13,10 +16,34 @@ export type HeaderProps = HeaderLogos & {
13
16
  scheme?: ColorSelection.Schemes;
14
17
  };
15
18
  export declare function Header(p: HeaderProps): import("react/jsx-runtime").JSX.Element;
19
+ /**
20
+ * Component to display an image logo from asset files.
21
+ *
22
+ * Props:
23
+ * - src: string - The source path for the light theme logo image.
24
+ * - srcDark?: string - Optional source path for the dark theme logo image.
25
+ * - onTap?: () => void - Optional callback function to be called when the logo is clicked.
26
+ * - height?: remSize - Optional height of the logo in rem units (default is 1.25rem).
27
+ *
28
+ * Example usage:
29
+ * ```tsx
30
+ * <AssetLogo
31
+ * src="/assets/logo_light.png"
32
+ * srcDark="/assets/logo_dark.png"
33
+ * onTap={() => window.open("https://example.com", "_blank")}
34
+ * height={2}
35
+ * />
36
+ * ```
37
+ */
38
+ export declare function AssetLogo(p: {
39
+ src: string;
40
+ srcDark?: string;
41
+ onTap?: () => void;
42
+ height?: remSize;
43
+ }): import("react/jsx-runtime").JSX.Element;
16
44
  export declare function _Logo(p: {
17
45
  flex?: boolean;
18
- logo: string | ElbeChild;
19
- logoDark?: string | ElbeChild | null;
46
+ logo: ElbeChild;
20
47
  lMargin?: number;
21
48
  rMargin?: number;
22
49
  }): import("react/jsx-runtime").JSX.Element | null;
@@ -1,19 +1,17 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { ChevronLeft, MenuIcon, XIcon } from "lucide-react";
3
- import { useMemo, useState } from "react";
4
- import { Card, IconButton, Text, useLayoutMode, useSiteScroll, } from "../../..";
3
+ import { useMemo } from "react";
4
+ import { Card, IconButton, metaTagContent, Text, useLayoutMode, useSiteScroll, } from "../../..";
5
5
  import { useApp } from "../../app/app_ctxt";
6
6
  import { _Toolbar } from "./toolbar";
7
7
  export function Header(p) {
8
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
9
- const { _appThemeContext, appConfig, menu } = useApp();
10
- const { theme, useWith } = _appThemeContext.useTheme();
8
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j;
9
+ const gap = 1;
10
+ const { _appThemeContext, appConfig, menu } = useApp({ useFallback: true });
11
+ const { theme } = _appThemeContext.useTheme();
11
12
  const layoutMode = useLayoutMode();
12
13
  const scroll = useSiteScroll();
13
- const secTheme = useWith((t) => ({
14
- color: Object.assign(Object.assign({}, t.color), { selection: Object.assign(Object.assign({}, t.color.selection), { scheme: "secondary", manner: "plain" }) }),
15
- }), [theme]);
16
- return (_jsxs(Card, { padding: 0, scheme: (_a = p.scheme) !== null && _a !== void 0 ? _a : "primary", manner: "plain", frosted: !theme.color.isContrast,
14
+ return (_jsxs(Card, { typeLabel: "elbe_header", padding: 0, scheme: (_a = p.scheme) !== null && _a !== void 0 ? _a : "primary", manner: "plain", frosted: !theme.color.isContrast,
17
15
  //elevated={!!scroll}
18
16
  bordered: true, sharp: true, style: {
19
17
  position: "sticky",
@@ -27,39 +25,85 @@ export function Header(p) {
27
25
  borderTopStyle: "none",
28
26
  borderLeftStyle: "none",
29
27
  borderRightStyle: "none",
30
- borderColor: theme.color.isContrast || scroll
28
+ borderBottomColor: theme.color.isContrast || scroll
31
29
  ? theme.color.currentColor.border
32
30
  .withAlpha(theme.color.isContrast ? 1 : 0.25)
33
31
  .asCss()
34
32
  : "transparent",
35
- borderWidth: theme.geometry.borderWidth + "rem",
36
- gap: "1rem",
33
+ borderBottomWidth: theme.geometry.borderWidth + "rem",
34
+ gap: `${gap}rem`,
37
35
  zIndex: 80,
38
- }, children: [p.leading && p.leading !== "back" && p.leading !== "close"
39
- ? p.leading
40
- : !layoutMode.isWide &&
41
- menu && (_jsx(IconButton.plain, { ariaLabel: "open/close menu", onTap: () => menu.setOpen(!menu.isOpen), icon: MenuIcon })), p.leading === "back" && _jsx(BackButton, {}), p.leading === "close" && _jsx(BackButton, { close: true }), !layoutMode.isMobile && (_jsx(_Logo, { logo: (_b = p.logo) !== null && _b !== void 0 ? _b : (_c = appConfig === null || appConfig === void 0 ? void 0 : appConfig.icons) === null || _c === void 0 ? void 0 : _c.logo, logoDark: (_d = p.logoDark) !== null && _d !== void 0 ? _d : (_e = appConfig === null || appConfig === void 0 ? void 0 : appConfig.icons) === null || _e === void 0 ? void 0 : _e.logoDark, lMargin: 0.5 })), (!appConfig || layoutMode.isWide) && (_jsx("div", { style: { margin: "-1rem", width: "1.5rem" } })), _jsx(_HeaderTitle, { title: p.title, center: (_f = p.centerTitle) !== null && _f !== void 0 ? _f : false }), _jsx(_Toolbar, { actions: [...((_g = p.actions) !== null && _g !== void 0 ? _g : []), ...((_h = appConfig === null || appConfig === void 0 ? void 0 : appConfig.globalActions) !== null && _h !== void 0 ? _h : [])] }), layoutMode.isWide && (_jsx(_Logo, { logo: (_j = p.endLogo) !== null && _j !== void 0 ? _j : (_k = appConfig === null || appConfig === void 0 ? void 0 : appConfig.icons) === null || _k === void 0 ? void 0 : _k.endLogo, logoDark: (_l = p.endLogoDark) !== null && _l !== void 0 ? _l : (_m = appConfig === null || appConfig === void 0 ? void 0 : appConfig.icons) === null || _m === void 0 ? void 0 : _m.endLogoDark, rMargin: 0.5 }))] }));
36
+ }, children: [_jsx(_LeadingIcon, { leading: (_b = p.leading) !== null && _b !== void 0 ? _b : null, isWide: layoutMode.isWide, gap: gap }), !layoutMode.isMobile && (_jsx(_Logo, { logo: (_c = p.logo) !== null && _c !== void 0 ? _c : (_d = appConfig === null || appConfig === void 0 ? void 0 : appConfig.branding) === null || _d === void 0 ? void 0 : _d.logo })), _jsx(_HeaderTitle, { title: p.title, center: (_e = p.centerTitle) !== null && _e !== void 0 ? _e : false }), _jsx(_Toolbar, { actions: [...((_f = p.actions) !== null && _f !== void 0 ? _f : []), ...((_g = appConfig === null || appConfig === void 0 ? void 0 : appConfig.globalActions) !== null && _g !== void 0 ? _g : [])] }), layoutMode.isWide && (_jsx(_Logo, { logo: (_h = p.endLogo) !== null && _h !== void 0 ? _h : (_j = appConfig === null || appConfig === void 0 ? void 0 : appConfig.branding) === null || _j === void 0 ? void 0 : _j.endLogo, rMargin: 0.5 }))] }));
42
37
  }
43
- export function _Logo(p) {
38
+ function _LeadingIcon(p) {
44
39
  var _a, _b;
45
- const { _appThemeContext } = useApp();
40
+ const { router, menu } = useApp({ useFallback: true });
41
+ const canGoBack = ((_b = (_a = router.history) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0) < 2;
42
+ // if leading is custom component, just return it
43
+ if (p.leading && typeof p.leading !== "string")
44
+ return p.leading;
45
+ // if you can go back and leading is "back" or "close", show it
46
+ if ((p.leading === "back" || p.leading === "close") && canGoBack) {
47
+ return _jsx(BackButton, { close: p.leading === "close" });
48
+ }
49
+ // if the layout is not wide and there is a menu, show menu button
50
+ if (!p.isWide && menu) {
51
+ return (_jsx(IconButton.plain, { ariaLabel: "open/close menu", onTap: () => menu.setOpen(!(menu === null || menu === void 0 ? void 0 : menu.isOpen)), icon: MenuIcon }));
52
+ }
53
+ // return a spacer so content is not squeezed to the left if there is no icon
54
+ return (_jsx("div", { style: {
55
+ marginRight: `-${p.gap}rem`,
56
+ width: ".5rem",
57
+ } }));
58
+ }
59
+ /**
60
+ * Component to display an image logo from asset files.
61
+ *
62
+ * Props:
63
+ * - src: string - The source path for the light theme logo image.
64
+ * - srcDark?: string - Optional source path for the dark theme logo image.
65
+ * - onTap?: () => void - Optional callback function to be called when the logo is clicked.
66
+ * - height?: remSize - Optional height of the logo in rem units (default is 1.25rem).
67
+ *
68
+ * Example usage:
69
+ * ```tsx
70
+ * <AssetLogo
71
+ * src="/assets/logo_light.png"
72
+ * srcDark="/assets/logo_dark.png"
73
+ * onTap={() => window.open("https://example.com", "_blank")}
74
+ * height={2}
75
+ * />
76
+ * ```
77
+ */
78
+ export function AssetLogo(p) {
79
+ var _a;
80
+ const { _appThemeContext } = useApp({ useFallback: true });
46
81
  const { theme } = _appThemeContext.useTheme();
47
- const [logo, setLogo] = useState(p.logo);
48
- useMemo(() => { var _a; return setLogo(theme.color.isDark ? (_a = p.logoDark) !== null && _a !== void 0 ? _a : p.logo : p.logo); }, [theme]);
49
- return !logo ? null : (_jsx("div", { style: {
82
+ const trueSrc = getTrueSrc(theme.color.isDark && p.srcDark ? p.srcDark : p.src);
83
+ return (_jsx("img", { src: trueSrc, onClick: (e) => {
84
+ var _a;
85
+ (_a = p.onTap) === null || _a === void 0 ? void 0 : _a.call(p);
86
+ e.preventDefault();
87
+ e.stopPropagation();
88
+ }, style: {
89
+ cursor: p.onTap ? "pointer" : "default",
90
+ height: `${(_a = p.height) !== null && _a !== void 0 ? _a : 1.25}rem`,
91
+ } }));
92
+ }
93
+ export function _Logo(p) {
94
+ var _a, _b;
95
+ return !p.logo ? null : (_jsx("div", { style: {
50
96
  flex: p.flex ? 1 : undefined,
51
97
  display: "flex",
52
98
  alignItems: "center",
53
99
  justifyContent: "center",
54
100
  marginLeft: `${(_a = p.lMargin) !== null && _a !== void 0 ? _a : 0}rem`,
55
101
  marginRight: `${(_b = p.rMargin) !== null && _b !== void 0 ? _b : 0}rem`,
56
- }, children: typeof logo === "string" ? (_jsx("img", { src: logo, style: {
57
- height: "1.25rem",
58
- } })) : (logo) }));
102
+ }, children: p.logo }));
59
103
  }
60
104
  export function BackButton(p) {
61
105
  var _a, _b;
62
- const { router } = useApp();
106
+ const { router } = useApp({ useFallback: true });
63
107
  const hidden = ((_b = (_a = router.history) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0) < 2;
64
108
  return hidden ? null : (_jsx(IconButton.plain, { ariaLabel: p.close ? "close" : "go back", onTap: () => router.goBack(), icon: p.close ? XIcon : ChevronLeft }, "hello-back"));
65
109
  }
@@ -81,3 +125,10 @@ export function _HeaderTitle(p) {
81
125
  left: globalCenter ? "50%" : "0",
82
126
  }, children: typeof p.title === "string" ? (_jsx(Text.h3, { align: p.center ? "center" : "start", v: p.title })) : (p.title) }) }));
83
127
  }
128
+ function getTrueSrc(src) {
129
+ var _a;
130
+ const _basePath = (_a = metaTagContent("basepath")) !== null && _a !== void 0 ? _a : "/";
131
+ return src.startsWith("./") && typeof window !== "undefined"
132
+ ? window.location.origin + _basePath + src.slice(2)
133
+ : src;
134
+ }
@@ -7,7 +7,7 @@ import { Card } from "../base/card";
7
7
  import { Button } from "../button/button";
8
8
  import { Column } from "./flex";
9
9
  export function Menu(p) {
10
- const { _appThemeContext, menu } = useApp();
10
+ const { _appThemeContext, menu } = useApp({ useFallback: true });
11
11
  const { theme } = _appThemeContext.useTheme();
12
12
  const layoutMode = useLayoutMode();
13
13
  const isWideOrOpen = useMemo(() => {
@@ -42,8 +42,8 @@ export function Menu(p) {
42
42
  })) }), _jsx(_Menu, { topBot: topBot, wideOrOpen: isWideOrOpen, menuWidth: menuWidth })] }));
43
43
  }
44
44
  function _Menu(p) {
45
- var _a, _b;
46
- const { _appThemeContext, menu, appConfig } = useApp();
45
+ var _a;
46
+ const { _appThemeContext, menu, appConfig } = useApp({ useFallback: true });
47
47
  const { theme } = _appThemeContext.useTheme();
48
48
  const layoutMode = useLayoutMode();
49
49
  if (!menu)
@@ -73,10 +73,10 @@ function _Menu(p) {
73
73
  transition: theme.motion.reduced ? "none" : "width 200ms ease-in-out",
74
74
  }, children: p.wideOrOpen && (_jsxs(_Fragment, { children: [_jsx(Button.plain, { sharp: layoutMode.isWide, contentAlign: "start", ariaLabel: "open/close menu", onTap: () => menu.setOpen(!menu.isOpen), icon: MenuIcon, style: {
75
75
  marginBottom: ".5rem",
76
- }, children: !layoutMode.isWide && (_jsx(_Logo, { logo: (_a = appConfig.icons) === null || _a === void 0 ? void 0 : _a.logo, logoDark: (_b = appConfig.icons) === null || _b === void 0 ? void 0 : _b.logoDark, lMargin: 0.5 })) }), _jsx(Column, { flex: 1, scroll: true, noScrollbar: true, children: p.topBot.top.map((i, index) => (_jsx(_MenuItemView, { item: i }, index))) }), p.topBot.bottom.map((i, index) => (_jsx(_MenuItemView, { item: i }, index)))] })) }));
76
+ }, children: !layoutMode.isWide && (_jsx(_Logo, { logo: (_a = appConfig.branding) === null || _a === void 0 ? void 0 : _a.logo, lMargin: 0.5 })) }), _jsx(Column, { flex: 1, scroll: true, noScrollbar: true, children: p.topBot.top.map((i, index) => (_jsx(_MenuItemView, { item: i }, index))) }), p.topBot.bottom.map((i, index) => (_jsx(_MenuItemView, { item: i }, index)))] })) }));
77
77
  }
78
78
  function _MenuItemView({ item }) {
79
- const { menu, router } = useApp();
79
+ const { menu, router } = useApp({ useFallback: true });
80
80
  if (!menu)
81
81
  return null;
82
82
  return (_jsx(Button
@@ -25,7 +25,7 @@ function _hasMoreThan(p, expected) {
25
25
  */
26
26
  export function Page(p) {
27
27
  var _a, _b;
28
- const appConfig = useApp();
28
+ const appConfig = useApp({ useFallback: true });
29
29
  const hasHeader = _hasMoreThan(p, [
30
30
  "children",
31
31
  "footer",
@@ -32,7 +32,7 @@ export function _Toolbar(p) {
32
32
  }
33
33
  export function OverflowMenu(p) {
34
34
  var _a;
35
- const { _appThemeContext } = useApp();
35
+ const { _appThemeContext } = useApp({ useFallback: true });
36
36
  const { theme } = _appThemeContext.useTheme();
37
37
  const [open, setOpen] = useState(false);
38
38
  return !((_a = p.items) === null || _a === void 0 ? void 0 : _a.length) ? null : (_jsxs("div", { style: {
@@ -19,7 +19,7 @@ import { WithTooltip } from "./tooltip";
19
19
  */
20
20
  export function Link(p) {
21
21
  var _a;
22
- const { _appThemeContext } = useApp();
22
+ const { _appThemeContext } = useApp({ useFallback: true });
23
23
  const baseTheme = _appThemeContext.useTheme().useWith(({ color }) => {
24
24
  var _a;
25
25
  return ({
@@ -21,7 +21,7 @@ import { useApp } from "../app/app_ctxt";
21
21
  */
22
22
  export function ProgressBar(_a) {
23
23
  var { value, max = 100, manner = "flat" } = _a, elbe = __rest(_a, ["value", "max", "manner"]);
24
- const { _appThemeContext } = useApp();
24
+ const { _appThemeContext } = useApp({ useFallback: true });
25
25
  const theme = _appThemeContext.useTheme().useWith(({ color }) => ({
26
26
  color: Object.assign(Object.assign({}, color), { selection: Object.assign(Object.assign({}, color.selection), { manner: manner }) }),
27
27
  }), [manner]);
@@ -26,5 +26,5 @@ export declare function MenuRoute(p: _MenuRouteProps): import("react/jsx-runtime
26
26
  * a helper function to create a <Wouter.Route> with a path.
27
27
  */
28
28
  export declare const Route: typeof Wouter.Route;
29
- export declare function isMenuRoute(r: ElbeRoute): r is React.ReactElement<_MenuRouteProps>;
29
+ export declare function isMenuRoute(r: React.ReactNode): r is React.ReactElement<_MenuRouteProps>;
30
30
  export {};
@@ -1,4 +1,5 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
+ import React from "react";
2
3
  import { Wouter } from "../../..";
3
4
  /**
4
5
  * a route that also renders a menu item in the <AppBase> component.
@@ -16,5 +17,11 @@ export function MenuRoute(p) {
16
17
  */
17
18
  export const Route = Wouter.Route;
18
19
  export function isMenuRoute(r) {
19
- return "path" in r.props && "label" in r.props && "icon" in r.props;
20
+ // check if r is a React element with props path, label and icon
21
+ if (!React.isValidElement(r))
22
+ return false;
23
+ const rEl = r;
24
+ if (!rEl.props || typeof rEl.props !== "object")
25
+ return false;
26
+ return "path" in rEl.props && "label" in rEl.props && "icon" in rEl.props;
20
27
  }
@@ -28,13 +28,13 @@ import { useApp } from "../app/app_ctxt";
28
28
  */
29
29
  export function SectionCard(p) {
30
30
  var _a;
31
- const _app = useApp();
31
+ const _app = useApp({ useFallback: true });
32
32
  const _appTheme = _app._appThemeContext.useTheme();
33
33
  const [collapsed, setCollapsed] = useState(p.collapsed);
34
34
  const [hintOpen, setHintOpen] = useState(false);
35
35
  return (_jsxs(Card, { bordered: p.bordered, style: {
36
36
  padding: ` ${1 - (p.bordered ? _appTheme.theme.geometry.borderWidth : 0)}rem`,
37
- }, children: [_jsx(Dialog, { title: p.title + " - Info", open: hintOpen, onClose: () => setHintOpen(false), children: typeof p.hint === "string" ? (_jsx("div", { className: "elbe-hint-markdown", children: _jsx(Markdown, { children: p.hint, allowElement: () => true }) })) : (p.hint) }), _jsxs(Column, { children: [_jsxs(Card, { onTap: collapsed === undefined
37
+ }, children: [_jsx(Dialog, { title: p.title + " - Info", open: hintOpen, maxWidth: 35, onClose: () => setHintOpen(false), children: typeof p.hint === "string" ? (_jsx("div", { className: "elbe-hint-markdown", children: _jsx(Markdown, { children: p.hint, allowElement: () => true }) })) : (p.hint) }), _jsxs(Column, { children: [_jsxs(Card, { onTap: collapsed === undefined
38
38
  ? undefined
39
39
  : () => setCollapsed(!collapsed), margin: -1, padding: 1, className: collapsed === undefined ? undefined : "hoverable_card", style: {
40
40
  border: "none",
@@ -19,7 +19,7 @@ function _toPath(c, yFac, yOffset = 0, clamp = [0, 1], xFac = 1) {
19
19
  export function Spinner(p) {
20
20
  var _a;
21
21
  const [x, setX] = useState(0);
22
- const { _appThemeContext } = useApp();
22
+ const { _appThemeContext } = useApp({ useFallback: true });
23
23
  const theme = _appThemeContext.useTheme().useWith(({ color }) => {
24
24
  var _a;
25
25
  return ({
@@ -29,7 +29,7 @@ import { useApp } from "../app/app_ctxt";
29
29
  */
30
30
  export function Table(p) {
31
31
  var _a, _b;
32
- const _app = useApp();
32
+ const _app = useApp({ useFallback: true });
33
33
  const _appTheme = _app._appThemeContext.useTheme();
34
34
  const themeSec = _appTheme.useWith(({ color }) => ({
35
35
  color: Object.assign(Object.assign({}, color), { selection: Object.assign(Object.assign({}, color.selection), { scheme: "secondary" }) }),
@@ -45,7 +45,7 @@ Text.defaultProps = {
45
45
  variant: "bodyM",
46
46
  };
47
47
  function _Text(p) {
48
- const { _appThemeContext } = useApp();
48
+ const { _appThemeContext } = useApp({ useFallback: true });
49
49
  const usedTheme = _appThemeContext.useTheme();
50
50
  const tVariant = useMemo(() => {
51
51
  var _a;
@@ -8,7 +8,7 @@ export function WithTooltip(p) {
8
8
  const timeoutRef = useRef(null);
9
9
  const [visible, setVisible] = useState(false);
10
10
  const [coords, setCoords] = useState({ x: 0, y: 0, top: false, left: false });
11
- const { _appThemeContext } = useApp();
11
+ const { _appThemeContext } = useApp({ useFallback: true });
12
12
  const { theme } = _appThemeContext.useTheme().useWith((c) => ({
13
13
  color: Object.assign(Object.assign({}, c.color), { selection: Object.assign(Object.assign({}, c.color.selection), { scheme: "inverse", kind: "accent", manner: "plain", state: "neutral" }) }),
14
14
  }), []);
@@ -6,3 +6,5 @@ export declare namespace css {
6
6
  function borderWidth(v: React.CSSProperties["borderLeftWidth"] | undefined): React.CSSProperties;
7
7
  function borderColor(v: React.CSSProperties["borderLeftColor"] | undefined): React.CSSProperties;
8
8
  }
9
+ export declare function isFragment(child: any): child is React.ReactElement;
10
+ export declare function unwrapFragments(children: React.ReactNode): React.ReactNode[];
@@ -1,3 +1,4 @@
1
+ import React from "react";
1
2
  export function elevatedShadow(dark) {
2
3
  return `0px 0px .625rem -.125rem ${dark ? "#ffffff60" : "#00000060"}`;
3
4
  }
@@ -40,3 +41,14 @@ export var css;
40
41
  }
41
42
  css.borderColor = borderColor;
42
43
  })(css || (css = {}));
44
+ export function isFragment(child) {
45
+ return React.isValidElement(child) && child.type === React.Fragment;
46
+ }
47
+ export function unwrapFragments(children) {
48
+ return React.Children.toArray(children).flatMap((child) => {
49
+ var _a, _b;
50
+ return isFragment(child)
51
+ ? React.Children.toArray((_b = (_a = child.props) === null || _a === void 0 ? void 0 : _a["children"]) !== null && _b !== void 0 ? _b : [])
52
+ : child;
53
+ });
54
+ }
@@ -17,7 +17,7 @@ export function useToast() {
17
17
  * @returns a context provider for toast messages
18
18
  */
19
19
  export function ToastProvider(p) {
20
- const { _appThemeContext } = useApp();
20
+ const { _appThemeContext } = useApp({ useFallback: true });
21
21
  const { theme } = _appThemeContext.useTheme();
22
22
  const rootDOM = useMemo(() => getRootElement("elbe_toast"), []);
23
23
  const [toasts, setToasts] = useState([]);
@@ -9,3 +9,4 @@ export type ElbeChildren = ReactNode;
9
9
  export type s = string;
10
10
  export type n = number;
11
11
  export type b = boolean;
12
+ export type remSize = float;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "elbe-ui",
3
- "version": "2.0.10",
3
+ "version": "2.0.12",
4
4
  "author": "Robin Naumann",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -23,7 +23,7 @@
23
23
  "build:dts": "tsc --declaration",
24
24
  "build:css": "sass -q style/elbe-util.scss dist/elbe.css",
25
25
  "build": "rm -rf ./dist && bun run build:ts && bun run build:dts && bun run build:css ",
26
- "dev": "bun run build && (cd example && bun run dev)",
26
+ "serve": "bun run build && (cd example && bun run dev)",
27
27
  "pub": "npm login && bun run build && npm publish && bun run pub:example",
28
28
  "pub:example": "bun run build && (cd example && bun run build) && open example/dist"
29
29
  },