@kth/style 0.0.11 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/dist/cjs/components/Button.d.ts +4 -4
  2. package/dist/cjs/components/ModalNavigationPanel.d.ts +4 -0
  3. package/dist/cjs/components/NavigationPanel.d.ts +7 -0
  4. package/dist/cjs/components/Radio.d.ts +2 -2
  5. package/dist/cjs/components/Select.d.ts +3 -5
  6. package/dist/cjs/components/Tabs.d.ts +1 -34
  7. package/dist/cjs/components/react/PersonalMenuPanel.d.ts +19 -0
  8. package/dist/cjs/components/react/Tabs.d.ts +34 -0
  9. package/dist/cjs/icons/400/ArrowBack.d.ts +2 -1
  10. package/dist/cjs/icons/400/Check.d.ts +2 -1
  11. package/dist/cjs/icons/500/ArrowForward.d.ts +2 -1
  12. package/dist/cjs/index.d.ts +3 -5
  13. package/dist/cjs/index.js +128 -157
  14. package/dist/cjs/react.d.ts +5 -0
  15. package/dist/cjs/react.js +179 -0
  16. package/dist/cjs/stories/ContentTabs.stories.d.ts +1 -2
  17. package/dist/esm/components/Button.d.ts +4 -4
  18. package/dist/esm/components/ModalNavigationPanel.d.ts +4 -0
  19. package/dist/esm/components/NavigationPanel.d.ts +7 -0
  20. package/dist/esm/components/Radio.d.ts +2 -2
  21. package/dist/esm/components/Select.d.ts +3 -5
  22. package/dist/esm/components/Tabs.d.ts +1 -34
  23. package/dist/esm/components/react/PersonalMenuPanel.d.ts +19 -0
  24. package/dist/esm/components/react/Tabs.d.ts +34 -0
  25. package/dist/esm/icons/400/ArrowBack.d.ts +2 -1
  26. package/dist/esm/icons/400/Check.d.ts +2 -1
  27. package/dist/esm/icons/500/ArrowForward.d.ts +2 -1
  28. package/dist/esm/index.d.ts +3 -5
  29. package/dist/esm/index.js +126 -129
  30. package/dist/esm/react.d.ts +5 -0
  31. package/dist/esm/react.js +149 -0
  32. package/dist/esm/stories/ContentTabs.stories.d.ts +1 -2
  33. package/package.json +14 -4
  34. package/scss/components/button.scss +41 -51
  35. package/scss/components/checkbox.scss +63 -0
  36. package/scss/components/details.scss +40 -0
  37. package/scss/components/fieldset.scss +60 -0
  38. package/scss/components/form-control.scss +25 -0
  39. package/scss/components/header-menu-item.scss +38 -0
  40. package/scss/components/input.scss +21 -0
  41. package/scss/components/main-header.scss +105 -0
  42. package/scss/components/search.scss +52 -0
  43. package/scss/components/select.scss +46 -0
  44. package/scss/tokens/colors.scss +63 -0
  45. package/scss/tokens/icons.scss +68 -0
  46. package/scss/tokens/{_spacing.scss → spacing.scss} +15 -0
  47. package/scss/tokens/typography.scss +35 -0
  48. package/scss/utils/mixins.scss +14 -0
  49. package/scss/utils/prose.scss +83 -76
  50. package/scss/utils/reset.scss +53 -255
  51. package/scss/components/content-tabs.scss +0 -68
  52. package/scss/components/filter-tabs.scss +0 -31
  53. package/scss/components/form.scss +0 -48
  54. package/scss/components/inline-icon.scss +0 -7
  55. package/scss/globals.scss +0 -5
  56. package/scss/tokens/_colors.scss +0 -20
  57. package/scss/tokens/_spacing.en.md +0 -40
  58. package/scss/tokens/_typography.scss +0 -71
  59. package/scss/tokens/index.scss +0 -6
  60. package/scss/utils/sizes.scss +0 -22
@@ -0,0 +1,179 @@
1
+ 'use strict';
2
+
3
+ var React = require('react');
4
+
5
+ function _interopNamespaceDefault(e) {
6
+ var n = Object.create(null);
7
+ if (e) {
8
+ Object.keys(e).forEach(function (k) {
9
+ if (k !== 'default') {
10
+ var d = Object.getOwnPropertyDescriptor(e, k);
11
+ Object.defineProperty(n, k, d.get ? d : {
12
+ enumerable: true,
13
+ get: function () { return e[k]; }
14
+ });
15
+ }
16
+ });
17
+ }
18
+ n.default = e;
19
+ return Object.freeze(n);
20
+ }
21
+
22
+ var React__namespace = /*#__PURE__*/_interopNamespaceDefault(React);
23
+
24
+ function getValueFromUrl(key) {
25
+ const url = new URL(location.href);
26
+ if (key) {
27
+ return url.searchParams.get(key);
28
+ }
29
+ else {
30
+ return url.hash === "" ? null : url.hash.slice(1);
31
+ }
32
+ }
33
+ /**
34
+ * Sync state with URL hash or query parameter.
35
+ * @param defaultValue Default state value
36
+ * @param key Query parameter to use. Hash if empty
37
+ * @param enableUrl Will sync with URL if true (this function behaves the same
38
+ * as `React.useState` if false)
39
+ */
40
+ function useUrlState(defaultValue = "", key = "", enableUrl = false) {
41
+ const initialValue = (enableUrl && getValueFromUrl(key)) || defaultValue;
42
+ const [value, _setValue] = React.useState(initialValue);
43
+ React.useEffect(() => {
44
+ function updateValue() {
45
+ if (enableUrl) {
46
+ _setValue(getValueFromUrl(key) || defaultValue);
47
+ }
48
+ }
49
+ window.addEventListener("popstate", updateValue);
50
+ return () => {
51
+ window.removeEventListener("popstate", updateValue);
52
+ };
53
+ });
54
+ function setValue(value) {
55
+ _setValue(value);
56
+ const url = new URL(location.href);
57
+ if (key !== "") {
58
+ url.searchParams.set(key, value);
59
+ }
60
+ else {
61
+ url.hash = "#" + value;
62
+ }
63
+ if (enableUrl) {
64
+ history.pushState(undefined, "", url);
65
+ }
66
+ }
67
+ return [value, setValue];
68
+ }
69
+ function handleKeyDown(event, index, tabs, setActiveTab) {
70
+ event.preventDefault();
71
+ switch (event.key) {
72
+ case "ArrowLeft":
73
+ case "ArrowUp":
74
+ if (index > 0) {
75
+ setActiveTab(tabs[index - 1].props.id);
76
+ }
77
+ break;
78
+ case "ArrowRight":
79
+ case "ArrowDown":
80
+ if (index < tabs.length - 1) {
81
+ setActiveTab(tabs[index + 1].props.id);
82
+ }
83
+ break;
84
+ case "Home":
85
+ setActiveTab(tabs[0].props.id);
86
+ break;
87
+ case "End":
88
+ setActiveTab(tabs[tabs.length - 1].props.id);
89
+ break;
90
+ }
91
+ }
92
+ function useFocus(element) {
93
+ element?.scrollIntoView({ block: "nearest", inline: "nearest" });
94
+ element?.focus();
95
+ }
96
+ /**
97
+ * Highly customizable Tabs component made for testing purposes.
98
+ * You should use {@link NavigationTabs} or {@link ContentTabs} instead.
99
+ */
100
+ function GenericTabs({ classPrefix, children, id, defaultValue, url = "none", }) {
101
+ const ref = React.useRef(null);
102
+ const [activeTab, setActiveTab] = useUrlState(defaultValue, url === "query" ? id : "", url === "query" || url === "hash");
103
+ let activeTabIndex = children.findIndex((c) => c.props.id === activeTab);
104
+ if (activeTabIndex === -1) {
105
+ activeTabIndex = 0;
106
+ }
107
+ useFocus(ref.current?.querySelector(`#${activeTab}-tab`));
108
+ return (React.createElement(React.Fragment, null,
109
+ React.createElement("div", { ref: ref, className: `${classPrefix}`, id: id },
110
+ React.createElement("ul", { className: `${classPrefix}__tablist`, role: "tablist" }, children.map((child, index) => (React.createElement("li", { role: "presentation", className: `${classPrefix}__tab-element` },
111
+ React.createElement("button", { key: child.props.id, role: "tab", "aria-selected": index === activeTabIndex, "aria-controls": child.props.id, id: `${child.props.id}-tab`, className: `${classPrefix}__tab`, tabIndex: index === activeTabIndex ? 0 : -1, onKeyDown: (event) => {
112
+ handleKeyDown(event, index, children, setActiveTab);
113
+ }, onClick: (event) => {
114
+ event.preventDefault();
115
+ setActiveTab(child.props.id);
116
+ } }, child.props.title)))))),
117
+ children.map((child, index) => (React.createElement("div", { className: `${classPrefix}__tabpanel`, role: "tabpanel", "aria-labelledby": `${child.props.id}-tab`, id: child.props.id, key: index, hidden: index !== activeTabIndex }, child)))));
118
+ }
119
+ function NavigationTabs({ id, children, url = "query", defaultValue, }) {
120
+ return (React.createElement(GenericTabs, { id: id, children: children, url: url, defaultValue: defaultValue, classPrefix: "kth-navigation-tabs" }));
121
+ }
122
+ function ContentTabs({ id, children, url = "hash", defaultValue, }) {
123
+ return (React.createElement(GenericTabs, { id: id, children: children, url: url, defaultValue: defaultValue, classPrefix: "kth-content-tabs" }));
124
+ }
125
+ function Tab({ children }) {
126
+ return React.createElement(React.Fragment, null, children);
127
+ }
128
+
129
+ function Select({ name, label, description, value, onChange, children, error, }) {
130
+ const id = `select-${name}`;
131
+ return (React.createElement("div", { className: "kth-select" },
132
+ React.createElement("label", { htmlFor: id }, label),
133
+ description && React.createElement("p", { id: `${id}-description` }, description),
134
+ React.createElement("select", { id: id, "aria-describedby": description && `${id}-description`, name: name, value: value, onChange: (e) => onChange(e.target.value), "aria-invalid": error !== undefined ? "true" : "false" }, children),
135
+ error && (React.createElement("p", { className: "kth-select__error", role: "alert" }, error))));
136
+ }
137
+ function OptionGroup({ label, children }) {
138
+ return React.createElement("optgroup", { label: label }, children);
139
+ }
140
+ function Option({ value, children }) {
141
+ return React.createElement("option", { value: value }, children);
142
+ }
143
+
144
+ const SvgArrowBack = (props) => (React__namespace.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "1.25em", height: "1.25em", viewBox: "0 0 20 20", ...props },
145
+ React__namespace.createElement("path", { fill: "currentColor", d: "m10 16-6-6 6-6 1.063 1.063L6.875 9.25H16v1.5H6.875l4.188 4.188L10 16Z" })));
146
+
147
+ const SvgArrowForward = (props) => (React__namespace.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "1.25em", height: "1.25em", viewBox: "0 0 20 20", ...props },
148
+ React__namespace.createElement("path", { fill: "currentColor", d: "m10 16.075-1.227-1.227 3.983-3.983h-8.83v-1.73h8.83L8.773 5.152 10 3.925 16.075 10 10 16.075Z" })));
149
+
150
+ /** A button with just text */
151
+ function Button({ children, onClick, appearance }) {
152
+ const className = ["kth-button", appearance].join(" ");
153
+ return (React.createElement("button", { onClick: onClick, className: className }, children));
154
+ }
155
+ function BackButton({ children, onClick }) {
156
+ return (React.createElement("button", { onClick: onClick, className: "kth-button tertiary" },
157
+ React.createElement(SvgArrowBack, null),
158
+ children));
159
+ }
160
+ function ForwardButton({ children, onClick }) {
161
+ return (React.createElement("button", { onClick: onClick, className: "kth-button primary" },
162
+ children,
163
+ React.createElement(SvgArrowForward, null)));
164
+ }
165
+
166
+ const SvgCheck = (props) => (React__namespace.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "1.25em", height: "1.25em", viewBox: "0 0 20 20", ...props },
167
+ React__namespace.createElement("path", { fill: "currentColor", d: "M8.23 14.063 4.707 10.52 5.75 9.479l2.48 2.459 6.02-6L15.292 7l-7.063 7.063Z" })));
168
+
169
+ exports.BackButton = BackButton;
170
+ exports.Button = Button;
171
+ exports.ContentTabs = ContentTabs;
172
+ exports.ForwardButton = ForwardButton;
173
+ exports.IconArrowBack = SvgArrowBack;
174
+ exports.IconCheck = SvgCheck;
175
+ exports.NavigationTabs = NavigationTabs;
176
+ exports.Option = Option;
177
+ exports.OptionGroup = OptionGroup;
178
+ exports.Select = Select;
179
+ exports.Tab = Tab;
@@ -1,10 +1,9 @@
1
1
  import type { StoryObj } from "@storybook/react";
2
- import { ContentTabs } from "../components/Tabs";
3
2
  import "../../scss/globals.scss";
4
3
  import "../../scss/components/content-tabs.scss";
5
4
  declare const meta: {
6
5
  title: string;
7
- component: typeof ContentTabs;
6
+ component: any;
8
7
  tags: string[];
9
8
  };
10
9
  export default meta;
@@ -1,4 +1,4 @@
1
- /// <reference types="react" />
1
+ import React from "react";
2
2
  interface ButtonProps {
3
3
  /** The label of the button */
4
4
  children?: string;
@@ -14,7 +14,7 @@ interface IconButtonProps {
14
14
  onClick?: () => void;
15
15
  }
16
16
  /** A button with just text */
17
- export declare function Button({ children, onClick, appearance }: ButtonProps): JSX.Element;
18
- export declare function BackButton({ children, onClick }: IconButtonProps): JSX.Element;
19
- export declare function ForwardButton({ children, onClick }: IconButtonProps): JSX.Element;
17
+ export declare function Button({ children, onClick, appearance }: ButtonProps): React.JSX.Element;
18
+ export declare function BackButton({ children, onClick }: IconButtonProps): React.JSX.Element;
19
+ export declare function ForwardButton({ children, onClick }: IconButtonProps): React.JSX.Element;
20
20
  export {};
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Add open/close functionality to a set of navigation panels
3
+ */
4
+ export declare function setModalNavigationPanels(items: NodeListOf<Element>): void;
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Add open/close functionality to a set of navigation panels
3
+ *
4
+ * @param container The element containing all the menus
5
+ * @param items A list of all menu elements
6
+ */
7
+ export declare function setNavigationPanels(container: HTMLElement | null, items: NodeListOf<Element>): void;
@@ -14,7 +14,7 @@ interface RadioProps {
14
14
  label: string;
15
15
  }
16
16
  /** Implemented as fancy radio buttons */
17
- export declare function FilterTabs({ children, value, onChange }: RadioGroupProps): JSX.Element;
17
+ export declare function FilterTabs({ children, value, onChange }: RadioGroupProps): React.JSX.Element;
18
18
  /** A single radio button */
19
- export declare function Radio({ value, label }: RadioProps): JSX.Element;
19
+ export declare function Radio({ value, label }: RadioProps): React.JSX.Element;
20
20
  export {};
@@ -23,14 +23,12 @@ interface OptionProps {
23
23
  value: string;
24
24
  /** Human-readable label for the option */
25
25
  children: string;
26
- /** True if the option should be disabled */
27
- disabled: boolean;
28
26
  }
29
27
  interface OptionGroupProps {
30
28
  label: string;
31
29
  children: React.ReactNode;
32
30
  }
33
- export declare function Select({ name, label, description, value, onChange, children, error, }: SelectProps): JSX.Element;
34
- export declare function OptionGroup({ label, children }: OptionGroupProps): JSX.Element;
35
- export declare function Option({ value, children, disabled }: OptionProps): JSX.Element;
31
+ export declare function Select({ name, label, description, value, onChange, children, error, }: SelectProps): React.JSX.Element;
32
+ export declare function OptionGroup({ label, children }: OptionGroupProps): React.JSX.Element;
33
+ export declare function Option({ value, children }: OptionProps): React.JSX.Element;
36
34
  export {};
@@ -1,34 +1 @@
1
- import React from "react";
2
- interface TabProps {
3
- children?: React.ReactNode;
4
- id: string;
5
- title: string;
6
- }
7
- interface GenericTabsProps {
8
- classPrefix: string;
9
- children: React.ReactElement<TabProps>[];
10
- id: string;
11
- defaultValue?: string;
12
- url: "query" | "hash" | "none";
13
- }
14
- interface NavigationTabsProps {
15
- id: string;
16
- children: React.ReactElement<TabProps>[];
17
- url?: "query" | "none";
18
- defaultValue?: string;
19
- }
20
- interface ContentTabsProps {
21
- id: string;
22
- children: React.ReactElement<TabProps>[];
23
- url?: "hash" | "none";
24
- defaultValue?: string;
25
- }
26
- /**
27
- * Highly customizable Tabs component made for testing purposes.
28
- * You should use {@link NavigationTabs} or {@link ContentTabs} instead.
29
- */
30
- export declare function GenericTabs({ classPrefix, children, id, defaultValue, url, }: GenericTabsProps): JSX.Element;
31
- export declare function NavigationTabs({ id, children, url, defaultValue, }: NavigationTabsProps): JSX.Element;
32
- export declare function ContentTabs({ id, children, url, defaultValue, }: ContentTabsProps): JSX.Element;
33
- export declare function Tab({ children }: TabProps): JSX.Element;
34
- export {};
1
+ export declare function initTabs(container: Element): void;
@@ -0,0 +1,19 @@
1
+ import React from "react";
2
+ /**
3
+ * A panel with a button that opens it.
4
+ *
5
+ * - `children` is mounted the first time the dialog is opened. It is _not_
6
+ * unmounted after the dialog is closed.
7
+ */
8
+ export declare function PersonalMenuPanel({ label, children }: {
9
+ label: any;
10
+ children: any;
11
+ }): React.JSX.Element;
12
+ interface PersonalMenuPanelGroupProps {
13
+ children: React.ReactElement;
14
+ }
15
+ /**
16
+ * Contains all <PersonalMenuPanel /> components in a menu
17
+ */
18
+ export declare function PersonalMenuPanelGroup({ children, }: PersonalMenuPanelGroupProps): React.JSX.Element;
19
+ export {};
@@ -0,0 +1,34 @@
1
+ import React from "react";
2
+ interface TabProps {
3
+ children?: React.ReactNode;
4
+ id: string;
5
+ title: string;
6
+ }
7
+ interface GenericTabsProps {
8
+ classPrefix: string;
9
+ children: React.ReactElement<TabProps>[];
10
+ id: string;
11
+ defaultValue?: string;
12
+ url: "query" | "hash" | "none";
13
+ }
14
+ interface NavigationTabsProps {
15
+ id: string;
16
+ children: React.ReactElement<TabProps>[];
17
+ url?: "query" | "none";
18
+ defaultValue?: string;
19
+ }
20
+ interface ContentTabsProps {
21
+ id: string;
22
+ children: React.ReactElement<TabProps>[];
23
+ url?: "hash" | "none";
24
+ defaultValue?: string;
25
+ }
26
+ /**
27
+ * Highly customizable Tabs component made for testing purposes.
28
+ * You should use {@link NavigationTabs} or {@link ContentTabs} instead.
29
+ */
30
+ export declare function GenericTabs({ classPrefix, children, id, defaultValue, url, }: GenericTabsProps): React.JSX.Element;
31
+ export declare function NavigationTabs({ id, children, url, defaultValue, }: NavigationTabsProps): React.JSX.Element;
32
+ export declare function ContentTabs({ id, children, url, defaultValue, }: ContentTabsProps): React.JSX.Element;
33
+ export declare function Tab({ children }: TabProps): React.JSX.Element;
34
+ export {};
@@ -1,3 +1,4 @@
1
+ import * as React from "react";
1
2
  import type { SVGProps } from "react";
2
- declare const SvgArrowBack: (props: SVGProps<SVGSVGElement>) => JSX.Element;
3
+ declare const SvgArrowBack: (props: SVGProps<SVGSVGElement>) => React.JSX.Element;
3
4
  export default SvgArrowBack;
@@ -1,3 +1,4 @@
1
+ import * as React from "react";
1
2
  import type { SVGProps } from "react";
2
- declare const SvgCheck: (props: SVGProps<SVGSVGElement>) => JSX.Element;
3
+ declare const SvgCheck: (props: SVGProps<SVGSVGElement>) => React.JSX.Element;
3
4
  export default SvgCheck;
@@ -1,3 +1,4 @@
1
+ import * as React from "react";
1
2
  import type { SVGProps } from "react";
2
- declare const SvgArrowForward: (props: SVGProps<SVGSVGElement>) => JSX.Element;
3
+ declare const SvgArrowForward: (props: SVGProps<SVGSVGElement>) => React.JSX.Element;
3
4
  export default SvgArrowForward;
@@ -1,5 +1,3 @@
1
- export { Tab, ContentTabs, NavigationTabs } from "./components/Tabs";
2
- export { Select, Option, OptionGroup } from "./components/Select";
3
- export { BackButton, Button, ForwardButton } from "./components/Button";
4
- export { default as IconArrowBack } from "./icons/400/ArrowBack";
5
- export { default as IconCheck } from "./icons/400/Check";
1
+ export { setNavigationPanels } from "./components/NavigationPanel";
2
+ export { setModalNavigationPanels } from "./components/ModalNavigationPanel";
3
+ export { initTabs } from "./components/Tabs";
package/dist/esm/index.js CHANGED
@@ -1,149 +1,146 @@
1
- import * as React from 'react';
2
- import React__default from 'react';
3
-
4
- function getValueFromUrl(key) {
5
- const url = new URL(location.href);
6
- if (key) {
7
- return url.searchParams.get(key);
8
- }
9
- else {
10
- return url.hash === "" ? null : url.hash.slice(1);
11
- }
1
+ /**
2
+ * Close all <dialog>s (modal and non-modal) in a document
3
+ */
4
+ function closeAllDialogs$1() {
5
+ document.querySelectorAll("dialog").forEach((dialog) => dialog.close());
12
6
  }
13
7
  /**
14
- * Sync state with URL hash or query parameter.
15
- * @param defaultValue Default state value
16
- * @param key Query parameter to use. Hash if empty
17
- * @param enableUrl Will sync with URL if true (this function behaves the same
18
- * as `React.useState` if false)
8
+ * Add open/close functionality to a set of navigation panels
9
+ *
10
+ * @param container The element containing all the menus
11
+ * @param items A list of all menu elements
19
12
  */
20
- function useUrlState(defaultValue = "", key = "", enableUrl = false) {
21
- const initialValue = (enableUrl && getValueFromUrl(key)) || defaultValue;
22
- const [value, _setValue] = React__default.useState(initialValue);
23
- React__default.useEffect(() => {
24
- function updateValue() {
25
- if (enableUrl) {
26
- _setValue(getValueFromUrl(key) || defaultValue);
27
- }
28
- }
29
- window.addEventListener("popstate", updateValue);
30
- return () => {
31
- window.removeEventListener("popstate", updateValue);
32
- };
33
- });
34
- function setValue(value) {
35
- _setValue(value);
36
- const url = new URL(location.href);
37
- if (key !== "") {
38
- url.searchParams.set(key, value);
13
+ function setNavigationPanels(container, items) {
14
+ if (!container) {
15
+ return;
16
+ }
17
+ for (const item of items) {
18
+ if (!(item instanceof HTMLElement)) {
19
+ continue;
39
20
  }
40
- else {
41
- url.hash = "#" + value;
21
+ const dialog = item.nextElementSibling;
22
+ if (!(dialog instanceof HTMLDialogElement)) {
23
+ continue;
42
24
  }
43
- if (enableUrl) {
44
- history.pushState(undefined, "", url);
25
+ dialog.addEventListener("keydown", (e) => {
26
+ if (e.key === "Escape") {
27
+ closeAllDialogs$1();
28
+ }
29
+ });
30
+ const closeButton = dialog.querySelector(".close");
31
+ if (closeButton instanceof HTMLButtonElement) {
32
+ closeButton.addEventListener("click", () => {
33
+ closeAllDialogs$1();
34
+ });
45
35
  }
46
- }
47
- return [value, setValue];
48
- }
49
- function handleKeyDown(event, index, tabs, setActiveTab) {
50
- event.preventDefault();
51
- switch (event.key) {
52
- case "ArrowLeft":
53
- case "ArrowUp":
54
- if (index > 0) {
55
- setActiveTab(tabs[index - 1].props.id);
36
+ item.addEventListener("click", (e) => {
37
+ e.preventDefault();
38
+ if (!dialog.open) {
39
+ closeAllDialogs$1();
40
+ dialog.show();
56
41
  }
57
- break;
58
- case "ArrowRight":
59
- case "ArrowDown":
60
- if (index < tabs.length - 1) {
61
- setActiveTab(tabs[index + 1].props.id);
42
+ else {
43
+ closeAllDialogs$1();
62
44
  }
63
- break;
64
- case "Home":
65
- setActiveTab(tabs[0].props.id);
66
- break;
67
- case "End":
68
- setActiveTab(tabs[tabs.length - 1].props.id);
69
- break;
45
+ });
70
46
  }
47
+ container.addEventListener("focusout", function (e) {
48
+ const target = e.relatedTarget;
49
+ if (target && target instanceof Node && !container.contains(target)) {
50
+ closeAllDialogs$1();
51
+ }
52
+ });
71
53
  }
72
- function useFocus(element) {
73
- element?.scrollIntoView({ block: "nearest", inline: "nearest" });
74
- element?.focus();
54
+
55
+ /**
56
+ * Close all <dialog>s (modal and non-modal) in a document
57
+ */
58
+ function closeAllDialogs() {
59
+ document.querySelectorAll("dialog").forEach((dialog) => dialog.close());
75
60
  }
76
61
  /**
77
- * Highly customizable Tabs component made for testing purposes.
78
- * You should use {@link NavigationTabs} or {@link ContentTabs} instead.
62
+ * Add open/close functionality to a set of navigation panels
79
63
  */
80
- function GenericTabs({ classPrefix, children, id, defaultValue, url = "none", }) {
81
- const ref = React__default.useRef(null);
82
- const [activeTab, setActiveTab] = useUrlState(defaultValue, url === "query" ? id : "", url === "query" || url === "hash");
83
- let activeTabIndex = children.findIndex((c) => c.props.id === activeTab);
84
- if (activeTabIndex === -1) {
85
- activeTabIndex = 0;
64
+ function setModalNavigationPanels(items) {
65
+ for (const item of items) {
66
+ if (!(item instanceof HTMLElement)) {
67
+ continue;
68
+ }
69
+ const dialog = item.nextElementSibling;
70
+ if (!(dialog instanceof HTMLDialogElement)) {
71
+ continue;
72
+ }
73
+ dialog.addEventListener("keydown", (e) => {
74
+ e.stopPropagation();
75
+ if (e.key === "Escape") {
76
+ dialog.close();
77
+ }
78
+ });
79
+ const closeButton = dialog.querySelector(".close");
80
+ if (closeButton instanceof HTMLButtonElement) {
81
+ closeButton.addEventListener("click", () => {
82
+ closeAllDialogs();
83
+ });
84
+ }
85
+ item.addEventListener("click", (e) => {
86
+ e.preventDefault();
87
+ // closeAllDialogs();
88
+ dialog.showModal();
89
+ });
86
90
  }
87
- useFocus(ref.current?.querySelector(`#${activeTab}-tab`));
88
- return (React__default.createElement(React__default.Fragment, null,
89
- React__default.createElement("div", { ref: ref, className: `${classPrefix}`, id: id },
90
- React__default.createElement("ul", { className: `${classPrefix}__tablist`, role: "tablist" }, children.map((child, index) => (React__default.createElement("li", { role: "presentation", className: `${classPrefix}__tab-element` },
91
- React__default.createElement("button", { key: child.props.id, role: "tab", "aria-selected": index === activeTabIndex, "aria-controls": child.props.id, id: `${child.props.id}-tab`, className: `${classPrefix}__tab`, tabIndex: index === activeTabIndex ? 0 : -1, onKeyDown: (event) => {
92
- handleKeyDown(event, index, children, setActiveTab);
93
- }, onClick: (event) => {
94
- event.preventDefault();
95
- setActiveTab(child.props.id);
96
- } }, child.props.title)))))),
97
- children.map((child, index) => (React__default.createElement("div", { className: `${classPrefix}__tabpanel`, role: "tabpanel", "aria-labelledby": `${child.props.id}-tab`, id: child.props.id, key: index, hidden: index !== activeTabIndex }, child)))));
98
- }
99
- function NavigationTabs({ id, children, url = "query", defaultValue, }) {
100
- return (React__default.createElement(GenericTabs, { id: id, children: children, url: url, defaultValue: defaultValue, classPrefix: "kth-navigation-tabs" }));
101
- }
102
- function ContentTabs({ id, children, url = "hash", defaultValue, }) {
103
- return (React__default.createElement(GenericTabs, { id: id, children: children, url: url, defaultValue: defaultValue, classPrefix: "kth-content-tabs" }));
104
- }
105
- function Tab({ children }) {
106
- return React__default.createElement(React__default.Fragment, null, children);
107
- }
108
-
109
- function Select({ name, label, description, value, onChange, children, error, }) {
110
- const id = `select-${name}`;
111
- return (React__default.createElement("div", { className: "kth-select" },
112
- React__default.createElement("label", { htmlFor: id }, label),
113
- description && React__default.createElement("p", { id: `${id}-description` }, description),
114
- React__default.createElement("select", { id: id, "aria-describedby": description && `${id}-description`, name: name, value: value, onChange: (e) => onChange(e.target.value), "aria-invalid": error !== undefined ? "true" : "false" }, children),
115
- error && (React__default.createElement("p", { className: "kth-select__error", role: "alert" }, error))));
116
- }
117
- function OptionGroup({ label, children }) {
118
- return React__default.createElement("optgroup", { label: label }, children);
119
- }
120
- function Option({ value, children, disabled }) {
121
- return (React__default.createElement("option", { value: value, disabled: disabled }, children));
122
91
  }
123
92
 
124
- const SvgArrowBack = (props) => (React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "1.25em", height: "1.25em", viewBox: "0 0 20 20", ...props },
125
- React.createElement("path", { fill: "currentColor", d: "m10 16-6-6 6-6 1.063 1.063L6.875 9.25H16v1.5H6.875l4.188 4.188L10 16Z" })));
126
-
127
- const SvgArrowForward = (props) => (React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "1.25em", height: "1.25em", viewBox: "0 0 20 20", ...props },
128
- React.createElement("path", { fill: "currentColor", d: "m10 16.075-1.227-1.227 3.983-3.983h-8.83v-1.73h8.83L8.773 5.152 10 3.925 16.075 10 10 16.075Z" })));
129
-
130
- /** A button with just text */
131
- function Button({ children, onClick, appearance }) {
132
- const className = ["kth-button", appearance].join(" ");
133
- return (React__default.createElement("button", { onClick: onClick, className: className }, children));
93
+ function getPanel(tab) {
94
+ const panelId = tab.getAttribute("aria-controls");
95
+ if (!panelId) {
96
+ throw new Error();
97
+ }
98
+ const panel = document.getElementById(panelId);
99
+ if (!(panel instanceof HTMLElement)) {
100
+ throw new Error();
101
+ }
102
+ return panel;
134
103
  }
135
- function BackButton({ children, onClick }) {
136
- return (React__default.createElement("button", { onClick: onClick, className: "kth-button tertiary" },
137
- React__default.createElement(SvgArrowBack, null),
138
- children));
104
+ function closeAllTabs(tabs) {
105
+ for (const tab of tabs) {
106
+ if (tab instanceof HTMLElement) {
107
+ tab.ariaSelected = "false";
108
+ const panel = getPanel(tab);
109
+ if (panel) {
110
+ panel.hidden = true;
111
+ }
112
+ }
113
+ }
139
114
  }
140
- function ForwardButton({ children, onClick }) {
141
- return (React__default.createElement("button", { onClick: onClick, className: "kth-button primary" },
142
- children,
143
- React__default.createElement(SvgArrowForward, null)));
115
+ function initTabs(container) {
116
+ if (!(container instanceof HTMLElement)) {
117
+ return;
118
+ }
119
+ const tablist = container.querySelector("[role=tablist]");
120
+ if (!tablist) {
121
+ return;
122
+ }
123
+ const tabs = tablist.querySelectorAll("[role=tab]");
124
+ function openTab(tab) {
125
+ const panel = getPanel(tab);
126
+ if (!panel) {
127
+ return;
128
+ }
129
+ tab.ariaSelected = "true";
130
+ panel.hidden = false;
131
+ }
132
+ for (const tab of tabs) {
133
+ if (tab instanceof HTMLElement) {
134
+ tab.addEventListener("click", () => {
135
+ closeAllTabs(tabs);
136
+ openTab(tab);
137
+ });
138
+ }
139
+ }
140
+ if (tabs[0] instanceof HTMLElement) {
141
+ closeAllTabs(tabs);
142
+ openTab(tabs[0]);
143
+ }
144
144
  }
145
145
 
146
- const SvgCheck = (props) => (React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "1.25em", height: "1.25em", viewBox: "0 0 20 20", ...props },
147
- React.createElement("path", { fill: "currentColor", d: "M8.23 14.063 4.707 10.52 5.75 9.479l2.48 2.459 6.02-6L15.292 7l-7.063 7.063Z" })));
148
-
149
- export { BackButton, Button, ContentTabs, ForwardButton, SvgArrowBack as IconArrowBack, SvgCheck as IconCheck, NavigationTabs, Option, OptionGroup, Select, Tab };
146
+ export { initTabs, setModalNavigationPanels, setNavigationPanels };