@sveltia/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 (104) hide show
  1. package/LICENSE.txt +21 -0
  2. package/package/components/composite/calendar.svelte +240 -0
  3. package/package/components/composite/calendar.svelte.d.ts +27 -0
  4. package/package/components/composite/checkbox-group.svelte +43 -0
  5. package/package/components/composite/checkbox-group.svelte.d.ts +34 -0
  6. package/package/components/composite/combobox.svelte +179 -0
  7. package/package/components/composite/combobox.svelte.d.ts +47 -0
  8. package/package/components/composite/disclosure.svelte +60 -0
  9. package/package/components/composite/disclosure.svelte.d.ts +35 -0
  10. package/package/components/composite/grid.svelte +24 -0
  11. package/package/components/composite/grid.svelte.d.ts +31 -0
  12. package/package/components/composite/listbox.svelte +63 -0
  13. package/package/components/composite/listbox.svelte.d.ts +52 -0
  14. package/package/components/composite/menu-item-group.svelte +31 -0
  15. package/package/components/composite/menu-item-group.svelte.d.ts +33 -0
  16. package/package/components/composite/menu.svelte +44 -0
  17. package/package/components/composite/menu.svelte.d.ts +41 -0
  18. package/package/components/composite/radio-button-group.svelte +44 -0
  19. package/package/components/composite/radio-button-group.svelte.d.ts +36 -0
  20. package/package/components/composite/select-button-group.svelte +69 -0
  21. package/package/components/composite/select-button-group.svelte.d.ts +44 -0
  22. package/package/components/composite/select.svelte +34 -0
  23. package/package/components/composite/select.svelte.d.ts +38 -0
  24. package/package/components/composite/tab-list.svelte +76 -0
  25. package/package/components/composite/tab-list.svelte.d.ts +55 -0
  26. package/package/components/core/button.svelte +209 -0
  27. package/package/components/core/button.svelte.d.ts +113 -0
  28. package/package/components/core/checkbox.svelte +105 -0
  29. package/package/components/core/checkbox.svelte.d.ts +43 -0
  30. package/package/components/core/dialog.svelte +258 -0
  31. package/package/components/core/dialog.svelte.d.ts +73 -0
  32. package/package/components/core/grid-cell.svelte +14 -0
  33. package/package/components/core/grid-cell.svelte.d.ts +29 -0
  34. package/package/components/core/group.svelte +31 -0
  35. package/package/components/core/group.svelte.d.ts +33 -0
  36. package/package/components/core/icon.svelte +21 -0
  37. package/package/components/core/icon.svelte.d.ts +27 -0
  38. package/package/components/core/menu-button.svelte +65 -0
  39. package/package/components/core/menu-button.svelte.d.ts +36 -0
  40. package/package/components/core/menu-item-checkbox.svelte +24 -0
  41. package/package/components/core/menu-item-checkbox.svelte.d.ts +34 -0
  42. package/package/components/core/menu-item-radio.svelte +19 -0
  43. package/package/components/core/menu-item-radio.svelte.d.ts +34 -0
  44. package/package/components/core/menu-item.svelte +113 -0
  45. package/package/components/core/menu-item.svelte.d.ts +44 -0
  46. package/package/components/core/number-input.svelte +109 -0
  47. package/package/components/core/number-input.svelte.d.ts +40 -0
  48. package/package/components/core/option.svelte +57 -0
  49. package/package/components/core/option.svelte.d.ts +44 -0
  50. package/package/components/core/password-input.svelte +76 -0
  51. package/package/components/core/password-input.svelte.d.ts +36 -0
  52. package/package/components/core/radio-button.svelte +91 -0
  53. package/package/components/core/radio-button.svelte.d.ts +37 -0
  54. package/package/components/core/row-group.svelte +14 -0
  55. package/package/components/core/row-group.svelte.d.ts +29 -0
  56. package/package/components/core/row.svelte +14 -0
  57. package/package/components/core/row.svelte.d.ts +33 -0
  58. package/package/components/core/search-bar.svelte +90 -0
  59. package/package/components/core/search-bar.svelte.d.ts +49 -0
  60. package/package/components/core/select-button.svelte +29 -0
  61. package/package/components/core/select-button.svelte.d.ts +40 -0
  62. package/package/components/core/separator.svelte +28 -0
  63. package/package/components/core/separator.svelte.d.ts +26 -0
  64. package/package/components/core/spacer.svelte +22 -0
  65. package/package/components/core/spacer.svelte.d.ts +25 -0
  66. package/package/components/core/switch.svelte +80 -0
  67. package/package/components/core/switch.svelte.d.ts +37 -0
  68. package/package/components/core/tab-panel.svelte +23 -0
  69. package/package/components/core/tab-panel.svelte.d.ts +33 -0
  70. package/package/components/core/tab.svelte +20 -0
  71. package/package/components/core/tab.svelte.d.ts +33 -0
  72. package/package/components/core/text-area.svelte +90 -0
  73. package/package/components/core/text-area.svelte.d.ts +57 -0
  74. package/package/components/core/text-input.svelte +145 -0
  75. package/package/components/core/text-input.svelte.d.ts +71 -0
  76. package/package/components/core/toolbar.svelte +74 -0
  77. package/package/components/core/toolbar.svelte.d.ts +35 -0
  78. package/package/components/editor/markdown.svelte +75 -0
  79. package/package/components/editor/markdown.svelte.d.ts +25 -0
  80. package/package/components/helpers/group.d.ts +37 -0
  81. package/package/components/helpers/group.js +246 -0
  82. package/package/components/helpers/popup.d.ts +31 -0
  83. package/package/components/helpers/popup.js +134 -0
  84. package/package/components/helpers/util.d.ts +1 -0
  85. package/package/components/helpers/util.js +8 -0
  86. package/package/components/util/app-shell.svelte +282 -0
  87. package/package/components/util/app-shell.svelte.d.ts +38 -0
  88. package/package/components/util/misc.d.ts +2 -0
  89. package/package/components/util/misc.js +22 -0
  90. package/package/components/util/popup.svelte +110 -0
  91. package/package/components/util/popup.svelte.d.ts +46 -0
  92. package/package/components/util/portal.svelte +34 -0
  93. package/package/components/util/portal.svelte.d.ts +28 -0
  94. package/package/index.d.ts +40 -0
  95. package/package/index.js +65 -0
  96. package/package/locales/en.d.ts +42 -0
  97. package/package/locales/en.js +41 -0
  98. package/package/locales/ja.d.ts +42 -0
  99. package/package/locales/ja.js +41 -0
  100. package/package/styles/core.scss +134 -0
  101. package/package/styles/variables.scss +113 -0
  102. package/package/typedef.d.ts +0 -0
  103. package/package/typedef.js +0 -0
  104. package/package.json +461 -0
@@ -0,0 +1,246 @@
1
+ /* eslint-disable no-plusplus */
2
+ /* eslint-disable no-param-reassign */
3
+
4
+ import { sleep } from '../util/misc';
5
+ import { getRandomId } from './util';
6
+
7
+ const config = {
8
+ grid: {
9
+ orientation: 'vertical',
10
+ childRoles: ['row'],
11
+ childSelectedAttr: 'aria-selected',
12
+ },
13
+ listbox: {
14
+ orientation: 'vertical',
15
+ childRoles: ['option'],
16
+ childSelectedAttr: 'aria-selected',
17
+ },
18
+ menu: {
19
+ orientation: 'vertical',
20
+ childRoles: ['menuitem', 'menuitemcheckbox', 'menuitemradio'],
21
+ childSelectedAttr: 'aria-checked',
22
+ },
23
+ menubar: {
24
+ orientation: 'horizontal',
25
+ childRoles: ['menuitem', 'menuitemcheckbox', 'menuitemradio'],
26
+ childSelectedAttr: 'aria-checked',
27
+ },
28
+ radiogroup: {
29
+ orientation: 'horizontal',
30
+ childRoles: ['radio'],
31
+ childSelectedAttr: 'aria-checked',
32
+ },
33
+ tablist: {
34
+ orientation: 'horizontal',
35
+ childRoles: ['tab'],
36
+ childSelectedAttr: 'aria-selected',
37
+ },
38
+ };
39
+
40
+ /**
41
+ * Implement keyboard and mouse interactions for a grouping composite widget.
42
+ */
43
+ class Group {
44
+ /**
45
+ *
46
+ * @param {HTMLElement} parent
47
+ * @todo Check for added elements probably with `MutationObserver`.
48
+ */
49
+ constructor(parent) {
50
+ this.parent = parent;
51
+ this.role = parent.getAttribute('role');
52
+ this.grid = this.role === 'listbox' && parent.matches('.grid');
53
+ this.multi = this.parent.getAttribute('aria-multiselectable') === 'true';
54
+ this.id = getRandomId(this.role);
55
+ this.parentGroupSelector = `[role="group"], [role="${this.role}"]`;
56
+
57
+ const { orientation, childSelectedAttr } = config[this.role];
58
+
59
+ this.orientation = this.grid
60
+ ? 'horizontal'
61
+ : this.parent.getAttribute('aria-orientation') || orientation;
62
+ this.childSelectedAttr = childSelectedAttr;
63
+
64
+ const { allMembers } = this;
65
+
66
+ const hasSelected = allMembers.some((element) =>
67
+ element.matches(`[${childSelectedAttr}="true"]`),
68
+ );
69
+
70
+ allMembers.forEach((element, index) => {
71
+ const isSelected = element.matches(`[${childSelectedAttr}="true"]`);
72
+ const controls = document.querySelector(`#${element.getAttribute('aria-controls')}`);
73
+
74
+ element.id ||= `${this.id}-item-${index}`;
75
+ element.tabIndex ||= isSelected || (!hasSelected && index === 0) ? 0 : -1;
76
+ element.setAttribute(this.childSelectedAttr, isSelected);
77
+ controls?.setAttribute('aria-labelledby', element.id);
78
+ controls?.setAttribute('aria-hidden', !isSelected);
79
+ });
80
+
81
+ parent.addEventListener('click', (event) => {
82
+ this.onClick(event);
83
+ });
84
+
85
+ parent.addEventListener('keydown', (event) => {
86
+ this.onKeyDown(event);
87
+ });
88
+ }
89
+
90
+ /** @type {string} */
91
+ get selector() {
92
+ const roles = config[this.role].childRoles;
93
+
94
+ return roles ? roles.map((role) => `[role="${role}"]`).join(',') : '';
95
+ }
96
+
97
+ /** @type {HTMLElement[]} */
98
+ get allMembers() {
99
+ return [...this.parent.querySelectorAll(this.selector)];
100
+ }
101
+
102
+ /** @type {HTMLElement[]} */
103
+ get activeMembers() {
104
+ return this.allMembers.filter((element) => !element.matches('[aria-disabled="true"]'));
105
+ }
106
+
107
+ /**
108
+ *
109
+ * @param {KeyboardEvent}
110
+ */
111
+ onClick(event) {
112
+ const { target } = event;
113
+
114
+ if (!target.matches(this.selector)) {
115
+ return;
116
+ }
117
+
118
+ const targetParentGroup = target.closest(this.parentGroupSelector);
119
+
120
+ this.allMembers.forEach((element) => {
121
+ const isTarget = element === target;
122
+
123
+ element.tabIndex = element === target ? 0 : -1;
124
+
125
+ // Groups can be nested, e.g. `menu` > `group` > `menuitem`, so check if the parent is the
126
+ // same as the target’s parent
127
+ if (
128
+ (element.matches('[role="radio"], [role="menuitemradio"]') ||
129
+ (element.matches('[role="row"], [role="option"], [role="tab"]') && !this.multi)) &&
130
+ element.closest(this.parentGroupSelector) === targetParentGroup
131
+ ) {
132
+ element.setAttribute(this.childSelectedAttr, isTarget);
133
+ }
134
+
135
+ const controls = element.getAttribute('aria-controls');
136
+
137
+ if (controls) {
138
+ document.getElementById(controls)?.setAttribute('aria-hidden', !isTarget);
139
+ }
140
+ });
141
+
142
+ this.parent.dispatchEvent(
143
+ new CustomEvent('select', {
144
+ detail: {
145
+ value: target.value,
146
+ name: target.name,
147
+ },
148
+ }),
149
+ );
150
+ }
151
+
152
+ /**
153
+ *
154
+ * @param {KeyboardEvent}
155
+ */
156
+ onKeyDown(event) {
157
+ const { target, key, ctrlKey, metaKey, shiftKey, altKey } = event;
158
+
159
+ if (target.matches(this.selector) && !ctrlKey && !metaKey && !shiftKey && !altKey) {
160
+ if ([' ', 'ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight'].includes(key)) {
161
+ event.preventDefault();
162
+ }
163
+
164
+ if (key === ' ' || (key === 'Enter' && !target.matches('button'))) {
165
+ event.preventDefault();
166
+ target.click();
167
+
168
+ return;
169
+ }
170
+
171
+ const { allMembers, activeMembers } = this;
172
+ let index;
173
+ let newTarget;
174
+
175
+ if (this.grid) {
176
+ const colCount = Math.floor(this.parent.clientWidth / target.clientWidth);
177
+
178
+ index = allMembers.indexOf(target);
179
+
180
+ if (key === 'ArrowUp' && index > 0) {
181
+ newTarget = allMembers[index - colCount];
182
+ }
183
+
184
+ if (key === 'ArrowDown' && index < allMembers.length - 1) {
185
+ newTarget = allMembers[index + colCount];
186
+ }
187
+
188
+ if (key === 'ArrowLeft' && index > 0) {
189
+ newTarget = allMembers[index - 1];
190
+ }
191
+
192
+ if (key === 'ArrowRight' && index < allMembers.length - 1) {
193
+ newTarget = allMembers[index + 1];
194
+ }
195
+
196
+ if (newTarget?.getAttribute('aria-disabled') === 'true') {
197
+ newTarget = undefined;
198
+ }
199
+ } else {
200
+ index = activeMembers.indexOf(target);
201
+
202
+ if (key === (this.orientation === 'horizontal' ? 'ArrowLeft' : 'ArrowUp')) {
203
+ if (index > 0) {
204
+ // Previous member
205
+ newTarget = activeMembers[index - 1];
206
+ }
207
+
208
+ if (index === 0) {
209
+ // Last member
210
+ newTarget = activeMembers[activeMembers.length - 1];
211
+ }
212
+ }
213
+
214
+ if (key === (this.orientation === 'horizontal' ? 'ArrowRight' : 'ArrowDown')) {
215
+ if (index < activeMembers.length - 1) {
216
+ // Next member
217
+ newTarget = activeMembers[index + 1];
218
+ }
219
+
220
+ if (index === activeMembers.length - 1) {
221
+ // First member
222
+ [newTarget] = activeMembers;
223
+ }
224
+ }
225
+ }
226
+
227
+ if (newTarget && newTarget !== target) {
228
+ activeMembers.forEach((element) => {
229
+ element.tabIndex = element === newTarget ? 0 : -1;
230
+ });
231
+
232
+ newTarget.focus();
233
+ }
234
+ }
235
+ }
236
+ }
237
+
238
+ /**
239
+ *
240
+ */
241
+ export const activateGroup = async (...args) => {
242
+ // Wait a bit before the relevant components, including the `aria-controls` target are mounted
243
+ await sleep(100);
244
+
245
+ return new Group(...args);
246
+ };
@@ -0,0 +1,31 @@
1
+ export function activatePopup(...args: any[]): Popup;
2
+ export type PopupPosition = ('top-left' | 'top-right' | 'right-top' | 'right-bottom' | 'bottom-left' | 'bottom-right' | 'left-top' | 'left-bottom');
3
+ /**
4
+ * @typedef {('top-left'|'top-right'|'right-top'|'right-bottom'|'bottom-left'|'bottom-right'|'left-top'|'left-bottom')} PopupPosition
5
+ */
6
+ declare class Popup {
7
+ /**
8
+ *
9
+ * @param {HTMLElement} anchorElement
10
+ * @param {HTMLElement} popupElement
11
+ * @param {PopupPosition} position
12
+ */
13
+ constructor(anchorElement: HTMLElement, popupElement: HTMLElement, position: PopupPosition);
14
+ open: import("svelte/store").Writable<boolean>;
15
+ style: import("svelte/store").Writable<{
16
+ inset: any;
17
+ zIndex: any;
18
+ width: any;
19
+ height: any;
20
+ }>;
21
+ observer: IntersectionObserver;
22
+ anchorElement: HTMLElement;
23
+ popupElement: HTMLElement;
24
+ position: PopupPosition;
25
+ id: string;
26
+ /**
27
+ * Continue checking the position in case the window or parent element resizes.
28
+ */
29
+ checkPosition(): void;
30
+ }
31
+ export {};
@@ -0,0 +1,134 @@
1
+ /* eslint-disable max-len */
2
+ /* eslint-disable no-nested-ternary */
3
+
4
+ import { get, writable } from 'svelte/store';
5
+ import { getRandomId } from './util';
6
+
7
+ /**
8
+ * @typedef {('top-left'|'top-right'|'right-top'|'right-bottom'|'bottom-left'|'bottom-right'|'left-top'|'left-bottom')} PopupPosition
9
+ */
10
+
11
+ class Popup {
12
+ open = writable(false);
13
+
14
+ style = writable({ inset: undefined, zIndex: undefined, width: undefined, height: undefined });
15
+
16
+ observer = new IntersectionObserver((entries) => {
17
+ entries.forEach(({ intersectionRect, rootBounds }) => {
18
+ if (!intersectionRect || !rootBounds) {
19
+ return;
20
+ }
21
+
22
+ const top = this.position.startsWith('bottom-')
23
+ ? `${Math.round(intersectionRect.bottom)}px`
24
+ : this.position.endsWith('-top')
25
+ ? `${Math.round(intersectionRect.top)}px`
26
+ : 'auto';
27
+
28
+ const right = this.position.startsWith('left-')
29
+ ? `${Math.round(rootBounds.width - intersectionRect.left)}px`
30
+ : this.position.endsWith('-right')
31
+ ? `${Math.round(rootBounds.width - intersectionRect.right)}px`
32
+ : 'auto';
33
+
34
+ const bottom = this.position.startsWith('top-')
35
+ ? `${Math.round(rootBounds.height - intersectionRect.top)}px`
36
+ : this.position.endsWith('-bottom')
37
+ ? `${Math.round(rootBounds.height - intersectionRect.bottom)}px`
38
+ : 'auto';
39
+
40
+ const left = this.position.startsWith('right-')
41
+ ? `${Math.round(intersectionRect.right)}px`
42
+ : this.position.endsWith('-left')
43
+ ? `${Math.round(intersectionRect.left)}px`
44
+ : 'auto';
45
+
46
+ const width = `${Math.round(intersectionRect.width)}px`;
47
+ const height = `${Math.round(rootBounds.height - intersectionRect.bottom - 8)}px`;
48
+ const anchorPopup = this.anchorElement.closest('.popup');
49
+
50
+ // @todo fix the final position
51
+ this.style.set({
52
+ inset: [top, right, bottom, left].join(' '),
53
+ zIndex: anchorPopup ? Number(anchorPopup.style.zIndex) + 1 : 1000,
54
+ width,
55
+ height,
56
+ });
57
+ });
58
+ });
59
+
60
+ /**
61
+ *
62
+ * @param {HTMLElement} anchorElement
63
+ * @param {HTMLElement} popupElement
64
+ * @param {PopupPosition} position
65
+ */
66
+ constructor(anchorElement, popupElement, position) {
67
+ this.anchorElement = anchorElement;
68
+ this.popupElement = popupElement; // = backdrop
69
+ this.position = position;
70
+ this.id = getRandomId('popup');
71
+
72
+ this.anchorElement.setAttribute('aria-controls', this.id);
73
+ this.popupElement.setAttribute('id', this.id);
74
+
75
+ this.anchorElement.addEventListener('click', () => {
76
+ if (!this.anchorElement.matches('[aria-disabled="true"]')) {
77
+ this.open.set(!get(this.open));
78
+ }
79
+ });
80
+
81
+ this.popupElement.addEventListener('click', (event) => {
82
+ if (get(this.open) && event.target !== this.anchorElement) {
83
+ this.open.set(false);
84
+ }
85
+ });
86
+
87
+ [this.anchorElement, this.popupElement].forEach((element) => {
88
+ element.addEventListener('keydown', (event) => {
89
+ const { key, ctrlKey, metaKey, shiftKey, altKey } = event;
90
+
91
+ if (
92
+ get(this.open) &&
93
+ ['Escape'].includes(key) &&
94
+ !ctrlKey &&
95
+ !metaKey &&
96
+ !shiftKey &&
97
+ !altKey
98
+ ) {
99
+ this.open.set(false);
100
+ }
101
+ });
102
+ });
103
+
104
+ this.open.subscribe((open) => {
105
+ if (open) {
106
+ this.checkPosition();
107
+ } else {
108
+ this.anchorElement.focus();
109
+ }
110
+
111
+ this.anchorElement.setAttribute('aria-expanded', open);
112
+ });
113
+ }
114
+
115
+ /**
116
+ * Continue checking the position in case the window or parent element resizes.
117
+ */
118
+ checkPosition() {
119
+ this.observer.observe(this.anchorElement);
120
+
121
+ window.requestAnimationFrame(() => {
122
+ this.observer.unobserve(this.anchorElement);
123
+
124
+ if (get(this.open)) {
125
+ this.checkPosition();
126
+ }
127
+ });
128
+ }
129
+ }
130
+
131
+ /**
132
+ *
133
+ */
134
+ export const activatePopup = (...args) => new Popup(...args);
@@ -0,0 +1 @@
1
+ export function getRandomId(prefix?: string, length?: number): string;
@@ -0,0 +1,8 @@
1
+ export const getRandomId = (prefix = '', length = 7) =>
2
+ [
3
+ prefix,
4
+ new Array(length)
5
+ .fill()
6
+ .map(() => '0123456789abcdef'[Math.floor(Math.random() * 12)])
7
+ .join(''),
8
+ ].join('-');
@@ -0,0 +1,282 @@
1
+ <!--
2
+ @component
3
+ Provide an application’s shell that makes the web app more like a native app. It also handles the
4
+ dark/light mode switching. This component has to be placed directly under `<body>` (or
5
+ `<div style="display:contents">` in a SvelteKit app).
6
+ -->
7
+ <script>
8
+ import { onMount } from 'svelte';
9
+
10
+ onMount(() => {
11
+ const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
12
+ const { dataset } = document.documentElement;
13
+
14
+ const applyTheme = () => {
15
+ if (dataset.autoTheming !== 'false') {
16
+ dataset.theme = mediaQuery.matches ? 'dark' : 'light';
17
+ }
18
+ };
19
+
20
+ applyTheme();
21
+
22
+ mediaQuery.onchange = () => {
23
+ applyTheme();
24
+ };
25
+ });
26
+ </script>
27
+
28
+ <div
29
+ class="sui app-shell"
30
+ on:dragover|preventDefault
31
+ on:drop|preventDefault
32
+ on:contextmenu={(event) => {
33
+ // Disable the native context menu
34
+ if (!event.target?.matches('input[type="text"], textarea')) {
35
+ event.preventDefault();
36
+ }
37
+ }}
38
+ >
39
+ <slot />
40
+ </div>
41
+
42
+ <style global>@import url("https://fonts.googleapis.com/css2?family=Merriweather+Sans:ital,wght@0,300;0,600;1,300&family=Noto+Sans+Mono&display=swap");
43
+ @import url("https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200&display=block");
44
+ :global(:root) {
45
+ --hue: 210;
46
+ --highlight-foreground-color: hsl(var(--foreground-color-1-hsl));
47
+ --primary-foreground-color: hsl(var(--foreground-color-2-hsl));
48
+ --secondary-foreground-color: hsl(var(--foreground-color-3-hsl));
49
+ --ternary-foreground-color: hsl(var(--foreground-color-3-hsl));
50
+ --disabled-foreground-color: hsl(var(--foreground-color-4-hsl));
51
+ --danger-foreground-color: hsl(var(--danger-color));
52
+ --highlight-background-color: hsl(var(--background-color-5-hsl));
53
+ --content-background-color: hsl(var(--background-color-1-hsl));
54
+ --primary-background-color: hsl(var(--background-color-2-hsl));
55
+ --secondary-background-color: hsl(var(--background-color-3-hsl));
56
+ --ternary-background-color: hsl(var(--background-color-4-hsl));
57
+ --control-background-color: hsl(var(--background-color-1-hsl));
58
+ --disabled-background-color: hsl(var(--background-color-4-hsl));
59
+ --danger-background-color: hsl(var(--danger-color));
60
+ --primary-border-color: hsl(var(--border-color-1-hsl));
61
+ --secondary-border-color: hsl(var(--border-color-2-hsl));
62
+ --control-border-color: hsl(var(--border-color-2-hsl));
63
+ --popup-shadow-color: hsl(var(--shadow-color) / 20%);
64
+ --popup-backdrop-color: hsl(var(--shadow-color) / 10%);
65
+ --default-font-family: "Merriweather Sans", sans-serif;
66
+ --default-font-size: 13px;
67
+ --default-font-weight-regular: 300;
68
+ --default-font-weight-bold: 600;
69
+ --monospace-font-family: "Noto Sans Mono", monospace;
70
+ --monospace-font-size: 13px;
71
+ --control--small--border-width: 1px;
72
+ --control--small--border-radius: 2px;
73
+ --control--small--height: 24px;
74
+ --control--medium--border-width: 1px;
75
+ --control--medium--border-radius: 4px;
76
+ --control--medium--height: 32px;
77
+ --control--large--border-width: 1px;
78
+ --control--large--border-radius: 8px;
79
+ --control--large--height: 40px;
80
+ --button--small--border-radius: var(--control--small--border-radius);
81
+ --button--small--height: var(--control--small--height);
82
+ --button--medium--border-radius: var(--control--medium--border-radius);
83
+ --button--medium--height: var(--control--medium--height);
84
+ --button--large--border-radius: var(--control--large--border-radius);
85
+ --button--large--height: var(--control--large--height);
86
+ --option--small--border-radius: var(--control--small--border-radius);
87
+ --option--small--height: var(--control--small--height);
88
+ --option--medium--border-radius: var(--control--medium--border-radius);
89
+ --option--medium--height: var(--control--medium--height);
90
+ --option--large--border-radius: var(--control--large--border-radius);
91
+ --option--large--height: var(--control--large--height);
92
+ --input--small--border-radius: var(--control--small--border-radius);
93
+ --input--small--height: var(--control--small--height);
94
+ --input--medium--border-radius: var(--control--medium--border-radius);
95
+ --input--medium--height: var(--control--medium--height);
96
+ --input--large--border-radius: var(--control--large--border-radius);
97
+ --input--large--height: var(--control--large--height);
98
+ --tab--small--height: var(--control--small--height);
99
+ --tab--medium--height: var(--control--medium--height);
100
+ --tab--large--height: var(--control--large--height);
101
+ }
102
+
103
+ :global(:root[data-theme=light]) {
104
+ --foreground-color-1-hsl: var(--hue) 5% 0%;
105
+ --foreground-color-2-hsl: var(--hue) 5% 20%;
106
+ --foreground-color-3-hsl: var(--hue) 5% 40%;
107
+ --foreground-color-4-hsl: var(--hue) 5% 60%;
108
+ --border-color-1-hsl: var(--hue) 5% 75%;
109
+ --border-color-2-hsl: var(--hue) 5% 80%;
110
+ --background-color-1-hsl: var(--hue) 5% 100%;
111
+ --background-color-2-hsl: var(--hue) 5% 98%;
112
+ --background-color-3-hsl: var(--hue) 5% 96%;
113
+ --background-color-4-hsl: var(--hue) 5% 94%;
114
+ --background-color-5-hsl: var(--hue) 5% 90%;
115
+ --shadow-color: var(--hue) 10% 0%;
116
+ --primary-accent-color: hsl(var(--hue) 80% 45%);
117
+ --primary-accent-color-lighter: hsl(var(--hue) 80% 40%);
118
+ --primary-accent-color-darker: hsl(var(--hue) 80% 50%);
119
+ --primary-accent-color-foreground: hsl(var(--hue) 10% 100%);
120
+ --danger-color: 0 68% 42%;
121
+ }
122
+
123
+ :global(:root[data-theme=dark]) {
124
+ --foreground-color-1-hsl: var(--hue) 10% 100%;
125
+ --foreground-color-2-hsl: var(--hue) 10% 80%;
126
+ --foreground-color-3-hsl: var(--hue) 10% 60%;
127
+ --foreground-color-4-hsl: var(--hue) 10% 40%;
128
+ --border-color-1-hsl: var(--hue) 10% 25%;
129
+ --border-color-2-hsl: var(--hue) 10% 20%;
130
+ --background-color-1-hsl: var(--hue) 10% 8%;
131
+ --background-color-2-hsl: var(--hue) 10% 10%;
132
+ --background-color-3-hsl: var(--hue) 10% 12%;
133
+ --background-color-4-hsl: var(--hue) 10% 14%;
134
+ --background-color-5-hsl: var(--hue) 10% 18%;
135
+ --shadow-color: var(--hue) 10% 0%;
136
+ --primary-accent-color: hsl(var(--hue) 100% 45%);
137
+ --primary-accent-color-lighter: hsl(var(--hue) 100% 50%);
138
+ --primary-accent-color-darker: hsl(var(--hue) 100% 40%);
139
+ --primary-accent-color-foreground: hsl(var(--hue) 10% 100%);
140
+ --danger-color: 0 68% 42%;
141
+ }
142
+
143
+ :global(.material-symbols-outlined) {
144
+ font-variation-settings: "FILL" 0, "wght" 300, "GRAD" 0, "opsz" 24;
145
+ }
146
+
147
+ :global(*) {
148
+ scroll-behavior: smooth;
149
+ box-sizing: border-box;
150
+ border-width: 0;
151
+ border-style: solid;
152
+ }
153
+
154
+ :global(:focus) {
155
+ z-index: 1;
156
+ outline-width: 0;
157
+ }
158
+
159
+ :global(:focus-visible) {
160
+ outline-offset: -2px;
161
+ outline-width: 2px !important;
162
+ outline-style: solid;
163
+ outline-color: hsl(var(--hue), 100%, 50%, 25%);
164
+ }
165
+
166
+ :global(h1),
167
+ :global(h2),
168
+ :global(h3),
169
+ :global(h4),
170
+ :global(h5),
171
+ :global(h6) {
172
+ margin: 0;
173
+ font-weight: var(--default-font-weight-bold);
174
+ }
175
+
176
+ :global(strong) {
177
+ font-weight: var(--default-font-weight-bold);
178
+ }
179
+
180
+ :global(a) {
181
+ color: var(--primary-accent-color-lighter);
182
+ text-decoration: none;
183
+ }
184
+
185
+ :global(img),
186
+ :global(svg),
187
+ :global(iframe) {
188
+ vertical-align: top;
189
+ }
190
+
191
+ :global(button),
192
+ :global(input),
193
+ :global(textarea),
194
+ :global(select),
195
+ :global(option) {
196
+ font-family: inherit;
197
+ font-size: inherit;
198
+ color: inherit;
199
+ }
200
+
201
+ :global(p),
202
+ :global(li) {
203
+ line-height: 1.75;
204
+ }
205
+
206
+ :global([role=grid]) {
207
+ display: table;
208
+ width: 100%;
209
+ }
210
+ :global([role=grid]) :global(.colgroup) {
211
+ display: table-column-group;
212
+ }
213
+ :global([role=grid]) :global(.colgroup) :global(.col) {
214
+ display: table-column;
215
+ }
216
+
217
+ :global(code),
218
+ :global(pre) {
219
+ font-family: var(--monospace-font-family);
220
+ }
221
+
222
+ :global(pre) {
223
+ line-height: 1.5;
224
+ -webkit-user-select: text;
225
+ user-select: text;
226
+ }
227
+
228
+ :global(dialog) {
229
+ position: fixed;
230
+ inset: 0;
231
+ outline: 0;
232
+ margin: 0;
233
+ border: 0;
234
+ padding: 0;
235
+ width: 100%;
236
+ max-width: 100%;
237
+ height: 100%;
238
+ max-height: 100%;
239
+ color: inherit;
240
+ background: transparent;
241
+ -webkit-user-select: none;
242
+ user-select: none;
243
+ touch-action: none;
244
+ cursor: default;
245
+ }
246
+ :global(dialog::backdrop) {
247
+ background: transparent;
248
+ }
249
+
250
+ :global(.thead[role=rowgroup]) {
251
+ display: table-header-group;
252
+ }
253
+
254
+ :global(.tbody[role=rowgroup]) {
255
+ display: table-row-group;
256
+ }
257
+
258
+ :global([role=row]) {
259
+ display: table-row;
260
+ }
261
+
262
+ :global([role=columnheader]),
263
+ :global([role=gridcell]) {
264
+ display: table-cell;
265
+ }
266
+
267
+ :global(.app-shell) {
268
+ position: fixed;
269
+ inset: 0;
270
+ overflow: hidden;
271
+ width: 100%;
272
+ height: 100%;
273
+ color: var(--primary-foreground-color);
274
+ background-color: var(--primary-background-color);
275
+ font-family: var(--default-font-family);
276
+ font-size: var(--default-font-size);
277
+ font-weight: var(--default-font-weight-regular);
278
+ -webkit-user-select: none;
279
+ user-select: none;
280
+ touch-action: none;
281
+ cursor: default;
282
+ }</style>