p-elements-core 1.2.32-rc8 → 1.2.32

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 (64) hide show
  1. package/.editorconfig +17 -17
  2. package/.gitlab-ci.yml +18 -18
  3. package/CHANGELOG.md +201 -201
  4. package/demo/sample.js +1 -1
  5. package/demo/screen.css +16 -16
  6. package/dist/p-elements-core-modern.js +1 -1
  7. package/dist/p-elements-core.js +1 -1
  8. package/docs/package-lock.json +6897 -6897
  9. package/docs/package.json +27 -27
  10. package/docs/src/404.md +8 -8
  11. package/docs/src/_data/demos/hello-world/hello-world.tsx +35 -35
  12. package/docs/src/_data/demos/hello-world/index.html +10 -10
  13. package/docs/src/_data/demos/hello-world/project.json +7 -7
  14. package/docs/src/_data/demos/timer/demo-timer.tsx +120 -120
  15. package/docs/src/_data/demos/timer/icons.tsx +62 -62
  16. package/docs/src/_data/demos/timer/index.html +12 -12
  17. package/docs/src/_data/demos/timer/project.json +8 -8
  18. package/docs/src/_data/global.js +13 -13
  19. package/docs/src/_data/helpers.js +19 -19
  20. package/docs/src/_includes/layouts/base.njk +30 -30
  21. package/docs/src/_includes/layouts/playground.njk +40 -40
  22. package/docs/src/_includes/partials/app-header.njk +8 -8
  23. package/docs/src/_includes/partials/head.njk +14 -14
  24. package/docs/src/_includes/partials/nav.njk +19 -19
  25. package/docs/src/_includes/partials/top-nav.njk +51 -51
  26. package/docs/src/documentation/custom-element.md +221 -221
  27. package/docs/src/documentation/decorators/bind.md +71 -71
  28. package/docs/src/documentation/decorators/custom-element-config.md +63 -63
  29. package/docs/src/documentation/decorators/property.md +83 -83
  30. package/docs/src/documentation/decorators/query.md +66 -66
  31. package/docs/src/documentation/decorators/render-property-on-set.md +60 -60
  32. package/docs/src/documentation/decorators.md +9 -9
  33. package/docs/src/documentation/reactive-properties.md +53 -53
  34. package/docs/src/index.d.ts +25 -25
  35. package/docs/src/index.md +3 -3
  36. package/docs/src/scripts/components/app-mode-switch/app-mode-switch.css +78 -78
  37. package/docs/src/scripts/components/app-mode-switch/app-mode-switch.tsx +166 -166
  38. package/docs/src/scripts/components/app-playground/app-playground.tsx +189 -189
  39. package/docs/tsconfig.json +22 -22
  40. package/index.html +10 -2
  41. package/package.json +1 -1
  42. package/readme.md +206 -206
  43. package/src/custom-element-controller.ts +31 -31
  44. package/src/custom-element.test.ts +906 -906
  45. package/src/custom-element.ts +3 -8
  46. package/src/decorators/bind.test.ts +163 -163
  47. package/src/decorators/bind.ts +46 -46
  48. package/src/decorators/custom-element-config.ts +17 -17
  49. package/src/decorators/property.test.ts +279 -279
  50. package/src/decorators/query.test.ts +146 -146
  51. package/src/decorators/query.ts +12 -12
  52. package/src/decorators/render-property-on-set.ts +3 -3
  53. package/src/helpers/css.ts +71 -71
  54. package/src/maquette/cache.ts +35 -35
  55. package/src/maquette/dom.ts +115 -115
  56. package/src/maquette/h.ts +100 -100
  57. package/src/maquette/index.ts +12 -12
  58. package/src/maquette/interfaces.ts +536 -536
  59. package/src/maquette/jsx.ts +61 -61
  60. package/src/maquette/mapping.ts +56 -56
  61. package/src/maquette/projection.ts +666 -666
  62. package/src/maquette/projector.ts +205 -205
  63. package/src/sample/mixin/highlight.tsx +33 -33
  64. package/src/sample/sample.tsx +98 -0
@@ -1,54 +1,54 @@
1
- ---
2
- title: "ReactiveProperties"
3
- layout: "base.njk"
4
- description: "Reactive properties"
5
- permalink: "/documentation/reactive-properties.html"
6
- eleventyNavigation:
7
- key: ReactiveProperties
8
- title: Reactive properties
9
- order: 4
10
- ---
11
-
12
- # Reactive properties
13
-
14
- P-Elements receive input and store their state as JavaScript class fields or properties. Reactive properties are properties that can trigger the reactive update cycle when changed, re-rendering the component, and optionally be read or written to attributes.
15
-
16
- ```typescript
17
- @CustomElementConfig({ tagName: 'my-greeting' })
18
- class MyGreeting extends CustomElement {
19
-
20
- static readonly style = `...`;
21
-
22
- @Property({ type: 'string', reflect: true, attribute: 'name' })
23
- name = 'World';
24
-
25
- render() : VNode {
26
- return <h1>Hello, ${this.name}!</h1>;
27
- }
28
- }
29
- ```
30
-
31
- ## Typescript config
32
-
33
- To use experimental decorators you must enable the `experimentalDecorators` compiler option.
34
-
35
- You should also ensure that the `useDefineForClassFields` setting is false. This is needed to avoid issues with class fields when declaring properties.
36
-
37
- <!-- todo in next version p-elements support standard decorator syntax -->
38
-
39
- ```json
40
- // tsconfig.json
41
- {
42
- "compilerOptions": {
43
- "experimentalDecorators": true,
44
- "useDefineForClassFields": false,
45
- }
46
- }
47
- ```
48
-
49
- ## Decorators
50
-
51
- For more info:
52
-
53
- - [@Property](./decorators/property.html)
1
+ ---
2
+ title: "ReactiveProperties"
3
+ layout: "base.njk"
4
+ description: "Reactive properties"
5
+ permalink: "/documentation/reactive-properties.html"
6
+ eleventyNavigation:
7
+ key: ReactiveProperties
8
+ title: Reactive properties
9
+ order: 4
10
+ ---
11
+
12
+ # Reactive properties
13
+
14
+ P-Elements receive input and store their state as JavaScript class fields or properties. Reactive properties are properties that can trigger the reactive update cycle when changed, re-rendering the component, and optionally be read or written to attributes.
15
+
16
+ ```typescript
17
+ @CustomElementConfig({ tagName: 'my-greeting' })
18
+ class MyGreeting extends CustomElement {
19
+
20
+ static readonly style = `...`;
21
+
22
+ @Property({ type: 'string', reflect: true, attribute: 'name' })
23
+ name = 'World';
24
+
25
+ render() : VNode {
26
+ return <h1>Hello, ${this.name}!</h1>;
27
+ }
28
+ }
29
+ ```
30
+
31
+ ## Typescript config
32
+
33
+ To use experimental decorators you must enable the `experimentalDecorators` compiler option.
34
+
35
+ You should also ensure that the `useDefineForClassFields` setting is false. This is needed to avoid issues with class fields when declaring properties.
36
+
37
+ <!-- todo in next version p-elements support standard decorator syntax -->
38
+
39
+ ```json
40
+ // tsconfig.json
41
+ {
42
+ "compilerOptions": {
43
+ "experimentalDecorators": true,
44
+ "useDefineForClassFields": false,
45
+ }
46
+ }
47
+ ```
48
+
49
+ ## Decorators
50
+
51
+ For more info:
52
+
53
+ - [@Property](./decorators/property.html)
54
54
  - [@PropertyRenderOnSet](./decorators/property-render-on-set.html)
@@ -1,25 +1,25 @@
1
- /// <reference types="p-elements-core" />
2
- /// <reference types="@types/animejs" />
3
- /// <reference types="@types/underscore" />
4
-
5
- declare namespace JSX {
6
- interface IntrinsicElements {
7
- [tagName: string]: VNodeProperties;
8
- }
9
- type Element = VNode;
10
- }
11
-
12
- declare const _: _.UnderscoreStatic;
13
-
14
- declare const anime: (params: anime.AnimeParams) => anime.AnimeInstance;
15
-
16
- declare const Maquette: {
17
- h: H;
18
- createProjector: (projectorOptions?: ProjectorOptions) => Projector;
19
- };
20
-
21
- declare let notifyContainer: NotifyContainerElement;
22
-
23
- declare module "*.css";
24
- declare module "*.html";
25
- declare module "*.svg";
1
+ /// <reference types="p-elements-core" />
2
+ /// <reference types="@types/animejs" />
3
+ /// <reference types="@types/underscore" />
4
+
5
+ declare namespace JSX {
6
+ interface IntrinsicElements {
7
+ [tagName: string]: VNodeProperties;
8
+ }
9
+ type Element = VNode;
10
+ }
11
+
12
+ declare const _: _.UnderscoreStatic;
13
+
14
+ declare const anime: (params: anime.AnimeParams) => anime.AnimeInstance;
15
+
16
+ declare const Maquette: {
17
+ h: H;
18
+ createProjector: (projectorOptions?: ProjectorOptions) => Projector;
19
+ };
20
+
21
+ declare let notifyContainer: NotifyContainerElement;
22
+
23
+ declare module "*.css";
24
+ declare module "*.html";
25
+ declare module "*.svg";
package/docs/src/index.md CHANGED
@@ -1,3 +1,3 @@
1
- <script>
2
- document.location.href="./documentation/index.html";
3
- </script>
1
+ <script>
2
+ document.location.href="./documentation/index.html";
3
+ </script>
@@ -1,78 +1,78 @@
1
- :host {
2
- background: none;
3
- border: none;
4
- padding: 0;
5
- cursor: pointer;
6
- touch-action: manipulation;
7
- -webkit-tap-highlight-color: transparent;
8
- display: inline-block;
9
-
10
- }
11
-
12
- :host > div{
13
- display: flex;
14
- align-items: center;
15
- justify-content: center;
16
- gap: .5rem;
17
- }
18
-
19
-
20
- .sun-and-moon > :is(.moon, .sun, .sun-beams) {
21
- transform-origin: center center;
22
- }
23
-
24
-
25
- svg {
26
- margin: auto;
27
- stroke-linecap: round;
28
- }
29
-
30
- svg + div {
31
- display: flex;
32
- align-items: center;
33
- justify-content: center;
34
- }
35
-
36
- :host([mode="light"]) .sun-and-moon > .sun {
37
- transform: scale(1.75);
38
- }
39
-
40
- :host([mode="light"]) .sun-and-moon > .sun-beams {
41
- opacity: 0;
42
- }
43
-
44
- :host([mode="light"]) .sun-and-moon > .moon > circle {
45
- transform: translate(-7px);
46
- }
47
-
48
- /* Animations */
49
-
50
- :host([mode="dark"]) .sun-and-moon > .sun {
51
- transition: transform 0.5s cubic-bezier(0.5, 1.25, 0.75, 1.25);
52
- }
53
-
54
- :host([mode="dark"]) .sun-and-moon > .sun-beams {
55
- transition:
56
- transform 0.5s cubic-bezier(0.5, 1.5, 0.75, 1.25),
57
- opacity 0.5s cubic-bezier(0.25, 0, 0.3, 1);
58
- }
59
-
60
- :host([mode="darkt"]) .sun-and-moon .moon > circle {
61
- transition: transform 0.25s cubic-bezier(0, 0, 0, 1);
62
- }
63
-
64
- :host([mode="light"]) .sun-and-moon > .sun {
65
- transform: scale(1.75);
66
- transition-timing-function: cubic-bezier(0.25, 0, 0.3, 1);
67
- transition-duration: 0.25s;
68
- }
69
-
70
- :host([mode="light"]) .sun-and-moon > .sun-beams {
71
- transform: rotate(-25deg);
72
- transition-duration: 0.15s;
73
- }
74
-
75
- :host([mode="light"]) .sun-and-moon > .moon > circle {
76
- transition-delay: 0.25s;
77
- transition-duration: 0.5s;
78
- }
1
+ :host {
2
+ background: none;
3
+ border: none;
4
+ padding: 0;
5
+ cursor: pointer;
6
+ touch-action: manipulation;
7
+ -webkit-tap-highlight-color: transparent;
8
+ display: inline-block;
9
+
10
+ }
11
+
12
+ :host > div{
13
+ display: flex;
14
+ align-items: center;
15
+ justify-content: center;
16
+ gap: .5rem;
17
+ }
18
+
19
+
20
+ .sun-and-moon > :is(.moon, .sun, .sun-beams) {
21
+ transform-origin: center center;
22
+ }
23
+
24
+
25
+ svg {
26
+ margin: auto;
27
+ stroke-linecap: round;
28
+ }
29
+
30
+ svg + div {
31
+ display: flex;
32
+ align-items: center;
33
+ justify-content: center;
34
+ }
35
+
36
+ :host([mode="light"]) .sun-and-moon > .sun {
37
+ transform: scale(1.75);
38
+ }
39
+
40
+ :host([mode="light"]) .sun-and-moon > .sun-beams {
41
+ opacity: 0;
42
+ }
43
+
44
+ :host([mode="light"]) .sun-and-moon > .moon > circle {
45
+ transform: translate(-7px);
46
+ }
47
+
48
+ /* Animations */
49
+
50
+ :host([mode="dark"]) .sun-and-moon > .sun {
51
+ transition: transform 0.5s cubic-bezier(0.5, 1.25, 0.75, 1.25);
52
+ }
53
+
54
+ :host([mode="dark"]) .sun-and-moon > .sun-beams {
55
+ transition:
56
+ transform 0.5s cubic-bezier(0.5, 1.5, 0.75, 1.25),
57
+ opacity 0.5s cubic-bezier(0.25, 0, 0.3, 1);
58
+ }
59
+
60
+ :host([mode="darkt"]) .sun-and-moon .moon > circle {
61
+ transition: transform 0.25s cubic-bezier(0, 0, 0, 1);
62
+ }
63
+
64
+ :host([mode="light"]) .sun-and-moon > .sun {
65
+ transform: scale(1.75);
66
+ transition-timing-function: cubic-bezier(0.25, 0, 0.3, 1);
67
+ transition-duration: 0.25s;
68
+ }
69
+
70
+ :host([mode="light"]) .sun-and-moon > .sun-beams {
71
+ transform: rotate(-25deg);
72
+ transition-duration: 0.15s;
73
+ }
74
+
75
+ :host([mode="light"]) .sun-and-moon > .moon > circle {
76
+ transition-delay: 0.25s;
77
+ transition-duration: 0.5s;
78
+ }
@@ -1,166 +1,166 @@
1
- import css from "./app-mode-switch.css";
2
-
3
- export enum ThemeMode {
4
- Light = "light",
5
- Dark = "dark",
6
- }
7
-
8
- interface AppModeSwitchEventMap {
9
- modeChange: CustomEvent<{ mode: ThemeMode }>;
10
- click: MouseEvent;
11
- }
12
-
13
- @CustomElementConfig({
14
- tagName: "app-mode-switch",
15
- })
16
- export class AppModeSwitchElement extends CustomElement {
17
- static readonly style = css;
18
-
19
- @Property({ type: "string", attribute: "mode", reflect: true })
20
- mode: ThemeMode = ThemeMode.Light;
21
-
22
- render(): VNode {
23
- return (
24
- <div>
25
- <svg
26
- class="sun-and-moon"
27
- aria-hidden="true"
28
- width="24"
29
- height="24"
30
- viewBox="0 0 24 24"
31
- >
32
- <mask class="moon" id="moon-mask">
33
- <rect x="0" y="0" width="100%" height="100%" fill="white"></rect>
34
- <circle cx="24" cy="10" r="6" fill="black"></circle>
35
- </mask>
36
- <circle
37
- class="sun"
38
- cx="12"
39
- cy="12"
40
- r="6"
41
- mask="url(#moon-mask)"
42
- fill="currentColor"
43
- ></circle>
44
- <g class="sun-beams" stroke="currentColor">
45
- <line x1="12" y1="1" x2="12" y2="3"></line>
46
- <line x1="12" y1="21" x2="12" y2="23"></line>
47
- <line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line>
48
- <line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line>
49
- <line x1="1" y1="12" x2="3" y2="12"></line>
50
- <line x1="21" y1="12" x2="23" y2="12"></line>
51
- <line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line>
52
- <line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line>
53
- </g>
54
- </svg>
55
- <div>
56
- <slot name={this.mode === ThemeMode.Dark ? ThemeMode.Light : ThemeMode.Dark }></slot>
57
- </div>
58
- </div>
59
- );
60
- }
61
-
62
- addEventListener<T extends keyof AppModeSwitchEventMap>(
63
- type: T,
64
- listener: (this: AppModeSwitchElement, ev: AppModeSwitchEventMap[T]) => any,
65
- options?: boolean | AddEventListenerOptions
66
- ): void;
67
-
68
- addEventListener(
69
- type: string,
70
- listener: (this: AppModeSwitchElement, ev: Event) => any,
71
- options?: boolean | AddEventListenerOptions
72
- ): void {
73
- super.addEventListener(type, listener, options);
74
- }
75
-
76
- private onClick = () => {
77
- this.mode =
78
- this.mode === ThemeMode.Light ? ThemeMode.Dark : ThemeMode.Light;
79
- };
80
-
81
- updated(propertyName: string, oldValue: any, newValue: any): void {
82
- if (propertyName === "mode") {
83
- this.dispatchEvent(
84
- new CustomEvent("modeChange", { detail: { mode: newValue } })
85
- );
86
- }
87
- }
88
-
89
- connectedCallback() {
90
- super.connectedCallback();
91
- if (!this.hasAttribute("tabindex")) {
92
- this.setAttribute("tabindex", "0");
93
- }
94
- this.setAttribute("role", "button");
95
- this.addEventListener("click", this.onClick);
96
- }
97
-
98
- disconnectedCallback() {
99
- super.disconnectedCallback();
100
- this.removeEventListener("click", this.onClick);
101
- }
102
- }
103
-
104
- // init theme
105
- let currentTheme: ThemeMode;
106
-
107
- const darkSchemeMediaQueryList = window.matchMedia(
108
- "(prefers-color-scheme: dark)"
109
- );
110
-
111
- function setTheme(theme: ThemeMode) {
112
- if (currentTheme === theme) return;
113
- currentTheme = theme;
114
- document.documentElement.setAttribute("theme", theme);
115
- if (systemTheme.startsWith(theme)) {
116
- localStorage.removeItem("theme");
117
- } else {
118
- localStorage.setItem("theme", theme);
119
- }
120
- }
121
-
122
- let systemTheme = darkSchemeMediaQueryList.matches
123
- ? `${ThemeMode.Dark}-mode`
124
- : `${ThemeMode.Light}-mode`;
125
-
126
- darkSchemeMediaQueryList.addEventListener("change", ({ matches }) => {
127
- const modeSwitch =
128
- document.querySelector<AppModeSwitchElement>("app-mode-switch");
129
- if (matches) {
130
- systemTheme = ThemeMode.Dark;
131
- setTheme(ThemeMode.Dark);
132
- if (modeSwitch){
133
- modeSwitch.mode = ThemeMode.Dark;
134
- }
135
- } else {
136
- systemTheme = ThemeMode.Light;
137
- setTheme(ThemeMode.Light);
138
- if (modeSwitch){
139
- modeSwitch.mode = ThemeMode.Light;
140
- }
141
- }
142
- });
143
-
144
- const savedTheme = localStorage.getItem("theme") as ThemeMode;
145
- if (savedTheme) {
146
- setTheme(savedTheme);
147
- } else {
148
- setTheme(systemTheme.split("-")[0] as ThemeMode);
149
- }
150
-
151
- document.addEventListener("DOMContentLoaded", () => {
152
- const modeSwitch =
153
- document.querySelector<AppModeSwitchElement>("app-mode-switch");
154
- if (!modeSwitch) return;
155
- modeSwitch.mode = savedTheme
156
- ? savedTheme
157
- : (systemTheme.split("-")[0] as ThemeMode);
158
- modeSwitch.addEventListener("modeChange", (e: CustomEventInit) => {
159
- if (e.detail.mode === ThemeMode.Dark) {
160
- setTheme(ThemeMode.Dark);
161
- } else if (e.detail.mode === ThemeMode.Light) {
162
- setTheme(ThemeMode.Light);
163
- }
164
- });
165
- });
166
-
1
+ import css from "./app-mode-switch.css";
2
+
3
+ export enum ThemeMode {
4
+ Light = "light",
5
+ Dark = "dark",
6
+ }
7
+
8
+ interface AppModeSwitchEventMap {
9
+ modeChange: CustomEvent<{ mode: ThemeMode }>;
10
+ click: MouseEvent;
11
+ }
12
+
13
+ @CustomElementConfig({
14
+ tagName: "app-mode-switch",
15
+ })
16
+ export class AppModeSwitchElement extends CustomElement {
17
+ static readonly style = css;
18
+
19
+ @Property({ type: "string", attribute: "mode", reflect: true })
20
+ mode: ThemeMode = ThemeMode.Light;
21
+
22
+ render(): VNode {
23
+ return (
24
+ <div>
25
+ <svg
26
+ class="sun-and-moon"
27
+ aria-hidden="true"
28
+ width="24"
29
+ height="24"
30
+ viewBox="0 0 24 24"
31
+ >
32
+ <mask class="moon" id="moon-mask">
33
+ <rect x="0" y="0" width="100%" height="100%" fill="white"></rect>
34
+ <circle cx="24" cy="10" r="6" fill="black"></circle>
35
+ </mask>
36
+ <circle
37
+ class="sun"
38
+ cx="12"
39
+ cy="12"
40
+ r="6"
41
+ mask="url(#moon-mask)"
42
+ fill="currentColor"
43
+ ></circle>
44
+ <g class="sun-beams" stroke="currentColor">
45
+ <line x1="12" y1="1" x2="12" y2="3"></line>
46
+ <line x1="12" y1="21" x2="12" y2="23"></line>
47
+ <line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line>
48
+ <line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line>
49
+ <line x1="1" y1="12" x2="3" y2="12"></line>
50
+ <line x1="21" y1="12" x2="23" y2="12"></line>
51
+ <line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line>
52
+ <line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line>
53
+ </g>
54
+ </svg>
55
+ <div>
56
+ <slot name={this.mode === ThemeMode.Dark ? ThemeMode.Light : ThemeMode.Dark }></slot>
57
+ </div>
58
+ </div>
59
+ );
60
+ }
61
+
62
+ addEventListener<T extends keyof AppModeSwitchEventMap>(
63
+ type: T,
64
+ listener: (this: AppModeSwitchElement, ev: AppModeSwitchEventMap[T]) => any,
65
+ options?: boolean | AddEventListenerOptions
66
+ ): void;
67
+
68
+ addEventListener(
69
+ type: string,
70
+ listener: (this: AppModeSwitchElement, ev: Event) => any,
71
+ options?: boolean | AddEventListenerOptions
72
+ ): void {
73
+ super.addEventListener(type, listener, options);
74
+ }
75
+
76
+ private onClick = () => {
77
+ this.mode =
78
+ this.mode === ThemeMode.Light ? ThemeMode.Dark : ThemeMode.Light;
79
+ };
80
+
81
+ updated(propertyName: string, oldValue: any, newValue: any): void {
82
+ if (propertyName === "mode") {
83
+ this.dispatchEvent(
84
+ new CustomEvent("modeChange", { detail: { mode: newValue } })
85
+ );
86
+ }
87
+ }
88
+
89
+ connectedCallback() {
90
+ super.connectedCallback();
91
+ if (!this.hasAttribute("tabindex")) {
92
+ this.setAttribute("tabindex", "0");
93
+ }
94
+ this.setAttribute("role", "button");
95
+ this.addEventListener("click", this.onClick);
96
+ }
97
+
98
+ disconnectedCallback() {
99
+ super.disconnectedCallback();
100
+ this.removeEventListener("click", this.onClick);
101
+ }
102
+ }
103
+
104
+ // init theme
105
+ let currentTheme: ThemeMode;
106
+
107
+ const darkSchemeMediaQueryList = window.matchMedia(
108
+ "(prefers-color-scheme: dark)"
109
+ );
110
+
111
+ function setTheme(theme: ThemeMode) {
112
+ if (currentTheme === theme) return;
113
+ currentTheme = theme;
114
+ document.documentElement.setAttribute("theme", theme);
115
+ if (systemTheme.startsWith(theme)) {
116
+ localStorage.removeItem("theme");
117
+ } else {
118
+ localStorage.setItem("theme", theme);
119
+ }
120
+ }
121
+
122
+ let systemTheme = darkSchemeMediaQueryList.matches
123
+ ? `${ThemeMode.Dark}-mode`
124
+ : `${ThemeMode.Light}-mode`;
125
+
126
+ darkSchemeMediaQueryList.addEventListener("change", ({ matches }) => {
127
+ const modeSwitch =
128
+ document.querySelector<AppModeSwitchElement>("app-mode-switch");
129
+ if (matches) {
130
+ systemTheme = ThemeMode.Dark;
131
+ setTheme(ThemeMode.Dark);
132
+ if (modeSwitch){
133
+ modeSwitch.mode = ThemeMode.Dark;
134
+ }
135
+ } else {
136
+ systemTheme = ThemeMode.Light;
137
+ setTheme(ThemeMode.Light);
138
+ if (modeSwitch){
139
+ modeSwitch.mode = ThemeMode.Light;
140
+ }
141
+ }
142
+ });
143
+
144
+ const savedTheme = localStorage.getItem("theme") as ThemeMode;
145
+ if (savedTheme) {
146
+ setTheme(savedTheme);
147
+ } else {
148
+ setTheme(systemTheme.split("-")[0] as ThemeMode);
149
+ }
150
+
151
+ document.addEventListener("DOMContentLoaded", () => {
152
+ const modeSwitch =
153
+ document.querySelector<AppModeSwitchElement>("app-mode-switch");
154
+ if (!modeSwitch) return;
155
+ modeSwitch.mode = savedTheme
156
+ ? savedTheme
157
+ : (systemTheme.split("-")[0] as ThemeMode);
158
+ modeSwitch.addEventListener("modeChange", (e: CustomEventInit) => {
159
+ if (e.detail.mode === ThemeMode.Dark) {
160
+ setTheme(ThemeMode.Dark);
161
+ } else if (e.detail.mode === ThemeMode.Light) {
162
+ setTheme(ThemeMode.Light);
163
+ }
164
+ });
165
+ });
166
+