darkify-js 1.1.13-beta.0 → 1.1.13-beta.2

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.
package/dist/darkify.d.ts CHANGED
@@ -1,13 +1,13 @@
1
- interface DarkifyPlugin {
2
- el?: HTMLElement | ShadowRoot;
3
- render(): void | HTMLElement | ShadowRoot;
1
+ interface DarkifyPlugin<T extends HTMLElement = HTMLElement> {
2
+ el?: T;
3
+ render(): void | T;
4
4
  onThemeChange?: (theme: string) => void;
5
5
  onDestroy?: () => void;
6
6
  }
7
7
 
8
- interface DarkifyPluginElement {
9
- new (host: any, options?: object): DarkifyPlugin;
8
+ interface DarkifyPluginConstructor {
10
9
  pluginId: string;
10
+ new (host: any, options?: any): DarkifyPlugin;
11
11
  }
12
12
 
13
13
  type StorageType = 'local' | 'session' | 'none';
@@ -16,7 +16,7 @@ interface Options {
16
16
  autoMatchTheme: boolean;
17
17
  useColorScheme: [string, string?];
18
18
  useStorage: StorageType;
19
- usePlugins?: (DarkifyPluginElement | [DarkifyPluginElement, any])[];
19
+ usePlugins?: (DarkifyPluginConstructor | [DarkifyPluginConstructor, any])[];
20
20
  }
21
21
 
22
22
  declare class Darkify {
@@ -27,10 +27,20 @@ declare class Darkify {
27
27
  private _elm;
28
28
  private _meta;
29
29
  private _style;
30
+ /**
31
+ * Creates a new Darkify instance with default options
32
+ * @param element - Button ID (recommended) or HTML element selector
33
+ */
34
+ constructor(element: string);
35
+ /**
36
+ * Creates a new Darkify instance with custom options only
37
+ * @param options - Options
38
+ */
39
+ constructor(options: Partial<Options>);
30
40
  /**
31
41
  * Creates a new Darkify instance for managing dark/light theme
32
42
  * @param element - Button ID (recommended) or HTML element selector
33
- * @param options - Configuration options for customizing behavior
43
+ * @param options - Options
34
44
  * @see {@link https://github.com/emrocode/darkify-js/wiki|Documentation}
35
45
  */
36
46
  constructor(element: string, options: Partial<Options>);
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  *
3
3
  * @author Emilio Romero <emrocode@gmail.com>
4
- * @version 1.1.13-beta.0
4
+ * @version 1.1.13-beta.2
5
5
  * @license MIT
6
6
  */
7
7
  class EventListenerManager {
@@ -36,13 +36,15 @@ class Darkify {
36
36
  if (!isBrowser)
37
37
  return;
38
38
  this._elm = new EventListenerManager();
39
- const opts = Object.assign(Object.assign({}, defaultOptions), options);
39
+ const el = typeof element === 'string' ? element : undefined;
40
+ const inputOpts = element && typeof element === 'object' ? element : options;
41
+ const opts = Object.assign(Object.assign({}, defaultOptions), inputOpts);
40
42
  this.options = opts;
41
43
  this.theme = this.getOsPreference();
42
44
  this._style = document.createElement('style');
43
45
  this._meta = document.createElement('meta');
44
- this.init(element);
45
46
  this.createAttribute();
47
+ this.init(el);
46
48
  this.syncThemeBetweenTabs();
47
49
  }
48
50
  init(element) {
@@ -50,16 +52,20 @@ class Darkify {
50
52
  this.theme = isDark ? 'dark' : 'light';
51
53
  this.createAttribute();
52
54
  });
53
- this.initPlugins();
54
- const hasWidget = this.plugins.some(p => p.el !== undefined);
55
- if (element && !hasWidget) {
56
- this._elm.addListener(document, 'DOMContentLoaded', () => {
55
+ const setup = () => {
56
+ this.initPlugins();
57
+ const hasWidget = this.plugins.some(p => p.el !== undefined);
58
+ if (element && !hasWidget) {
57
59
  const htmlElement = document.querySelector(element);
58
60
  if (htmlElement) {
59
61
  this._elm.addListener(htmlElement, 'click', () => this.toggleTheme());
60
62
  }
61
- });
63
+ }
64
+ };
65
+ if (document.readyState !== 'loading') {
66
+ return setup();
62
67
  }
68
+ this._elm.addListener(document, 'DOMContentLoaded', setup);
63
69
  }
64
70
  initPlugins() {
65
71
  var _a;
@@ -67,7 +73,7 @@ class Darkify {
67
73
  const [Plugin, pluginOptions] = Array.isArray(p) ? p : [p, undefined];
68
74
  const plugin = new Plugin(this, pluginOptions);
69
75
  const renderedNode = plugin.render();
70
- if (renderedNode instanceof HTMLElement || renderedNode instanceof ShadowRoot) {
76
+ if (renderedNode) {
71
77
  plugin.el = renderedNode;
72
78
  }
73
79
  this.plugins.push(plugin);
@@ -155,9 +161,6 @@ class Darkify {
155
161
  if (this.plugins.length > 0) {
156
162
  this.plugins.forEach(plugin => {
157
163
  var _a;
158
- if (plugin.el) {
159
- (plugin.el instanceof ShadowRoot ? plugin.el.host : plugin.el).remove();
160
- }
161
164
  (_a = plugin.onDestroy) === null || _a === void 0 ? void 0 : _a.call(plugin);
162
165
  });
163
166
  this.plugins = [];
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  *
3
3
  * @author Emilio Romero <emrocode@gmail.com>
4
- * @version 1.1.13-beta.0
4
+ * @version 1.1.13-beta.2
5
5
  * @license MIT
6
6
  */
7
- !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).Darkify=t()}(this,function(){"use strict";class e{constructor(){this.listeners=[]}addListener(e,t,s,i){e.addEventListener(t,s,i),this.listeners.push({target:e,event:t,handler:s,options:i})}clearListeners(){this.listeners.forEach(({target:e,event:t,handler:s,options:i})=>{e.removeEventListener(t,s,i)}),this.listeners=[]}}const t={autoMatchTheme:!0,useColorScheme:["#ffffff","#000000"],useStorage:"local"},s="undefined"!=typeof window;class i{constructor(i,n){if(this.options=t,this.plugins=[],this.theme="light",!s)return;this._elm=new e;const o=Object.assign(Object.assign({},t),n);this.options=o,this.theme=this.getOsPreference(),this._style=document.createElement("style"),this._meta=document.createElement("meta"),this.init(i),this.createAttribute(),this.syncThemeBetweenTabs()}init(e){this._elm.addListener(window.matchMedia("(prefers-color-scheme: dark)"),"change",({matches:e})=>{this.theme=e?"dark":"light",this.createAttribute()}),this.initPlugins();const t=this.plugins.some(e=>void 0!==e.el);e&&!t&&this._elm.addListener(document,"DOMContentLoaded",()=>{const t=document.querySelector(e);t&&this._elm.addListener(t,"click",()=>this.toggleTheme())})}initPlugins(){var e;null===(e=this.options.usePlugins)||void 0===e||e.forEach(e=>{const[t,s]=Array.isArray(e)?e:[e,void 0],i=new t(this,s),n=i.render();(n instanceof HTMLElement||n instanceof ShadowRoot)&&(i.el=n),this.plugins.push(i)})}notifyPlugins(e){this.plugins.forEach(t=>{var s;null===(s=t.onThemeChange)||void 0===s||s.call(t,e)})}getStorage(){const{useStorage:e}=this.options;if("none"!==e)return"local"===e?window.localStorage:window.sessionStorage}getOsPreference(){const e=this.getStorage();if(e){const t=e.getItem(i.storageKey);if(t)return t}return this.options.autoMatchTheme&&window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light"}createAttribute(){const e=document.documentElement,{useColorScheme:t}=this.options,s=`/**! Darkify / A simple dark mode toggle library **/\n:root:where([data-theme="${this.theme}"]),[data-theme="${this.theme}"]{color-scheme:${this.theme}}`;e.dataset.theme=this.theme,this.updateTags(s,t),this.savePreference()}updateTags(e,t){const[s,i]=t;this._meta.name="theme-color",this._meta.media=`(prefers-color-scheme: ${this.theme})`,this._meta.content="light"===this.theme?s:null!=i?i:s,this._style.innerHTML=e;const n=document.head;this._meta.parentNode||n.appendChild(this._meta),this._style.parentNode||n.appendChild(this._style)}savePreference(){const{useStorage:e}=this.options;if("none"===e)return;const t="local"===e,s=t?window.localStorage:window.sessionStorage;(t?window.sessionStorage:window.localStorage).removeItem(i.storageKey),s.setItem(i.storageKey,this.theme)}syncThemeBetweenTabs(){this._elm.addListener(window,"storage",e=>{e.key===i.storageKey&&e.newValue&&(this.theme=e.newValue,this.createAttribute(),this.notifyPlugins(e.newValue))})}setTheme(e){this.theme=e,this.createAttribute(),this.notifyPlugins(e)}toggleTheme(){this.setTheme("light"===this.theme?"dark":"light")}getCurrentTheme(){return this.theme}destroy(){var e,t,s,i;this._elm.clearListeners(),null===(t=null===(e=this._style)||void 0===e?void 0:e.parentNode)||void 0===t||t.removeChild(this._style),null===(i=null===(s=this._meta)||void 0===s?void 0:s.parentNode)||void 0===i||i.removeChild(this._meta),this.plugins.length>0&&(this.plugins.forEach(e=>{var t;e.el&&(e.el instanceof ShadowRoot?e.el.host:e.el).remove(),null===(t=e.onDestroy)||void 0===t||t.call(e)}),this.plugins=[])}}return i.storageKey="theme",i});
7
+ !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).Darkify=t()}(this,function(){"use strict";class e{constructor(){this.listeners=[]}addListener(e,t,s,i){e.addEventListener(t,s,i),this.listeners.push({target:e,event:t,handler:s,options:i})}clearListeners(){this.listeners.forEach(({target:e,event:t,handler:s,options:i})=>{e.removeEventListener(t,s,i)}),this.listeners=[]}}const t={autoMatchTheme:!0,useColorScheme:["#ffffff","#000000"],useStorage:"local"},s="undefined"!=typeof window;class i{constructor(i,n){if(this.options=t,this.plugins=[],this.theme="light",!s)return;this._elm=new e;const o="string"==typeof i?i:void 0,h=i&&"object"==typeof i?i:n,r=Object.assign(Object.assign({},t),h);this.options=r,this.theme=this.getOsPreference(),this._style=document.createElement("style"),this._meta=document.createElement("meta"),this.createAttribute(),this.init(o),this.syncThemeBetweenTabs()}init(e){this._elm.addListener(window.matchMedia("(prefers-color-scheme: dark)"),"change",({matches:e})=>{this.theme=e?"dark":"light",this.createAttribute()});const t=()=>{this.initPlugins();const t=this.plugins.some(e=>void 0!==e.el);if(e&&!t){const t=document.querySelector(e);t&&this._elm.addListener(t,"click",()=>this.toggleTheme())}};if("loading"!==document.readyState)return t();this._elm.addListener(document,"DOMContentLoaded",t)}initPlugins(){var e;null===(e=this.options.usePlugins)||void 0===e||e.forEach(e=>{const[t,s]=Array.isArray(e)?e:[e,void 0],i=new t(this,s),n=i.render();n&&(i.el=n),this.plugins.push(i)})}notifyPlugins(e){this.plugins.forEach(t=>{var s;null===(s=t.onThemeChange)||void 0===s||s.call(t,e)})}getStorage(){const{useStorage:e}=this.options;if("none"!==e)return"local"===e?window.localStorage:window.sessionStorage}getOsPreference(){const e=this.getStorage();if(e){const t=e.getItem(i.storageKey);if(t)return t}return this.options.autoMatchTheme&&window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light"}createAttribute(){const e=document.documentElement,{useColorScheme:t}=this.options,s=`/**! Darkify / A simple dark mode toggle library **/\n:root:where([data-theme="${this.theme}"]),[data-theme="${this.theme}"]{color-scheme:${this.theme}}`;e.dataset.theme=this.theme,this.updateTags(s,t),this.savePreference()}updateTags(e,t){const[s,i]=t;this._meta.name="theme-color",this._meta.media=`(prefers-color-scheme: ${this.theme})`,this._meta.content="light"===this.theme?s:null!=i?i:s,this._style.innerHTML=e;const n=document.head;this._meta.parentNode||n.appendChild(this._meta),this._style.parentNode||n.appendChild(this._style)}savePreference(){const{useStorage:e}=this.options;if("none"===e)return;const t="local"===e,s=t?window.localStorage:window.sessionStorage;(t?window.sessionStorage:window.localStorage).removeItem(i.storageKey),s.setItem(i.storageKey,this.theme)}syncThemeBetweenTabs(){this._elm.addListener(window,"storage",e=>{e.key===i.storageKey&&e.newValue&&(this.theme=e.newValue,this.createAttribute(),this.notifyPlugins(e.newValue))})}setTheme(e){this.theme=e,this.createAttribute(),this.notifyPlugins(e)}toggleTheme(){this.setTheme("light"===this.theme?"dark":"light")}getCurrentTheme(){return this.theme}destroy(){var e,t,s,i;this._elm.clearListeners(),null===(t=null===(e=this._style)||void 0===e?void 0:e.parentNode)||void 0===t||t.removeChild(this._style),null===(i=null===(s=this._meta)||void 0===s?void 0:s.parentNode)||void 0===i||i.removeChild(this._meta),this.plugins.length>0&&(this.plugins.forEach(e=>{var t;null===(t=e.onDestroy)||void 0===t||t.call(e)}),this.plugins=[])}}return i.storageKey="theme",i});
@@ -1,31 +1,42 @@
1
- interface DarkifyPlugin {
2
- el?: HTMLElement | ShadowRoot;
3
- render(): void | HTMLElement | ShadowRoot;
4
- onThemeChange?: (theme: string) => void;
5
- onDestroy?: () => void;
6
- }
1
+ import { DarkifyPlugin } from '../darkify';
7
2
 
8
3
  interface ThemeWidgetOptions {
9
- position?: 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';
10
- size?: 'small' | 'medium' | 'large';
4
+ position: 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';
5
+ size: 'small' | 'medium' | 'large';
11
6
  shortcut?: string;
12
7
  }
13
- declare class ThemeWidget implements DarkifyPlugin {
14
- el?: ShadowRoot;
8
+ declare class ThemeWidgetElement extends HTMLElement {
15
9
  private _host;
10
+ private _theme;
11
+ private _initialized;
12
+ private _wrapper;
13
+ private _button;
14
+ private _span;
15
+ options: ThemeWidgetOptions;
16
+ private static _styles;
17
+ static get observedAttributes(): string[];
18
+ constructor();
19
+ init(host: any, options: Required<ThemeWidgetOptions>): void;
20
+ connectedCallback(): void;
21
+ disconnectedCallback(): void;
22
+ attributeChangedCallback(name: string, oldValue: string, newValue: string): void;
23
+ onThemeChange(theme: string): void;
24
+ render(): void;
25
+ }
26
+ declare global {
27
+ interface HTMLElementTagNameMap {
28
+ 'd-widget': ThemeWidgetElement;
29
+ }
30
+ }
31
+
32
+ declare class ThemeWidget implements DarkifyPlugin<ThemeWidgetElement> {
16
33
  static readonly pluginId = "d-widget";
34
+ el: ThemeWidgetElement;
17
35
  private options;
18
- /**
19
- * Creates a theme toggle widget button
20
- * @param host - The darkify instance that controls theme state
21
- * @param options - Widget configuration (position, size, shortcut)
22
- */
23
36
  constructor(host: any, options?: ThemeWidgetOptions);
24
- render(): ShadowRoot;
37
+ render(): ThemeWidgetElement;
25
38
  onThemeChange(theme: string): void;
26
39
  onDestroy(): void;
27
- private getPositionVars;
28
- private getSizeVar;
29
40
  }
30
41
 
31
42
  interface KeyboardShortcutOptions {
@@ -33,15 +44,13 @@ interface KeyboardShortcutOptions {
33
44
  ctrl?: boolean;
34
45
  shift?: boolean;
35
46
  target?: 'body' | 'input' | 'all';
47
+ cooldown?: number;
36
48
  }
37
49
  declare class KeyboardShortcut implements DarkifyPlugin {
50
+ static readonly pluginId = "d-keyboard-shortcut";
38
51
  private _host;
39
52
  private options;
40
- /**
41
- * Creates a keyboard shortcut listener for theme toggling
42
- * @param host - The darkify instance that controls theme state
43
- * @param options - Shortcut configuration (key, ctrl, shift, target)
44
- */
53
+ private _lastTriggered;
45
54
  constructor(host: any, options?: KeyboardShortcutOptions);
46
55
  private handleKeyDown;
47
56
  render(): void;
@@ -51,4 +60,3 @@ declare class KeyboardShortcut implements DarkifyPlugin {
51
60
  }
52
61
 
53
62
  export { KeyboardShortcut, ThemeWidget };
54
- export type { KeyboardShortcutOptions, ThemeWidgetOptions };
@@ -0,0 +1,249 @@
1
+ const pluginId = 'd-widget';
2
+ class ThemeWidgetElement extends HTMLElement {
3
+ static get observedAttributes() {
4
+ return ['position', 'size'];
5
+ }
6
+ constructor() {
7
+ super();
8
+ this._initialized = false;
9
+ const shadow = this.attachShadow({ mode: 'open' });
10
+ const style = document.createElement('style');
11
+ style.textContent = ThemeWidgetElement._styles;
12
+ shadow.appendChild(style);
13
+ }
14
+ init(host, options) {
15
+ this._host = host;
16
+ this._theme = host.getCurrentTheme();
17
+ this.options = options;
18
+ this.setAttribute('position', this.options.position);
19
+ this.setAttribute('size', this.options.size);
20
+ this.render();
21
+ }
22
+ connectedCallback() {
23
+ this.render();
24
+ }
25
+ disconnectedCallback() {
26
+ this._host._elm.clearListeners();
27
+ }
28
+ attributeChangedCallback(name, oldValue, newValue) {
29
+ if (oldValue !== newValue && (name === 'position' || name === 'size')) {
30
+ this.render();
31
+ }
32
+ }
33
+ onThemeChange(theme) {
34
+ this._theme = theme;
35
+ this.render();
36
+ }
37
+ render() {
38
+ const icon = this._theme === 'light' ? '🌞' : '🌚';
39
+ if (!this._initialized) {
40
+ this._wrapper = document.createElement('div');
41
+ this._wrapper.className = 'd-wrapper';
42
+ this._button = document.createElement('button');
43
+ this._button.className = 'd-button';
44
+ this._button.setAttribute('aria-label', 'Toggle theme');
45
+ this._host._elm.addListener(this._button, 'click', () => this._host.toggleTheme());
46
+ this._span = document.createElement('span');
47
+ this._span.className = 'd-icon';
48
+ this._button.appendChild(this._span);
49
+ if (this.options.shortcut) {
50
+ const kbd = document.createElement('kbd');
51
+ kbd.className = 'd-kbd';
52
+ kbd.textContent = this.options.shortcut;
53
+ this.options.position.includes('left')
54
+ ? this._wrapper.append(this._button, kbd)
55
+ : this._wrapper.append(kbd, this._button);
56
+ }
57
+ else {
58
+ this._wrapper.appendChild(this._button);
59
+ }
60
+ this.shadowRoot.appendChild(this._wrapper);
61
+ this._initialized = true;
62
+ return;
63
+ }
64
+ this._span.textContent = icon;
65
+ }
66
+ }
67
+ ThemeWidgetElement._styles = `
68
+ :host {
69
+ --widget-safe-top: env(safe-area-inset-top, 0px);
70
+ --widget-safe-right: env(safe-area-inset-right, 0px);
71
+ --widget-safe-bottom: env(safe-area-inset-bottom, 0px);
72
+ --widget-safe-left: env(safe-area-inset-left, 0px);
73
+ --margin: 24px;
74
+ --top: var(--margin);
75
+ --right: var(--margin);
76
+ --bottom: auto;
77
+ --left: auto;
78
+ }
79
+ :host([position='top-left']) {
80
+ --top: var(--margin);
81
+ --right: auto;
82
+ --bottom: auto;
83
+ --left: var(--margin);
84
+ }
85
+ :host([position='top-right']) {
86
+ --top: var(--margin);
87
+ --right: var(--margin);
88
+ --bottom: auto;
89
+ --left: auto;
90
+ }
91
+ :host([position='bottom-left']) {
92
+ --top: auto;
93
+ --right: auto;
94
+ --bottom: calc(var(--margin) * 2);
95
+ --left: var(--margin);
96
+ }
97
+ :host([position='bottom-right']) {
98
+ --top: auto;
99
+ --right: var(--margin);
100
+ --bottom: calc(var(--margin) * 2);
101
+ --left: auto;
102
+ }
103
+ :host([size='small']) { --size: 36px; }
104
+ :host([size='medium']) { --size: 56px; }
105
+ :host([size='large']) { --size: 72px; }
106
+ .d-wrapper {
107
+ position: fixed;
108
+ top: calc(var(--top) + var(--widget-safe-top));
109
+ right: calc(var(--right) + var(--widget-safe-right));
110
+ bottom: calc(var(--bottom) + var(--widget-safe-bottom));
111
+ left: calc(var(--left) + var(--widget-safe-left));
112
+ z-index: 9999;
113
+ max-width: fit-content;
114
+ display: flex;
115
+ align-items: center;
116
+ column-gap: 0.5rem;
117
+ }
118
+ .d-button {
119
+ --icon-size: calc(var(--size) * 0.4);
120
+ position: relative;
121
+ width: var(--size);
122
+ height: var(--size);
123
+ border: none;
124
+ border-bottom: 1px solid hsl(from canvastext h s l / calc(alpha * 0.5));
125
+ border-radius: 50%;
126
+ box-shadow: 0 1px 3px 0 hsla(210, 6%, 25%, 0.3), 0 4px 8px 3px hsla(210, 6%, 25%, 0.3);
127
+ background-color: transparent;
128
+ color: canvastext;
129
+ cursor: pointer;
130
+ font-size: var(--icon-size);
131
+ display: flex;
132
+ flex-direction: column;
133
+ align-items: center;
134
+ justify-content: center;
135
+ overflow: hidden;
136
+ user-select: none;
137
+ -webkit-user-select: none;
138
+ -webkit-tap-highlight-color: transparent;
139
+ }
140
+ .d-button::before {
141
+ content: '';
142
+ position: absolute;
143
+ inset: 0;
144
+ z-index: -1;
145
+ border: none;
146
+ background-color: canvas;
147
+ filter: invert(90%);
148
+ }
149
+ .d-button:focus-visible {
150
+ outline: 2px solid currentcolor;
151
+ outline-offset: 2px;
152
+ }
153
+ .d-button:active {
154
+ transform: scale(0.98);
155
+ transition: transform 0.4s ease-in-out;
156
+ }
157
+ .d-kbd {
158
+ position: relative;
159
+ padding: 0.25em 0.4em;
160
+ font-size: 11px;
161
+ font-family: ui-monospace, monospace;
162
+ line-height: 1;
163
+ letter-spacing: -0.025em;
164
+ background-color: canvas;
165
+ color: canvastext;
166
+ filter: invert(90%);
167
+ border: none;
168
+ border-bottom: 1px solid hsl(from canvastext h s l / calc(alpha * 0.5));
169
+ border-radius: 0.25rem;
170
+ box-shadow: 0 0 2px hsla(0, 0%, 0%, 0.1);
171
+ user-select: none;
172
+ -webkit-user-select: none;
173
+ }
174
+ `;
175
+ customElements.define(pluginId, ThemeWidgetElement);
176
+
177
+ class ThemeWidget {
178
+ constructor(host, options) {
179
+ var _a, _b, _c;
180
+ this.options = {
181
+ position: (_a = options === null || options === void 0 ? void 0 : options.position) !== null && _a !== void 0 ? _a : 'bottom-right',
182
+ size: (_b = options === null || options === void 0 ? void 0 : options.size) !== null && _b !== void 0 ? _b : 'medium',
183
+ shortcut: (_c = options === null || options === void 0 ? void 0 : options.shortcut) !== null && _c !== void 0 ? _c : '',
184
+ };
185
+ this.el = document.createElement(pluginId);
186
+ this.el.init(host, this.options);
187
+ }
188
+ render() {
189
+ document.body.appendChild(this.el);
190
+ return this.el;
191
+ }
192
+ onThemeChange(theme) {
193
+ this.el.onThemeChange(theme);
194
+ }
195
+ onDestroy() {
196
+ this.el.remove();
197
+ }
198
+ }
199
+ ThemeWidget.pluginId = pluginId;
200
+
201
+ class KeyboardShortcut {
202
+ constructor(host, options) {
203
+ var _a, _b, _c, _d, _e;
204
+ this._lastTriggered = 0;
205
+ this.handleKeyDown = (e) => {
206
+ if (this.options.target === 'body' && this.isTyping(e))
207
+ return;
208
+ if (this.options.target === 'input' && !this.isTyping(e))
209
+ return;
210
+ if (this.matches(e)) {
211
+ e.preventDefault();
212
+ const now = Date.now();
213
+ if (now - this._lastTriggered < this.options.cooldown)
214
+ return;
215
+ this._lastTriggered = now;
216
+ this._host.toggleTheme();
217
+ }
218
+ };
219
+ this._host = host;
220
+ this.options = {
221
+ key: (_a = options === null || options === void 0 ? void 0 : options.key) !== null && _a !== void 0 ? _a : 'd',
222
+ ctrl: (_b = options === null || options === void 0 ? void 0 : options.ctrl) !== null && _b !== void 0 ? _b : false,
223
+ shift: (_c = options === null || options === void 0 ? void 0 : options.shift) !== null && _c !== void 0 ? _c : false,
224
+ target: (_d = options === null || options === void 0 ? void 0 : options.target) !== null && _d !== void 0 ? _d : 'body',
225
+ cooldown: (_e = options === null || options === void 0 ? void 0 : options.cooldown) !== null && _e !== void 0 ? _e : 300,
226
+ };
227
+ }
228
+ render() {
229
+ document.addEventListener('keydown', this.handleKeyDown);
230
+ }
231
+ onDestroy() {
232
+ document.removeEventListener('keydown', this.handleKeyDown);
233
+ }
234
+ matches(e) {
235
+ return (e.key.toLowerCase() === this.options.key.toLowerCase() &&
236
+ (!this.options.ctrl || e.ctrlKey || e.metaKey) &&
237
+ (!this.options.shift || e.shiftKey) &&
238
+ (this.options.ctrl || (!e.ctrlKey && !e.metaKey && !e.altKey)));
239
+ }
240
+ isTyping(e) {
241
+ const target = e.target;
242
+ const tagName = target.tagName.toLowerCase();
243
+ const isEditable = target.isContentEditable || tagName === 'input' || tagName === 'textarea';
244
+ return isEditable;
245
+ }
246
+ }
247
+ KeyboardShortcut.pluginId = 'd-keyboard-shortcut';
248
+
249
+ export { KeyboardShortcut, ThemeWidget };
@@ -1 +1 @@
1
- !function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).DarkifyPlugins={})}(this,function(t){"use strict";class e{constructor(t,e){var n,o,i;this._host=t,this.options={position:null!==(n=null==e?void 0:e.position)&&void 0!==n?n:"bottom-right",size:null!==(o=null==e?void 0:e.size)&&void 0!==o?o:"medium",shortcut:null!==(i=null==e?void 0:e.shortcut)&&void 0!==i?i:""}}render(){var t;const n=document.createElement("div");n.id=e.pluginId,this.el=n.attachShadow({mode:"open"});const o=this.getPositionVars(),i=this.getSizeVar(),s=new CSSStyleSheet;s.replaceSync(`\n :host {\n --widget-safe-top: env(safe-area-inset-top, 0px);\n --widget-safe-right: env(safe-area-inset-right, 0px);\n --widget-safe-bottom: env(safe-area-inset-bottom, 0px);\n --widget-safe-left: env(safe-area-inset-left, 0px);\n --widget-margin: 24px;\n }\n\n .d-wrapper {\n --margin: max(var(--widget-margin), var(--widget-safe-bottom));\n ${o}\n ${i}\n position: fixed;\n top: calc(var(--pos-top) + var(--widget-safe-top));\n right: calc(var(--pos-right) + var(--widget-safe-right));\n bottom: calc(var(--pos-bottom) + var(--widget-safe-bottom));\n left: calc(var(--pos-left) + var(--widget-safe-left));\n z-index: 9999;\n max-width: fit-content;\n display: flex;\n align-items: center;\n column-gap: 0.5rem;\n }\n\n .d-button {\n --icon-size: calc(var(--size) * 0.4);\n position: relative;\n width: var(--size);\n height: var(--size);\n border-radius: 50%;\n border: none;\n border-bottom: 2px solid var(--widget-accent, hsl(0,0%,0%,0.30));\n box-shadow: 0 1px 3px 0 hsla(210,6%,25%,0.30), 0 4px 8px 3px hsla(210,6%,25%,0.30);\n background-color: transparent;\n color: canvastext;\n cursor: pointer;\n font-size: var(--icon-size);\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n overflow: hidden;\n transition: transform 0.4s ease-in-out;\n user-select: none;\n -webkit-user-select: none;\n -webkit-tap-highlight-color: transparent;\n }\n\n .d-button::before {\n content: "";\n position: absolute;\n inset: 0;\n z-index: -1;\n border: none;\n border-radius: 50%;\n background-color: canvas;\n filter: invert(90%);\n }\n\n .d-button.light { --widget-accent: hsl(45,99%,54%); }\n .d-button.dark { --widget-accent: hsl(200,29%,43%); }\n\n @media (prefers-reduced-motion: no-preference) {\n .d-button {\n animation: dEnter 0.4s cubic-bezier(0.34,1.56,0.64,1);\n animation-fill-mode: backwards;\n }\n }\n\n @keyframes dEnter {\n from {\n opacity: 0;\n transform: scale(0.6);\n }\n to {\n opacity: 1;\n transform: scale(1);\n }\n }\n\n .d-kbd {\n position: relative;\n padding: 0.25em 0.4em;\n font-size: 11px;\n font-family: ui-monospace, monospace;\n line-height: 1;\n letter-spacing: -0.025em;\n background-color: canvas;\n color: canvastext;\n filter: invert(90%);\n border: none;\n border-bottom: 2px solid hsl(from canvastext h s l / calc(alpha * 0.5));\n border-radius: 0.25rem;\n box-shadow: 0 0 2px hsla(0,0%,0%,0.10);\n user-select: none;\n -webkit-user-select: none;\n }\n `),this.el.adoptedStyleSheets=[s];const a=document.createElement("div");a.className="d-wrapper";const r=document.createElement("button");r.className="d-button",r.setAttribute("aria-label","Toggle theme"),r.addEventListener("click",()=>this._host.toggleTheme());const l=document.createElement("span");l.className="d-icon",r.appendChild(l);const d=null===(t=this.options.position)||void 0===t?void 0:t.includes("left");if(this.options.shortcut){const t=document.createElement("kbd");t.className="d-kbd",t.textContent=this.options.shortcut,d?(a.appendChild(r),a.appendChild(t)):(a.appendChild(t),a.appendChild(r))}else a.appendChild(r);return this.el.appendChild(a),document.body.appendChild(n),this.onThemeChange(this._host.getCurrentTheme()),this.el}onThemeChange(t){var e,n;const o=null===(e=this.el)||void 0===e?void 0:e.querySelector("button.d-button"),i=null===(n=this.el)||void 0===n?void 0:n.querySelector("span.d-icon");o&&i&&(o.className=`d-button ${t}`,i.textContent="light"===t?"🌞":"🌚")}onDestroy(){this.el&&this.el.host&&this.el.host.remove()}getPositionVars(){return{"top-left":"--pos-top:var(--margin);--pos-right:auto;--pos-bottom:auto;--pos-left:var(--margin);","top-right":"--pos-top:var(--margin);--pos-right:var(--margin);--pos-bottom:auto;--pos-left:auto;","bottom-left":"--pos-top:auto;--pos-right:auto;--pos-bottom:calc(var(--margin)*2);--pos-left:var(--margin);","bottom-right":"--pos-top:auto;--pos-right:var(--margin);--pos-bottom:calc(var(--margin)*2);--pos-left:auto;"}[this.options.position]}getSizeVar(){return{small:"--size:36px;",medium:"--size:56px;",large:"--size:72px;"}[this.options.size]}}e.pluginId="d-widget";t.KeyboardShortcut=class{constructor(t,e){var n,o,i,s;this.handleKeyDown=t=>{"body"===this.options.target&&this.isTyping(t)||("input"!==this.options.target||this.isTyping(t))&&this.matches(t)&&(t.preventDefault(),this._host.toggleTheme())},this._host=t,this.options={key:null!==(n=null==e?void 0:e.key)&&void 0!==n?n:"d",ctrl:null!==(o=null==e?void 0:e.ctrl)&&void 0!==o&&o,shift:null!==(i=null==e?void 0:e.shift)&&void 0!==i&&i,target:null!==(s=null==e?void 0:e.target)&&void 0!==s?s:"body"}}render(){document.addEventListener("keydown",this.handleKeyDown)}onDestroy(){document.removeEventListener("keydown",this.handleKeyDown)}matches(t){return t.key.toLowerCase()===this.options.key.toLowerCase()&&(!this.options.ctrl||t.ctrlKey||t.metaKey)&&(!this.options.shift||t.shiftKey)&&(this.options.ctrl||!t.ctrlKey&&!t.metaKey&&!t.altKey)}isTyping(t){const e=t.target,n=e.tagName.toLowerCase();return e.isContentEditable||"input"===n||"textarea"===n}},t.ThemeWidget=e});
1
+ !function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).DarkifyPlugins={})}(this,function(t){"use strict";const e="d-widget";class n extends HTMLElement{static get observedAttributes(){return["position","size"]}constructor(){super(),this._initialized=!1;const t=this.attachShadow({mode:"open"}),e=document.createElement("style");e.textContent=n._styles,t.appendChild(e)}init(t,e){this._host=t,this._theme=t.getCurrentTheme(),this.options=e,this.setAttribute("position",this.options.position),this.setAttribute("size",this.options.size),this.render()}connectedCallback(){this.render()}disconnectedCallback(){this._host._elm.clearListeners()}attributeChangedCallback(t,e,n){e===n||"position"!==t&&"size"!==t||this.render()}onThemeChange(t){this._theme=t,this.render()}render(){const t="light"===this._theme?"🌞":"🌚";if(!this._initialized){if(this._wrapper=document.createElement("div"),this._wrapper.className="d-wrapper",this._button=document.createElement("button"),this._button.className="d-button",this._button.setAttribute("aria-label","Toggle theme"),this._host._elm.addListener(this._button,"click",()=>this._host.toggleTheme()),this._span=document.createElement("span"),this._span.className="d-icon",this._button.appendChild(this._span),this.options.shortcut){const t=document.createElement("kbd");t.className="d-kbd",t.textContent=this.options.shortcut,this.options.position.includes("left")?this._wrapper.append(this._button,t):this._wrapper.append(t,this._button)}else this._wrapper.appendChild(this._button);return this.shadowRoot.appendChild(this._wrapper),void(this._initialized=!0)}this._span.textContent=t}}n._styles="\n:host {\n --widget-safe-top: env(safe-area-inset-top, 0px);\n --widget-safe-right: env(safe-area-inset-right, 0px);\n --widget-safe-bottom: env(safe-area-inset-bottom, 0px);\n --widget-safe-left: env(safe-area-inset-left, 0px);\n --margin: 24px;\n --top: var(--margin);\n --right: var(--margin);\n --bottom: auto;\n --left: auto;\n}\n:host([position='top-left']) {\n --top: var(--margin);\n --right: auto;\n --bottom: auto;\n --left: var(--margin);\n}\n:host([position='top-right']) {\n --top: var(--margin);\n --right: var(--margin);\n --bottom: auto;\n --left: auto;\n}\n:host([position='bottom-left']) {\n --top: auto;\n --right: auto;\n --bottom: calc(var(--margin) * 2);\n --left: var(--margin);\n}\n:host([position='bottom-right']) {\n --top: auto;\n --right: var(--margin);\n --bottom: calc(var(--margin) * 2);\n --left: auto;\n}\n:host([size='small']) { --size: 36px; }\n:host([size='medium']) { --size: 56px; }\n:host([size='large']) { --size: 72px; }\n.d-wrapper {\n position: fixed;\n top: calc(var(--top) + var(--widget-safe-top));\n right: calc(var(--right) + var(--widget-safe-right));\n bottom: calc(var(--bottom) + var(--widget-safe-bottom));\n left: calc(var(--left) + var(--widget-safe-left));\n z-index: 9999;\n max-width: fit-content;\n display: flex;\n align-items: center;\n column-gap: 0.5rem;\n}\n.d-button {\n --icon-size: calc(var(--size) * 0.4);\n position: relative;\n width: var(--size);\n height: var(--size);\n border: none;\n border-bottom: 1px solid hsl(from canvastext h s l / calc(alpha * 0.5));\n border-radius: 50%;\n box-shadow: 0 1px 3px 0 hsla(210, 6%, 25%, 0.3), 0 4px 8px 3px hsla(210, 6%, 25%, 0.3);\n background-color: transparent;\n color: canvastext;\n cursor: pointer;\n font-size: var(--icon-size);\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n overflow: hidden;\n user-select: none;\n -webkit-user-select: none;\n -webkit-tap-highlight-color: transparent;\n}\n.d-button::before {\n content: '';\n position: absolute;\n inset: 0;\n z-index: -1;\n border: none;\n background-color: canvas;\n filter: invert(90%);\n}\n.d-button:focus-visible {\n outline: 2px solid currentcolor;\n outline-offset: 2px;\n}\n.d-button:active {\n transform: scale(0.98);\n transition: transform 0.4s ease-in-out;\n}\n.d-kbd {\n position: relative;\n padding: 0.25em 0.4em;\n font-size: 11px;\n font-family: ui-monospace, monospace;\n line-height: 1;\n letter-spacing: -0.025em;\n background-color: canvas;\n color: canvastext;\n filter: invert(90%);\n border: none;\n border-bottom: 1px solid hsl(from canvastext h s l / calc(alpha * 0.5));\n border-radius: 0.25rem;\n box-shadow: 0 0 2px hsla(0, 0%, 0%, 0.1);\n user-select: none;\n -webkit-user-select: none;\n}\n",customElements.define(e,n);class o{constructor(t,n){var o,i,s;this.options={position:null!==(o=null==n?void 0:n.position)&&void 0!==o?o:"bottom-right",size:null!==(i=null==n?void 0:n.size)&&void 0!==i?i:"medium",shortcut:null!==(s=null==n?void 0:n.shortcut)&&void 0!==s?s:""},this.el=document.createElement(e),this.el.init(t,this.options)}render(){return document.body.appendChild(this.el),this.el}onThemeChange(t){this.el.onThemeChange(t)}onDestroy(){this.el.remove()}}o.pluginId=e;class i{constructor(t,e){var n,o,i,s,r;this._lastTriggered=0,this.handleKeyDown=t=>{if(("body"!==this.options.target||!this.isTyping(t))&&("input"!==this.options.target||this.isTyping(t))&&this.matches(t)){t.preventDefault();const e=Date.now();if(e-this._lastTriggered<this.options.cooldown)return;this._lastTriggered=e,this._host.toggleTheme()}},this._host=t,this.options={key:null!==(n=null==e?void 0:e.key)&&void 0!==n?n:"d",ctrl:null!==(o=null==e?void 0:e.ctrl)&&void 0!==o&&o,shift:null!==(i=null==e?void 0:e.shift)&&void 0!==i&&i,target:null!==(s=null==e?void 0:e.target)&&void 0!==s?s:"body",cooldown:null!==(r=null==e?void 0:e.cooldown)&&void 0!==r?r:300}}render(){document.addEventListener("keydown",this.handleKeyDown)}onDestroy(){document.removeEventListener("keydown",this.handleKeyDown)}matches(t){return t.key.toLowerCase()===this.options.key.toLowerCase()&&(!this.options.ctrl||t.ctrlKey||t.metaKey)&&(!this.options.shift||t.shiftKey)&&(this.options.ctrl||!t.ctrlKey&&!t.metaKey&&!t.altKey)}isTyping(t){const e=t.target,n=e.tagName.toLowerCase();return e.isContentEditable||"input"===n||"textarea"===n}}i.pluginId="d-keyboard-shortcut",t.KeyboardShortcut=i,t.ThemeWidget=o});
package/package.json CHANGED
@@ -1,11 +1,8 @@
1
1
  {
2
2
  "name": "darkify-js",
3
- "version": "1.1.13-beta.0",
3
+ "version": "1.1.13-beta.2",
4
4
  "description": "A simple dark mode toggle library",
5
5
  "type": "module",
6
- "main": "dist/darkify.umd.js",
7
- "module": "dist/darkify.esm.js",
8
- "types": "dist/darkify.d.ts",
9
6
  "exports": {
10
7
  ".": {
11
8
  "import": "./dist/darkify.esm.js",
@@ -13,10 +10,11 @@
13
10
  "types": "./dist/darkify.d.ts"
14
11
  },
15
12
  "./plugins": {
16
- "import": "./dist/plugins/index.mjs",
13
+ "import": "./dist/plugins/index.esm.js",
17
14
  "require": "./dist/plugins/index.umd.js",
18
15
  "types": "./dist/plugins/index.d.ts"
19
- }
16
+ },
17
+ "./package.json": "./package.json"
20
18
  },
21
19
  "files": [
22
20
  "dist"
@@ -27,7 +25,8 @@
27
25
  "build": "npm run _cls && npm run _bundle",
28
26
  "format": "prettier --write src/",
29
27
  "test": "NODE_OPTIONS=\"$NODE_OPTIONS --experimental-vm-modules\" jest",
30
- "prepublishOnly": "npm run test && npm run build"
28
+ "demo": "npm run build && sh demo.sh",
29
+ "prepublishOnly": "npm run build"
31
30
  },
32
31
  "repository": {
33
32
  "type": "git",
@@ -46,18 +45,19 @@
46
45
  "author": "Emilio Romero <emrocode@gmail.com>",
47
46
  "license": "MIT",
48
47
  "devDependencies": {
48
+ "@rollup/plugin-node-resolve": "^16.0.3",
49
49
  "@rollup/plugin-terser": "^1.0.0",
50
50
  "@rollup/plugin-typescript": "^12.3.0",
51
51
  "@types/jest": "^30.0.0",
52
52
  "jest": "^30.3.0",
53
53
  "jest-environment-jsdom": "^30.3.0",
54
54
  "prettier": "^3.8.1",
55
- "rollup": "^4.59.0",
55
+ "rollup": "^4.60.0",
56
56
  "rollup-plugin-cleanup": "^3.2.1",
57
- "rollup-plugin-dts": "^6.4.0",
57
+ "rollup-plugin-dts": "^6.4.1",
58
58
  "ts-jest": "^29.4.6",
59
59
  "ts-node": "^10.9.2",
60
60
  "tslib": "^2.8.1",
61
- "typescript": "^5.9.3"
61
+ "typescript": "~5.9.3"
62
62
  }
63
63
  }
@@ -1,226 +0,0 @@
1
- class ThemeWidget {
2
- constructor(host, options) {
3
- var _a, _b, _c;
4
- this._host = host;
5
- this.options = {
6
- position: (_a = options === null || options === void 0 ? void 0 : options.position) !== null && _a !== void 0 ? _a : 'bottom-right',
7
- size: (_b = options === null || options === void 0 ? void 0 : options.size) !== null && _b !== void 0 ? _b : 'medium',
8
- shortcut: (_c = options === null || options === void 0 ? void 0 : options.shortcut) !== null && _c !== void 0 ? _c : '',
9
- };
10
- }
11
- render() {
12
- var _a;
13
- const container = document.createElement('div');
14
- container.id = ThemeWidget.pluginId;
15
- this.el = container.attachShadow({ mode: 'open' });
16
- const positionVars = this.getPositionVars();
17
- const sizeVars = this.getSizeVar();
18
- const sheet = new CSSStyleSheet();
19
- sheet.replaceSync(`
20
- :host {
21
- --widget-safe-top: env(safe-area-inset-top, 0px);
22
- --widget-safe-right: env(safe-area-inset-right, 0px);
23
- --widget-safe-bottom: env(safe-area-inset-bottom, 0px);
24
- --widget-safe-left: env(safe-area-inset-left, 0px);
25
- --widget-margin: 24px;
26
- }
27
-
28
- .d-wrapper {
29
- --margin: max(var(--widget-margin), var(--widget-safe-bottom));
30
- ${positionVars}
31
- ${sizeVars}
32
- position: fixed;
33
- top: calc(var(--pos-top) + var(--widget-safe-top));
34
- right: calc(var(--pos-right) + var(--widget-safe-right));
35
- bottom: calc(var(--pos-bottom) + var(--widget-safe-bottom));
36
- left: calc(var(--pos-left) + var(--widget-safe-left));
37
- z-index: 9999;
38
- max-width: fit-content;
39
- display: flex;
40
- align-items: center;
41
- column-gap: 0.5rem;
42
- }
43
-
44
- .d-button {
45
- --icon-size: calc(var(--size) * 0.4);
46
- position: relative;
47
- width: var(--size);
48
- height: var(--size);
49
- border-radius: 50%;
50
- border: none;
51
- border-bottom: 2px solid var(--widget-accent, hsl(0,0%,0%,0.30));
52
- box-shadow: 0 1px 3px 0 hsla(210,6%,25%,0.30), 0 4px 8px 3px hsla(210,6%,25%,0.30);
53
- background-color: transparent;
54
- color: canvastext;
55
- cursor: pointer;
56
- font-size: var(--icon-size);
57
- display: flex;
58
- flex-direction: column;
59
- align-items: center;
60
- justify-content: center;
61
- overflow: hidden;
62
- transition: transform 0.4s ease-in-out;
63
- user-select: none;
64
- -webkit-user-select: none;
65
- -webkit-tap-highlight-color: transparent;
66
- }
67
-
68
- .d-button::before {
69
- content: "";
70
- position: absolute;
71
- inset: 0;
72
- z-index: -1;
73
- border: none;
74
- border-radius: 50%;
75
- background-color: canvas;
76
- filter: invert(90%);
77
- }
78
-
79
- .d-button.light { --widget-accent: hsl(45,99%,54%); }
80
- .d-button.dark { --widget-accent: hsl(200,29%,43%); }
81
-
82
- @media (prefers-reduced-motion: no-preference) {
83
- .d-button {
84
- animation: dEnter 0.4s cubic-bezier(0.34,1.56,0.64,1);
85
- animation-fill-mode: backwards;
86
- }
87
- }
88
-
89
- @keyframes dEnter {
90
- from {
91
- opacity: 0;
92
- transform: scale(0.6);
93
- }
94
- to {
95
- opacity: 1;
96
- transform: scale(1);
97
- }
98
- }
99
-
100
- .d-kbd {
101
- position: relative;
102
- padding: 0.25em 0.4em;
103
- font-size: 11px;
104
- font-family: ui-monospace, monospace;
105
- line-height: 1;
106
- letter-spacing: -0.025em;
107
- background-color: canvas;
108
- color: canvastext;
109
- filter: invert(90%);
110
- border: none;
111
- border-bottom: 2px solid hsl(from canvastext h s l / calc(alpha * 0.5));
112
- border-radius: 0.25rem;
113
- box-shadow: 0 0 2px hsla(0,0%,0%,0.10);
114
- user-select: none;
115
- -webkit-user-select: none;
116
- }
117
- `);
118
- this.el.adoptedStyleSheets = [sheet];
119
- const wrapper = document.createElement('div');
120
- wrapper.className = 'd-wrapper';
121
- const button = document.createElement('button');
122
- button.className = 'd-button';
123
- button.setAttribute('aria-label', 'Toggle theme');
124
- button.addEventListener('click', () => this._host.toggleTheme());
125
- const icon = document.createElement('span');
126
- icon.className = 'd-icon';
127
- button.appendChild(icon);
128
- const isLeftPosition = (_a = this.options.position) === null || _a === void 0 ? void 0 : _a.includes('left');
129
- if (this.options.shortcut) {
130
- const kbd = document.createElement('kbd');
131
- kbd.className = 'd-kbd';
132
- kbd.textContent = this.options.shortcut;
133
- if (isLeftPosition) {
134
- wrapper.appendChild(button);
135
- wrapper.appendChild(kbd);
136
- }
137
- else {
138
- wrapper.appendChild(kbd);
139
- wrapper.appendChild(button);
140
- }
141
- }
142
- else {
143
- wrapper.appendChild(button);
144
- }
145
- this.el.appendChild(wrapper);
146
- document.body.appendChild(container);
147
- this.onThemeChange(this._host.getCurrentTheme());
148
- return this.el;
149
- }
150
- onThemeChange(theme) {
151
- var _a, _b;
152
- const button = (_a = this.el) === null || _a === void 0 ? void 0 : _a.querySelector('button.d-button');
153
- const icon = (_b = this.el) === null || _b === void 0 ? void 0 : _b.querySelector('span.d-icon');
154
- if (button && icon) {
155
- button.className = `d-button ${theme}`;
156
- icon.textContent = theme === 'light' ? '🌞' : '🌚';
157
- }
158
- }
159
- onDestroy() {
160
- if (this.el && this.el.host) {
161
- this.el.host.remove();
162
- }
163
- }
164
- getPositionVars() {
165
- const vars = {
166
- 'top-left': '--pos-top:var(--margin);--pos-right:auto;--pos-bottom:auto;--pos-left:var(--margin);',
167
- 'top-right': '--pos-top:var(--margin);--pos-right:var(--margin);--pos-bottom:auto;--pos-left:auto;',
168
- 'bottom-left': '--pos-top:auto;--pos-right:auto;--pos-bottom:calc(var(--margin)*2);--pos-left:var(--margin);',
169
- 'bottom-right': '--pos-top:auto;--pos-right:var(--margin);--pos-bottom:calc(var(--margin)*2);--pos-left:auto;',
170
- };
171
- return vars[this.options.position];
172
- }
173
- getSizeVar() {
174
- const vars = {
175
- small: '--size:36px;',
176
- medium: '--size:56px;',
177
- large: '--size:72px;',
178
- };
179
- return vars[this.options.size];
180
- }
181
- }
182
- ThemeWidget.pluginId = 'd-widget';
183
-
184
- class KeyboardShortcut {
185
- constructor(host, options) {
186
- var _a, _b, _c, _d;
187
- this.handleKeyDown = (e) => {
188
- if (this.options.target === 'body' && this.isTyping(e))
189
- return;
190
- if (this.options.target === 'input' && !this.isTyping(e))
191
- return;
192
- if (this.matches(e)) {
193
- e.preventDefault();
194
- this._host.toggleTheme();
195
- }
196
- };
197
- this._host = host;
198
- this.options = {
199
- key: (_a = options === null || options === void 0 ? void 0 : options.key) !== null && _a !== void 0 ? _a : 'd',
200
- ctrl: (_b = options === null || options === void 0 ? void 0 : options.ctrl) !== null && _b !== void 0 ? _b : false,
201
- shift: (_c = options === null || options === void 0 ? void 0 : options.shift) !== null && _c !== void 0 ? _c : false,
202
- target: (_d = options === null || options === void 0 ? void 0 : options.target) !== null && _d !== void 0 ? _d : 'body',
203
- };
204
- }
205
- render() {
206
- document.addEventListener('keydown', this.handleKeyDown);
207
- return;
208
- }
209
- onDestroy() {
210
- document.removeEventListener('keydown', this.handleKeyDown);
211
- }
212
- matches(e) {
213
- return (e.key.toLowerCase() === this.options.key.toLowerCase() &&
214
- (!this.options.ctrl || e.ctrlKey || e.metaKey) &&
215
- (!this.options.shift || e.shiftKey) &&
216
- (this.options.ctrl || (!e.ctrlKey && !e.metaKey && !e.altKey)));
217
- }
218
- isTyping(e) {
219
- const target = e.target;
220
- const tagName = target.tagName.toLowerCase();
221
- const isEditable = target.isContentEditable || tagName === 'input' || tagName === 'textarea';
222
- return isEditable;
223
- }
224
- }
225
-
226
- export { KeyboardShortcut, ThemeWidget };