@arsedizioni/ars-utils 18.2.247 → 18.2.250

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.
@@ -1843,39 +1843,159 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.1.1", ngImpor
1843
1843
  }]
1844
1844
  }] });
1845
1845
 
1846
+ /**
1847
+ * Standard Broadcast Messages Manager
1848
+ * https://developer.mozilla.org/en-US/docs/Web/API/BroadcastChannel
1849
+ */
1850
+ /**
1851
+ * Web Standard Broadcast Messages Manager
1852
+ * https://developer.mozilla.org/en-US/docs/Web/API/BroadcastChannel
1853
+ */
1854
+ class BroadcastChannelManager {
1855
+ /**
1856
+ * Get the current channel registration
1857
+ */
1858
+ get currentBus() {
1859
+ return this.channel?.name;
1860
+ }
1861
+ constructor(bus) {
1862
+ this.channel = undefined;
1863
+ this.subscriptions = [];
1864
+ this.channel = new BroadcastChannel(bus);
1865
+ this.channel.onmessageerror = (e) => {
1866
+ console.error('[BroadcastChannelManager] Errore di ricezione del messaggio', e);
1867
+ };
1868
+ this.channel.onmessage = (e) => {
1869
+ const bag = e.data;
1870
+ if (bag) {
1871
+ const bagInfo = this.subscriptions.find(m => m.messageId === bag.messageId);
1872
+ bagInfo?.action(bag);
1873
+ }
1874
+ };
1875
+ }
1876
+ dispose() {
1877
+ this.subscriptions = [];
1878
+ this.channel?.close();
1879
+ this.channel = null;
1880
+ }
1881
+ /**
1882
+ * overloads
1883
+ */
1884
+ sendMessage(messageIdorBag, dataOrDelay = null, delay = 0) {
1885
+ // console.warn({ messageIdorBag, dataOrDelay, delay });
1886
+ setTimeout(() => {
1887
+ if (typeof messageIdorBag === 'string') {
1888
+ this.channel?.postMessage({ messageId: messageIdorBag, data: dataOrDelay });
1889
+ }
1890
+ else {
1891
+ this.channel?.postMessage(messageIdorBag);
1892
+ }
1893
+ }, (typeof dataOrDelay === 'number' ? dataOrDelay : delay) ?? 0);
1894
+ }
1895
+ /**
1896
+ * Subscribe to a message
1897
+ * @param args The subscription info, see also {@link BroadcastChannelSubscriberInfo}
1898
+ */
1899
+ subscribe(args) {
1900
+ const i = this.subscriptions.findIndex(m => m.messageId === args.messageId);
1901
+ if (i === -1) {
1902
+ this.subscriptions.push(args);
1903
+ }
1904
+ else {
1905
+ this.subscriptions[i].action = args.action;
1906
+ }
1907
+ }
1908
+ /**
1909
+ * Remove a message subscription
1910
+ * @param messageId The message id
1911
+ */
1912
+ unsubscribe(messageId) {
1913
+ const i = this.subscriptions.findIndex(m => m.messageId === messageId);
1914
+ if (i !== -1) {
1915
+ this.subscriptions.splice(i, 1);
1916
+ }
1917
+ }
1918
+ /**
1919
+ * Remove all the current subscriptions
1920
+ */
1921
+ unsubscribeAll() {
1922
+ this.subscriptions = [];
1923
+ }
1924
+ }
1925
+
1846
1926
  class ThemeService {
1847
1927
  constructor() {
1928
+ // messaggi broadcast
1929
+ this.broadcastChannel = new BroadcastChannelManager('THEME-SERVICE');
1930
+ this.broadcastMessage = '$theme-changed';
1931
+ // per intercettare il cambio di tema a livello di sistema
1932
+ this.prefersColorSchemeMediaQueryList = window.matchMedia('(prefers-color-scheme: dark)');
1848
1933
  this.renderFactory2 = inject(RendererFactory2);
1849
1934
  this.renderer = this.renderFactory2.createRenderer(null, null);
1935
+ /**
1936
+ * Current theme
1937
+ */
1850
1938
  this.theme = signal("light");
1851
- this.themeIcon = computed(() => {
1852
- return this.theme() === "dark" ? "light_mode" : "dark_mode";
1853
- });
1854
- this.themeName = computed(() => {
1855
- return this.theme() === "dark" ? "Passa a tema chiaro" : "Passa a tema scuro";
1939
+ /**
1940
+ * The current theme is "System default"
1941
+ */
1942
+ this.auto = computed(() => this.theme() === 'system');
1943
+ /**
1944
+ * Configuration schema about the icon, the text and the toggle() sequence
1945
+ */
1946
+ this.themeInfo = {
1947
+ ['system']: { icon: 'auto_mode', name: 'Impostazione predefinita di sistema', next: 'light', tooltip: 'Passa a tema chiaro', },
1948
+ ['light']: { icon: 'light_mode', name: 'Tema chiaro', next: 'dark', tooltip: 'Passa a tema scuro', },
1949
+ ['dark']: { icon: 'dark_mode', name: 'Tema scuro', next: 'system', tooltip: 'Passa a tema predefinito di sistema', },
1950
+ };
1951
+ /**
1952
+ * Icon of the current theme (mat-icon code)
1953
+ */
1954
+ this.themeIcon = computed(() => this.themeInfo[this.theme()].icon);
1955
+ /**
1956
+ * Current theme name
1957
+ */
1958
+ this.themeName = computed(() => this.themeInfo[this.theme()].name);
1959
+ /**
1960
+ * Tooltip text on toggle
1961
+ */
1962
+ this.toggleTooltip = computed(() => this.themeInfo[this.theme()].tooltip);
1963
+ // reagisce al cambio di tema nel sistema
1964
+ this.prefersColorSchemeMediaQueryList.onchange = (_) => this.auto() ? this.setTheme() : null;
1965
+ // reagisce al messaggio broadcast (sincronizza i temi tra i popup dell'applicazione)
1966
+ this.broadcastChannel.subscribe({
1967
+ messageId: this.broadcastMessage,
1968
+ action: (bag) => {
1969
+ if (this.theme() !== bag.data) {
1970
+ this.setTheme(bag.data);
1971
+ }
1972
+ }
1856
1973
  });
1974
+ // inizializza il tema
1857
1975
  this.setTheme(localStorage.getItem("preferred-theme") ?? null);
1858
1976
  }
1977
+ ngOnDestroy() {
1978
+ // chiude il canale di comunicazione broadcast
1979
+ this.broadcastChannel.dispose();
1980
+ }
1859
1981
  /**
1860
1982
  * Set the new theme
1861
- * @param theme : the theme
1983
+ * @param theme the new theme
1862
1984
  */
1863
- setTheme(theme = null) {
1864
- if (!theme) {
1865
- this.theme.set(window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light");
1866
- }
1867
- else {
1868
- this.renderer.removeClass(document.body, this.theme());
1869
- this.theme.set(theme);
1870
- }
1871
- this.renderer.addClass(document.body, this.theme());
1985
+ setTheme(theme = 'system') {
1986
+ this.renderer.removeClass(document.body, 'light');
1987
+ this.renderer.removeClass(document.body, 'dark');
1988
+ this.theme.set(theme);
1872
1989
  localStorage.setItem("preferred-theme", this.theme());
1990
+ this.renderer.addClass(document.body, this.auto() ? (window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light") : theme);
1991
+ // lancia il messaggio broadcast
1992
+ this.broadcastChannel.sendMessage(this.broadcastMessage, this.theme());
1873
1993
  }
1874
1994
  /**
1875
1995
  * Toggle theme
1876
1996
  */
1877
1997
  toggleTheme() {
1878
- this.setTheme(this.theme() === "dark" ? "light" : "dark");
1998
+ this.setTheme(this.themeInfo[this.theme()].next);
1879
1999
  }
1880
2000
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.1.1", ngImport: i0, type: ThemeService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1881
2001
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.1.1", ngImport: i0, type: ThemeService, providedIn: "root" }); }