@lessonkit/themes 1.3.0 → 1.3.1

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/index.cjs CHANGED
@@ -74,7 +74,7 @@ function isNonEmptyString(v) {
74
74
  return typeof v === "string" && v.trim().length > 0;
75
75
  }
76
76
  function isSafeCssCustomPropertyValue(value) {
77
- return !/[;}\r\n]/.test(value) && !value.includes("/*");
77
+ return !/[;}\r\n\\<>]/.test(value) && !value.includes("/*");
78
78
  }
79
79
  function validateCssTokenValue(path, value, issues) {
80
80
  if (!isSafeCssCustomPropertyValue(value)) {
@@ -224,9 +224,16 @@ function mergeThemes(base, ...overrides) {
224
224
 
225
225
  // src/cssVariables.ts
226
226
  function sanitizeCssCustomPropertyValue(value) {
227
- if (/[;}\r\n]/.test(value) || value.includes("/*")) return null;
227
+ if (/[;}\r\n\\<>]/.test(value) || value.includes("/*")) return null;
228
228
  return value;
229
229
  }
230
+ function isSafeCssSelector(selector) {
231
+ if (selector === ":root") return true;
232
+ if (/^\.[a-zA-Z_][\w-]*$/.test(selector)) return true;
233
+ if (/^#[a-zA-Z_][\w-]*$/.test(selector)) return true;
234
+ if (/^\[data-lk-theme=(["'])[^"']+\1\]$/.test(selector)) return true;
235
+ return false;
236
+ }
230
237
  function assignCssVar(vars, key, value) {
231
238
  const safe = sanitizeCssCustomPropertyValue(value);
232
239
  if (safe !== null) vars[key] = safe;
@@ -283,6 +290,9 @@ function themeToCssVariables(theme) {
283
290
  }
284
291
  function themeToCssDeclarationBlock(theme, opts) {
285
292
  const selector = opts?.selector ?? ":root";
293
+ if (!isSafeCssSelector(selector)) {
294
+ throw new Error(`[lessonkit] unsafe CSS selector for theme block: ${selector}`);
295
+ }
286
296
  const vars = themeToCssVariables(theme);
287
297
  const body = Object.entries(vars).map(([k, v]) => ` ${k}: ${v};`).join("\n");
288
298
  return `${selector} {
@@ -400,8 +410,11 @@ var PRESETS = {
400
410
  dark: darkTheme,
401
411
  brand: brandTheme
402
412
  };
413
+ function cloneTheme(theme) {
414
+ return JSON.parse(JSON.stringify(theme));
415
+ }
403
416
  function getPresetTheme(preset) {
404
- return PRESETS[preset];
417
+ return cloneTheme(PRESETS[preset]);
405
418
  }
406
419
 
407
420
  // src/catalog.ts
package/dist/index.js CHANGED
@@ -25,7 +25,7 @@ function isNonEmptyString(v) {
25
25
  return typeof v === "string" && v.trim().length > 0;
26
26
  }
27
27
  function isSafeCssCustomPropertyValue(value) {
28
- return !/[;}\r\n]/.test(value) && !value.includes("/*");
28
+ return !/[;}\r\n\\<>]/.test(value) && !value.includes("/*");
29
29
  }
30
30
  function validateCssTokenValue(path, value, issues) {
31
31
  if (!isSafeCssCustomPropertyValue(value)) {
@@ -175,9 +175,16 @@ function mergeThemes(base, ...overrides) {
175
175
 
176
176
  // src/cssVariables.ts
177
177
  function sanitizeCssCustomPropertyValue(value) {
178
- if (/[;}\r\n]/.test(value) || value.includes("/*")) return null;
178
+ if (/[;}\r\n\\<>]/.test(value) || value.includes("/*")) return null;
179
179
  return value;
180
180
  }
181
+ function isSafeCssSelector(selector) {
182
+ if (selector === ":root") return true;
183
+ if (/^\.[a-zA-Z_][\w-]*$/.test(selector)) return true;
184
+ if (/^#[a-zA-Z_][\w-]*$/.test(selector)) return true;
185
+ if (/^\[data-lk-theme=(["'])[^"']+\1\]$/.test(selector)) return true;
186
+ return false;
187
+ }
181
188
  function assignCssVar(vars, key, value) {
182
189
  const safe = sanitizeCssCustomPropertyValue(value);
183
190
  if (safe !== null) vars[key] = safe;
@@ -234,6 +241,9 @@ function themeToCssVariables(theme) {
234
241
  }
235
242
  function themeToCssDeclarationBlock(theme, opts) {
236
243
  const selector = opts?.selector ?? ":root";
244
+ if (!isSafeCssSelector(selector)) {
245
+ throw new Error(`[lessonkit] unsafe CSS selector for theme block: ${selector}`);
246
+ }
237
247
  const vars = themeToCssVariables(theme);
238
248
  const body = Object.entries(vars).map(([k, v]) => ` ${k}: ${v};`).join("\n");
239
249
  return `${selector} {
@@ -351,8 +361,11 @@ var PRESETS = {
351
361
  dark: darkTheme,
352
362
  brand: brandTheme
353
363
  };
364
+ function cloneTheme(theme) {
365
+ return JSON.parse(JSON.stringify(theme));
366
+ }
354
367
  function getPresetTheme(preset) {
355
- return PRESETS[preset];
368
+ return cloneTheme(PRESETS[preset]);
356
369
  }
357
370
 
358
371
  // src/catalog.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lessonkit/themes",
3
- "version": "1.3.0",
3
+ "version": "1.3.1",
4
4
  "private": false,
5
5
  "description": "Theme primitives and tokens for LessonKit.",
6
6
  "license": "Apache-2.0",