@uniweb/theming 0.1.11 → 0.1.12

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 (2) hide show
  1. package/package.json +1 -1
  2. package/src/processor.js +44 -2
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uniweb/theming",
3
- "version": "0.1.11",
3
+ "version": "0.1.12",
4
4
  "description": "Theming utilities for the Uniweb platform — shade generation, CSS generation, theme processing",
5
5
  "type": "module",
6
6
  "exports": {
package/src/processor.js CHANGED
@@ -378,6 +378,49 @@ export function validateThemeConfig(config) {
378
378
  }
379
379
  }
380
380
 
381
+ /**
382
+ * Merge inline text styles over the framework defaults, property by property.
383
+ *
384
+ * Everything else in theme.yml merges at the granularity of the leaf value —
385
+ * `contexts[name]` merges your tokens into the default context object, `colors`
386
+ * and `appearance` merge per key. This does the same one level down, so a site
387
+ * declares only the deltas:
388
+ *
389
+ * inline:
390
+ * accent:
391
+ * font-weight: inherit # keeps the default colour
392
+ *
393
+ * A shallow merge replaced the whole style object instead, so the example above
394
+ * silently produced `span[accent] { font-weight: inherit }` with no colour at
395
+ * all, and accented text rendered in the surrounding heading colour. The failure
396
+ * was subtractive and invisible in the config — you had to know what the default
397
+ * contained to notice it was gone. Three of the shipped templates carried a
398
+ * verbatim restatement of the default `accent` style purely to work around this.
399
+ *
400
+ * To *drop* a default property rather than change it, give it a neutral CSS
401
+ * value — `font-weight: inherit` to follow the surrounding text, or `initial` /
402
+ * `unset` / `revert`. Setting a whole style to null still removes it entirely
403
+ * (the CSS generator skips non-object entries).
404
+ *
405
+ * @param {Object} defaults - DEFAULT_INLINE
406
+ * @param {Object} [overrides] - rawConfig.inline
407
+ * @returns {Object} merged style map
408
+ */
409
+ function mergeInlineStyles(defaults, overrides) {
410
+ const merged = { ...defaults }
411
+
412
+ for (const [name, style] of Object.entries(overrides || {})) {
413
+ // Non-objects (null/false) pass through so a site can delete a default
414
+ // style outright; anything else layers over the default of the same name.
415
+ merged[name] =
416
+ style && typeof style === 'object' && !Array.isArray(style)
417
+ ? { ...(defaults[name] || {}), ...style }
418
+ : style
419
+ }
420
+
421
+ return merged
422
+ }
423
+
381
424
  /**
382
425
  * Normalize appearance configuration
383
426
  *
@@ -659,8 +702,7 @@ export function processTheme(rawConfig = {}, options = {}) {
659
702
  const background = rawConfig.background || null
660
703
 
661
704
  // Inline text styles (semantic names → CSS declarations)
662
- // Merge framework defaults with user overrides (user values win)
663
- const inline = { ...DEFAULT_INLINE, ...(rawConfig.inline || {}) }
705
+ const inline = mergeInlineStyles(DEFAULT_INLINE, rawConfig.inline)
664
706
 
665
707
  const config = {
666
708
  colors, // Raw colors for CSS generator