@seamline-kit/seamline-settings 0.0.4 → 0.0.6

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/README.md CHANGED
@@ -1 +1,5 @@
1
1
  # Seamline Settings
2
+
3
+ > [!WARNING]
4
+ > Seamline Kit is in early development and is not ready for production use yet.
5
+ > APIs may change without notice, and bugs are expected.
package/dist/main.cjs CHANGED
@@ -74,6 +74,39 @@ function SettingsPage({ defaultTheme }) {
74
74
  })] });
75
75
  }
76
76
 
77
+ //#endregion
78
+ //#region src/theme-persistence.ts
79
+ const THEME_STORAGE_KEY = `${DEFAULT_PREFIX}-theme`;
80
+ function getStorage() {
81
+ try {
82
+ return globalThis.localStorage ?? null;
83
+ } catch {
84
+ return null;
85
+ }
86
+ }
87
+ function readPersistedTheme() {
88
+ const storage = getStorage();
89
+ if (!storage) return null;
90
+ let value = null;
91
+ try {
92
+ value = storage.getItem(THEME_STORAGE_KEY);
93
+ } catch {
94
+ return null;
95
+ }
96
+ if (!isTheme(value)) return null;
97
+ return value;
98
+ }
99
+ function persistTheme(theme) {
100
+ const storage = getStorage();
101
+ if (!storage) return;
102
+ try {
103
+ storage.setItem(THEME_STORAGE_KEY, theme);
104
+ } catch {
105
+ return;
106
+ }
107
+ }
108
+ const THEME_BOOTSTRAP_SCRIPT = "try{let theme=localStorage.getItem('slk-settings-theme');if(['system','light','dark'].includes(theme)){document.documentElement.setAttribute('data-slk-settings-theme',theme)}}catch{}";
109
+
77
110
  //#endregion
78
111
  //#region src/theme-form-controller.ts
79
112
  function getSelectedTheme(form) {
@@ -96,13 +129,17 @@ function bindThemeForm(onThemeChange) {
96
129
  const selectedTheme = getSelectedTheme(form);
97
130
  if (!selectedTheme) return;
98
131
  onThemeChange(selectedTheme);
132
+ persistTheme(selectedTheme);
99
133
  }
100
- const initialSelectedTheme = getSelectedTheme(form);
134
+ const persistedTheme = readPersistedTheme();
135
+ if (persistedTheme) syncThemeStateToDom(radios, persistedTheme);
136
+ const initialSelectedTheme = persistedTheme ?? getSelectedTheme(form);
101
137
  if (initialSelectedTheme) onThemeChange(initialSelectedTheme);
102
138
  form.addEventListener("change", syncThemeFromForm);
103
139
  return {
104
140
  sync(theme) {
105
141
  syncThemeStateToDom(radios, theme);
142
+ persistTheme(theme);
106
143
  },
107
144
  unbind() {
108
145
  form.removeEventListener("change", syncThemeFromForm);
@@ -122,10 +159,7 @@ function render(defaultTheme) {
122
159
  }
123
160
 
124
161
  //#endregion
125
- exports.DEFAULT_PREFIX = DEFAULT_PREFIX;
126
162
  exports.DEFAULT_THEME = DEFAULT_THEME;
127
- exports.SETTINGS_PAGE_NAMES = SETTINGS_PAGE_NAMES;
128
- exports.THEME_FIELD_NAME = THEME_FIELD_NAME;
163
+ exports.THEME_BOOTSTRAP_SCRIPT = THEME_BOOTSTRAP_SCRIPT;
129
164
  exports.bindThemeForm = bindThemeForm;
130
- exports.init = init;
131
- exports.isTheme = isTheme;
165
+ exports.init = init;
package/dist/main.d.cts CHANGED
@@ -3,20 +3,10 @@ import { Result } from "hastscript";
3
3
  //#region src/theme.d.ts
4
4
  declare const THEMES: readonly ["system", "light", "dark"];
5
5
  type Theme = (typeof THEMES)[number];
6
- declare const THEME_FIELD_NAME: string;
7
6
  declare const DEFAULT_THEME: Theme;
8
- declare function isTheme(value: unknown): value is Theme;
9
7
  //#endregion
10
- //#region src/settings-page-names.d.ts
11
- declare const DEFAULT_PREFIX = "slk-settings";
12
- interface SettingsPageNames {
13
- appearanceTitle: string;
14
- appearanceForm: string;
15
- themeSystem: string;
16
- themeLight: string;
17
- themeDark: string;
18
- }
19
- declare const SETTINGS_PAGE_NAMES: SettingsPageNames;
8
+ //#region src/theme-persistence.d.ts
9
+ declare const THEME_BOOTSTRAP_SCRIPT = "try{let theme=localStorage.getItem('slk-settings-theme');if(['system','light','dark'].includes(theme)){document.documentElement.setAttribute('data-slk-settings-theme',theme)}}catch{}";
20
10
  //#endregion
21
11
  //#region src/theme-form-controller.d.ts
22
12
  interface ThemeFormBinding {
@@ -36,5 +26,5 @@ declare function init({
36
26
  defaultTheme
37
27
  }?: InitOptions): SettingsRenderer;
38
28
  //#endregion
39
- export { DEFAULT_PREFIX, DEFAULT_THEME, SETTINGS_PAGE_NAMES, THEME_FIELD_NAME, type Theme, bindThemeForm, init, isTheme };
29
+ export { DEFAULT_THEME, THEME_BOOTSTRAP_SCRIPT, type Theme, bindThemeForm, init };
40
30
  //# sourceMappingURL=main.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"main.d.cts","names":[],"sources":["../src/theme.ts","../src/settings-page-names.ts","../src/theme-form-controller.ts","../src/main.ts"],"mappings":";;;cAEM,MAAA;AAAA,KACM,KAAA,WAAgB,MAAA;AAAA,cAEf,gBAAA;AAAA,cACA,aAAA,EAAe,KAAA;AAAA,iBAEZ,OAAA,CAAQ,KAAA,YAAiB,KAAA,IAAS,KAAA;;;cCRrC,cAAA;AAAA,UAEI,iBAAA;EACf,eAAA;EACA,cAAA;EACA,WAAA;EACA,UAAA;EACA,SAAA;AAAA;AAAA,cAGW,mBAAA,EAAqB,iBAAA;;;UCPxB,gBAAA;EACR,IAAA,GAAO,KAAA,EAAO,KAAA;EACd,MAAA;AAAA;AAAA,iBAsBc,aAAA,CAAc,aAAA,GAAgB,KAAA,EAAO,KAAA,YAAiB,gBAAA;;;UCvB5D,WAAA;EACR,YAAA,GAAe,KAAA;AAAA;AAAA,UAGP,gBAAA;EACR,MAAA,QAAc,MAAA;AAAA;AAAA,iBAGA,IAAA,CAAA;EAAO;AAAA,IAAgC,WAAA,GAAmB,gBAAA"}
1
+ {"version":3,"file":"main.d.cts","names":[],"sources":["../src/theme.ts","../src/theme-persistence.ts","../src/theme-form-controller.ts","../src/main.ts"],"mappings":";;;cAEM,MAAA;AAAA,KACM,KAAA,WAAgB,MAAA;AAAA,cAGf,aAAA,EAAe,KAAA;;;cCwCf,sBAAA;;;UC1CH,gBAAA;EACR,IAAA,GAAO,KAAA,EAAO,KAAA;EACd,MAAA;AAAA;AAAA,iBAsBc,aAAA,CAAc,aAAA,GAAgB,KAAA,EAAO,KAAA,YAAiB,gBAAA;;;UCvB5D,WAAA;EACR,YAAA,GAAe,KAAA;AAAA;AAAA,UAGP,gBAAA;EACR,MAAA,QAAc,MAAA;AAAA;AAAA,iBAGA,IAAA,CAAA;EAAO;AAAA,IAAgC,WAAA,GAAmB,gBAAA"}
package/dist/main.d.ts CHANGED
@@ -3,20 +3,10 @@ import { Result } from "hastscript";
3
3
  //#region src/theme.d.ts
4
4
  declare const THEMES: readonly ["system", "light", "dark"];
5
5
  type Theme = (typeof THEMES)[number];
6
- declare const THEME_FIELD_NAME: string;
7
6
  declare const DEFAULT_THEME: Theme;
8
- declare function isTheme(value: unknown): value is Theme;
9
7
  //#endregion
10
- //#region src/settings-page-names.d.ts
11
- declare const DEFAULT_PREFIX = "slk-settings";
12
- interface SettingsPageNames {
13
- appearanceTitle: string;
14
- appearanceForm: string;
15
- themeSystem: string;
16
- themeLight: string;
17
- themeDark: string;
18
- }
19
- declare const SETTINGS_PAGE_NAMES: SettingsPageNames;
8
+ //#region src/theme-persistence.d.ts
9
+ declare const THEME_BOOTSTRAP_SCRIPT = "try{let theme=localStorage.getItem('slk-settings-theme');if(['system','light','dark'].includes(theme)){document.documentElement.setAttribute('data-slk-settings-theme',theme)}}catch{}";
20
10
  //#endregion
21
11
  //#region src/theme-form-controller.d.ts
22
12
  interface ThemeFormBinding {
@@ -36,5 +26,5 @@ declare function init({
36
26
  defaultTheme
37
27
  }?: InitOptions): SettingsRenderer;
38
28
  //#endregion
39
- export { DEFAULT_PREFIX, DEFAULT_THEME, SETTINGS_PAGE_NAMES, THEME_FIELD_NAME, type Theme, bindThemeForm, init, isTheme };
29
+ export { DEFAULT_THEME, THEME_BOOTSTRAP_SCRIPT, type Theme, bindThemeForm, init };
40
30
  //# sourceMappingURL=main.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"main.d.ts","names":[],"sources":["../src/theme.ts","../src/settings-page-names.ts","../src/theme-form-controller.ts","../src/main.ts"],"mappings":";;;cAEM,MAAA;AAAA,KACM,KAAA,WAAgB,MAAA;AAAA,cAEf,gBAAA;AAAA,cACA,aAAA,EAAe,KAAA;AAAA,iBAEZ,OAAA,CAAQ,KAAA,YAAiB,KAAA,IAAS,KAAA;;;cCRrC,cAAA;AAAA,UAEI,iBAAA;EACf,eAAA;EACA,cAAA;EACA,WAAA;EACA,UAAA;EACA,SAAA;AAAA;AAAA,cAGW,mBAAA,EAAqB,iBAAA;;;UCPxB,gBAAA;EACR,IAAA,GAAO,KAAA,EAAO,KAAA;EACd,MAAA;AAAA;AAAA,iBAsBc,aAAA,CAAc,aAAA,GAAgB,KAAA,EAAO,KAAA,YAAiB,gBAAA;;;UCvB5D,WAAA;EACR,YAAA,GAAe,KAAA;AAAA;AAAA,UAGP,gBAAA;EACR,MAAA,QAAc,MAAA;AAAA;AAAA,iBAGA,IAAA,CAAA;EAAO;AAAA,IAAgC,WAAA,GAAmB,gBAAA"}
1
+ {"version":3,"file":"main.d.ts","names":[],"sources":["../src/theme.ts","../src/theme-persistence.ts","../src/theme-form-controller.ts","../src/main.ts"],"mappings":";;;cAEM,MAAA;AAAA,KACM,KAAA,WAAgB,MAAA;AAAA,cAGf,aAAA,EAAe,KAAA;;;cCwCf,sBAAA;;;UC1CH,gBAAA;EACR,IAAA,GAAO,KAAA,EAAO,KAAA;EACd,MAAA;AAAA;AAAA,iBAsBc,aAAA,CAAc,aAAA,GAAgB,KAAA,EAAO,KAAA,YAAiB,gBAAA;;;UCvB5D,WAAA;EACR,YAAA,GAAe,KAAA;AAAA;AAAA,UAGP,gBAAA;EACR,MAAA,QAAc,MAAA;AAAA;AAAA,iBAGA,IAAA,CAAA;EAAO;AAAA,IAAgC,WAAA,GAAmB,gBAAA"}
package/dist/main.js CHANGED
@@ -73,6 +73,39 @@ function SettingsPage({ defaultTheme }) {
73
73
  })] });
74
74
  }
75
75
 
76
+ //#endregion
77
+ //#region src/theme-persistence.ts
78
+ const THEME_STORAGE_KEY = `${DEFAULT_PREFIX}-theme`;
79
+ function getStorage() {
80
+ try {
81
+ return globalThis.localStorage ?? null;
82
+ } catch {
83
+ return null;
84
+ }
85
+ }
86
+ function readPersistedTheme() {
87
+ const storage = getStorage();
88
+ if (!storage) return null;
89
+ let value = null;
90
+ try {
91
+ value = storage.getItem(THEME_STORAGE_KEY);
92
+ } catch {
93
+ return null;
94
+ }
95
+ if (!isTheme(value)) return null;
96
+ return value;
97
+ }
98
+ function persistTheme(theme) {
99
+ const storage = getStorage();
100
+ if (!storage) return;
101
+ try {
102
+ storage.setItem(THEME_STORAGE_KEY, theme);
103
+ } catch {
104
+ return;
105
+ }
106
+ }
107
+ const THEME_BOOTSTRAP_SCRIPT = "try{let theme=localStorage.getItem('slk-settings-theme');if(['system','light','dark'].includes(theme)){document.documentElement.setAttribute('data-slk-settings-theme',theme)}}catch{}";
108
+
76
109
  //#endregion
77
110
  //#region src/theme-form-controller.ts
78
111
  function getSelectedTheme(form) {
@@ -95,13 +128,17 @@ function bindThemeForm(onThemeChange) {
95
128
  const selectedTheme = getSelectedTheme(form);
96
129
  if (!selectedTheme) return;
97
130
  onThemeChange(selectedTheme);
131
+ persistTheme(selectedTheme);
98
132
  }
99
- const initialSelectedTheme = getSelectedTheme(form);
133
+ const persistedTheme = readPersistedTheme();
134
+ if (persistedTheme) syncThemeStateToDom(radios, persistedTheme);
135
+ const initialSelectedTheme = persistedTheme ?? getSelectedTheme(form);
100
136
  if (initialSelectedTheme) onThemeChange(initialSelectedTheme);
101
137
  form.addEventListener("change", syncThemeFromForm);
102
138
  return {
103
139
  sync(theme) {
104
140
  syncThemeStateToDom(radios, theme);
141
+ persistTheme(theme);
105
142
  },
106
143
  unbind() {
107
144
  form.removeEventListener("change", syncThemeFromForm);
@@ -121,5 +158,5 @@ function render(defaultTheme) {
121
158
  }
122
159
 
123
160
  //#endregion
124
- export { DEFAULT_PREFIX, DEFAULT_THEME, SETTINGS_PAGE_NAMES, THEME_FIELD_NAME, bindThemeForm, init, isTheme };
161
+ export { DEFAULT_THEME, THEME_BOOTSTRAP_SCRIPT, bindThemeForm, init };
125
162
  //# sourceMappingURL=main.js.map
package/dist/main.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"main.js","names":[],"sources":["../src/settings-page-names.ts","../src/theme.ts","../src/settings-page.tsx","../src/theme-form-controller.ts","../src/main.ts"],"sourcesContent":["export const DEFAULT_PREFIX = \"slk-settings\";\n\nexport interface SettingsPageNames {\n appearanceTitle: string;\n appearanceForm: string;\n themeSystem: string;\n themeLight: string;\n themeDark: string;\n}\n\nexport const SETTINGS_PAGE_NAMES: SettingsPageNames = {\n appearanceTitle: `${DEFAULT_PREFIX}-appearance-title`,\n appearanceForm: `${DEFAULT_PREFIX}-appearance-form`,\n themeSystem: `${DEFAULT_PREFIX}-theme-system`,\n themeLight: `${DEFAULT_PREFIX}-theme-light`,\n themeDark: `${DEFAULT_PREFIX}-theme-dark`,\n};\n","import { DEFAULT_PREFIX } from \"./settings-page-names\";\n\nconst THEMES = [\"system\", \"light\", \"dark\"] as const;\nexport type Theme = (typeof THEMES)[number];\n\nexport const THEME_FIELD_NAME: string = `${DEFAULT_PREFIX}-theme`;\nexport const DEFAULT_THEME: Theme = THEMES[0];\n\nexport function isTheme(value: unknown): value is Theme {\n return THEMES.some((theme) => theme === value);\n}\n","/** @jsxImportSource hastscript */\n\nimport type { Result as HastResult } from \"hastscript\";\nimport { SETTINGS_PAGE_NAMES } from \"./settings-page-names\";\nimport { THEME_FIELD_NAME, type Theme } from \"./theme\";\n\nexport interface SettingsPageProps {\n defaultTheme: Theme;\n}\n\nexport function SettingsPage({ defaultTheme }: SettingsPageProps): HastResult {\n return (\n <>\n <h1>Settings</h1>\n <section aria-labelledby={SETTINGS_PAGE_NAMES.appearanceTitle}>\n <h2 id={SETTINGS_PAGE_NAMES.appearanceTitle}>Appearance</h2>\n <form id={SETTINGS_PAGE_NAMES.appearanceForm}>\n <fieldset>\n <legend>Theme</legend>\n <input\n type=\"radio\"\n id={SETTINGS_PAGE_NAMES.themeSystem}\n name={THEME_FIELD_NAME}\n value=\"system\"\n checked={defaultTheme === \"system\"}\n />\n <label for={SETTINGS_PAGE_NAMES.themeSystem}>System</label>\n <input\n type=\"radio\"\n id={SETTINGS_PAGE_NAMES.themeLight}\n name={THEME_FIELD_NAME}\n value=\"light\"\n checked={defaultTheme === \"light\"}\n />\n <label for={SETTINGS_PAGE_NAMES.themeLight}>Light</label>\n <input\n type=\"radio\"\n id={SETTINGS_PAGE_NAMES.themeDark}\n name={THEME_FIELD_NAME}\n value=\"dark\"\n checked={defaultTheme === \"dark\"}\n />\n <label for={SETTINGS_PAGE_NAMES.themeDark}>Dark</label>\n </fieldset>\n </form>\n </section>\n </>\n );\n}\n","import { SETTINGS_PAGE_NAMES } from \"./settings-page-names\";\nimport { isTheme, THEME_FIELD_NAME, type Theme } from \"./theme\";\n\ninterface ThemeFormBinding {\n sync: (theme: Theme) => void;\n unbind: () => void;\n}\n\nfunction getSelectedTheme(form: HTMLFormElement): Theme | null {\n const theme = new FormData(form).get(THEME_FIELD_NAME);\n if (!isTheme(theme)) {\n return null;\n }\n\n return theme;\n}\n\nfunction syncThemeStateToDom(radios: NodeListOf<HTMLInputElement>, theme: Theme) {\n for (const radio of radios) {\n const checked = radio.value === theme;\n radio.checked = checked;\n radio.defaultChecked = checked;\n }\n\n document.documentElement.setAttribute(`data-${THEME_FIELD_NAME}`, theme);\n}\n\nexport function bindThemeForm(onThemeChange: (theme: Theme) => void): ThemeFormBinding {\n const form = document.getElementById(SETTINGS_PAGE_NAMES.appearanceForm) as HTMLFormElement;\n const radios = form.querySelectorAll<HTMLInputElement>(`input[name=\"${THEME_FIELD_NAME}\"]`);\n\n function syncThemeFromForm() {\n const selectedTheme = getSelectedTheme(form);\n if (!selectedTheme) {\n return;\n }\n\n onThemeChange(selectedTheme);\n }\n\n const initialSelectedTheme = getSelectedTheme(form);\n if (initialSelectedTheme) {\n onThemeChange(initialSelectedTheme);\n }\n\n form.addEventListener(\"change\", syncThemeFromForm);\n\n return {\n sync(theme: Theme) {\n syncThemeStateToDom(radios, theme);\n },\n unbind() {\n form.removeEventListener(\"change\", syncThemeFromForm);\n },\n };\n}\n","import type { Result as HastResult } from \"hastscript\";\nimport { SettingsPage } from \"./settings-page\";\nimport { DEFAULT_THEME, type Theme } from \"./theme\";\n\ninterface InitOptions {\n defaultTheme?: Theme;\n}\n\ninterface SettingsRenderer {\n render: () => HastResult;\n}\n\nexport function init({ defaultTheme = DEFAULT_THEME }: InitOptions = {}): SettingsRenderer {\n return {\n render() {\n return render(defaultTheme);\n },\n };\n}\n\nfunction render(defaultTheme: Theme): HastResult {\n return SettingsPage({ defaultTheme });\n}\n\nexport { DEFAULT_PREFIX, SETTINGS_PAGE_NAMES } from \"./settings-page-names\";\nexport { bindThemeForm } from \"./theme-form-controller\";\nexport { DEFAULT_THEME, THEME_FIELD_NAME, isTheme, type Theme } from \"./theme\";\n"],"mappings":";;;AAAA,MAAa,iBAAiB;AAU9B,MAAa,sBAAyC;CACpD,iBAAiB,GAAG,eAAe;CACnC,gBAAgB,GAAG,eAAe;CAClC,aAAa,GAAG,eAAe;CAC/B,YAAY,GAAG,eAAe;CAC9B,WAAW,GAAG,eAAe;CAC9B;;;;ACdD,MAAM,SAAS;CAAC;CAAU;CAAS;CAAO;AAG1C,MAAa,mBAA2B,GAAG,eAAe;AAC1D,MAAa,gBAAuB,OAAO;AAE3C,SAAgB,QAAQ,OAAgC;AACtD,QAAO,OAAO,MAAM,UAAU,UAAU,MAAM;;;;;ACChD,SAAgB,aAAa,EAAE,gBAA+C;AAC5E,QACE,4CACE,oBAAC,kBAAG,aAAa,EACjB,qBAAC;EAAQ,mBAAiB,oBAAoB;aAC5C,oBAAC;GAAG,IAAI,oBAAoB;aAAiB;IAAe,EAC5D,oBAAC;GAAK,IAAI,oBAAoB;aAC5B,qBAAC;IACC,oBAAC,sBAAO,UAAc;IACtB,oBAAC;KACC,MAAK;KACL,IAAI,oBAAoB;KACxB,MAAM;KACN,OAAM;KACN,SAAS,iBAAiB;MAC1B;IACF,oBAAC;KAAM,KAAK,oBAAoB;eAAa;MAAc;IAC3D,oBAAC;KACC,MAAK;KACL,IAAI,oBAAoB;KACxB,MAAM;KACN,OAAM;KACN,SAAS,iBAAiB;MAC1B;IACF,oBAAC;KAAM,KAAK,oBAAoB;eAAY;MAAa;IACzD,oBAAC;KACC,MAAK;KACL,IAAI,oBAAoB;KACxB,MAAM;KACN,OAAM;KACN,SAAS,iBAAiB;MAC1B;IACF,oBAAC;KAAM,KAAK,oBAAoB;eAAW;MAAY;OAC9C;IACN;GACC,IACT;;;;;ACtCP,SAAS,iBAAiB,MAAqC;CAC7D,MAAM,QAAQ,IAAI,SAAS,KAAK,CAAC,IAAI,iBAAiB;AACtD,KAAI,CAAC,QAAQ,MAAM,CACjB,QAAO;AAGT,QAAO;;AAGT,SAAS,oBAAoB,QAAsC,OAAc;AAC/E,MAAK,MAAM,SAAS,QAAQ;EAC1B,MAAM,UAAU,MAAM,UAAU;AAChC,QAAM,UAAU;AAChB,QAAM,iBAAiB;;AAGzB,UAAS,gBAAgB,aAAa,QAAQ,oBAAoB,MAAM;;AAG1E,SAAgB,cAAc,eAAyD;CACrF,MAAM,OAAO,SAAS,eAAe,oBAAoB,eAAe;CACxE,MAAM,SAAS,KAAK,iBAAmC,eAAe,iBAAiB,IAAI;CAE3F,SAAS,oBAAoB;EAC3B,MAAM,gBAAgB,iBAAiB,KAAK;AAC5C,MAAI,CAAC,cACH;AAGF,gBAAc,cAAc;;CAG9B,MAAM,uBAAuB,iBAAiB,KAAK;AACnD,KAAI,qBACF,eAAc,qBAAqB;AAGrC,MAAK,iBAAiB,UAAU,kBAAkB;AAElD,QAAO;EACL,KAAK,OAAc;AACjB,uBAAoB,QAAQ,MAAM;;EAEpC,SAAS;AACP,QAAK,oBAAoB,UAAU,kBAAkB;;EAExD;;;;;AC1CH,SAAgB,KAAK,EAAE,eAAe,kBAA+B,EAAE,EAAoB;AACzF,QAAO,EACL,SAAS;AACP,SAAO,OAAO,aAAa;IAE9B;;AAGH,SAAS,OAAO,cAAiC;AAC/C,QAAO,aAAa,EAAE,cAAc,CAAC"}
1
+ {"version":3,"file":"main.js","names":[],"sources":["../src/settings-page-names.ts","../src/theme.ts","../src/settings-page.tsx","../src/theme-persistence.ts","../src/theme-form-controller.ts","../src/main.ts"],"sourcesContent":["export const DEFAULT_PREFIX = \"slk-settings\";\n\nexport interface SettingsPageNames {\n appearanceTitle: string;\n appearanceForm: string;\n themeSystem: string;\n themeLight: string;\n themeDark: string;\n}\n\nexport const SETTINGS_PAGE_NAMES: SettingsPageNames = {\n appearanceTitle: `${DEFAULT_PREFIX}-appearance-title`,\n appearanceForm: `${DEFAULT_PREFIX}-appearance-form`,\n themeSystem: `${DEFAULT_PREFIX}-theme-system`,\n themeLight: `${DEFAULT_PREFIX}-theme-light`,\n themeDark: `${DEFAULT_PREFIX}-theme-dark`,\n};\n","import { DEFAULT_PREFIX } from \"./settings-page-names\";\n\nconst THEMES = [\"system\", \"light\", \"dark\"] as const;\nexport type Theme = (typeof THEMES)[number];\n\nexport const THEME_FIELD_NAME: string = `${DEFAULT_PREFIX}-theme`;\nexport const DEFAULT_THEME: Theme = THEMES[0];\n\nexport function isTheme(value: unknown): value is Theme {\n return THEMES.some((theme) => theme === value);\n}\n","/** @jsxImportSource hastscript */\n\nimport type { Result as HastResult } from \"hastscript\";\nimport { SETTINGS_PAGE_NAMES } from \"./settings-page-names\";\nimport { THEME_FIELD_NAME, type Theme } from \"./theme\";\n\nexport interface SettingsPageProps {\n defaultTheme: Theme;\n}\n\nexport function SettingsPage({ defaultTheme }: SettingsPageProps): HastResult {\n return (\n <>\n <h1>Settings</h1>\n <section aria-labelledby={SETTINGS_PAGE_NAMES.appearanceTitle}>\n <h2 id={SETTINGS_PAGE_NAMES.appearanceTitle}>Appearance</h2>\n <form id={SETTINGS_PAGE_NAMES.appearanceForm}>\n <fieldset>\n <legend>Theme</legend>\n <input\n type=\"radio\"\n id={SETTINGS_PAGE_NAMES.themeSystem}\n name={THEME_FIELD_NAME}\n value=\"system\"\n checked={defaultTheme === \"system\"}\n />\n <label for={SETTINGS_PAGE_NAMES.themeSystem}>System</label>\n <input\n type=\"radio\"\n id={SETTINGS_PAGE_NAMES.themeLight}\n name={THEME_FIELD_NAME}\n value=\"light\"\n checked={defaultTheme === \"light\"}\n />\n <label for={SETTINGS_PAGE_NAMES.themeLight}>Light</label>\n <input\n type=\"radio\"\n id={SETTINGS_PAGE_NAMES.themeDark}\n name={THEME_FIELD_NAME}\n value=\"dark\"\n checked={defaultTheme === \"dark\"}\n />\n <label for={SETTINGS_PAGE_NAMES.themeDark}>Dark</label>\n </fieldset>\n </form>\n </section>\n </>\n );\n}\n","import { DEFAULT_PREFIX } from \"./settings-page-names\";\nimport { isTheme, type Theme } from \"./theme\";\n\nconst THEME_STORAGE_KEY: string = `${DEFAULT_PREFIX}-theme`;\n\nfunction getStorage(): Storage | null {\n try {\n return globalThis.localStorage ?? null;\n } catch {\n return null;\n }\n}\n\nexport function readPersistedTheme(): Theme | null {\n const storage = getStorage();\n if (!storage) {\n return null;\n }\n\n let value: string | null = null;\n try {\n value = storage.getItem(THEME_STORAGE_KEY);\n } catch {\n return null;\n }\n\n if (!isTheme(value)) {\n return null;\n }\n\n return value;\n}\n\nexport function persistTheme(theme: Theme): void {\n const storage = getStorage();\n if (!storage) {\n return;\n }\n\n try {\n storage.setItem(THEME_STORAGE_KEY, theme);\n } catch {\n return;\n }\n}\n\nexport const THEME_BOOTSTRAP_SCRIPT =\n \"try{let theme=localStorage.getItem('slk-settings-theme');if(['system','light','dark'].includes(theme)){document.documentElement.setAttribute('data-slk-settings-theme',theme)}}catch{}\";\n","import { SETTINGS_PAGE_NAMES } from \"./settings-page-names\";\nimport { isTheme, THEME_FIELD_NAME, type Theme } from \"./theme\";\nimport { persistTheme, readPersistedTheme } from \"./theme-persistence\";\n\ninterface ThemeFormBinding {\n sync: (theme: Theme) => void;\n unbind: () => void;\n}\n\nfunction getSelectedTheme(form: HTMLFormElement): Theme | null {\n const theme = new FormData(form).get(THEME_FIELD_NAME);\n if (!isTheme(theme)) {\n return null;\n }\n\n return theme;\n}\n\nfunction syncThemeStateToDom(radios: NodeListOf<HTMLInputElement>, theme: Theme) {\n for (const radio of radios) {\n const checked = radio.value === theme;\n radio.checked = checked;\n radio.defaultChecked = checked;\n }\n\n document.documentElement.setAttribute(`data-${THEME_FIELD_NAME}`, theme);\n}\n\nexport function bindThemeForm(onThemeChange: (theme: Theme) => void): ThemeFormBinding {\n const form = document.getElementById(SETTINGS_PAGE_NAMES.appearanceForm) as HTMLFormElement;\n const radios = form.querySelectorAll<HTMLInputElement>(`input[name=\"${THEME_FIELD_NAME}\"]`);\n\n function syncThemeFromForm() {\n const selectedTheme = getSelectedTheme(form);\n if (!selectedTheme) {\n return;\n }\n\n onThemeChange(selectedTheme);\n persistTheme(selectedTheme);\n }\n\n const persistedTheme = readPersistedTheme();\n if (persistedTheme) {\n syncThemeStateToDom(radios, persistedTheme);\n }\n\n const initialSelectedTheme = persistedTheme ?? getSelectedTheme(form);\n if (initialSelectedTheme) {\n onThemeChange(initialSelectedTheme);\n }\n\n form.addEventListener(\"change\", syncThemeFromForm);\n\n return {\n sync(theme: Theme) {\n syncThemeStateToDom(radios, theme);\n persistTheme(theme);\n },\n unbind() {\n form.removeEventListener(\"change\", syncThemeFromForm);\n },\n };\n}\n","import type { Result as HastResult } from \"hastscript\";\nimport { SettingsPage } from \"./settings-page\";\nimport { DEFAULT_THEME, type Theme } from \"./theme\";\nimport { THEME_BOOTSTRAP_SCRIPT } from \"./theme-persistence\";\n\ninterface InitOptions {\n defaultTheme?: Theme;\n}\n\ninterface SettingsRenderer {\n render: () => HastResult;\n}\n\nexport function init({ defaultTheme = DEFAULT_THEME }: InitOptions = {}): SettingsRenderer {\n return {\n render() {\n return render(defaultTheme);\n },\n };\n}\n\nfunction render(defaultTheme: Theme): HastResult {\n return SettingsPage({ defaultTheme });\n}\n\nexport { bindThemeForm } from \"./theme-form-controller\";\nexport { DEFAULT_THEME, type Theme } from \"./theme\";\nexport { THEME_BOOTSTRAP_SCRIPT };\n"],"mappings":";;;AAAA,MAAa,iBAAiB;AAU9B,MAAa,sBAAyC;CACpD,iBAAiB,GAAG,eAAe;CACnC,gBAAgB,GAAG,eAAe;CAClC,aAAa,GAAG,eAAe;CAC/B,YAAY,GAAG,eAAe;CAC9B,WAAW,GAAG,eAAe;CAC9B;;;;ACdD,MAAM,SAAS;CAAC;CAAU;CAAS;CAAO;AAG1C,MAAa,mBAA2B,GAAG,eAAe;AAC1D,MAAa,gBAAuB,OAAO;AAE3C,SAAgB,QAAQ,OAAgC;AACtD,QAAO,OAAO,MAAM,UAAU,UAAU,MAAM;;;;;ACChD,SAAgB,aAAa,EAAE,gBAA+C;AAC5E,QACE,4CACE,oBAAC,kBAAG,aAAa,EACjB,qBAAC;EAAQ,mBAAiB,oBAAoB;aAC5C,oBAAC;GAAG,IAAI,oBAAoB;aAAiB;IAAe,EAC5D,oBAAC;GAAK,IAAI,oBAAoB;aAC5B,qBAAC;IACC,oBAAC,sBAAO,UAAc;IACtB,oBAAC;KACC,MAAK;KACL,IAAI,oBAAoB;KACxB,MAAM;KACN,OAAM;KACN,SAAS,iBAAiB;MAC1B;IACF,oBAAC;KAAM,KAAK,oBAAoB;eAAa;MAAc;IAC3D,oBAAC;KACC,MAAK;KACL,IAAI,oBAAoB;KACxB,MAAM;KACN,OAAM;KACN,SAAS,iBAAiB;MAC1B;IACF,oBAAC;KAAM,KAAK,oBAAoB;eAAY;MAAa;IACzD,oBAAC;KACC,MAAK;KACL,IAAI,oBAAoB;KACxB,MAAM;KACN,OAAM;KACN,SAAS,iBAAiB;MAC1B;IACF,oBAAC;KAAM,KAAK,oBAAoB;eAAW;MAAY;OAC9C;IACN;GACC,IACT;;;;;AC3CP,MAAM,oBAA4B,GAAG,eAAe;AAEpD,SAAS,aAA6B;AACpC,KAAI;AACF,SAAO,WAAW,gBAAgB;SAC5B;AACN,SAAO;;;AAIX,SAAgB,qBAAmC;CACjD,MAAM,UAAU,YAAY;AAC5B,KAAI,CAAC,QACH,QAAO;CAGT,IAAI,QAAuB;AAC3B,KAAI;AACF,UAAQ,QAAQ,QAAQ,kBAAkB;SACpC;AACN,SAAO;;AAGT,KAAI,CAAC,QAAQ,MAAM,CACjB,QAAO;AAGT,QAAO;;AAGT,SAAgB,aAAa,OAAoB;CAC/C,MAAM,UAAU,YAAY;AAC5B,KAAI,CAAC,QACH;AAGF,KAAI;AACF,UAAQ,QAAQ,mBAAmB,MAAM;SACnC;AACN;;;AAIJ,MAAa,yBACX;;;;ACtCF,SAAS,iBAAiB,MAAqC;CAC7D,MAAM,QAAQ,IAAI,SAAS,KAAK,CAAC,IAAI,iBAAiB;AACtD,KAAI,CAAC,QAAQ,MAAM,CACjB,QAAO;AAGT,QAAO;;AAGT,SAAS,oBAAoB,QAAsC,OAAc;AAC/E,MAAK,MAAM,SAAS,QAAQ;EAC1B,MAAM,UAAU,MAAM,UAAU;AAChC,QAAM,UAAU;AAChB,QAAM,iBAAiB;;AAGzB,UAAS,gBAAgB,aAAa,QAAQ,oBAAoB,MAAM;;AAG1E,SAAgB,cAAc,eAAyD;CACrF,MAAM,OAAO,SAAS,eAAe,oBAAoB,eAAe;CACxE,MAAM,SAAS,KAAK,iBAAmC,eAAe,iBAAiB,IAAI;CAE3F,SAAS,oBAAoB;EAC3B,MAAM,gBAAgB,iBAAiB,KAAK;AAC5C,MAAI,CAAC,cACH;AAGF,gBAAc,cAAc;AAC5B,eAAa,cAAc;;CAG7B,MAAM,iBAAiB,oBAAoB;AAC3C,KAAI,eACF,qBAAoB,QAAQ,eAAe;CAG7C,MAAM,uBAAuB,kBAAkB,iBAAiB,KAAK;AACrE,KAAI,qBACF,eAAc,qBAAqB;AAGrC,MAAK,iBAAiB,UAAU,kBAAkB;AAElD,QAAO;EACL,KAAK,OAAc;AACjB,uBAAoB,QAAQ,MAAM;AAClC,gBAAa,MAAM;;EAErB,SAAS;AACP,QAAK,oBAAoB,UAAU,kBAAkB;;EAExD;;;;;ACjDH,SAAgB,KAAK,EAAE,eAAe,kBAA+B,EAAE,EAAoB;AACzF,QAAO,EACL,SAAS;AACP,SAAO,OAAO,aAAa;IAE9B;;AAGH,SAAS,OAAO,cAAiC;AAC/C,QAAO,aAAa,EAAE,cAAc,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@seamline-kit/seamline-settings",
3
- "version": "0.0.4",
3
+ "version": "0.0.6",
4
4
  "license": "MIT",
5
5
  "files": [
6
6
  "dist"
@@ -19,6 +19,16 @@
19
19
  "publishConfig": {
20
20
  "access": "public"
21
21
  },
22
+ "dependencies": {
23
+ "hastscript": "9.0.1"
24
+ },
25
+ "devDependencies": {
26
+ "@vitest/browser-playwright": "4.0.18",
27
+ "oxfmt": "0.35.0",
28
+ "oxlint": "1.50.0",
29
+ "tsdown": "0.20.3",
30
+ "vitest": "4.0.18"
31
+ },
22
32
  "scripts": {
23
33
  "dev": "tsdown --watch",
24
34
  "build": "tsdown",
@@ -33,16 +43,5 @@
33
43
  "lint:fix": "oxlint --fix",
34
44
  "format": "oxfmt --ignore-path ../../.gitignore .",
35
45
  "format:check": "oxfmt --check --ignore-path ../../.gitignore ."
36
- },
37
- "dependencies": {
38
- "hastscript": "9.0.1"
39
- },
40
- "devDependencies": {
41
- "@vitest/browser-playwright": "4.0.18",
42
- "oxfmt": "0.32.0",
43
- "oxlint": "1.47.0",
44
- "tsdown": "0.20.3",
45
- "vitest": "4.0.18"
46
- },
47
- "packageManager": "pnpm@10.29.3"
48
- }
46
+ }
47
+ }