@cedx/ui 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 (108) hide show
  1. package/License.md +20 -0
  2. package/ReadMe.md +17 -0
  3. package/lib/Alignment.d.ts +22 -0
  4. package/lib/Alignment.d.ts.map +1 -0
  5. package/lib/Alignment.js +17 -0
  6. package/lib/AppTheme.d.ts +34 -0
  7. package/lib/AppTheme.d.ts.map +1 -0
  8. package/lib/AppTheme.js +41 -0
  9. package/lib/Components/BackButton.d.ts +27 -0
  10. package/lib/Components/BackButton.d.ts.map +1 -0
  11. package/lib/Components/BackButton.js +29 -0
  12. package/lib/Components/DialogBox.d.ts +151 -0
  13. package/lib/Components/DialogBox.d.ts.map +1 -0
  14. package/lib/Components/DialogBox.js +268 -0
  15. package/lib/Components/FullScreenToggler.d.ts +42 -0
  16. package/lib/Components/FullScreenToggler.d.ts.map +1 -0
  17. package/lib/Components/FullScreenToggler.js +103 -0
  18. package/lib/Components/KeyboardAccelerator.d.ts +36 -0
  19. package/lib/Components/KeyboardAccelerator.d.ts.map +1 -0
  20. package/lib/Components/KeyboardAccelerator.js +78 -0
  21. package/lib/Components/LoadingIndicator.d.ts +58 -0
  22. package/lib/Components/LoadingIndicator.d.ts.map +1 -0
  23. package/lib/Components/LoadingIndicator.js +93 -0
  24. package/lib/Components/MenuActivator.d.ts +26 -0
  25. package/lib/Components/MenuActivator.d.ts.map +1 -0
  26. package/lib/Components/MenuActivator.js +42 -0
  27. package/lib/Components/OfflineIndicator.d.ts +59 -0
  28. package/lib/Components/OfflineIndicator.d.ts.map +1 -0
  29. package/lib/Components/OfflineIndicator.js +106 -0
  30. package/lib/Components/TabActivator.d.ts +49 -0
  31. package/lib/Components/TabActivator.d.ts.map +1 -0
  32. package/lib/Components/TabActivator.js +70 -0
  33. package/lib/Components/ThemeDropdown.d.ts +86 -0
  34. package/lib/Components/ThemeDropdown.d.ts.map +1 -0
  35. package/lib/Components/ThemeDropdown.js +207 -0
  36. package/lib/Components/Toast.d.ts +94 -0
  37. package/lib/Components/Toast.d.ts.map +1 -0
  38. package/lib/Components/Toast.js +284 -0
  39. package/lib/Components/Toaster.d.ts +119 -0
  40. package/lib/Components/Toaster.d.ts.map +1 -0
  41. package/lib/Components/Toaster.js +153 -0
  42. package/lib/Components/TypeAhead.d.ts +53 -0
  43. package/lib/Components/TypeAhead.d.ts.map +1 -0
  44. package/lib/Components/TypeAhead.js +138 -0
  45. package/lib/Context.d.ts +38 -0
  46. package/lib/Context.d.ts.map +1 -0
  47. package/lib/Context.js +42 -0
  48. package/lib/DialogResult.d.ts +30 -0
  49. package/lib/DialogResult.d.ts.map +1 -0
  50. package/lib/DialogResult.js +29 -0
  51. package/lib/File.d.ts +25 -0
  52. package/lib/File.d.ts.map +1 -0
  53. package/lib/File.js +66 -0
  54. package/lib/Form.d.ts +33 -0
  55. package/lib/Form.d.ts.map +1 -0
  56. package/lib/Form.js +50 -0
  57. package/lib/Htmx.d.ts +12 -0
  58. package/lib/Htmx.d.ts.map +1 -0
  59. package/lib/Htmx.js +2 -0
  60. package/lib/KeyboardModifiers.d.ts +26 -0
  61. package/lib/KeyboardModifiers.d.ts.map +1 -0
  62. package/lib/KeyboardModifiers.js +25 -0
  63. package/lib/Position.d.ts +52 -0
  64. package/lib/Position.d.ts.map +1 -0
  65. package/lib/Position.js +59 -0
  66. package/lib/Size.d.ts +40 -0
  67. package/lib/Size.d.ts.map +1 -0
  68. package/lib/Size.js +44 -0
  69. package/lib/StorageArea.d.ts +18 -0
  70. package/lib/StorageArea.d.ts.map +1 -0
  71. package/lib/StorageArea.js +13 -0
  72. package/lib/Tags.d.ts +15 -0
  73. package/lib/Tags.d.ts.map +1 -0
  74. package/lib/Tags.js +48 -0
  75. package/lib/Variant.d.ts +36 -0
  76. package/lib/Variant.d.ts.map +1 -0
  77. package/lib/Variant.js +31 -0
  78. package/lib/ViewportScroller.d.ts +49 -0
  79. package/lib/ViewportScroller.d.ts.map +1 -0
  80. package/lib/ViewportScroller.js +69 -0
  81. package/package.json +58 -0
  82. package/src/Client/Alignment.ts +25 -0
  83. package/src/Client/AppTheme.ts +51 -0
  84. package/src/Client/Components/BackButton.ts +45 -0
  85. package/src/Client/Components/DialogBox.ts +344 -0
  86. package/src/Client/Components/FullScreenToggler.ts +122 -0
  87. package/src/Client/Components/KeyboardAccelerator.ts +97 -0
  88. package/src/Client/Components/LoadingIndicator.ts +113 -0
  89. package/src/Client/Components/MenuActivator.ts +58 -0
  90. package/src/Client/Components/OfflineIndicator.ts +125 -0
  91. package/src/Client/Components/TabActivator.ts +93 -0
  92. package/src/Client/Components/ThemeDropdown.ts +235 -0
  93. package/src/Client/Components/Toast.ts +319 -0
  94. package/src/Client/Components/Toaster.ts +224 -0
  95. package/src/Client/Components/TypeAhead.ts +153 -0
  96. package/src/Client/Context.ts +53 -0
  97. package/src/Client/DialogResult.ts +35 -0
  98. package/src/Client/File.ts +73 -0
  99. package/src/Client/Form.ts +55 -0
  100. package/src/Client/Htmx.ts +13 -0
  101. package/src/Client/KeyboardModifiers.ts +30 -0
  102. package/src/Client/Position.ts +74 -0
  103. package/src/Client/Size.ts +56 -0
  104. package/src/Client/StorageArea.ts +20 -0
  105. package/src/Client/Tags.ts +58 -0
  106. package/src/Client/Variant.ts +42 -0
  107. package/src/Client/ViewportScroller.ts +89 -0
  108. package/src/Client/tsconfig.json +19 -0
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Defines contextual modifiers.
3
+ */
4
+ export const Context = Object.freeze({
5
+
6
+ /**
7
+ * A danger.
8
+ */
9
+ Danger: "Danger",
10
+
11
+ /**
12
+ * A warning.
13
+ */
14
+ Warning: "Warning",
15
+
16
+ /**
17
+ * An information.
18
+ */
19
+ Info: "Info",
20
+
21
+ /**
22
+ * A success.
23
+ */
24
+ Success: "Success"
25
+ });
26
+
27
+ /**
28
+ * Defines contextual modifiers.
29
+ */
30
+ export type Context = typeof Context[keyof typeof Context];
31
+
32
+ /**
33
+ * Returns the CSS class of the specified context.
34
+ * @param context The context.
35
+ * @returns The CSS class of the specified context.
36
+ */
37
+ export function cssClass(context: Context): string {
38
+ return context.toLowerCase();
39
+ }
40
+
41
+ /**
42
+ * Gets the icon corresponding to the specified context.
43
+ * @param context The context.
44
+ * @returns The icon corresponding to the specified context.
45
+ */
46
+ export function icon(context: Context): string {
47
+ switch (context) {
48
+ case Context.Danger: return "error";
49
+ case Context.Success: return "check_circle";
50
+ case Context.Warning: return "warning";
51
+ default: return "info";
52
+ }
53
+ }
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Specifies common return values of a dialog box.
3
+ */
4
+ export const DialogResult = Object.freeze({
5
+
6
+ /**
7
+ * The dialog box does not return any value.
8
+ */
9
+ None: "",
10
+
11
+ /**
12
+ * The return value of the dialog box is "OK".
13
+ */
14
+ OK: "OK",
15
+
16
+ /**
17
+ * The return value of the dialog box is "Cancel".
18
+ */
19
+ Cancel: "Cancel",
20
+
21
+ /**
22
+ * The return value of the dialog box is "Abort".
23
+ */
24
+ Abort: "Abort",
25
+
26
+ /**
27
+ * The return value of the dialog box is "Retry".
28
+ */
29
+ Retry: "Retry",
30
+
31
+ /**
32
+ * The return value of the dialog box is "Ignore".
33
+ */
34
+ Ignore: "Ignore"
35
+ });
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Downloads the specified file.
3
+ * @param file The file to be downloaded.
4
+ */
5
+ export function download(file: File): void {
6
+ const url = URL.createObjectURL(file);
7
+ const anchor = document.createElement("a");
8
+ anchor.download = file.name;
9
+ anchor.href = url;
10
+
11
+ document.body.appendChild(anchor);
12
+ anchor.click();
13
+ document.body.removeChild(anchor);
14
+ URL.revokeObjectURL(url);
15
+ }
16
+
17
+ /**
18
+ * Opens the specified file.
19
+ * @param file The file to be opened.
20
+ * @param options Value indicating whether to open the file in a new tab.
21
+ */
22
+ export function open(file: File, options: {newTab?: boolean} = {}): void {
23
+ const url = URL.createObjectURL(file);
24
+ if (!options.newTab) {
25
+ location.assign(url);
26
+ return;
27
+ }
28
+
29
+ const handle = window.open(url, "_blank");
30
+ if (!handle) {
31
+ location.assign(url);
32
+ return;
33
+ }
34
+
35
+ const timer = window.setInterval(() => {
36
+ if (!handle.closed) return;
37
+ clearInterval(timer);
38
+ URL.revokeObjectURL(url);
39
+ }, 5_000);
40
+ }
41
+
42
+ /**
43
+ * Prints the specified file.
44
+ * @param file The file to be printed.
45
+ */
46
+ export function print(file: File): void {
47
+ const url = URL.createObjectURL(file);
48
+ const frame = document.createElement("iframe");
49
+ frame.addEventListener("load", () => frame.contentWindow?.print());
50
+ frame.hidden = true;
51
+ frame.src = url;
52
+
53
+ window.addEventListener("focus", () => {
54
+ document.body.removeChild(frame);
55
+ URL.revokeObjectURL(url);
56
+ }, {once: true});
57
+
58
+ document.body.appendChild(frame);
59
+ }
60
+
61
+ /**
62
+ * Converts the specified file to a data URL.
63
+ * @param file The file to convert.
64
+ * @returns The data URL corresponding to the given file.
65
+ */
66
+ export function toDataUrl(file: File): Promise<URL> {
67
+ return new Promise((resolve, reject) => {
68
+ const reader = new FileReader;
69
+ reader.addEventListener("error", reject);
70
+ reader.addEventListener("load", () => resolve(new URL(reader.result as string)));
71
+ reader.readAsDataURL(file);
72
+ });
73
+ }
@@ -0,0 +1,55 @@
1
+ /**
2
+ * The types of form controls that are not text inputs.
3
+ */
4
+ const nonTextualTypes = new Set<string>(["button", "checkbox", "file", "hidden", "image", "password", "radio", "range", "reset", "submit"]);
5
+
6
+ /**
7
+ * Represents a form control.
8
+ */
9
+ export type FormControl = HTMLInputElement|HTMLSelectElement|HTMLTextAreaElement;
10
+
11
+ /**
12
+ * Gets all controls belonging to the specified form.
13
+ * @param form The form element.
14
+ * @returns The controls belonging to the specified form.
15
+ */
16
+ export function getControls(form: HTMLFormElement): FormControl[] {
17
+ return Array.from(form.elements).filter(isControl);
18
+ }
19
+
20
+ /**
21
+ * Returns the first invalid control from the specified form.
22
+ * @param form The form element.
23
+ * @returns The first invalid control, or `null` if all controls are valid.
24
+ */
25
+ export function invalidControl(form: HTMLFormElement): FormControl|null {
26
+ return form.querySelector(":not(fieldset):invalid");
27
+ }
28
+
29
+ /**
30
+ * Returns a value indicating whether the specified element is a form control.
31
+ * @param element The element to check.
32
+ * @returns `true` if the specified element is a form control, otherwise `false`.
33
+ */
34
+ export function isControl(element: Element): element is FormControl {
35
+ return element instanceof HTMLInputElement || element instanceof HTMLSelectElement || element instanceof HTMLTextAreaElement;
36
+ }
37
+
38
+ /**
39
+ * Resets the validity of the specified element.
40
+ * @param element The element to process.
41
+ */
42
+ export function resetValidity(element: Element): void {
43
+ if (element instanceof HTMLFormElement) getControls(element).forEach(control => control.setCustomValidity(""));
44
+ else if (isControl(element)) element.setCustomValidity("");
45
+ }
46
+
47
+ /**
48
+ * Removes whitespace from both ends of the value of the specified element.
49
+ * @param element The element to process.
50
+ */
51
+ export function trimControl(element: Element): void {
52
+ if (element instanceof HTMLFormElement) getControls(element).forEach(trimControl);
53
+ else if (element instanceof HTMLInputElement && !nonTextualTypes.has(element.type)) element.value = element.value.trim();
54
+ else if (element instanceof HTMLTextAreaElement) element.value = element.value.trim();
55
+ }
@@ -0,0 +1,13 @@
1
+ import htmx, {type HtmxResponseInfo} from "htmx.org";
2
+ export const Htmx = htmx as unknown as typeof htmx.default;
3
+
4
+ /**
5
+ * Provides details about an `htmx` event.
6
+ */
7
+ export type HtmxEventDetail = HtmxResponseInfo & {
8
+
9
+ /**
10
+ * The element involved in the operation that just occurred.
11
+ */
12
+ elt: Element;
13
+ };
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Enumerates modifier flags for keyboard accelerators.
3
+ */
4
+ export const KeyboardModifiers = Object.freeze({
5
+
6
+ /**
7
+ * Indicates no modifier.
8
+ */
9
+ None: 0,
10
+
11
+ /**
12
+ * Indicates the `Control` modifier.
13
+ */
14
+ Ctrl: 1,
15
+
16
+ /**
17
+ * Indicates the `Shift` modifier.
18
+ */
19
+ Shift: 2,
20
+
21
+ /**
22
+ * Indicates the `Alt` modifier (`Option` key on macOS, `Menu` key on Windows).
23
+ */
24
+ Alt: 4,
25
+
26
+ /**
27
+ * Indicates the `Meta` modifier (`Command` key on macOS, `Windows` key on Windows).
28
+ */
29
+ Meta: 8
30
+ });
@@ -0,0 +1,74 @@
1
+ /**
2
+ * Defines the position of an element.
3
+ */
4
+ export const Position = Object.freeze({
5
+
6
+ /**
7
+ * Top left.
8
+ */
9
+ TopStart: "TopStart",
10
+
11
+ /**
12
+ * Top center.
13
+ */
14
+ TopCenter: "TopCenter",
15
+
16
+ /**
17
+ * Top right.
18
+ */
19
+ TopEnd: "TopEnd",
20
+
21
+ /**
22
+ * Middle left.
23
+ */
24
+ MiddleStart: "MiddleStart",
25
+
26
+ /**
27
+ * Middle center.
28
+ */
29
+ MiddleCenter: "MiddleCenter",
30
+
31
+ /**
32
+ * Middle right.
33
+ */
34
+ MiddleEnd: "MiddleEnd",
35
+
36
+ /**
37
+ * Bottom left.
38
+ */
39
+ BottomStart: "BottomStart",
40
+
41
+ /**
42
+ * Bottom center.
43
+ */
44
+ BottomCenter: "BottomCenter",
45
+
46
+ /**
47
+ * Bottom right.
48
+ */
49
+ BottomEnd: "BottomEnd"
50
+ });
51
+
52
+ /**
53
+ * Defines the placement of an element.
54
+ */
55
+ export type Position = typeof Position[keyof typeof Position];
56
+
57
+ /**
58
+ * Returns the CSS class of the specified position.
59
+ * @param position The position.
60
+ * @returns The CSS class of the specified position.
61
+ */
62
+ export function cssClass(position: Position): string {
63
+ switch (position) {
64
+ case Position.TopCenter: return "top-0 start-50 translate-middle-x";
65
+ case Position.TopEnd: return "top-0 end-0";
66
+ case Position.MiddleStart: return "top-50 start-0 translate-middle-y";
67
+ case Position.MiddleCenter: return "top-50 start-50 translate-middle";
68
+ case Position.MiddleEnd: return "top-50 end-0 translate-middle-y";
69
+ case Position.BottomStart: return "bottom-0 start-0";
70
+ case Position.BottomCenter: return "bottom-0 start-50 translate-middle-x";
71
+ case Position.BottomEnd: return "bottom-0 end-0";
72
+ default: return "top-0 start-0";
73
+ }
74
+ }
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Defines the size of an element.
3
+ */
4
+ export const Size = Object.freeze({
5
+
6
+ /**
7
+ * An extra small size.
8
+ */
9
+ ExtraSmall: "ExtraSmall",
10
+
11
+ /**
12
+ * A small size.
13
+ */
14
+ Small: "Small",
15
+
16
+ /**
17
+ * A medium size.
18
+ */
19
+ Medium: "Medium",
20
+
21
+ /**
22
+ * A large size.
23
+ */
24
+ Large: "Large",
25
+
26
+ /**
27
+ * An extra large size.
28
+ */
29
+ ExtraLarge: "ExtraLarge",
30
+
31
+ /**
32
+ * An extra extra large size.
33
+ */
34
+ ExtraExtraLarge: "ExtraExtraLarge"
35
+ });
36
+
37
+ /**
38
+ * Defines the size of an element.
39
+ */
40
+ export type Size = typeof Size[keyof typeof Size];
41
+
42
+ /**
43
+ * Returns the CSS class of the specified size.
44
+ * @param size The size.
45
+ * @returns The CSS class of the specified size.
46
+ */
47
+ export function cssClass(size: Size): string {
48
+ switch (size) {
49
+ case Size.ExtraSmall: return "xs";
50
+ case Size.Small: return "sm";
51
+ case Size.Large: return "lg";
52
+ case Size.ExtraLarge: return "xl";
53
+ case Size.ExtraExtraLarge: return "xxl";
54
+ default: return "md";
55
+ }
56
+ }
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Identifies the web storage area.
3
+ */
4
+ export const StorageArea = Object.freeze({
5
+
6
+ /**
7
+ * Indicates the local storage.
8
+ */
9
+ Local: "Local",
10
+
11
+ /**
12
+ * Indicates the session storage.
13
+ */
14
+ Session: "Session"
15
+ });
16
+
17
+ /**
18
+ * Identifies the web storage area.
19
+ */
20
+ export type StorageArea = typeof StorageArea[keyof typeof StorageArea];
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Creates a CSS stylesheet from the specified template literal.
3
+ * @param fragments The string fragments.
4
+ * @param values The interpolated values.
5
+ * @returns The CSS stylesheet corresponding to the specified template literal.
6
+ */
7
+ export function css(fragments: TemplateStringsArray, ...values: unknown[]): CSSStyleSheet {
8
+ const styleSheet = new CSSStyleSheet;
9
+ styleSheet.replaceSync(fragments.length == 1 ? fragments[0] : values.reduce(
10
+ (fragment: string, value: unknown, index: number) => fragment + stringFromCss(value) + fragments[index + 1],
11
+ fragments[0]
12
+ ));
13
+
14
+ return styleSheet;
15
+ }
16
+
17
+ /**
18
+ * Creates a document fragment from the specified template literal.
19
+ * @param fragments The string fragments.
20
+ * @param values The interpolated values.
21
+ * @returns The document fragment corresponding to the specified template literal.
22
+ */
23
+ export function html(fragments: TemplateStringsArray, ...values: unknown[]): DocumentFragment {
24
+ return document.createRange().createContextualFragment(fragments.length == 1 ? fragments[0] : values.reduce(
25
+ (fragment: string, value: unknown, index: number) => fragment + stringFromHtml(value) + fragments[index + 1],
26
+ fragments[0]
27
+ ));
28
+ }
29
+
30
+ /**
31
+ * Converts the specified value to a CSS string.
32
+ * @param value A value representing a CSS fragment.
33
+ * @returns The CSS string corresponding to the specified value.
34
+ */
35
+ function stringFromCss(value: unknown): string {
36
+ if (!(value instanceof CSSStyleSheet)) {
37
+ if (Array.isArray(value)) return value.map(stringFromCss).join("\n");
38
+ return value === null || typeof value == "undefined" ? "" : String(value); // eslint-disable-line @typescript-eslint/no-base-to-string
39
+ }
40
+
41
+ return Array.from(value.cssRules).map(cssRule => cssRule.cssText).join("\n");
42
+ }
43
+
44
+ /**
45
+ * Converts the specified value to an HTML string.
46
+ * @param value A value representing an HTML fragment.
47
+ * @returns The HTML string corresponding to the specified value.
48
+ */
49
+ function stringFromHtml(value: unknown): string {
50
+ if (!(value instanceof DocumentFragment)) {
51
+ if (Array.isArray(value)) return value.map(stringFromHtml).join("");
52
+ return value === null || typeof value == "undefined" ? "" : String(value); // eslint-disable-line @typescript-eslint/no-base-to-string
53
+ }
54
+
55
+ const element = document.createElement("div");
56
+ element.appendChild(value);
57
+ return element.innerHTML;
58
+ }
@@ -0,0 +1,42 @@
1
+ import {Context} from "./Context.js";
2
+
3
+ /**
4
+ * Defines tone variants.
5
+ */
6
+ export const Variant = Object.freeze({
7
+ ...Context,
8
+
9
+ /**
10
+ * A primary tone.
11
+ */
12
+ Primary: "Primary",
13
+
14
+ /**
15
+ * A secondary tone.
16
+ */
17
+ Secondary: "Secondary",
18
+
19
+ /**
20
+ * A light tone.
21
+ */
22
+ Light: "Light",
23
+
24
+ /**
25
+ * A dark tone.
26
+ */
27
+ Dark: "Dark"
28
+ });
29
+
30
+ /**
31
+ * Defines tone variants.
32
+ */
33
+ export type Variant = typeof Variant[keyof typeof Variant];
34
+
35
+ /**
36
+ * Returns the CSS class of the specified variant.
37
+ * @param variant The variant.
38
+ * @returns The CSS class of the specified variant.
39
+ */
40
+ export function cssClass(variant: Variant): string {
41
+ return variant.toLowerCase();
42
+ }
@@ -0,0 +1,89 @@
1
+ /**
2
+ * Defines the scrolling options.
3
+ */
4
+ export type ScrollOptions = Partial<{
5
+
6
+ /**
7
+ * Value indicating whether scrolling is instant or animates smoothly.
8
+ */
9
+ behavior: ScrollBehavior
10
+ }>;
11
+
12
+ /**
13
+ * Manages the scroll position.
14
+ */
15
+ export class ViewportScroller {
16
+
17
+ /**
18
+ * The top offset used when scrolling to an element.
19
+ */
20
+ #scrollOffset = -1;
21
+
22
+ /**
23
+ * The function returning the element used as viewport.
24
+ */
25
+ readonly #viewport: () => Element;
26
+
27
+ /**
28
+ * Creates a new viewport scroller.
29
+ * @param viewport A function that returns the element used as viewport.
30
+ */
31
+ constructor(viewport: () => Element = () => document.scrollingElement ?? document.documentElement) {
32
+ this.#viewport = viewport;
33
+ }
34
+
35
+ /**
36
+ * The top offset used when scrolling to an element.
37
+ */
38
+ get scrollOffset(): number {
39
+ if (this.#scrollOffset < 0) {
40
+ const fontSize = Number.parseInt(getComputedStyle(document.body).fontSize, 10);
41
+ this.#scrollOffset = Number.isNaN(fontSize) ? 0 : fontSize * 2;
42
+
43
+ const navbar = document.body.querySelector<HTMLElement>(".navbar");
44
+ this.#scrollOffset += (navbar?.offsetHeight ?? 0);
45
+ }
46
+
47
+ const actionBar = document.body.querySelector<HTMLElement>("action-bar");
48
+ return this.#scrollOffset + (actionBar?.offsetHeight ?? 0);
49
+ }
50
+
51
+ /**
52
+ * Scrolls to the specified anchor.
53
+ * @param anchor The identifier or name of an element.
54
+ * @param options Value indicating whether scrolling is instant or animates smoothly.
55
+ */
56
+ scrollToAnchor(anchor: string, options: ScrollOptions = {}): void {
57
+ const element = document.getElementById(anchor) ?? this.#viewport().querySelector(`[name="${anchor}"]`);
58
+ if (element) this.scrollToElement(element, options);
59
+ }
60
+
61
+ /**
62
+ * Scrolls to the specified element.
63
+ * @param element The element to scroll to.
64
+ * @param options Value indicating whether scrolling is instant or animates smoothly.
65
+ */
66
+ scrollToElement(element: Element, options: ScrollOptions = {}): void {
67
+ const {left, top} = element.getBoundingClientRect();
68
+ const {scrollLeft, scrollTop} = this.#viewport();
69
+ this.scrollToPosition(left + scrollLeft, top + scrollTop - this.scrollOffset, options);
70
+ }
71
+
72
+ /**
73
+ * Scrolls to the specified position.
74
+ * @param x The pixel along the horizontal axis.
75
+ * @param y The pixel along the vertical axis.
76
+ * @param options Value indicating whether scrolling is instant or animates smoothly.
77
+ */
78
+ scrollToPosition(x: number, y: number, options: ScrollOptions = {}): void {
79
+ this.#viewport().scrollTo({left: x, top: y, behavior: options.behavior ?? "auto"});
80
+ }
81
+
82
+ /**
83
+ * Scrolls to the top.
84
+ * @param options Value indicating whether scrolling is instant or animates smoothly.
85
+ */
86
+ scrollToTop(options: ScrollOptions = {}): void {
87
+ this.scrollToPosition(0, 0, options);
88
+ }
89
+ }
@@ -0,0 +1,19 @@
1
+ {
2
+ "include": ["**/*.ts"],
3
+ "compilerOptions": {
4
+ "declaration": true,
5
+ "declarationMap": true,
6
+ "erasableSyntaxOnly": true,
7
+ "incremental": true,
8
+ "module": "NodeNext",
9
+ "noEmit": false,
10
+ "noImplicitOverride": true,
11
+ "outDir": "../../lib",
12
+ "resolveJsonModule": true,
13
+ "skipLibCheck": true,
14
+ "target": "ESNext",
15
+ "tsBuildInfoFile": "../../var/tsbuildinfo.json",
16
+ "types": ["bootstrap"],
17
+ "verbatimModuleSyntax": true
18
+ }
19
+ }