@green-on-grey/ui-kit 0.0.0-stage → 0.1.1

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.
@@ -0,0 +1,83 @@
1
+ declare const PATHS: {
2
+ readonly user: '<circle cx="12" cy="8" r="4"/><path d="M4 21c0-4 3.6-6 8-6s8 2 8 6"/>';
3
+ readonly hash: '<path d="M5 9h14M5 15h14M10 4 8 20M16 4l-2 16"/>';
4
+ readonly graph: '<circle cx="6" cy="7" r="2.5"/><circle cx="18" cy="6" r="2.5"/><circle cx="12" cy="18" r="2.5"/><path d="M8.3 8l2.5 7.8M16 7.8l-3 8M8.5 6.8l7-.6"/>';
5
+ readonly table: '<rect x="3" y="4" width="18" height="16" rx="2"/><path d="M3 10h18M3 15h18M9 4v16"/>';
6
+ readonly ext: '<path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/>';
7
+ readonly pause: '<path d="M8 5v14M16 5v14"/>';
8
+ readonly search: '<circle cx="11" cy="11" r="7"/><path d="m20 20-3.5-3.5"/>';
9
+ readonly mail: '<rect x="3" y="5" width="18" height="14" rx="2"/><path d="m4 7 8 6 8-6"/>';
10
+ readonly archive: '<rect x="3" y="4" width="18" height="5" rx="1"/><path d="M5 9v10a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1V9M10 13h4"/>';
11
+ readonly key: '<circle cx="8" cy="15" r="4"/><path d="m11 12 9-9M16 7l3 3M14 9l2 2"/>';
12
+ readonly gear: '<circle cx="12" cy="12" r="3"/><path d="M12 3v3M12 18v3M3 12h3M18 12h3M5.6 5.6l2.1 2.1M16.3 16.3l2.1 2.1M5.6 18.4l2.1-2.1M16.3 7.7l2.1-2.1"/>';
13
+ readonly mic: '<rect x="9" y="3" width="6" height="11" rx="3"/><path d="M5 11a7 7 0 0 0 14 0M12 18v3"/>';
14
+ readonly clip: '<path d="m21 11-8.5 8.5a5 5 0 0 1-7-7L14 4a3.5 3.5 0 0 1 5 5l-8.5 8.5a2 2 0 0 1-3-3L15 7"/>';
15
+ readonly send: '<path d="M5 12h14M13 6l6 6-6 6"/>';
16
+ readonly x: '<path d="M6 6l12 12M18 6 6 18"/>';
17
+ readonly menu: '<path d="M4 7h16M4 12h16M4 17h16"/>';
18
+ readonly check: '<path d="m5 12 5 5 9-10"/>';
19
+ readonly lock: '<rect x="5" y="11" width="14" height="10" rx="2"/><path d="M8 11V8a4 4 0 0 1 8 0v3"/>';
20
+ readonly branch: '<circle cx="6" cy="5" r="2"/><circle cx="6" cy="19" r="2"/><circle cx="18" cy="8" r="2"/><path d="M6 7v10M18 10c0 5-8 4-11 7"/>';
21
+ readonly plus: '<path d="M12 5v14M5 12h14"/>';
22
+ readonly back: '<path d="M19 12H5M11 6l-6 6 6 6"/>';
23
+ readonly files: '<path d="M14 3H7a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V8z"/><path d="M14 3v5h5"/>';
24
+ readonly clock: '<circle cx="12" cy="12" r="8"/><path d="M12 8v4l3 2"/>';
25
+ readonly msg: '<path d="M4 5h16v11H9l-5 4z"/>';
26
+ readonly out: '<path d="M15 4h4v16h-4M10 8l-4 4 4 4M6 12h10"/>';
27
+ readonly users: '<circle cx="9" cy="8" r="3"/><path d="M3 20a6 6 0 0 1 12 0M16 5a3 3 0 0 1 0 6M21 20a6 6 0 0 0-4-5.6"/>';
28
+ readonly grid: '<rect x="4" y="4" width="7" height="7" rx="1"/><rect x="13" y="4" width="7" height="7" rx="1"/><rect x="4" y="13" width="7" height="7" rx="1"/><rect x="13" y="13" width="7" height="7" rx="1"/>';
29
+ readonly book: '<path d="M5 4h11a3 3 0 0 1 3 3v13H8a3 3 0 0 1-3-3z"/><path d="M5 17a3 3 0 0 1 3-3h11"/>';
30
+ readonly wrench: '<path d="M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.8-3.8a6 6 0 0 1-7.9 7.9l-6.9 6.9a2.1 2.1 0 0 1-3-3l6.9-6.9a6 6 0 0 1 7.9-7.9z"/>';
31
+ readonly upload: '<path d="M12 16V4M7 9l5-5 5 5M5 20h14"/>';
32
+ readonly dots: '<circle cx="5" cy="12" r="1.3"/><circle cx="12" cy="12" r="1.3"/><circle cx="19" cy="12" r="1.3"/>';
33
+ readonly trash: '<path d="M4 7h16M9 7V4h6v3M6 7l1 13h10l1-13M10 11v6M14 11v6"/>';
34
+ readonly cpu: '<rect x="7" y="7" width="10" height="10" rx="1.5"/><rect x="10" y="10" width="4" height="4"/><path d="M10 3v4M14 3v4M10 17v4M14 17v4M3 10h4M3 14h4M17 10h4M17 14h4"/>';
35
+ readonly alert: '<path d="M12 4 2 20h20z"/><path d="M12 10v4M12 17v.5"/>';
36
+ readonly sparkle: '<path d="M12 3v4M12 17v4M3 12h4M17 12h4M6 6l2.5 2.5M15.5 15.5 18 18M6 18l2.5-2.5M15.5 8.5 18 6"/>';
37
+ readonly stop: '<rect x="7" y="7" width="10" height="10" rx="1.5"/>';
38
+ readonly bulb: '<path d="M9 18h6M10 21h4M12 3a6 6 0 0 0-3.5 10.9c.6.5 1 1.2 1 2.1h5c0-.9.4-1.6 1-2.1A6 6 0 0 0 12 3z"/>';
39
+ readonly bug: '<rect x="8" y="7" width="8" height="12" rx="4"/><path d="M12 7V5M9 5l1.5 2M15 5l-1.5 2M4 11h4M16 11h4M4 17l4-2M20 17l-4-2"/>';
40
+ readonly rocket: '<path d="M5 15c-1.5 1.5-2 4-2 6 2 0 4.5-.5 6-2M9 15l-3-3c1.5-5 5.5-8 12-9-1 6.5-4 10.5-9 12z"/><circle cx="14.5" cy="9.5" r="1.5"/>';
41
+ readonly undo: '<path d="M9 14 4 9l5-5"/><path d="M4 9h10a6 6 0 0 1 0 12h-3"/>';
42
+ readonly flag: '<path d="M5 21V4M5 4h11l-2 4 2 4H5"/>';
43
+ readonly code: '<path d="m8 8-4 4 4 4M16 8l4 4-4 4M13 5l-2 14"/>';
44
+ readonly flask: '<path d="M9 3h6M10 3v6L5 19a1.5 1.5 0 0 0 1.3 2h11.4a1.5 1.5 0 0 0 1.3-2l-5-10V3"/>';
45
+ readonly target: '<circle cx="12" cy="12" r="8"/><circle cx="12" cy="12" r="4"/><circle cx="12" cy="12" r=".6"/>';
46
+ readonly merge: '<circle cx="6" cy="5" r="2"/><circle cx="6" cy="19" r="2"/><circle cx="18" cy="19" r="2"/><path d="M6 7v10M6 7c0 6 12 4 12 10"/>';
47
+ readonly server: '<rect x="4" y="4" width="16" height="7" rx="1.5"/><rect x="4" y="13" width="16" height="7" rx="1.5"/><path d="M8 7.5h.01M8 16.5h.01"/>';
48
+ readonly copy: '<rect x="9" y="9" width="11" height="11" rx="2"/><path d="M5 15V5a2 2 0 0 1 2-2h8"/>';
49
+ readonly briefcase: '<rect x="3" y="7" width="18" height="13" rx="2"/><path d="M9 7V5a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v2M3 13h18"/>';
50
+ readonly smile: '<circle cx="12" cy="12" r="8"/><path d="M8.5 14a4 4 0 0 0 7 0M9.5 10h.01M14.5 10h.01"/>';
51
+ readonly bolt: '<path d="M13 3 5 14h6l-1 7 8-11h-6z"/>';
52
+ readonly link: '<path d="M10 14a4 4 0 0 0 5.7 0l3-3a4 4 0 0 0-5.7-5.7l-1 1"/><path d="M14 10a4 4 0 0 0-5.7 0l-3 3a4 4 0 0 0 5.7 5.7l1-1"/>';
53
+ readonly refresh: '<path d="M20 11a8 8 0 0 0-14.5-4.5L4 8M4 4v4h4M4 13a8 8 0 0 0 14.5 4.5L20 16M20 20v-4h-4"/>';
54
+ readonly tBusiness: '<rect x="3" y="7" width="18" height="13" rx="2"/><path d="M9 7V5h6v2M3 12h18"/>';
55
+ readonly tFriendly: '<circle cx="12" cy="12" r="9"/><path d="M8 14c1 1.5 2.4 2.2 4 2.2s3-.7 4-2.2M9 9.5h.01M15 9.5h.01"/>';
56
+ readonly tBrief: '<path d="M13 3L5 13h6l-1 8 8-10h-6z"/>';
57
+ readonly tMentor: '<path d="M3 6c3-1 6-1 9 1 3-2 6-2 9-1v13c-3-1-6-1-9 1-3-2-6-2-9-1zM12 7v13"/>';
58
+ readonly tg: '<path d="M3 11l18-7-3 16-6-5-3 3v-5l9-7-11 6z"/>';
59
+ readonly msg2: '<path d="M4 5h16v11H8l-4 4z"/>';
60
+ readonly plug: '<path d="M9 3v5M15 3v5M6 8h12v3a6 6 0 0 1-12 0zM12 17v4"/>';
61
+ readonly repeat: '<path d="M17 2l3 3-3 3M4 11V9a4 4 0 0 1 4-4h12M7 22l-3-3 3-3M20 13v2a4 4 0 0 1-4 4H4"/>';
62
+ readonly shield: '<path d="M12 3l8 3v6c0 5-4 8-8 9-4-1-8-4-8-9V6z"/>';
63
+ readonly box: '<path d="M3 7l9-4 9 4v10l-9 4-9-4zM3 7l9 4 9-4M12 11v10"/>';
64
+ readonly brain: '<path d="M9 4a3 3 0 0 0-3 3 3 3 0 0 0-2 5 3 3 0 0 0 2 5 3 3 0 0 0 6 1V5a3 3 0 0 0-3-1zM15 4a3 3 0 0 1 3 3 3 3 0 0 1 2 5 3 3 0 0 1-2 5 3 3 0 0 1-6 1"/>';
65
+ readonly chart: '<path d="M4 20h16M6 16l4-5 3 3 5-7"/>';
66
+ readonly play: '<path d="M7 5l12 7-12 7z"/>';
67
+ readonly spark: '<path d="M12 3l1.8 5.2L19 10l-5.2 1.8L12 17l-1.8-5.2L5 10l5.2-1.8z"/>';
68
+ readonly tag: '<path d="M3 12V4h8l9 9-8 8z"/><circle cx="7.5" cy="8.5" r="1.3"/>';
69
+ readonly globe: '<circle cx="12" cy="12" r="9"/><path d="M3 12h18M12 3a14 14 0 0 1 0 18M12 3a14 14 0 0 0 0 18"/>';
70
+ readonly download: '<path d="M12 4v12M7 11l5 5 5-5M5 20h14"/>';
71
+ readonly pin: '<path d="M9 4h6l-1 6 4 4H6l4-4zM12 14v6"/>';
72
+ readonly edit: '<path d="M4 20h4L19 9l-4-4L4 16zM14 6l4 4"/>';
73
+ };
74
+ export type IconName = keyof typeof PATHS;
75
+ export declare function Icon({ name, size, className }: {
76
+ name: IconName;
77
+ size?: number;
78
+ className?: string;
79
+ }): import("react").JSX.Element;
80
+ export declare function GitHubIcon(): import("react").JSX.Element;
81
+ /** Names of all icons, for the showcase. */
82
+ export declare const ICON_NAMES: IconName[];
83
+ export {};
@@ -0,0 +1,3 @@
1
+ export declare function Markdown({ text }: {
2
+ text: string;
3
+ }): import("react").JSX.Element;
@@ -0,0 +1,10 @@
1
+ import { type ReactNode } from "react";
2
+ /** `.menu`: a popover closed by Escape and by a click outside; it is mounted while
3
+ * open. `onClose` must keep its identity between renders. What is inside
4
+ * (sections `.sec`, lines `.line`, actions `.action`) belongs to the product. */
5
+ export declare function Menu({ onClose, label, className, children }: {
6
+ onClose: () => void;
7
+ label?: string;
8
+ className?: string;
9
+ children: ReactNode;
10
+ }): import("react").JSX.Element;
@@ -0,0 +1,11 @@
1
+ import { type ReactNode } from "react";
2
+ /** `.tabs` with the keyboard of a tab list: arrows, Home and End move the choice. */
3
+ export declare function Tabs<K extends string>({ items, value, onChange, label }: {
4
+ items: {
5
+ key: K;
6
+ label: ReactNode;
7
+ }[];
8
+ value: K;
9
+ onChange: (key: K) => void;
10
+ label?: string;
11
+ }): import("react").JSX.Element;
@@ -0,0 +1,32 @@
1
+ import { type ReactNode } from "react";
2
+ /** The link of the product: the kit does not depend on a router (arch §4.2). */
3
+ export type LinkComponent = (props: {
4
+ href: string;
5
+ className?: string;
6
+ onClick?: () => void;
7
+ "aria-current"?: "page";
8
+ children: ReactNode;
9
+ }) => ReactNode;
10
+ export interface TopBarSection {
11
+ key: string;
12
+ label: ReactNode;
13
+ href: string;
14
+ active: boolean;
15
+ }
16
+ /** The top bar (FTR.NAB.CMN-0005 R5, design §4): the logo and the name, the
17
+ * sections in a row and behind the burger on a phone, the actions of the product,
18
+ * the avatar that opens the profile menu. The profile menu and the list of
19
+ * sections are never open together. */
20
+ export declare function TopBar({ logo, name, home, sections, Link, center, actions, avatar, profileMenu }: {
21
+ logo: string;
22
+ name: string;
23
+ home?: string;
24
+ sections: TopBarSection[];
25
+ Link: LinkComponent;
26
+ /** Between the sections and the actions: the search of Hammurapi. */
27
+ center?: ReactNode;
28
+ /** Before the avatar. */
29
+ actions?: ReactNode;
30
+ avatar: ReactNode;
31
+ profileMenu: (close: () => void) => ReactNode;
32
+ }): import("react").JSX.Element;
@@ -0,0 +1,50 @@
1
+ import { type ReactNode } from "react";
2
+ import { type IconName } from "./Icon";
3
+ export declare function Modal({ title, onClose, children, footer, wide }: {
4
+ title: ReactNode;
5
+ onClose: () => void;
6
+ children: ReactNode;
7
+ footer?: ReactNode;
8
+ wide?: boolean;
9
+ }): import("react").JSX.Element;
10
+ export interface ToastSpec {
11
+ kind?: "error" | "ok" | "info";
12
+ title: string;
13
+ text?: ReactNode;
14
+ actions?: {
15
+ label: string;
16
+ primary?: boolean;
17
+ onClick: () => void;
18
+ }[];
19
+ sticky?: boolean;
20
+ }
21
+ export declare function ToastProvider({ children }: {
22
+ children: ReactNode;
23
+ }): import("react").JSX.Element;
24
+ export declare const useToast: () => (t: ToastSpec) => void;
25
+ /** Two letters of a name for an avatar without a picture. */
26
+ export declare function initials(name: string): string;
27
+ /** The avatar of a user or of an agent. What an agent looks like is decided by the
28
+ * product (R7): it gives the icon and the colour variant — a class beside `.avatar.agent`. */
29
+ export declare function Avatar({ name, url, small, agent, icon, variant }: {
30
+ name: string;
31
+ url?: string | null;
32
+ small?: boolean;
33
+ agent?: boolean;
34
+ icon?: IconName;
35
+ variant?: string;
36
+ }): import("react").JSX.Element;
37
+ export declare function Switch({ on, onChange, label, disabled }: {
38
+ on: boolean;
39
+ onChange: (v: boolean) => void;
40
+ label?: ReactNode;
41
+ disabled?: boolean;
42
+ }): import("react").JSX.Element;
43
+ export declare function Empty({ icon, title, children }: {
44
+ icon: IconName;
45
+ title: ReactNode;
46
+ children?: ReactNode;
47
+ }): import("react").JSX.Element;
48
+ export declare function Loading(): import("react").JSX.Element;
49
+ /** Popover menu closed by an outside click. */
50
+ export declare function useOutside<T extends HTMLElement>(open: boolean, close: () => void): import("react").RefObject<T | null>;
@@ -0,0 +1,7 @@
1
+ import { useTranslation as e } from "react-i18next";
2
+ //#region src/i18n.ts
3
+ var t = "uikit", n = () => e(t).t;
4
+ //#endregion
5
+ export { n, t };
6
+
7
+ //# sourceMappingURL=i18n-BJ8rsBp6.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"i18n-BJ8rsBp6.js","names":["UIKIT_NS","useKitT","useTranslation"],"sources":["../src/i18n.ts"],"sourcesContent":["import { useTranslation } from \"react-i18next\";\n\n/** The namespace of the strings of the kit in the i18next instance of a product\n * (FTR.NAB.CMN-0005 arch §4.1): `resources[lng].uikit = kit[lng]`. */\nexport const UIKIT_NS = \"uikit\";\n\n/** `t` of the strings of the kit. */\nexport const useKitT = () => useTranslation(UIKIT_NS).t;\n"],"mappings":";;AAIA,IAAaA,IAAW,SAGXC,UAAgBC,EAAeF,CAAQ,CAAC,CAAC"}
package/dist/i18n.d.ts ADDED
@@ -0,0 +1,5 @@
1
+ /** The namespace of the strings of the kit in the i18next instance of a product
2
+ * (FTR.NAB.CMN-0005 arch §4.1): `resources[lng].uikit = kit[lng]`. */
3
+ export declare const UIKIT_NS = "uikit";
4
+ /** `t` of the strings of the kit. */
5
+ export declare const useKitT: () => import("i18next").TFunction<"uikit", undefined>;
@@ -0,0 +1,8 @@
1
+ export { Icon, GitHubIcon, type IconName } from "./components/Icon";
2
+ export { Markdown } from "./components/Markdown";
3
+ export { Button, IconButton } from "./components/Button";
4
+ export { Tabs } from "./components/Tabs";
5
+ export { Menu } from "./components/Menu";
6
+ export { TopBar, type LinkComponent, type TopBarSection } from "./components/TopBar";
7
+ export { Modal, ToastProvider, useToast, Avatar, Switch, Empty, Loading, useOutside, type ToastSpec } from "./components/ui";
8
+ export { UIKIT_NS } from "./i18n";
package/dist/index.js ADDED
@@ -0,0 +1,144 @@
1
+ import { a as e, c as t, d as n, i as r, l as i, n as a, o, r as s, s as c, t as l, u } from "./ui-CGgZtEVm.js";
2
+ import { n as d, t as f } from "./i18n-BJ8rsBp6.js";
3
+ import { jsx as p, jsxs as m } from "react/jsx-runtime";
4
+ import { useCallback as h, useEffect as g, useRef as _, useState as v } from "react";
5
+ //#region src/components/Button.tsx
6
+ function y({ variant: e, size: t, className: n, type: r = "button", ...i }) {
7
+ let a = [
8
+ "btn",
9
+ e,
10
+ t,
11
+ n
12
+ ].filter(Boolean).join(" ");
13
+ return /* @__PURE__ */ p("button", {
14
+ type: r,
15
+ className: a,
16
+ ...i
17
+ });
18
+ }
19
+ function b({ label: e, fill: t, on: n, className: r, type: i = "button", ...a }) {
20
+ let o = [
21
+ "iconbtn",
22
+ t && "fill",
23
+ n && "on",
24
+ r
25
+ ].filter(Boolean).join(" ");
26
+ return /* @__PURE__ */ p("button", {
27
+ type: i,
28
+ className: o,
29
+ "aria-label": e,
30
+ ...a
31
+ });
32
+ }
33
+ //#endregion
34
+ //#region src/components/Tabs.tsx
35
+ function x({ items: e, value: t, onChange: n, label: r }) {
36
+ let i = _(null);
37
+ return /* @__PURE__ */ p("div", {
38
+ className: "tabs",
39
+ role: "tablist",
40
+ "aria-label": r,
41
+ ref: i,
42
+ onKeyDown: (r) => {
43
+ let a = e.findIndex((e) => e.key === t), o = r.key === "ArrowRight" ? (a + 1) % e.length : r.key === "ArrowLeft" ? (a - 1 + e.length) % e.length : r.key === "Home" ? 0 : r.key === "End" ? e.length - 1 : -1;
44
+ o < 0 || (r.preventDefault(), n(e[o].key), i.current?.querySelectorAll("[role=\"tab\"]")[o]?.focus());
45
+ },
46
+ children: e.map((e) => /* @__PURE__ */ p("button", {
47
+ type: "button",
48
+ role: "tab",
49
+ "aria-selected": e.key === t,
50
+ tabIndex: e.key === t ? 0 : -1,
51
+ className: e.key === t ? "on" : void 0,
52
+ onClick: () => n(e.key),
53
+ children: e.label
54
+ }, e.key))
55
+ });
56
+ }
57
+ //#endregion
58
+ //#region src/components/Menu.tsx
59
+ function S({ onClose: e, label: t, className: n, children: r }) {
60
+ let i = c(!0, e);
61
+ return g(() => {
62
+ let e = document.activeElement;
63
+ return () => e?.focus?.();
64
+ }, []), /* @__PURE__ */ p("div", {
65
+ className: `menu${n ? ` ${n}` : ""}`,
66
+ role: "dialog",
67
+ "aria-label": t,
68
+ ref: i,
69
+ children: r
70
+ });
71
+ }
72
+ //#endregion
73
+ //#region src/components/TopBar.tsx
74
+ function C({ logo: e, name: t, home: r = "/", sections: i, Link: a, center: o, actions: s, avatar: l, profileMenu: u }) {
75
+ let f = d(), [g, _] = v(!1), [y, b] = v(!1), x = h(() => b(!1), []), S = h(() => _(!1), []), C = c(y, x), w = i.map((e) => /* @__PURE__ */ p(a, {
76
+ href: e.href,
77
+ className: e.active ? "on" : void 0,
78
+ "aria-current": e.active ? "page" : void 0,
79
+ onClick: x,
80
+ children: e.label
81
+ }, e.key));
82
+ return /* @__PURE__ */ m("div", {
83
+ className: "topbar",
84
+ children: [
85
+ /* @__PURE__ */ m(a, {
86
+ href: r,
87
+ className: "brand",
88
+ children: [/* @__PURE__ */ p("img", {
89
+ src: e,
90
+ alt: ""
91
+ }), /* @__PURE__ */ p("span", {
92
+ className: "hide-m",
93
+ children: t
94
+ })]
95
+ }),
96
+ /* @__PURE__ */ p("nav", {
97
+ className: "nav hide-m",
98
+ "aria-label": f("topbar.sections"),
99
+ children: w
100
+ }),
101
+ o,
102
+ /* @__PURE__ */ m("div", {
103
+ className: "top-actions",
104
+ children: [
105
+ s,
106
+ /* @__PURE__ */ p("button", {
107
+ className: "avatar",
108
+ style: g ? { boxShadow: "0 0 0 2px var(--violet)" } : void 0,
109
+ onClick: () => {
110
+ b(!1), _((e) => !e);
111
+ },
112
+ "aria-label": f("topbar.profile"),
113
+ "aria-expanded": g,
114
+ children: l
115
+ }),
116
+ /* @__PURE__ */ m("div", {
117
+ className: "burger",
118
+ ref: C,
119
+ children: [/* @__PURE__ */ p("button", {
120
+ className: `iconbtn${y ? " on" : ""}`,
121
+ onClick: () => {
122
+ _(!1), b((e) => !e);
123
+ },
124
+ "aria-label": f("topbar.sections"),
125
+ "aria-expanded": y,
126
+ "aria-controls": "nav-sections",
127
+ children: /* @__PURE__ */ p(n, { name: y ? "x" : "menu" })
128
+ }), y && /* @__PURE__ */ p("nav", {
129
+ id: "nav-sections",
130
+ className: "navmenu",
131
+ "aria-label": f("topbar.sections"),
132
+ children: w
133
+ })]
134
+ })
135
+ ]
136
+ }),
137
+ g && u(S)
138
+ ]
139
+ });
140
+ }
141
+ //#endregion
142
+ export { l as Avatar, y as Button, a as Empty, u as GitHubIcon, n as Icon, b as IconButton, s as Loading, i as Markdown, S as Menu, r as Modal, e as Switch, x as Tabs, o as ToastProvider, C as TopBar, f as UIKIT_NS, c as useOutside, t as useToast };
143
+
144
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":["Switch","useToast","Icon","Modal","Markdown","Empty","Loading","useOutside","Avatar","useKitT","UIKIT_NS","Button","rest","cls","variant","size","className","IconButton","fill","on","label","Tabs","ref","useRef","i","items","it","value","to","e","onChange","Menu","onClose","useEffect","opener","TopBar","t","profileOpen","setProfileOpen","useState","sectionsOpen","setSectionsOpen","closeSections","useCallback","closeProfile","links","sections","Link","s","home","logo","name","center","actions","v","avatar","profileMenu","GitHubIcon","ToastProvider"],"sources":["../src/components/Button.tsx","../src/components/Tabs.tsx","../src/components/Menu.tsx","../src/components/TopBar.tsx"],"sourcesContent":["import type { ButtonHTMLAttributes } from \"react\";\n\ntype Native = ButtonHTMLAttributes<HTMLButtonElement>;\n\n/** `button.btn` with its variants. The classes stay a legitimate way to use a\n * button (FTR.NAB.CMN-0005 tech, decision 1); the component is for new code. */\nexport function Button({ variant, size, className, type = \"button\", ...rest }: Native & {\n variant?: \"primary\" | \"ghost\" | \"danger\"; size?: \"sm\";\n}) {\n const cls = [\"btn\", variant, size, className].filter(Boolean).join(\" \");\n return <button type={type} className={cls} {...rest} />;\n}\n\n/** `button.iconbtn`: a button with an icon only, so the label is required. */\nexport function IconButton({ label, fill, on, className, type = \"button\", ...rest }: Omit<Native, \"aria-label\"> & {\n label: string; fill?: boolean; on?: boolean;\n}) {\n const cls = [\"iconbtn\", fill && \"fill\", on && \"on\", className].filter(Boolean).join(\" \");\n return <button type={type} className={cls} aria-label={label} {...rest} />;\n}\n","import { useRef, type KeyboardEvent, type ReactNode } from \"react\";\n\n/** `.tabs` with the keyboard of a tab list: arrows, Home and End move the choice. */\nexport function Tabs<K extends string>({ items, value, onChange, label }: {\n items: { key: K; label: ReactNode }[]; value: K; onChange: (key: K) => void; label?: string;\n}) {\n const ref = useRef<HTMLDivElement>(null);\n const onKey = (e: KeyboardEvent) => {\n const i = items.findIndex((it) => it.key === value);\n const to = e.key === \"ArrowRight\" ? (i + 1) % items.length\n : e.key === \"ArrowLeft\" ? (i - 1 + items.length) % items.length\n : e.key === \"Home\" ? 0 : e.key === \"End\" ? items.length - 1 : -1;\n if (to < 0) return;\n e.preventDefault();\n onChange(items[to].key);\n ref.current?.querySelectorAll<HTMLElement>('[role=\"tab\"]')[to]?.focus();\n };\n return (\n <div className=\"tabs\" role=\"tablist\" aria-label={label} ref={ref} onKeyDown={onKey}>\n {items.map((it) => (\n <button key={it.key} type=\"button\" role=\"tab\" aria-selected={it.key === value} tabIndex={it.key === value ? 0 : -1}\n className={it.key === value ? \"on\" : undefined} onClick={() => onChange(it.key)}>\n {it.label}\n </button>\n ))}\n </div>\n );\n}\n","import { useEffect, type ReactNode } from \"react\";\nimport { useOutside } from \"./ui\";\n\n/** `.menu`: a popover closed by Escape and by a click outside; it is mounted while\n * open. `onClose` must keep its identity between renders. What is inside\n * (sections `.sec`, lines `.line`, actions `.action`) belongs to the product. */\nexport function Menu({ onClose, label, className, children }: {\n onClose: () => void; label?: string; className?: string; children: ReactNode;\n}) {\n const ref = useOutside<HTMLDivElement>(true, onClose);\n // the focus returns to what opened the menu (CMP-05)\n useEffect(() => {\n const opener = document.activeElement as HTMLElement | null;\n return () => opener?.focus?.();\n }, []);\n return (\n <div className={`menu${className ? ` ${className}` : \"\"}`} role=\"dialog\" aria-label={label} ref={ref}>\n {children}\n </div>\n );\n}\n","import { useCallback, useState, type ReactNode } from \"react\";\nimport { useKitT } from \"../i18n\";\nimport { Icon } from \"./Icon\";\nimport { useOutside } from \"./ui\";\n\n/** The link of the product: the kit does not depend on a router (arch §4.2). */\nexport type LinkComponent = (props: {\n href: string; className?: string; onClick?: () => void; \"aria-current\"?: \"page\"; children: ReactNode;\n}) => ReactNode;\n\nexport interface TopBarSection { key: string; label: ReactNode; href: string; active: boolean }\n\n/** The top bar (FTR.NAB.CMN-0005 R5, design §4): the logo and the name, the\n * sections in a row and behind the burger on a phone, the actions of the product,\n * the avatar that opens the profile menu. The profile menu and the list of\n * sections are never open together. */\nexport function TopBar({ logo, name, home = \"/\", sections, Link, center, actions, avatar, profileMenu }: {\n logo: string; name: string; home?: string; sections: TopBarSection[]; Link: LinkComponent;\n /** Between the sections and the actions: the search of Hammurapi. */\n center?: ReactNode;\n /** Before the avatar. */\n actions?: ReactNode;\n avatar: ReactNode;\n profileMenu: (close: () => void) => ReactNode;\n}) {\n const t = useKitT();\n const [profileOpen, setProfileOpen] = useState(false);\n const [sectionsOpen, setSectionsOpen] = useState(false);\n const closeSections = useCallback(() => setSectionsOpen(false), []);\n const closeProfile = useCallback(() => setProfileOpen(false), []);\n const ref = useOutside<HTMLDivElement>(sectionsOpen, closeSections);\n const links = sections.map((s) => (\n <Link key={s.key} href={s.href} className={s.active ? \"on\" : undefined} aria-current={s.active ? \"page\" : undefined} onClick={closeSections}>\n {s.label}\n </Link>\n ));\n return (\n <div className=\"topbar\">\n <Link href={home} className=\"brand\">\n <img src={logo} alt=\"\" />\n <span className=\"hide-m\">{name}</span>\n </Link>\n <nav className=\"nav hide-m\" aria-label={t(\"topbar.sections\")}>{links}</nav>\n {center}\n <div className=\"top-actions\">\n {actions}\n <button className=\"avatar\" style={profileOpen ? { boxShadow: \"0 0 0 2px var(--violet)\" } : undefined}\n onClick={() => { setSectionsOpen(false); setProfileOpen((v) => !v); }} aria-label={t(\"topbar.profile\")} aria-expanded={profileOpen}>\n {avatar}\n </button>\n <div className=\"burger\" ref={ref}>\n <button className={`iconbtn${sectionsOpen ? \" on\" : \"\"}`} onClick={() => { setProfileOpen(false); setSectionsOpen((v) => !v); }}\n aria-label={t(\"topbar.sections\")} aria-expanded={sectionsOpen} aria-controls=\"nav-sections\">\n <Icon name={sectionsOpen ? \"x\" : \"menu\"} />\n </button>\n {sectionsOpen && <nav id=\"nav-sections\" className=\"navmenu\" aria-label={t(\"topbar.sections\")}>{links}</nav>}\n </div>\n </div>\n {profileOpen && profileMenu(closeProfile)}\n </div>\n );\n}\n"],"mappings":"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"}