@adamjanicki/ui 1.8.1 → 1.8.3

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 (54) hide show
  1. package/components/Accordion/Accordion.d.ts +2 -1
  2. package/components/Animated/Animated.d.ts +2 -2
  3. package/components/Avatar/Avatar.js +2 -1
  4. package/components/Banner/Banner.d.ts +1 -1
  5. package/components/Button/Button.d.ts +2 -2
  6. package/components/Carousel/Carousel.d.ts +2 -2
  7. package/components/Carousel/Carousel.js +2 -2
  8. package/components/ErrorBoundary/ErrorBoundary.d.ts +2 -1
  9. package/components/Link/Link.d.ts +11 -22
  10. package/components/Link/Link.js +33 -6
  11. package/components/Modal/Modal.d.ts +4 -0
  12. package/components/Modal/Modal.js +4 -13
  13. package/components/Select/Select.d.ts +2 -1
  14. package/components/ui.js +1 -1
  15. package/functions/classNames.d.ts +2 -1
  16. package/hooks/useMergeRefs.d.ts +2 -1
  17. package/index.d.ts +1 -0
  18. package/index.js +2 -0
  19. package/package.json +3 -3
  20. package/router/PathParamsContext.d.ts +4 -0
  21. package/router/PathParamsContext.js +3 -0
  22. package/router/Route.d.ts +17 -0
  23. package/router/Route.js +6 -0
  24. package/router/Router.d.ts +8 -0
  25. package/router/Router.js +36 -0
  26. package/router/RouterContext.d.ts +12 -0
  27. package/router/RouterContext.js +3 -0
  28. package/router/Routes.d.ts +18 -0
  29. package/router/Routes.js +31 -0
  30. package/router/history.d.ts +10 -0
  31. package/router/history.js +46 -0
  32. package/router/hooks/useLocation.d.ts +7 -0
  33. package/router/hooks/useLocation.js +10 -0
  34. package/router/hooks/useNavigate.d.ts +7 -0
  35. package/router/hooks/useNavigate.js +10 -0
  36. package/router/hooks/usePathParams.d.ts +8 -0
  37. package/router/hooks/usePathParams.js +15 -0
  38. package/router/hooks/useRouterContext.d.ts +5 -0
  39. package/router/hooks/useRouterContext.js +9 -0
  40. package/router/hooks/useSearchParams.d.ts +2 -0
  41. package/router/hooks/useSearchParams.js +47 -0
  42. package/router/href.d.ts +8 -0
  43. package/router/href.js +43 -0
  44. package/router/index.d.ts +7 -0
  45. package/router/index.js +7 -0
  46. package/router/path.d.ts +2 -0
  47. package/router/path.js +38 -0
  48. package/router/string.d.ts +2 -0
  49. package/router/string.js +6 -0
  50. package/router/types.d.ts +33 -0
  51. package/router/types.js +1 -0
  52. package/style.css +1 -1
  53. package/utils/transformVfx.js +4 -0
  54. package/utils/types.d.ts +6 -3
@@ -1,10 +1,11 @@
1
1
  import React from "react";
2
2
  import { type BoxProps } from "../Box/Box";
3
+ import type { ReadonlyableArray } from "../../utils/types";
3
4
  type Props = Omit<BoxProps, "children"> & {
4
5
  /**
5
6
  * Drawers to render as accordion sections
6
7
  */
7
- drawers: Drawer[];
8
+ drawers: ReadonlyableArray<Drawer>;
8
9
  /**
9
10
  * Duration of the drawer animation (in seconds)
10
11
  */
@@ -1,5 +1,5 @@
1
1
  import React from "react";
2
- import type { Vfx, Style } from "../../utils/types";
2
+ import type { ReadonlyableArray, Style, Vfx } from "../../utils/types";
3
3
  import { type BoxProps } from "../Box/Box";
4
4
  type AnimationState = {
5
5
  /**
@@ -52,7 +52,7 @@ type Props = BoxProps & {
52
52
  * The properties to apply a transition
53
53
  * @default ['all']
54
54
  */
55
- transitionProperties?: string[];
55
+ transitionProperties?: ReadonlyableArray<string>;
56
56
  };
57
57
  declare const Animated: React.ForwardRefExoticComponent<Omit<Props, "ref"> & React.RefAttributes<HTMLDivElement>>;
58
58
  export default Animated;
@@ -22,6 +22,7 @@ var __rest = (this && this.__rest) || function (s, e) {
22
22
  };
23
23
  import { jsx as _jsx } from "react/jsx-runtime";
24
24
  import React, { useState } from "react";
25
+ import ui from "../ui";
25
26
  import Box from "../Box/Box";
26
27
  import { classNames } from "../../functions";
27
28
  var Avatar = React.forwardRef(function (_a, ref) {
@@ -45,7 +46,7 @@ var Avatar = React.forwardRef(function (_a, ref) {
45
46
  imageClassName = "aui-avatar-".concat(size);
46
47
  }
47
48
  var fallbackCharacter = username[0];
48
- return (_jsx(Box, __assign({ className: classNames(avatarClassName, className), style: __assign(__assign({}, avatarStyle), style), vfx: __assign({ radius: "rounded", overflow: "hidden", fontWeight: 6, textAlign: "center" }, vfx) }, rest, { ref: ref, children: !useFallback ? (_jsx("img", { src: backgroundImage, alt: "", className: imageClassName, onError: function () { return setImageError(true); }, style: imageStyle })) : (fallbackCharacter) })));
49
+ return (_jsx(Box, __assign({ className: classNames(avatarClassName, className), style: __assign(__assign({}, avatarStyle), style), vfx: __assign({ radius: "rounded", overflow: "hidden", fontWeight: 6, textAlign: "center" }, vfx) }, rest, { ref: ref, children: !useFallback ? (_jsx(ui.img, { src: backgroundImage, alt: "", className: imageClassName, onError: function () { return setImageError(true); }, style: imageStyle })) : (fallbackCharacter) })));
49
50
  });
50
51
  var colorOptions = ["red", "yellow", "green", "blue", "purple"];
51
52
  // simple deterministic "hash" to get a background color
@@ -3,7 +3,7 @@ import type { ContentType } from "../../utils/types";
3
3
  import { type BoxProps } from "../Box/Box";
4
4
  type Props = BoxProps & {
5
5
  /**
6
- * The type of badge to display.
6
+ * The type of banner to display.
7
7
  */
8
8
  type: ContentType;
9
9
  };
@@ -40,8 +40,8 @@ type IconButtonProps = Omit<DefaultButtonProps, "children"> & {
40
40
  export declare const IconButton: React.ForwardRefExoticComponent<Omit<IconButtonProps, "ref"> & React.RefAttributes<HTMLButtonElement>>;
41
41
  declare const Button: React.ForwardRefExoticComponent<Omit<ButtonProps, "ref"> & React.RefAttributes<HTMLButtonElement>>;
42
42
  export declare const getButtonProps: ({ variant, size, }: VisualButtonProps) => {
43
- className: string;
44
- vfx: {
43
+ readonly className: "aui-button-primary" | "aui-button-secondary";
44
+ readonly vfx: {
45
45
  readonly radius: "rounded";
46
46
  readonly fontWeight: 6;
47
47
  readonly fontSize: "xs";
@@ -1,5 +1,5 @@
1
1
  import React from "react";
2
- import type { Children, Style } from "../../utils/types";
2
+ import type { Children, ReadonlyableArray, Style } from "../../utils/types";
3
3
  import { type BoxProps } from "../Box/Box";
4
4
  type ButtonProps = {
5
5
  /**
@@ -19,7 +19,7 @@ type Props = BoxProps & {
19
19
  /**
20
20
  * The child elements/slides of the carousel
21
21
  */
22
- children: React.ReactNode[];
22
+ children: ReadonlyableArray<React.ReactNode>;
23
23
  /**
24
24
  * How long the transition lasts (in seconds)
25
25
  * @default 1
@@ -27,7 +27,7 @@ import Button from "../Button";
27
27
  import Box from "../Box/Box";
28
28
  import Icon from "../Icon";
29
29
  var DEFAULT_DURATION_S = 1;
30
- var itemVfx = { width: "full", height: "full" };
30
+ var itemVfx = { width: "full", height: "full", stretch: "max" };
31
31
  var Carousel = React.forwardRef(function (_a, ref) {
32
32
  var _b, _c;
33
33
  var children = _a.children, hideArrows = _a.hideArrows, vfx = _a.vfx, hideDots = _a.hideDots, dotProps = _a.dotProps, leftArrowProps = _a.leftArrowProps, rightArrowProps = _a.rightArrowProps, autoplayInterval = _a.autoplayInterval, duration = _a.duration, rest = __rest(_a, ["children", "hideArrows", "vfx", "hideDots", "dotProps", "leftArrowProps", "rightArrowProps", "autoplayInterval", "duration"]);
@@ -86,7 +86,7 @@ var Carousel = React.forwardRef(function (_a, ref) {
86
86
  axis: delta >= 0 ? "x" : "-x",
87
87
  width: "full",
88
88
  height: "full",
89
- }, style: animatingStyles, onTransitionEnd: onTransitionEnd, children: [_jsx(Box, { vfx: itemVfx, className: "aui-carousel-item", children: children[cur] }), _jsx(Box, { vfx: itemVfx, className: "aui-carousel-item", "aria-hidden": true, children: children[next] })] }), length > 1 && (_jsxs(_Fragment, { children: [!hideArrows && (_jsxs(_Fragment, { children: [_jsx(Button, { vfx: {
89
+ }, style: animatingStyles, onTransitionEnd: onTransitionEnd, children: [_jsx(Box, { vfx: itemVfx, children: children[cur] }), _jsx(Box, { vfx: itemVfx, "aria-hidden": true, children: children[next] })] }), length > 1 && (_jsxs(_Fragment, { children: [!hideArrows && (_jsxs(_Fragment, { children: [_jsx(Button, { vfx: {
90
90
  axis: "x",
91
91
  align: "center",
92
92
  justify: "center",
@@ -1,4 +1,5 @@
1
1
  import React from "react";
2
+ import type { ReadonlyableArray } from "../../utils/types";
2
3
  type FallbackProps = {
3
4
  error: Error;
4
5
  reset: () => void;
@@ -23,7 +24,7 @@ type Props = {
23
24
  /**
24
25
  * Dependencies to trigger a reset on change
25
26
  */
26
- deps?: unknown[];
27
+ deps?: ReadonlyableArray<unknown>;
27
28
  };
28
29
  type State = {
29
30
  error: Error | null;
@@ -1,24 +1,17 @@
1
1
  import React from "react";
2
+ import ui from "../ui";
2
3
  import { type VisualButtonProps } from "../Button/Button";
3
4
  import { Vfx } from "../../utils/types";
4
- export type BaseLinkProps = Omit<React.DetailedHTMLProps<React.AnchorHTMLAttributes<HTMLAnchorElement>, HTMLAnchorElement>, "href"> & {
5
+ export type LinkProps = Omit<React.ComponentProps<typeof ui.a>, "href"> & {
5
6
  /**
6
7
  * URL to navigate to
7
8
  */
8
9
  to: string;
9
- };
10
- type CustomLinkElement = React.ForwardRefExoticComponent<BaseLinkProps & React.RefAttributes<HTMLAnchorElement>>;
11
- type LinkProps = BaseLinkProps & {
12
- /**
13
- * Whether the link should open in a new tab
14
- */
15
- external?: boolean;
16
10
  /**
17
- * [Optional] Custom link element to use
18
- * This is useful for using a different link element, like a React Router Link
19
- * If this is not provided, a normal anchor tag will be used
11
+ * Whether to open the link in a new tab.
12
+ * @default false
20
13
  */
21
- LinkElement?: CustomLinkElement;
14
+ newTab?: boolean;
22
15
  /**
23
16
  * The VFX or other organizational css to apply to this element.
24
17
  * Properties are translated to class names before being applied.
@@ -26,22 +19,18 @@ type LinkProps = BaseLinkProps & {
26
19
  vfx?: Vfx;
27
20
  };
28
21
  export declare const UnstyledLink: React.ForwardRefExoticComponent<Omit<LinkProps, "ref"> & React.RefAttributes<HTMLAnchorElement>>;
29
- export declare const ButtonLink: React.ForwardRefExoticComponent<Omit<Omit<React.DetailedHTMLProps<React.AnchorHTMLAttributes<HTMLAnchorElement>, HTMLAnchorElement>, "href"> & {
22
+ export declare const ButtonLink: React.ForwardRefExoticComponent<Omit<Omit<Omit<React.ClassAttributes<HTMLAnchorElement> & React.AnchorHTMLAttributes<HTMLAnchorElement> & {
23
+ vfx?: Vfx;
24
+ }, "ref"> & React.RefAttributes<HTMLAnchorElement>, "href"> & {
30
25
  /**
31
26
  * URL to navigate to
32
27
  */
33
28
  to: string;
34
- } & {
35
- /**
36
- * Whether the link should open in a new tab
37
- */
38
- external?: boolean;
39
29
  /**
40
- * [Optional] Custom link element to use
41
- * This is useful for using a different link element, like a React Router Link
42
- * If this is not provided, a normal anchor tag will be used
30
+ * Whether to open the link in a new tab.
31
+ * @default false
43
32
  */
44
- LinkElement?: CustomLinkElement;
33
+ newTab?: boolean;
45
34
  /**
46
35
  * The VFX or other organizational css to apply to this element.
47
36
  * Properties are translated to class names before being applied.
@@ -22,16 +22,43 @@ var __rest = (this && this.__rest) || function (s, e) {
22
22
  };
23
23
  import { jsx as _jsx } from "react/jsx-runtime";
24
24
  import React from "react";
25
+ import ui from "../ui";
25
26
  import { getButtonProps } from "../Button/Button";
26
27
  import classNames from "../../functions/classNames";
27
- import transformVfx from "../../utils/transformVfx";
28
+ import RouterContext from "../../router/RouterContext";
29
+ import { getHref } from "../../router/href";
30
+ function routeInternally(event) {
31
+ // only route internally if it's a left click and no modifier keys are held down
32
+ return (event.button === 0 &&
33
+ !event.defaultPrevented &&
34
+ !event.metaKey &&
35
+ !event.altKey &&
36
+ !event.ctrlKey &&
37
+ !event.shiftKey);
38
+ }
28
39
  export var UnstyledLink = React.forwardRef(function (_a, ref) {
29
- var LinkElement = _a.LinkElement, to = _a.to, className = _a.className, vfx = _a.vfx, external = _a.external, rest = __rest(_a, ["LinkElement", "to", "className", "vfx", "external"]);
30
- var props = __assign(__assign(__assign({}, (external ? { target: "_blank", rel: "noreferrer noopener" } : {})), rest), { className: classNames("aui-action", transformVfx(vfx), className) });
31
- if (LinkElement) {
32
- return _jsx(LinkElement, __assign({}, props, { to: to, ref: ref }));
40
+ var to = _a.to, className = _a.className, newTab = _a.newTab, onClick = _a.onClick, target = _a.target, rel = _a.rel, rest = __rest(_a, ["to", "className", "newTab", "onClick", "target", "rel"]);
41
+ var router = React.useContext(RouterContext);
42
+ var href = router
43
+ ? getHref(to, router.location.pathname, router.basename)
44
+ : { type: "unknown", url: to };
45
+ if (newTab) {
46
+ target = "_blank";
47
+ rel = "noreferrer noopener";
33
48
  }
34
- return _jsx("a", __assign({}, props, { href: to, ref: ref }));
49
+ var handleClick = function (event) {
50
+ onClick === null || onClick === void 0 ? void 0 : onClick(event);
51
+ if (!router ||
52
+ newTab ||
53
+ href.type === "external" ||
54
+ href.type === "octo" ||
55
+ !routeInternally(event))
56
+ return;
57
+ // Client-side navigation
58
+ event.preventDefault();
59
+ router.navigate(to);
60
+ };
61
+ return (_jsx(ui.a, __assign({}, rest, { href: href.url, target: target, rel: rel, className: classNames("aui-action", className), onClick: handleClick, ref: ref })));
35
62
  });
36
63
  export var ButtonLink = React.forwardRef(function (_a, ref) {
37
64
  var className = _a.className, variant = _a.variant, vfx = _a.vfx, size = _a.size, props = __rest(_a, ["className", "variant", "vfx", "size"]);
@@ -38,6 +38,10 @@ type Props = BoxProps & {
38
38
  * @default false
39
39
  */
40
40
  returnFocusOnEscape?: boolean;
41
+ /**
42
+ * Props to pass to the outer box container
43
+ */
44
+ wrapperBoxProps?: Omit<BoxProps, "children">;
41
45
  };
42
46
  declare const Modal: React.ForwardRefExoticComponent<Omit<Props, "ref"> & React.RefAttributes<HTMLDivElement>>;
43
47
  export default Modal;
@@ -27,18 +27,9 @@ import Layer from "../Layer";
27
27
  import Button, { IconButton } from "../Button";
28
28
  import Animated from "../Animated";
29
29
  var Modal = React.forwardRef(function (_a, ref) {
30
- var open = _a.open, onClose = _a.onClose, onConfirm = _a.onConfirm, confirmButtonProps = _a.confirmButtonProps, cancelButtonProps = _a.cancelButtonProps, _b = _a.confirmLabel, confirmLabel = _b === void 0 ? "Ok" : _b, _c = _a.cancelLabel, cancelLabel = _c === void 0 ? "Cancel" : _c, returnFocusOnEscape = _a.returnFocusOnEscape, rest = __rest(_a, ["open", "onClose", "onConfirm", "confirmButtonProps", "cancelButtonProps", "confirmLabel", "cancelLabel", "returnFocusOnEscape"]);
31
- return (_jsx(Animated, { vfx: { z: "max" }, visible: open, animateTo: { vfx: { opacity: "full" } }, animateFrom: { vfx: { opacity: "none" } }, children: _jsx(Layer, { onClose: onClose, returnFocusOnEscape: returnFocusOnEscape, children: _jsxs(Box, { role: "dialog", "aria-modal": "true", vfx: {
32
- axis: "y",
33
- padding: "m",
34
- gap: "m",
35
- radius: "rounded",
36
- maxWidth: "full",
37
- shadow: "floating",
38
- border: true,
39
- color: "default",
40
- backgroundColor: "default",
41
- }, children: [_jsx(Box, { vfx: {
30
+ var open = _a.open, onClose = _a.onClose, onConfirm = _a.onConfirm, confirmButtonProps = _a.confirmButtonProps, cancelButtonProps = _a.cancelButtonProps, _b = _a.confirmLabel, confirmLabel = _b === void 0 ? "Ok" : _b, _c = _a.cancelLabel, cancelLabel = _c === void 0 ? "Cancel" : _c, returnFocusOnEscape = _a.returnFocusOnEscape, wrapperBoxProps = _a.wrapperBoxProps, rest = __rest(_a, ["open", "onClose", "onConfirm", "confirmButtonProps", "cancelButtonProps", "confirmLabel", "cancelLabel", "returnFocusOnEscape", "wrapperBoxProps"]);
31
+ var _d = wrapperBoxProps || {}, wrapperBoxVfx = _d.vfx, wrapperBoxRest = __rest(_d, ["vfx"]);
32
+ return (_jsx(Animated, { vfx: { z: "max" }, visible: open, animateTo: { vfx: { opacity: "full" } }, animateFrom: { vfx: { opacity: "none" } }, children: _jsx(Layer, { onClose: onClose, returnFocusOnEscape: returnFocusOnEscape, children: _jsxs(Box, __assign({ role: "dialog", "aria-modal": "true" }, wrapperBoxRest, { vfx: __assign({ axis: "y", padding: "m", gap: "m", radius: "rounded", maxWidth: "full", shadow: "floating", border: true, color: "default", backgroundColor: "default" }, wrapperBoxVfx), children: [_jsx(Box, { vfx: {
42
33
  axis: "x",
43
34
  align: "center",
44
35
  justify: "end",
@@ -52,6 +43,6 @@ var Modal = React.forwardRef(function (_a, ref) {
52
43
  }, children: [_jsx(Button, __assign({ variant: "secondary" }, cancelButtonProps, { onClick: onClose, children: cancelLabel })), _jsx(Button, __assign({}, confirmButtonProps, { onClick: function () {
53
44
  onConfirm();
54
45
  onClose();
55
- }, children: confirmLabel }))] })] }) }) }));
46
+ }, children: confirmLabel }))] })] })) }) }));
56
47
  });
57
48
  export default Modal;
@@ -1,12 +1,13 @@
1
1
  import React from "react";
2
2
  import { type BoxProps } from "../Box/Box";
3
3
  import ui from "../ui";
4
+ import type { ReadonlyableArray } from "../../utils/types";
4
5
  type SelectProps = React.ComponentProps<typeof ui.select>;
5
6
  type Props = Omit<BoxProps, "children" | "onChange"> & {
6
7
  /**
7
8
  * Array of options to display in the select
8
9
  */
9
- options: string[];
10
+ options: ReadonlyableArray<string>;
10
11
  /**
11
12
  * Mapper function to get the label of the option
12
13
  *
package/components/ui.js CHANGED
@@ -26,7 +26,7 @@ import transformVfx from "../utils/transformVfx";
26
26
  function createVfxElement(tag) {
27
27
  var Component = React.forwardRef(function (_a, ref) {
28
28
  var vfx = _a.vfx, className = _a.className, props = __rest(_a, ["vfx", "className"]);
29
- return React.createElement(tag, __assign(__assign({}, props), { ref: ref, className: classNames(transformVfx(vfx), className) }));
29
+ return React.createElement(tag, __assign(__assign({}, props), { ref: ref, className: classNames(className, transformVfx(vfx)) }));
30
30
  });
31
31
  return Component;
32
32
  }
@@ -1,7 +1,8 @@
1
+ import type { ReadonlyableArray } from "../utils/types";
1
2
  /**
2
3
  * Reduce a list of classnames into one string
3
4
  *
4
5
  * @param classNames list of class names to concatenate
5
6
  * @returns single aggregated string of classnames
6
7
  */
7
- export default function classNames(...classNames: Array<string | null | undefined>): string | undefined;
8
+ export default function classNames(...classNames: ReadonlyableArray<string | null | undefined>): string | undefined;
@@ -1,9 +1,10 @@
1
1
  import React from "react";
2
+ import type { ReadonlyableArray } from "../utils/types";
2
3
  /**
3
4
  * Simple hook that merges N refs into one callback
4
5
  *
5
6
  * @param refs all the refs you want to merge
6
7
  * @returns one combined ref
7
8
  */
8
- declare const useMergeRefs: <T>(...refs: (React.Ref<T> | null | undefined)[]) => React.Ref<T>;
9
+ declare const useMergeRefs: <T>(...refs: ReadonlyableArray<React.Ref<T> | null | undefined>) => React.Ref<T>;
9
10
  export default useMergeRefs;
package/index.d.ts CHANGED
@@ -24,3 +24,4 @@ export { default as Spinner } from "./components/Spinner";
24
24
  export { default as ui } from "./components/ui";
25
25
  export * from "./hooks";
26
26
  export * from "./functions";
27
+ export * from "./router";
package/index.js CHANGED
@@ -27,3 +27,5 @@ export { default as ui } from "./components/ui";
27
27
  export * from "./hooks";
28
28
  // Functions
29
29
  export * from "./functions";
30
+ // Router
31
+ export * from "./router";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adamjanicki/ui",
3
- "version": "1.8.1",
3
+ "version": "1.8.3",
4
4
  "description": "Basic UI components and hooks for React in TypeScript",
5
5
  "type": "module",
6
6
  "main": "./index.js",
@@ -29,8 +29,8 @@
29
29
  "@testing-library/react": "^16.3.0",
30
30
  "@testing-library/user-event": "^14.6.1",
31
31
  "@types/jest": "^30.0.0",
32
- "@types/react": "^19.1.9",
33
- "@types/react-dom": "^19.1.7",
32
+ "@types/react": "^19.2.7",
33
+ "@types/react-dom": "^19.2.3",
34
34
  "jest": "^30.0.5",
35
35
  "jest-environment-jsdom": "^30.0.5",
36
36
  "sass": "^1.90.0",
@@ -0,0 +1,4 @@
1
+ import React from "react";
2
+ import type { PathParams } from "./types";
3
+ declare const PathParamsContext: React.Context<PathParams | null>;
4
+ export default PathParamsContext;
@@ -0,0 +1,3 @@
1
+ import React from "react";
2
+ var PathParamsContext = React.createContext(null);
3
+ export default PathParamsContext;
@@ -0,0 +1,17 @@
1
+ import React from "react";
2
+ export type Props = {
3
+ /**
4
+ * Path pattern to match against window.location.pathname (e.g. `"/movie/:id"`)
5
+ * Currently, only 2 types are supported:
6
+ * 1. static: `/reviews/movies`
7
+ * 2. dynamic (params): `/reviews/:media/:title/view`
8
+ * In the future, I might extend use to include wildcard matching if I need it
9
+ */
10
+ path: string;
11
+ /** Element to render when the path matches */
12
+ element: React.ReactElement;
13
+ };
14
+ /**
15
+ * A simple wrapper to be used by <Routes>
16
+ */
17
+ export default function Route({}: Props): null;
@@ -0,0 +1,6 @@
1
+ /**
2
+ * A simple wrapper to be used by <Routes>
3
+ */
4
+ export default function Route(_a) {
5
+ return null;
6
+ }
@@ -0,0 +1,8 @@
1
+ import React from "react";
2
+ export type Props = {
3
+ /** Children to render inside the router provider */
4
+ children: React.ReactNode;
5
+ /** Optional basename prefix for all internal navigation (e.g. "/app") */
6
+ basename?: string;
7
+ };
8
+ export default function Router({ children, basename }: Props): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,36 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import React from "react";
3
+ import RouterContext from "./RouterContext";
4
+ import { createHistory, getCurrentLocation } from "./history";
5
+ import { getHref, normalizeBasename } from "./href";
6
+ export default function Router(_a) {
7
+ var children = _a.children, _b = _a.basename, basename = _b === void 0 ? "" : _b;
8
+ basename = normalizeBasename(basename);
9
+ var historyRef = React.useRef(null);
10
+ if (!historyRef.current)
11
+ historyRef.current = createHistory();
12
+ var history = historyRef.current;
13
+ var _c = React.useState(getCurrentLocation), location = _c[0], setLocation = _c[1];
14
+ // to avoid infinite rerenders
15
+ var locationRef = React.useRef(location);
16
+ React.useLayoutEffect(function () {
17
+ var removeListener = history.addListener(function (nextLocation) {
18
+ locationRef.current = nextLocation;
19
+ setLocation(nextLocation);
20
+ });
21
+ return function () {
22
+ removeListener();
23
+ history.cleanup();
24
+ };
25
+ }, [history]);
26
+ var navigate = React.useCallback(function (to) {
27
+ var currentPathname = locationRef.current.pathname;
28
+ history.push(getHref(to, currentPathname, basename).url);
29
+ }, [history, basename]);
30
+ var contextValue = React.useMemo(function () { return ({
31
+ location: location,
32
+ navigate: navigate,
33
+ basename: basename,
34
+ }); }, [location, navigate, basename]);
35
+ return (_jsx(RouterContext.Provider, { value: contextValue, children: children }));
36
+ }
@@ -0,0 +1,12 @@
1
+ import React from "react";
2
+ import type { Location, Navigate } from "./types";
3
+ type RouterContextValue = {
4
+ /** Current location */
5
+ location: Location;
6
+ /** Push-style navigation */
7
+ navigate: Navigate;
8
+ /** Optional basename prefix for all internal navigation */
9
+ basename: string;
10
+ };
11
+ declare const RouterContext: React.Context<RouterContextValue | null>;
12
+ export default RouterContext;
@@ -0,0 +1,3 @@
1
+ import React from "react";
2
+ var RouterContext = React.createContext(null);
3
+ export default RouterContext;
@@ -0,0 +1,18 @@
1
+ import React from "react";
2
+ import { Children } from "../utils/types";
3
+ export type Props = {
4
+ /**
5
+ * Child <Route> elements to switch between.
6
+ * Note: non <Route> children will be silently ignored
7
+ */
8
+ children: Children;
9
+ /**
10
+ * What to render when no routes match, like a 404 page.
11
+ */
12
+ fallback?: React.ReactNode;
13
+ };
14
+ /**
15
+ * Nested within a router component, this component handles rendering the proper route.
16
+ * Note: sticking any other components besides routes in here will not be rendered
17
+ */
18
+ export default function Routes({ children: rawChildren, fallback }: Props): string | number | bigint | boolean | Iterable<React.ReactNode> | Promise<string | number | bigint | boolean | React.ReactPortal | React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | Iterable<React.ReactNode> | null | undefined> | import("react/jsx-runtime").JSX.Element | null | undefined;
@@ -0,0 +1,31 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import React from "react";
3
+ import { matchPath } from "./path";
4
+ import PathParamsContext from "./PathParamsContext";
5
+ import Route from "./Route";
6
+ import useRouterContext from "./hooks/useRouterContext";
7
+ import { stripBasename } from "./href";
8
+ function findRouteElements(children) {
9
+ return children.filter(function (child) { return React.isValidElement(child) && child.type === Route; });
10
+ }
11
+ /**
12
+ * Nested within a router component, this component handles rendering the proper route.
13
+ * Note: sticking any other components besides routes in here will not be rendered
14
+ */
15
+ export default function Routes(_a) {
16
+ var rawChildren = _a.children, fallback = _a.fallback;
17
+ var router = useRouterContext("<Routes>");
18
+ var location = router.location, basename = router.basename;
19
+ var pathname = stripBasename(location.pathname, basename);
20
+ var children = Array.isArray(rawChildren) ? rawChildren : [rawChildren];
21
+ var routes = findRouteElements(children);
22
+ for (var _i = 0, routes_1 = routes; _i < routes_1.length; _i++) {
23
+ var routeElement = routes_1[_i];
24
+ var _b = routeElement.props, path = _b.path, element = _b.element;
25
+ var pathParams = matchPath(path, pathname);
26
+ if (pathParams) {
27
+ return (_jsx(PathParamsContext.Provider, { value: pathParams, children: element }));
28
+ }
29
+ }
30
+ return fallback;
31
+ }
@@ -0,0 +1,10 @@
1
+ import type { Location } from "./types";
2
+ export declare function getCurrentLocation(): Location;
3
+ type LocationListener = (location: Location) => void;
4
+ export declare function createHistory(): {
5
+ readonly push: (to: string) => void;
6
+ readonly addListener: (listener: LocationListener) => () => void;
7
+ readonly cleanup: () => void;
8
+ };
9
+ export type History = ReturnType<typeof createHistory>;
10
+ export {};
@@ -0,0 +1,46 @@
1
+ export function getCurrentLocation() {
2
+ return {
3
+ pathname: window.location.pathname,
4
+ search: window.location.search,
5
+ hash: window.location.hash,
6
+ };
7
+ }
8
+ export function createHistory() {
9
+ var listeners = new Set();
10
+ var notifyListeners = function () {
11
+ var location = getCurrentLocation();
12
+ listeners.forEach(function (listener) { return listener(location); });
13
+ };
14
+ var listening = false;
15
+ var startListening = function () {
16
+ if (listening)
17
+ return;
18
+ window.addEventListener("popstate", notifyListeners);
19
+ listening = true;
20
+ };
21
+ var stopListening = function () {
22
+ if (!listening)
23
+ return;
24
+ window.removeEventListener("popstate", notifyListeners);
25
+ listening = false;
26
+ };
27
+ return {
28
+ push: function (to) {
29
+ window.history.pushState(null, "", to);
30
+ notifyListeners();
31
+ },
32
+ addListener: function (listener) {
33
+ startListening();
34
+ listeners.add(listener);
35
+ return function () {
36
+ listeners.delete(listener);
37
+ if (listeners.size === 0)
38
+ stopListening();
39
+ };
40
+ },
41
+ cleanup: function () {
42
+ stopListening();
43
+ listeners.clear();
44
+ },
45
+ };
46
+ }
@@ -0,0 +1,7 @@
1
+ import type { Location } from "../types";
2
+ /**
3
+ * Get the current location (can only be used within a Router)
4
+ *
5
+ * @returns the current location
6
+ */
7
+ export default function useLocation(): Location;
@@ -0,0 +1,10 @@
1
+ import useRouterContext from "./useRouterContext";
2
+ /**
3
+ * Get the current location (can only be used within a Router)
4
+ *
5
+ * @returns the current location
6
+ */
7
+ export default function useLocation() {
8
+ var location = useRouterContext("useLocation()").location;
9
+ return location;
10
+ }
@@ -0,0 +1,7 @@
1
+ import type { Navigate } from "../types";
2
+ /**
3
+ * Get a navigate function (can only be used within a Router)
4
+ *
5
+ * @returns a navigate function
6
+ */
7
+ export default function useNavigate(): Navigate;
@@ -0,0 +1,10 @@
1
+ import useRouterContext from "./useRouterContext";
2
+ /**
3
+ * Get a navigate function (can only be used within a Router)
4
+ *
5
+ * @returns a navigate function
6
+ */
7
+ export default function useNavigate() {
8
+ var navigate = useRouterContext("useNavigate()").navigate;
9
+ return navigate;
10
+ }
@@ -0,0 +1,8 @@
1
+ import type { PathParams } from "../types";
2
+ /**
3
+ * Get the params from the current pathname
4
+ *
5
+ * @returns the params from the current path
6
+ * e.g. `{id: "1"}` for `/movie/:id <=> /movie/1`
7
+ */
8
+ export default function usePathParams(): PathParams;
@@ -0,0 +1,15 @@
1
+ import React from "react";
2
+ import PathParamsContext from "../PathParamsContext";
3
+ /**
4
+ * Get the params from the current pathname
5
+ *
6
+ * @returns the params from the current path
7
+ * e.g. `{id: "1"}` for `/movie/:id <=> /movie/1`
8
+ */
9
+ export default function usePathParams() {
10
+ var params = React.useContext(PathParamsContext);
11
+ if (!params) {
12
+ throw new Error("usePathParams() must be used inside of a <Router> component");
13
+ }
14
+ return params;
15
+ }
@@ -0,0 +1,5 @@
1
+ export default function useRouterContext(name: string): {
2
+ location: import("../types").Location;
3
+ navigate: import("../types").Navigate;
4
+ basename: string;
5
+ };
@@ -0,0 +1,9 @@
1
+ import React from "react";
2
+ import RouterContext from "../RouterContext";
3
+ export default function useRouterContext(name) {
4
+ var routerContext = React.useContext(RouterContext);
5
+ if (!routerContext) {
6
+ throw new Error("".concat(name, " must be used inside of a <Router> component"));
7
+ }
8
+ return routerContext;
9
+ }
@@ -0,0 +1,2 @@
1
+ import type { SearchParams, SetSearchParams } from "../types";
2
+ export default function useSearchParams(): [SearchParams, SetSearchParams];
@@ -0,0 +1,47 @@
1
+ import React from "react";
2
+ import useRouterContext from "./useRouterContext";
3
+ function deserialize(search) {
4
+ var urlSearchParams = new URLSearchParams(search);
5
+ var searchParams = {};
6
+ urlSearchParams.forEach(function (value, key) {
7
+ var existing = searchParams[key];
8
+ if (existing === undefined) {
9
+ searchParams[key] = value;
10
+ }
11
+ else if (Array.isArray(existing)) {
12
+ existing.push(value);
13
+ }
14
+ else {
15
+ searchParams[key] = [existing, value];
16
+ }
17
+ });
18
+ return searchParams;
19
+ }
20
+ function serialize(params) {
21
+ var urlSearchParams = new URLSearchParams();
22
+ Object.entries(params).forEach(function (_a) {
23
+ var key = _a[0], value = _a[1];
24
+ if (value !== undefined) {
25
+ if (Array.isArray(value)) {
26
+ value.forEach(function (subvalue) { return urlSearchParams.append(key, subvalue); });
27
+ }
28
+ else {
29
+ urlSearchParams.set(key, value);
30
+ }
31
+ }
32
+ });
33
+ var stringified = urlSearchParams.toString();
34
+ return stringified ? "?".concat(stringified) : "";
35
+ }
36
+ export default function useSearchParams() {
37
+ var router = useRouterContext("useSearchParams()");
38
+ var location = router.location, navigate = router.navigate;
39
+ var pathname = location.pathname, hash = location.hash, search = location.search;
40
+ var params = React.useMemo(function () { return deserialize(search); }, [search]);
41
+ var setSearchParams = React.useCallback(function (next) {
42
+ var nextParams = typeof next === "function" ? next(params) : next;
43
+ var url = pathname + serialize(nextParams) + hash;
44
+ navigate(url);
45
+ }, [navigate, pathname, hash, params]);
46
+ return [params, setSearchParams];
47
+ }
@@ -0,0 +1,8 @@
1
+ export type Href = {
2
+ type: "internal" | "external" | "octo" | "unknown";
3
+ url: string;
4
+ };
5
+ export declare function getHref(to: string, pathname: string, normalizedBasename: string): Href;
6
+ export declare function normalizeBasename(basename: string): string;
7
+ export declare function isExternal(to: string): boolean;
8
+ export declare function stripBasename(pathname: string, basename: string): string;
package/router/href.js ADDED
@@ -0,0 +1,43 @@
1
+ import { popSlash, prependSlash } from "./string";
2
+ // computes href given to, current pathname, and optional basename
3
+ export function getHref(to, pathname, normalizedBasename) {
4
+ // external
5
+ if (isExternal(to))
6
+ return { type: "external", url: to };
7
+ // hash only
8
+ if (to.startsWith("#"))
9
+ return { type: "octo", url: to };
10
+ var type = "internal";
11
+ // absolute
12
+ if (to.startsWith("/")) {
13
+ return { type: type, url: normalizedBasename + to };
14
+ }
15
+ // relative
16
+ pathname = stripBasename(prependSlash(pathname), normalizedBasename);
17
+ if (!to || to.startsWith("#"))
18
+ return { type: type, url: normalizedBasename + pathname + to };
19
+ return {
20
+ type: type,
21
+ url: normalizedBasename + popSlash(pathname) + prependSlash(to),
22
+ };
23
+ }
24
+ // formats with a starting slash and removes trailing slash
25
+ export function normalizeBasename(basename) {
26
+ if (!basename || basename === "/")
27
+ return "";
28
+ return prependSlash(popSlash(basename));
29
+ }
30
+ // simple heuristic check
31
+ export function isExternal(to) {
32
+ return /^(https?:\/\/|mailto:|tel:)/i.test(to);
33
+ }
34
+ export function stripBasename(pathname, basename) {
35
+ if (!basename)
36
+ return pathname;
37
+ if (pathname === basename)
38
+ return "/";
39
+ if (pathname.startsWith(basename + "/")) {
40
+ return pathname.slice(basename.length);
41
+ }
42
+ return pathname;
43
+ }
@@ -0,0 +1,7 @@
1
+ export { default as useLocation } from "./hooks/useLocation";
2
+ export { default as useNavigate } from "./hooks/useNavigate";
3
+ export { default as usePathParams } from "./hooks/usePathParams";
4
+ export { default as useSearchParams } from "./hooks/useSearchParams";
5
+ export { default as Router } from "./Router";
6
+ export { default as Route } from "./Route";
7
+ export { default as Routes } from "./Routes";
@@ -0,0 +1,7 @@
1
+ export { default as useLocation } from "./hooks/useLocation";
2
+ export { default as useNavigate } from "./hooks/useNavigate";
3
+ export { default as usePathParams } from "./hooks/usePathParams";
4
+ export { default as useSearchParams } from "./hooks/useSearchParams";
5
+ export { default as Router } from "./Router";
6
+ export { default as Route } from "./Route";
7
+ export { default as Routes } from "./Routes";
@@ -0,0 +1,2 @@
1
+ import type { PathParams } from "./types";
2
+ export declare function matchPath(pattern: string, pathname: string): PathParams | false;
package/router/path.js ADDED
@@ -0,0 +1,38 @@
1
+ import { popSlash, prependSlash } from "./string";
2
+ function normalizePath(path) {
3
+ path = prependSlash(path);
4
+ if (path.length > 1) {
5
+ path = popSlash(path);
6
+ }
7
+ return path;
8
+ }
9
+ // false == no match
10
+ export function matchPath(pattern, pathname) {
11
+ var normalizedPattern = normalizePath(pattern);
12
+ var normalizedPathname = normalizePath(pathname);
13
+ if (!normalizedPattern.includes(":")) {
14
+ return normalizedPattern === normalizedPathname ? {} : false;
15
+ }
16
+ var patternSegments = normalizedPattern.split("/").filter(Boolean);
17
+ var pathSegments = normalizedPathname.split("/").filter(Boolean);
18
+ if (patternSegments.length !== pathSegments.length) {
19
+ return false;
20
+ }
21
+ var params = {};
22
+ for (var i = 0; i < patternSegments.length; i++) {
23
+ var patternSegment = patternSegments[i];
24
+ var pathSegment = pathSegments[i];
25
+ // dynamic
26
+ if (patternSegment.startsWith(":")) {
27
+ var paramName = patternSegment.slice(1).trim();
28
+ if (!paramName)
29
+ return false;
30
+ params[paramName] = pathSegment;
31
+ }
32
+ // static
33
+ else if (patternSegment !== pathSegment) {
34
+ return false;
35
+ }
36
+ }
37
+ return params;
38
+ }
@@ -0,0 +1,2 @@
1
+ export declare function prependSlash(str: string): string;
2
+ export declare function popSlash(str: string): string;
@@ -0,0 +1,6 @@
1
+ export function prependSlash(str) {
2
+ return str.startsWith("/") ? str : "/".concat(str);
3
+ }
4
+ export function popSlash(str) {
5
+ return str.replace(/\/$/, "");
6
+ }
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Location object of the current URL.
3
+ */
4
+ export type Location = {
5
+ /** URL pathname (e.g. "/movies/123") */
6
+ pathname: string;
7
+ /** URL search (e.g. "?q=inception") */
8
+ search: string;
9
+ /** URL hash (e.g. "#home") */
10
+ hash: string;
11
+ };
12
+ /**
13
+ * A function to handle page navigation
14
+ */
15
+ export type Navigate = (to: string) => void;
16
+ /**
17
+ * Object containing params from the pathname
18
+ * e.g. `{id: "1"}` for `/movie/:id <=> /movie/1`
19
+ */
20
+ export type PathParams = {
21
+ [key: string]: string | undefined;
22
+ };
23
+ /**
24
+ * Object containing params from the search string
25
+ * e.g. `{id: "1", movies: ["inception", "alien"]}` for `"?id=1&movies=inception&movies=alien"`
26
+ */
27
+ export type SearchParams = {
28
+ [key: string]: string | string[] | undefined;
29
+ };
30
+ /** Callback or object to update search params */
31
+ export type SetSearchParamsArg = SearchParams | ((prev: SearchParams) => SearchParams);
32
+ /** Callback to update search params and reload relevant hooks */
33
+ export type SetSearchParams = (next: SetSearchParamsArg) => void;
@@ -0,0 +1 @@
1
+ export {};
package/style.css CHANGED
@@ -1 +1 @@
1
- :root{--aui-xxs: 2px;--aui-xs: 4px;--aui-s: 8px;--aui-m: 16px;--aui-l: 24px;--aui-xl: 32px;--aui-xxl: 64px;--aui-moon-gray: #ccc;--aui-dark-gray: #555;--aui-darkest-gray: #333;--aui-obsidian: #121212;--aui-focus-ring-color: #b2dbfa;--aui-color-default: black;--aui-color-muted: var(--aui-dark-gray);--aui-default-background: white;--aui-default-border: var(--aui-moon-gray);--aui-opacity-disabled: 0.5;--aui-opacity-dim: 0.75;--aui-default-transition: 0.25s ease-in-out;--aui-floating-box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);--aui-radius-none: 0;--aui-radius-subtle: 4px;--aui-radius-rounded: 8px;--aui-radius-max: 10000px;--aui-button-primary-background: black;--aui-button-primary-color: white;--aui-button-secondary-border-hover: var(--aui-darkest-gray);--aui-subtle-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.16);--aui-button-primary-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.36);--aui-success-background: #dff2e1;--aui-success-color: #1b5e20;--aui-success-border: #b2dfb1;--aui-warning-background: #fceeb6;--aui-warning-color: #b23904;--aui-warning-border: #e6d5a2;--aui-error-background: #fdecea;--aui-error-color: #b71c1c;--aui-error-border: #f5b7b7;--aui-info-background: #e3f2fd;--aui-info-color: #0d47a1;--aui-info-border: #90caf9;--aui-avatar-purple: #bc54d6;--aui-avatar-blue: #618bdc;--aui-avatar-red: #ee6060;--aui-avatar-green: #add386;--aui-avatar-yellow: #f5c76d;--aui-static-background: #e8e8e8;--aui-static-color: var(--aui-color-default);--aui-static-border: var(--aui-default-border);--aui-layer-backdrop-background: rgba(200, 200, 200, 0.6);--aui-link-color: #0070ff}[data-theme=dark]{--aui-focus-ring-color: #6699cc;--aui-color-default: white;--aui-color-muted: var(--aui-moon-gray);--aui-default-background: var(--aui-obsidian);--aui-default-border: var(--aui-dark-gray);--aui-floating-box-shadow: 0 4px 12px rgba(0, 0, 0, 0.5);--aui-button-primary-background: white;--aui-button-primary-color: var(--aui-obsidian);--aui-button-secondary-border-hover: var(--aui-moon-gray);--aui-subtle-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.4);--aui-button-primary-box-shadow: 0 1px 2px rgba(64, 64, 64, 0.8);--aui-success-background: #2a5733;--aui-success-color: #d9efd8;--aui-success-border: #439e4a;--aui-warning-background: #736230;--aui-warning-color: #fff6d1;--aui-warning-border: #927a3b;--aui-error-background: #663232;--aui-error-color: #f9dadc;--aui-error-border: #8d2a2a;--aui-info-background: #335f72;--aui-info-color: #d4f1f5;--aui-info-border: #1d8ea4;--aui-static-background: var(--aui-darkest-gray);--aui-static-color: var(--aui-color-default);--aui-static-border: var(--aui-default-border);--aui-avatar-purple: #771199;--aui-avatar-blue: #0b4cce;--aui-avatar-red: #bb1111;--aui-avatar-green: #307040;--aui-avatar-yellow: #bb8822;--aui-layer-backdrop-background: rgba(55, 55, 55, 0.7);--aui-link-color: #33bfff}*{box-sizing:border-box}html{font-family:system-ui,"Helvetica Neue",Helvetica,Arial,sans-serif;-webkit-text-size-adjust:100%;line-height:1.15;tab-size:4;-webkit-font-smoothing:antialiased}body{margin:0}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0}.aui-content-success{background-color:var(--aui-success-background);color:var(--aui-success-color);border-color:var(--aui-success-border)}.aui-content-warning{background-color:var(--aui-warning-background);color:var(--aui-warning-color);border-color:var(--aui-warning-border)}.aui-content-error{background-color:var(--aui-error-background);color:var(--aui-error-color);border-color:var(--aui-error-border)}.aui-content-info{background-color:var(--aui-info-background);color:var(--aui-info-color);border-color:var(--aui-info-border)}.aui-content-static{background-color:var(--aui-static-background);color:var(--aui-static-color);border-color:var(--aui-static-border)}.aui-alert,.aui-badge{border-style:solid;border-width:1px}.aui-action{color:inherit;text-decoration:none;cursor:pointer;outline-color:var(--aui-link-color)}.aui-action:focus:not(:focus-visible){outline:none}.aui-button{background:none;border:none;padding:0}.aui-button:disabled{cursor:default !important;opacity:var(--aui-opacity-disabled)}.aui-button-primary{background-color:var(--aui-button-primary-background);border:1px solid var(--aui-button-primary-background);color:var(--aui-button-primary-color);box-shadow:var(--aui-button-primary-box-shadow);transition:opacity var(--aui-default-transition)}.aui-button-secondary{color:var(--aui-color-default);background-color:var(--aui-default-background);border:1px solid var(--aui-default-border);box-shadow:var(--aui-subtle-box-shadow);transition:border var(--aui-default-transition)}.aui-dim,.aui-undim{transition:opacity var(--aui-default-transition)}.aui-dim{opacity:1}.aui-undim{opacity:var(--aui-opacity-dim)}.aui-link{color:var(--aui-link-color);transition:opacity var(--aui-default-transition)}@media(hover: hover){.aui-button-primary:not([disabled]):hover,.aui-dim:not([disabled]):hover,.aui-link:hover{opacity:var(--aui-opacity-dim)}.aui-button-secondary:not([disabled]):hover{border-color:var(--aui-button-secondary-border-hover)}.aui-undim:not([disabled]):hover{opacity:1}}.aui-input-base{outline:none;border:none;background-color:inherit;color:inherit;padding:var(--aui-s);font-weight:400}.aui-input-base::selection{background-color:var(--aui-focus-ring-color)}.aui-input,.aui-select-container{transition:box-shadow var(--aui-default-transition);border:1px solid var(--aui-default-border);box-shadow:var(--aui-subtle-box-shadow);background-color:var(--aui-default-background)}.aui-input:disabled{opacity:var(--aui-opacity-disabled);cursor:default}.aui-input:not([disabled]):focus-within,.aui-select-container:not([disabled]):focus-within{box-shadow:var(--aui-subtle-box-shadow),0 0 0 3px var(--aui-focus-ring-color)}.aui-select{width:100%;color:inherit;border:none;outline:none;box-shadow:none;cursor:pointer;background-color:rgba(0,0,0,0);padding:var(--aui-s) 28px var(--aui-s) var(--aui-s);font-weight:600;appearance:none;-webkit-appearance:none;-moz-appearance:none}.aui-select-disabled *{opacity:var(--aui-opacity-disabled);cursor:default}.aui-layer-backdrop{position:fixed;top:0;left:0;width:100vw;height:100vh;background:var(--aui-layer-backdrop-background)}.aui-icon *{color:currentColor;fill:currentColor}.aui-spinner{animation:aui-spinner-animation 1s linear infinite;transform-origin:center;height:var(--aui-l)}@keyframes aui-spinner-animation{0%{transform:rotate(0deg)}100%{transform:rotate(360deg)}}.aui-carousel-item{flex:0 0 100%}.aui-carousel-arrow{position:absolute;top:50%;transform:translateY(-50%);width:var(--aui-l);height:var(--aui-l)}.aui-carousel-dots{position:absolute;bottom:var(--aui-s);transform:translateX(-50%);left:50%}.aui-carousel-dot{width:var(--aui-m);height:var(--aui-s)}.aui-pos-static{position:static}.aui-pos-relative{position:relative}.aui-pos-absolute{position:absolute}.aui-pos-fixed{position:fixed}.aui-pos-sticky{position:sticky}.aui-flex-x{display:flex;flex-direction:row}.aui-flex-y{display:flex;flex-direction:column}.aui-flex--x{display:flex;flex-direction:row-reverse}.aui-flex--y{display:flex;flex-direction:column-reverse}.aui-flex-wrap{flex-wrap:wrap}.aui-align-start{align-items:flex-start}.aui-align-center{align-items:center}.aui-align-end{align-items:flex-end}.aui-justify-start{justify-content:flex-start}.aui-justify-center{justify-content:center}.aui-justify-end{justify-content:flex-end}.aui-justify-between{justify-content:space-between}.aui-justify-around{justify-content:space-around}.aui-avatar-red{background-color:var(--aui-avatar-red)}.aui-avatar-yellow{background-color:var(--aui-avatar-yellow)}.aui-avatar-green{background-color:var(--aui-avatar-green)}.aui-avatar-blue{background-color:var(--aui-avatar-blue)}.aui-avatar-purple{background-color:var(--aui-avatar-purple)}.aui-avatar-xxs{width:12px;height:12px;line-height:12px;font-size:9.6px}.aui-avatar-xs{width:16px;height:16px;line-height:16px;font-size:12.8px}.aui-avatar-s{width:24px;height:24px;line-height:24px;font-size:19.2px}.aui-avatar-m{width:32px;height:32px;line-height:32px;font-size:25.6px}.aui-avatar-l{width:48px;height:48px;line-height:48px;font-size:38.4px}.aui-avatar-xl{width:64px;height:64px;line-height:64px;font-size:51.2px}.aui-avatar-xxl{width:128px;height:128px;line-height:128px;font-size:102.4px}.aui-icon-xxs{width:8px;height:8px}.aui-icon-xs{width:12px;height:12px}.aui-icon-s{width:16px;height:16px}.aui-icon-m{width:24px;height:24px}.aui-icon-l{width:32px;height:32px}.aui-icon-xl{width:48px;height:48px}.aui-icon-xxl{width:64px;height:64px}.aui-pa-none{padding:0}.aui-pa-xxs{padding:var(--aui-xxs)}.aui-pa-xs{padding:var(--aui-xs)}.aui-pa-s{padding:var(--aui-s)}.aui-pa-m{padding:var(--aui-m)}.aui-pa-l{padding:var(--aui-l)}.aui-pa-xl{padding:var(--aui-xl)}.aui-pa-xxl{padding:var(--aui-xxl)}.aui-pt-none{padding-top:0}.aui-pt-xxs{padding-top:var(--aui-xxs)}.aui-pt-xs{padding-top:var(--aui-xs)}.aui-pt-s{padding-top:var(--aui-s)}.aui-pt-m{padding-top:var(--aui-m)}.aui-pt-l{padding-top:var(--aui-l)}.aui-pt-xl{padding-top:var(--aui-xl)}.aui-pt-xxl{padding-top:var(--aui-xxl)}.aui-pb-none{padding-bottom:0}.aui-pb-xxs{padding-bottom:var(--aui-xxs)}.aui-pb-xs{padding-bottom:var(--aui-xs)}.aui-pb-s{padding-bottom:var(--aui-s)}.aui-pb-m{padding-bottom:var(--aui-m)}.aui-pb-l{padding-bottom:var(--aui-l)}.aui-pb-xl{padding-bottom:var(--aui-xl)}.aui-pb-xxl{padding-bottom:var(--aui-xxl)}.aui-pl-none{padding-left:0}.aui-pl-xxs{padding-left:var(--aui-xxs)}.aui-pl-xs{padding-left:var(--aui-xs)}.aui-pl-s{padding-left:var(--aui-s)}.aui-pl-m{padding-left:var(--aui-m)}.aui-pl-l{padding-left:var(--aui-l)}.aui-pl-xl{padding-left:var(--aui-xl)}.aui-pl-xxl{padding-left:var(--aui-xxl)}.aui-pr-none{padding-right:0}.aui-pr-xxs{padding-right:var(--aui-xxs)}.aui-pr-xs{padding-right:var(--aui-xs)}.aui-pr-s{padding-right:var(--aui-s)}.aui-pr-m{padding-right:var(--aui-m)}.aui-pr-l{padding-right:var(--aui-l)}.aui-pr-xl{padding-right:var(--aui-xl)}.aui-pr-xxl{padding-right:var(--aui-xxl)}.aui-ma-auto{margin:auto}.aui-ma-none{margin:0}.aui-ma-xxs{margin:var(--aui-xxs)}.aui-ma-xs{margin:var(--aui-xs)}.aui-ma-s{margin:var(--aui-s)}.aui-ma-m{margin:var(--aui-m)}.aui-ma-l{margin:var(--aui-l)}.aui-ma-xl{margin:var(--aui-xl)}.aui-ma-xxl{margin:var(--aui-xxl)}.aui-mt-auto{margin-top:auto}.aui-mt-none{margin-top:0}.aui-mt-xxs{margin-top:var(--aui-xxs)}.aui-mt-xs{margin-top:var(--aui-xs)}.aui-mt-s{margin-top:var(--aui-s)}.aui-mt-m{margin-top:var(--aui-m)}.aui-mt-l{margin-top:var(--aui-l)}.aui-mt-xl{margin-top:var(--aui-xl)}.aui-mt-xxl{margin-top:var(--aui-xxl)}.aui-mb-auto{margin-bottom:auto}.aui-mb-none{margin-bottom:0}.aui-mb-xxs{margin-bottom:var(--aui-xxs)}.aui-mb-xs{margin-bottom:var(--aui-xs)}.aui-mb-s{margin-bottom:var(--aui-s)}.aui-mb-m{margin-bottom:var(--aui-m)}.aui-mb-l{margin-bottom:var(--aui-l)}.aui-mb-xl{margin-bottom:var(--aui-xl)}.aui-mb-xxl{margin-bottom:var(--aui-xxl)}.aui-ml-auto{margin-left:auto}.aui-ml-none{margin-left:0}.aui-ml-xxs{margin-left:var(--aui-xxs)}.aui-ml-xs{margin-left:var(--aui-xs)}.aui-ml-s{margin-left:var(--aui-s)}.aui-ml-m{margin-left:var(--aui-m)}.aui-ml-l{margin-left:var(--aui-l)}.aui-ml-xl{margin-left:var(--aui-xl)}.aui-ml-xxl{margin-left:var(--aui-xxl)}.aui-mr-auto{margin-right:auto}.aui-mr-none{margin-right:0}.aui-mr-xxs{margin-right:var(--aui-xxs)}.aui-mr-xs{margin-right:var(--aui-xs)}.aui-mr-s{margin-right:var(--aui-s)}.aui-mr-m{margin-right:var(--aui-m)}.aui-mr-l{margin-right:var(--aui-l)}.aui-mr-xl{margin-right:var(--aui-xl)}.aui-mr-xxl{margin-right:var(--aui-xxl)}.aui-gap-none{gap:0}.aui-gap-xxs{gap:var(--aui-xxs)}.aui-gap-xs{gap:var(--aui-xs)}.aui-gap-s{gap:var(--aui-s)}.aui-gap-m{gap:var(--aui-m)}.aui-gap-l{gap:var(--aui-l)}.aui-gap-xl{gap:var(--aui-xl)}.aui-gap-xxl{gap:var(--aui-xxl)}.aui-w-full{width:100%}.aui-w-fit{width:fit-content}.aui-w-min{width:min-content}.aui-w-max{width:max-content}.aui-mw-full{max-width:100%}.aui-mw-fit{max-width:fit-content}.aui-mw-min{max-width:min-content}.aui-mw-max{max-width:max-content}.aui-h-full{height:100%}.aui-h-fit{height:fit-content}.aui-h-min{height:min-content}.aui-h-max{height:max-content}.aui-mh-full{max-height:100%}.aui-mh-fit{max-height:fit-content}.aui-mh-min{max-height:min-content}.aui-mh-max{max-height:max-content}.aui-radius-none{border-radius:var(--aui-radius-none)}.aui-radius-subtle{border-radius:var(--aui-radius-subtle)}.aui-radius-rounded{border-radius:var(--aui-radius-rounded)}.aui-radius-max{border-radius:var(--aui-radius-max)}.aui-ba{border:1px solid var(--aui-default-border)}.aui-bt{border-top:1px solid var(--aui-default-border)}.aui-br{border-right:1px solid var(--aui-default-border)}.aui-bb{border-bottom:1px solid var(--aui-default-border)}.aui-bl{border-left:1px solid var(--aui-default-border)}.aui-bw-none{border-width:0px}.aui-bw-xs{border-width:1px}.aui-bw-s{border-width:2px}.aui-bw-m{border-width:4px}.aui-bw-l{border-width:8px}.aui-bw-xl{border-width:16px}.aui-bs-solid{border-style:solid}.aui-bs-dotted{border-style:dotted}.aui-bs-dashed{border-style:dashed}.aui-bs-none{border-style:none}.aui-bc-default{border-color:var(--aui-default-border)}.aui-bc-primary{border-color:var(--aui-color-default)}.aui-shadow-subtle{box-shadow:var(--aui-subtle-box-shadow)}.aui-shadow-floating{box-shadow:var(--aui-floating-box-shadow)}.aui-shadow-none{box-shadow:none}.aui-op-none{opacity:0}.aui-op-disabled{opacity:var(--aui-opacity-disabled)}.aui-op-dim{opacity:var(--aui-opacity-dim)}.aui-op-full{opacity:1}.aui-f-xxs{font-size:10px}.aui-f-xs{font-size:12px}.aui-f-s{font-size:14px}.aui-f-default{font-size:16px}.aui-f-m{font-size:20px}.aui-f-l{font-size:24px}.aui-f-xl{font-size:32px}.aui-f-xxl{font-size:48px}.aui-fw-1{font-weight:100}.aui-fw-2{font-weight:200}.aui-fw-3{font-weight:300}.aui-fw-4{font-weight:400}.aui-fw-5{font-weight:500}.aui-fw-6{font-weight:600}.aui-fw-7{font-weight:700}.aui-fw-8{font-weight:800}.aui-fw-9{font-weight:900}.aui-ta-left{text-align:left}.aui-ta-right{text-align:right}.aui-ta-center{text-align:center}.aui-it{font-style:italic}.aui-c-default{color:var(--aui-color-default)}.aui-c-muted{color:var(--aui-color-muted)}.aui-c-inherit{color:inherit}.aui-c-transparent{color:rgba(0,0,0,0)}.aui-bg-default{background-color:var(--aui-default-background)}.aui-bg-muted{background-color:var(--aui-static-background)}.aui-bg-inherit{background-color:inherit}.aui-bg-transparent{background-color:rgba(0,0,0,0)}.aui-ov-scroll{overflow:scroll}.aui-ov-x-scroll{overflow-x:scroll}.aui-ov-y-scroll{overflow-y:scroll}.aui-ov-hidden{overflow:hidden}.aui-ov-x-hidden{overflow-x:hidden}.aui-ov-y-hidden{overflow-y:hidden}.aui-z-auto{z-index:auto}.aui-z-floating{z-index:100}.aui-z-nav{z-index:1000}.aui-z-max{z-index:10000}.aui-cursor-auto{cursor:auto}.aui-cursor-pointer{cursor:pointer}.aui-select-icon{--size: 10px;color:var(--aui-color-muted);width:var(--size);height:var(--size);position:absolute;top:calc(50% + 1px);transform:translateY(-50%);right:var(--size);pointer-events:none}
1
+ :root{--aui-xxs: 2px;--aui-xs: 4px;--aui-s: 8px;--aui-m: 16px;--aui-l: 24px;--aui-xl: 32px;--aui-xxl: 64px;--aui-moon-gray: #ccc;--aui-dark-gray: #555;--aui-darkest-gray: #333;--aui-obsidian: #121212;--aui-focus-ring-color: #b2dbfa;--aui-color-default: black;--aui-color-muted: var(--aui-dark-gray);--aui-default-background: white;--aui-default-border: var(--aui-moon-gray);--aui-opacity-disabled: 0.5;--aui-opacity-dim: 0.75;--aui-default-transition: 0.25s ease-in-out;--aui-floating-box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);--aui-radius-none: 0;--aui-radius-subtle: 4px;--aui-radius-rounded: 8px;--aui-radius-max: 10000px;--aui-button-primary-background: black;--aui-button-primary-color: white;--aui-button-secondary-border-hover: var(--aui-darkest-gray);--aui-subtle-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.16);--aui-button-primary-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.36);--aui-success-background: #dff2e1;--aui-success-color: #1b5e20;--aui-success-border: #b2dfb1;--aui-warning-background: #fceeb6;--aui-warning-color: #b23904;--aui-warning-border: #e6d5a2;--aui-error-background: #fdecea;--aui-error-color: #b71c1c;--aui-error-border: #f5b7b7;--aui-info-background: #e3f2fd;--aui-info-color: #0d47a1;--aui-info-border: #90caf9;--aui-avatar-purple: #bc54d6;--aui-avatar-blue: #618bdc;--aui-avatar-red: #ee6060;--aui-avatar-green: #add386;--aui-avatar-yellow: #f5c76d;--aui-static-background: #e8e8e8;--aui-static-color: var(--aui-color-default);--aui-static-border: var(--aui-default-border);--aui-layer-backdrop-background: rgba(200, 200, 200, 0.6);--aui-link-color: #0070ff}[data-theme=dark]{--aui-focus-ring-color: #6699cc;--aui-color-default: white;--aui-color-muted: var(--aui-moon-gray);--aui-default-background: var(--aui-obsidian);--aui-default-border: var(--aui-dark-gray);--aui-floating-box-shadow: 0 4px 12px rgba(0, 0, 0, 0.5);--aui-button-primary-background: white;--aui-button-primary-color: var(--aui-obsidian);--aui-button-secondary-border-hover: var(--aui-moon-gray);--aui-subtle-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.4);--aui-button-primary-box-shadow: 0 1px 2px rgba(64, 64, 64, 0.8);--aui-success-background: #2a5733;--aui-success-color: #d9efd8;--aui-success-border: #439e4a;--aui-warning-background: #736230;--aui-warning-color: #fff6d1;--aui-warning-border: #927a3b;--aui-error-background: #663232;--aui-error-color: #f9dadc;--aui-error-border: #8d2a2a;--aui-info-background: #335f72;--aui-info-color: #d4f1f5;--aui-info-border: #1d8ea4;--aui-static-background: var(--aui-darkest-gray);--aui-static-color: var(--aui-color-default);--aui-static-border: var(--aui-default-border);--aui-avatar-purple: #771199;--aui-avatar-blue: #0b4cce;--aui-avatar-red: #bb1111;--aui-avatar-green: #307040;--aui-avatar-yellow: #bb8822;--aui-layer-backdrop-background: rgba(55, 55, 55, 0.7);--aui-link-color: #33bfff}*{box-sizing:border-box}html{font-family:system-ui,"Helvetica Neue",Helvetica,Arial,sans-serif;-webkit-text-size-adjust:100%;line-height:1.15;tab-size:4;-webkit-font-smoothing:antialiased}body{margin:0}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0}.aui-content-success{background-color:var(--aui-success-background);color:var(--aui-success-color);border-color:var(--aui-success-border)}.aui-content-warning{background-color:var(--aui-warning-background);color:var(--aui-warning-color);border-color:var(--aui-warning-border)}.aui-content-error{background-color:var(--aui-error-background);color:var(--aui-error-color);border-color:var(--aui-error-border)}.aui-content-info{background-color:var(--aui-info-background);color:var(--aui-info-color);border-color:var(--aui-info-border)}.aui-content-static{background-color:var(--aui-static-background);color:var(--aui-static-color);border-color:var(--aui-static-border)}.aui-alert,.aui-badge{border-style:solid;border-width:1px}.aui-action{color:inherit;text-decoration:none;cursor:pointer;outline-color:var(--aui-link-color)}.aui-action:focus:not(:focus-visible){outline:none}.aui-button{background:none;border:none;padding:0}.aui-button:disabled{cursor:default !important;opacity:var(--aui-opacity-disabled)}.aui-button-primary{background-color:var(--aui-button-primary-background);border:1px solid var(--aui-button-primary-background);color:var(--aui-button-primary-color);box-shadow:var(--aui-button-primary-box-shadow);transition:opacity var(--aui-default-transition)}.aui-button-secondary{color:var(--aui-color-default);background-color:var(--aui-default-background);border:1px solid var(--aui-default-border);box-shadow:var(--aui-subtle-box-shadow);transition:border var(--aui-default-transition)}.aui-dim,.aui-undim{transition:opacity var(--aui-default-transition)}.aui-dim{opacity:1}.aui-undim{opacity:var(--aui-opacity-dim)}.aui-link{color:var(--aui-link-color);transition:opacity var(--aui-default-transition)}@media(hover: hover){.aui-button-primary:not([disabled]):hover,.aui-dim:not([disabled]):hover,.aui-link:hover{opacity:var(--aui-opacity-dim)}.aui-button-secondary:not([disabled]):hover{border-color:var(--aui-button-secondary-border-hover)}.aui-undim:not([disabled]):hover{opacity:1}}.aui-input-base{outline:none;border:none;background-color:inherit;color:inherit;padding:var(--aui-s);font-weight:400}.aui-input-base::selection{background-color:var(--aui-focus-ring-color)}.aui-input,.aui-select-container{transition:box-shadow var(--aui-default-transition);border:1px solid var(--aui-default-border);box-shadow:var(--aui-subtle-box-shadow);background-color:var(--aui-default-background)}.aui-input:disabled{opacity:var(--aui-opacity-disabled);cursor:default}.aui-input:not([disabled]):focus-within,.aui-select-container:not([disabled]):focus-within{box-shadow:var(--aui-subtle-box-shadow),0 0 0 3px var(--aui-focus-ring-color)}.aui-select{width:100%;color:inherit;border:none;outline:none;box-shadow:none;cursor:pointer;background-color:rgba(0,0,0,0);padding:var(--aui-s) 28px var(--aui-s) var(--aui-s);font-weight:600;appearance:none;-webkit-appearance:none;-moz-appearance:none}.aui-select-disabled *{opacity:var(--aui-opacity-disabled);cursor:default}.aui-layer-backdrop{position:fixed;top:0;left:0;width:100vw;height:100vh;background:var(--aui-layer-backdrop-background)}.aui-icon *{color:currentColor;fill:currentColor}.aui-spinner{animation:aui-spinner-animation 1s linear infinite;transform-origin:center;height:var(--aui-l)}@keyframes aui-spinner-animation{0%{transform:rotate(0deg)}100%{transform:rotate(360deg)}}.aui-carousel-arrow{position:absolute;top:50%;transform:translateY(-50%);width:var(--aui-l);height:var(--aui-l)}.aui-carousel-dots{position:absolute;bottom:var(--aui-s);transform:translateX(-50%);left:50%}.aui-carousel-dot{width:var(--aui-m);height:var(--aui-s)}.aui-pos-static{position:static}.aui-pos-relative{position:relative}.aui-pos-absolute{position:absolute}.aui-pos-fixed{position:fixed}.aui-pos-sticky{position:sticky}.aui-flex-x{display:flex;flex-direction:row}.aui-flex-y{display:flex;flex-direction:column}.aui-flex--x{display:flex;flex-direction:row-reverse}.aui-flex--y{display:flex;flex-direction:column-reverse}.aui-flex-wrap{flex-wrap:wrap}.aui-align-start{align-items:flex-start}.aui-align-center{align-items:center}.aui-align-end{align-items:flex-end}.aui-justify-start{justify-content:flex-start}.aui-justify-center{justify-content:center}.aui-justify-end{justify-content:flex-end}.aui-justify-between{justify-content:space-between}.aui-justify-around{justify-content:space-around}.aui-stretch-even{flex:1 1 0}.aui-stretch-grow{flex-grow:1}.aui-stretch-min{flex-shrink:1}.aui-stretch-max{flex:0 0 100%}.aui-avatar-red{background-color:var(--aui-avatar-red)}.aui-avatar-yellow{background-color:var(--aui-avatar-yellow)}.aui-avatar-green{background-color:var(--aui-avatar-green)}.aui-avatar-blue{background-color:var(--aui-avatar-blue)}.aui-avatar-purple{background-color:var(--aui-avatar-purple)}.aui-avatar-xxs{width:12px;height:12px;line-height:12px;font-size:9.6px}.aui-avatar-xs{width:16px;height:16px;line-height:16px;font-size:12.8px}.aui-avatar-s{width:24px;height:24px;line-height:24px;font-size:19.2px}.aui-avatar-m{width:32px;height:32px;line-height:32px;font-size:25.6px}.aui-avatar-l{width:48px;height:48px;line-height:48px;font-size:38.4px}.aui-avatar-xl{width:64px;height:64px;line-height:64px;font-size:51.2px}.aui-avatar-xxl{width:128px;height:128px;line-height:128px;font-size:102.4px}.aui-icon-xxs{width:8px;height:8px}.aui-icon-xs{width:12px;height:12px}.aui-icon-s{width:16px;height:16px}.aui-icon-m{width:24px;height:24px}.aui-icon-l{width:32px;height:32px}.aui-icon-xl{width:48px;height:48px}.aui-icon-xxl{width:64px;height:64px}.aui-pa-none{padding:0}.aui-pa-xxs{padding:var(--aui-xxs)}.aui-pa-xs{padding:var(--aui-xs)}.aui-pa-s{padding:var(--aui-s)}.aui-pa-m{padding:var(--aui-m)}.aui-pa-l{padding:var(--aui-l)}.aui-pa-xl{padding:var(--aui-xl)}.aui-pa-xxl{padding:var(--aui-xxl)}.aui-pt-none{padding-top:0}.aui-pt-xxs{padding-top:var(--aui-xxs)}.aui-pt-xs{padding-top:var(--aui-xs)}.aui-pt-s{padding-top:var(--aui-s)}.aui-pt-m{padding-top:var(--aui-m)}.aui-pt-l{padding-top:var(--aui-l)}.aui-pt-xl{padding-top:var(--aui-xl)}.aui-pt-xxl{padding-top:var(--aui-xxl)}.aui-pb-none{padding-bottom:0}.aui-pb-xxs{padding-bottom:var(--aui-xxs)}.aui-pb-xs{padding-bottom:var(--aui-xs)}.aui-pb-s{padding-bottom:var(--aui-s)}.aui-pb-m{padding-bottom:var(--aui-m)}.aui-pb-l{padding-bottom:var(--aui-l)}.aui-pb-xl{padding-bottom:var(--aui-xl)}.aui-pb-xxl{padding-bottom:var(--aui-xxl)}.aui-pl-none{padding-left:0}.aui-pl-xxs{padding-left:var(--aui-xxs)}.aui-pl-xs{padding-left:var(--aui-xs)}.aui-pl-s{padding-left:var(--aui-s)}.aui-pl-m{padding-left:var(--aui-m)}.aui-pl-l{padding-left:var(--aui-l)}.aui-pl-xl{padding-left:var(--aui-xl)}.aui-pl-xxl{padding-left:var(--aui-xxl)}.aui-pr-none{padding-right:0}.aui-pr-xxs{padding-right:var(--aui-xxs)}.aui-pr-xs{padding-right:var(--aui-xs)}.aui-pr-s{padding-right:var(--aui-s)}.aui-pr-m{padding-right:var(--aui-m)}.aui-pr-l{padding-right:var(--aui-l)}.aui-pr-xl{padding-right:var(--aui-xl)}.aui-pr-xxl{padding-right:var(--aui-xxl)}.aui-ma-auto{margin:auto}.aui-ma-none{margin:0}.aui-ma-xxs{margin:var(--aui-xxs)}.aui-ma-xs{margin:var(--aui-xs)}.aui-ma-s{margin:var(--aui-s)}.aui-ma-m{margin:var(--aui-m)}.aui-ma-l{margin:var(--aui-l)}.aui-ma-xl{margin:var(--aui-xl)}.aui-ma-xxl{margin:var(--aui-xxl)}.aui-mt-auto{margin-top:auto}.aui-mt-none{margin-top:0}.aui-mt-xxs{margin-top:var(--aui-xxs)}.aui-mt-xs{margin-top:var(--aui-xs)}.aui-mt-s{margin-top:var(--aui-s)}.aui-mt-m{margin-top:var(--aui-m)}.aui-mt-l{margin-top:var(--aui-l)}.aui-mt-xl{margin-top:var(--aui-xl)}.aui-mt-xxl{margin-top:var(--aui-xxl)}.aui-mb-auto{margin-bottom:auto}.aui-mb-none{margin-bottom:0}.aui-mb-xxs{margin-bottom:var(--aui-xxs)}.aui-mb-xs{margin-bottom:var(--aui-xs)}.aui-mb-s{margin-bottom:var(--aui-s)}.aui-mb-m{margin-bottom:var(--aui-m)}.aui-mb-l{margin-bottom:var(--aui-l)}.aui-mb-xl{margin-bottom:var(--aui-xl)}.aui-mb-xxl{margin-bottom:var(--aui-xxl)}.aui-ml-auto{margin-left:auto}.aui-ml-none{margin-left:0}.aui-ml-xxs{margin-left:var(--aui-xxs)}.aui-ml-xs{margin-left:var(--aui-xs)}.aui-ml-s{margin-left:var(--aui-s)}.aui-ml-m{margin-left:var(--aui-m)}.aui-ml-l{margin-left:var(--aui-l)}.aui-ml-xl{margin-left:var(--aui-xl)}.aui-ml-xxl{margin-left:var(--aui-xxl)}.aui-mr-auto{margin-right:auto}.aui-mr-none{margin-right:0}.aui-mr-xxs{margin-right:var(--aui-xxs)}.aui-mr-xs{margin-right:var(--aui-xs)}.aui-mr-s{margin-right:var(--aui-s)}.aui-mr-m{margin-right:var(--aui-m)}.aui-mr-l{margin-right:var(--aui-l)}.aui-mr-xl{margin-right:var(--aui-xl)}.aui-mr-xxl{margin-right:var(--aui-xxl)}.aui-gap-none{gap:0}.aui-gap-xxs{gap:var(--aui-xxs)}.aui-gap-xs{gap:var(--aui-xs)}.aui-gap-s{gap:var(--aui-s)}.aui-gap-m{gap:var(--aui-m)}.aui-gap-l{gap:var(--aui-l)}.aui-gap-xl{gap:var(--aui-xl)}.aui-gap-xxl{gap:var(--aui-xxl)}.aui-w-full{width:100%}.aui-w-fit{width:fit-content}.aui-w-min{width:min-content}.aui-w-max{width:max-content}.aui-mw-full{max-width:100%}.aui-mw-fit{max-width:fit-content}.aui-mw-min{max-width:min-content}.aui-mw-max{max-width:max-content}.aui-h-full{height:100%}.aui-h-fit{height:fit-content}.aui-h-min{height:min-content}.aui-h-max{height:max-content}.aui-mh-full{max-height:100%}.aui-mh-fit{max-height:fit-content}.aui-mh-min{max-height:min-content}.aui-mh-max{max-height:max-content}.aui-radius-none{border-radius:var(--aui-radius-none)}.aui-radius-subtle{border-radius:var(--aui-radius-subtle)}.aui-radius-rounded{border-radius:var(--aui-radius-rounded)}.aui-radius-max{border-radius:var(--aui-radius-max)}.aui-ba{border:1px solid var(--aui-default-border)}.aui-bt{border-top:1px solid var(--aui-default-border)}.aui-br{border-right:1px solid var(--aui-default-border)}.aui-bb{border-bottom:1px solid var(--aui-default-border)}.aui-bl{border-left:1px solid var(--aui-default-border)}.aui-bw-none{border-width:0px}.aui-bw-xs{border-width:1px}.aui-bw-s{border-width:2px}.aui-bw-m{border-width:4px}.aui-bw-l{border-width:8px}.aui-bw-xl{border-width:16px}.aui-bs-solid{border-style:solid}.aui-bs-dotted{border-style:dotted}.aui-bs-dashed{border-style:dashed}.aui-bs-none{border-style:none}.aui-bc-default{border-color:var(--aui-default-border)}.aui-bc-primary{border-color:var(--aui-color-default)}.aui-shadow-subtle{box-shadow:var(--aui-subtle-box-shadow)}.aui-shadow-floating{box-shadow:var(--aui-floating-box-shadow)}.aui-shadow-none{box-shadow:none}.aui-op-none{opacity:0}.aui-op-disabled{opacity:var(--aui-opacity-disabled)}.aui-op-dim{opacity:var(--aui-opacity-dim)}.aui-op-full{opacity:1}.aui-f-xxs{font-size:10px}.aui-f-xs{font-size:12px}.aui-f-s{font-size:14px}.aui-f-default{font-size:16px}.aui-f-m{font-size:20px}.aui-f-l{font-size:24px}.aui-f-xl{font-size:32px}.aui-f-xxl{font-size:48px}.aui-fw-1{font-weight:100}.aui-fw-2{font-weight:200}.aui-fw-3{font-weight:300}.aui-fw-4{font-weight:400}.aui-fw-5{font-weight:500}.aui-fw-6{font-weight:600}.aui-fw-7{font-weight:700}.aui-fw-8{font-weight:800}.aui-fw-9{font-weight:900}.aui-ta-left{text-align:left}.aui-ta-right{text-align:right}.aui-ta-center{text-align:center}.aui-it{font-style:italic}.aui-c-default{color:var(--aui-color-default)}.aui-c-muted{color:var(--aui-color-muted)}.aui-c-inherit{color:inherit}.aui-c-transparent{color:rgba(0,0,0,0)}.aui-bg-default{background-color:var(--aui-default-background)}.aui-bg-muted{background-color:var(--aui-static-background)}.aui-bg-inherit{background-color:inherit}.aui-bg-transparent{background-color:rgba(0,0,0,0)}.aui-ov-scroll{overflow:scroll}.aui-ov-x-scroll{overflow-x:scroll}.aui-ov-y-scroll{overflow-y:scroll}.aui-ov-hidden{overflow:hidden}.aui-ov-x-hidden{overflow-x:hidden}.aui-ov-y-hidden{overflow-y:hidden}.aui-z-auto{z-index:auto}.aui-z-floating{z-index:100}.aui-z-nav{z-index:1000}.aui-z-max{z-index:10000}.aui-cursor-auto{cursor:auto}.aui-cursor-pointer{cursor:pointer}.aui-select-icon{--size: 10px;color:var(--aui-color-muted);width:var(--size);height:var(--size);position:absolute;top:calc(50% + 1px);transform:translateY(-50%);right:var(--size);pointer-events:none}
@@ -20,6 +20,10 @@ var transformers = {
20
20
  var justify = _a.justify;
21
21
  return "aui-justify-".concat(justify);
22
22
  },
23
+ stretch: function (_a) {
24
+ var stretch = _a.stretch;
25
+ return "aui-stretch-".concat(stretch);
26
+ },
23
27
  wrap: function () { return "aui-flex-wrap"; },
24
28
  overflow: function (_a) {
25
29
  var overflow = _a.overflow;
package/utils/types.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import React from "react";
2
- export type Children = React.ReactNode | React.ReactNode[];
2
+ export type ReadonlyableArray<T> = readonly T[] | T[];
3
+ export type Children = React.ReactNode | ReadonlyableArray<React.ReactNode>;
3
4
  export type ContentType = "success" | "warning" | "error" | "info" | "static";
4
5
  export type Style = React.CSSProperties;
5
6
  export type SizeDimension = "full" | "fit" | "min" | "max";
@@ -17,8 +18,10 @@ export type Vfx = {
17
18
  gap?: SpacingSize;
18
19
  /** Alignment orthogonal to the selected axis (Equivalent to align-items) */
19
20
  align?: "start" | "center" | "end";
20
- /** How to content the children (Equivalent to justify-content) */
21
+ /** How to space the children (Equivalent to justify-content) */
21
22
  justify?: "start" | "center" | "between" | "around" | "end";
23
+ /** Flex presets to determine how a node stretches within its container */
24
+ stretch?: "even" | "grow" | "min" | "max";
22
25
  /** Whether to allow wrapping of children */
23
26
  wrap?: boolean;
24
27
  /** How to handle overflow in the container */
@@ -63,7 +66,7 @@ export type Vfx = {
63
66
  maxWidth?: SizeDimension;
64
67
  /** Height of the content */
65
68
  height?: SizeDimension;
66
- /** Maximum of the content */
69
+ /** Maximum height of the content */
67
70
  maxHeight?: SizeDimension;
68
71
  /** Border radius of the content */
69
72
  radius?: "none" | "subtle" | "rounded" | "max";