@uniweb/theming 0.1.5 → 0.1.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uniweb/theming",
3
- "version": "0.1.5",
3
+ "version": "0.1.6",
4
4
  "description": "Theming utilities for the Uniweb platform — shade generation, CSS generation, theme processing",
5
5
  "type": "module",
6
6
  "exports": {
@@ -210,32 +210,56 @@ const GENERIC_FAMILIES = new Set([
210
210
  'inherit', 'initial', 'revert', 'unset',
211
211
  ])
212
212
 
213
+ // Foundation `font-*` vars that are CSS longhands, not typefaces — never
214
+ // treat their value as a family to load.
215
+ const NON_FAMILY_FONT_VARS = new Set([
216
+ 'font-weight', 'font-style', 'font-size', 'font-stretch',
217
+ 'font-feature-settings', 'font-variation-settings', 'font-variant',
218
+ 'font-kerning', 'font-optical-sizing', 'font-synthesis',
219
+ 'font-size-adjust', 'font-smoothing', 'font-palette', 'font-language-override',
220
+ ])
221
+
213
222
  /**
214
- * Extract font family names actually used by body/heading/mono slots.
223
+ * Extract the font family names the site actually references.
215
224
  *
216
- * Only considers slots the user explicitly configured (tracked via _userSlots
217
- * from the processor). Default system font stacks are ignored so they don't
218
- * trigger unnecessary font loading.
225
+ * Two sources count as "used":
226
+ * 1. The `body`/`heading`/`mono` slots the user explicitly configured
227
+ * (tracked via _userSlots from the processor). Default system stacks are
228
+ * ignored so they don't trigger unnecessary font loading.
229
+ * 2. Foundation `font-*` vars (e.g. an editorial `font-serif`). A foundation
230
+ * can declare a themeable typeface beyond the three built-in roles; the
231
+ * site sets its value and loads it with `fonts.import` / `fonts.faces`.
232
+ * Without counting these, such a family is filtered out as "unused" and
233
+ * never loads — capping a foundation at the three role slots.
219
234
  *
220
- * @param {Object} fonts - Font configuration
221
- * @returns {Set<string>} Lowercase family names referenced by user-set slots
235
+ * @param {Object} fonts - Font configuration (may carry _userSlots)
236
+ * @param {Object} [foundationVars] - Resolved foundation vars (name → { default } | value)
237
+ * @returns {Set<string>} Lowercase family names referenced by the site
222
238
  */
223
- function extractUsedFamilies(fonts) {
239
+ function extractUsedFamilies(fonts, foundationVars = {}) {
224
240
  const used = new Set()
225
- const slots = fonts._userSlots || ['body', 'heading', 'mono']
226
-
227
- for (const slot of slots) {
228
- const value = fonts[slot]
229
- if (!value) continue
230
241
 
242
+ const addFamiliesFrom = (value) => {
243
+ if (typeof value !== 'string') return
231
244
  for (const segment of value.split(',')) {
232
245
  const name = segment.trim().replace(/^["']|["']$/g, '').toLowerCase()
233
- if (name && !GENERIC_FAMILIES.has(name)) {
234
- used.add(name)
235
- }
246
+ // Skip generics, empties, and numeric/length tokens (a weight "600" or
247
+ // size "1rem" a non-family font-* var might carry).
248
+ if (!name || GENERIC_FAMILIES.has(name) || /^\d/.test(name)) continue
249
+ used.add(name)
236
250
  }
237
251
  }
238
252
 
253
+ const slots = fonts._userSlots || ['body', 'heading', 'mono']
254
+ for (const slot of slots) {
255
+ addFamiliesFrom(fonts[slot])
256
+ }
257
+
258
+ for (const [name, config] of Object.entries(foundationVars)) {
259
+ if (!name.startsWith('font-') || NON_FAMILY_FONT_VARS.has(name)) continue
260
+ addFamiliesFrom(typeof config === 'object' ? config?.default : config)
261
+ }
262
+
239
263
  return used
240
264
  }
241
265
 
@@ -288,11 +312,11 @@ function isGoogleFontsUrl(url) {
288
312
  * @param {Object} fonts - Font configuration
289
313
  * @returns {{ css: string, links: string }} css for <style>, links for <head>
290
314
  */
291
- function generateFontCSS(fonts = {}) {
315
+ function generateFontCSS(fonts = {}, foundationVars = {}) {
292
316
  const cssLines = []
293
317
  const linkTags = []
294
318
 
295
- const usedFamilies = extractUsedFamilies(fonts)
319
+ const usedFamilies = extractUsedFamilies(fonts, foundationVars)
296
320
 
297
321
  // --- @font-face rules from faces[] (filtered to used families) ---
298
322
  // Also generate <link rel="preload"> hints so browsers fetch fonts early
@@ -502,7 +526,9 @@ export function generateThemeCSS(config = {}) {
502
526
  const sections = []
503
527
 
504
528
  // 1. Font face rules and variables (links returned separately)
505
- const fontResult = generateFontCSS(fonts)
529
+ // foundationVars is passed so families referenced by a foundation `font-*`
530
+ // var (e.g. an editorial `font-serif`) survive the used-family filter.
531
+ const fontResult = generateFontCSS(fonts, foundationVars)
506
532
  if (fontResult.css) {
507
533
  sections.push('/* Typography */\n' + fontResult.css)
508
534
  }