@uniweb/theming 0.1.15 → 0.1.16
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 +1 -1
- package/src/section-overrides.js +73 -43
package/package.json
CHANGED
package/src/section-overrides.js
CHANGED
|
@@ -145,8 +145,19 @@ function buildRule(selector, vars) {
|
|
|
145
145
|
* Works with both Block instances and plain data objects — only reads:
|
|
146
146
|
* - block.stableId || block.id — for CSS selector
|
|
147
147
|
* - block.themeName — '' for Auto, 'light'/'medium'/'dark' for Pinned
|
|
148
|
-
* - block.
|
|
148
|
+
* - block.themeOverrides — the section's `theme:`, as @uniweb/core normalizes it:
|
|
149
|
+
* `{ colors, contexts, vars, tokens }` — a palette, tokens per color context, the
|
|
150
|
+
* foundation's variables, and tokens for the section in any context
|
|
149
151
|
* - block.componentVars — merged meta.js defaults + frontmatter overrides
|
|
152
|
+
* - block.standardOptions — ⚠️ the older editor envelope, `{ colors, foundationStyles }`,
|
|
153
|
+
* read by its own rules until an editor writes the section's `theme` instead
|
|
154
|
+
* - block.childBlocks — child sections get the same, at any depth: rendered as sections,
|
|
155
|
+
* they carry the `#section-{id}` these rules select [2026-09-28]
|
|
156
|
+
*
|
|
157
|
+
* ⭐ Which context's values apply, for the section's `theme`: a pinned section uses its own
|
|
158
|
+
* context's; a section that follows the site (Auto) uses `light` under a light scheme and
|
|
159
|
+
* `dark` under `.scheme-dark` — two rules, so no knowledge of whether the site can go dark
|
|
160
|
+
* is needed. A context's own token beats one written beside `mode`, being more specific.
|
|
150
161
|
*
|
|
151
162
|
* @param {Array<Object>} blocks - Block data objects
|
|
152
163
|
* @param {Object} appearance - Theme appearance config
|
|
@@ -158,59 +169,78 @@ export function buildSectionOverrides(blocks, appearance = {}) {
|
|
|
158
169
|
if (!blocks || blocks.length === 0) return ''
|
|
159
170
|
|
|
160
171
|
let css = ''
|
|
161
|
-
|
|
162
172
|
for (const block of blocks) {
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
const selector = `#section-${sectionId}`
|
|
173
|
+
css += buildBlockRules(block, appearance || {})
|
|
174
|
+
if (Array.isArray(block.childBlocks) && block.childBlocks.length > 0) {
|
|
175
|
+
css += buildSectionOverrides(block.childBlocks, appearance)
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
return css
|
|
179
|
+
}
|
|
171
180
|
|
|
172
|
-
|
|
181
|
+
/**
|
|
182
|
+
* The rules for one section: declarations for any scheme, and for an Auto section under a
|
|
183
|
+
* light and under a dark scheme.
|
|
184
|
+
*/
|
|
185
|
+
function buildBlockRules(block, appearance) {
|
|
186
|
+
const selector = `#section-${block.stableId || block.id}`
|
|
187
|
+
const isAuto = !block.themeName
|
|
188
|
+
const always = []
|
|
189
|
+
const light = []
|
|
190
|
+
const dark = []
|
|
191
|
+
|
|
192
|
+
// ⚠️ The older editor envelope — its rules unchanged, the `light` bucket without a toggle
|
|
193
|
+
// included, so an editor sending it renders as before.
|
|
194
|
+
const legacy = block.standardOptions
|
|
195
|
+
const compVars = buildFoundationVars(block.componentVars)
|
|
196
|
+
if (hasOverrides(legacy)) {
|
|
197
|
+
const { colors, foundationStyles } = legacy
|
|
173
198
|
const hasToggle = appearance.allowToggle
|
|
174
|
-
|
|
175
|
-
// Base palette is context-independent (always under 'light' key)
|
|
176
199
|
const paletteVars = buildPaletteVars(colors?.colors?.light)
|
|
177
|
-
|
|
178
|
-
// Split foundation styles: flat (context-independent) + context-keyed (color/gradient)
|
|
179
200
|
const { flat: flatFoundation, contexts: ctxFoundation } = splitFoundationStyles(foundationStyles)
|
|
180
201
|
const foundationVars = buildFoundationVars(flatFoundation)
|
|
181
|
-
|
|
182
|
-
// Component-level CSS vars are context-independent
|
|
183
|
-
const compVars = buildFoundationVars(block.componentVars)
|
|
184
|
-
|
|
185
202
|
if (isAuto && hasToggle) {
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
// Context-aware foundation vars (color/gradient types)
|
|
191
|
-
const lightFoundationCtx = buildFoundationVars(ctxFoundation.light)
|
|
192
|
-
const darkFoundationCtx = buildFoundationVars(ctxFoundation.dark)
|
|
193
|
-
|
|
194
|
-
// Context-independent rule: palette + flat foundation + component vars (apply in both schemes)
|
|
195
|
-
const sharedVars = [...paletteVars, ...foundationVars, ...compVars]
|
|
196
|
-
css += buildRule(selector, sharedVars)
|
|
197
|
-
|
|
198
|
-
// Light-only overrides (elements + context-aware foundation vars)
|
|
199
|
-
css += buildRule(`:root:not(.scheme-dark) ${selector}`, [...lightElementVars, ...lightFoundationCtx])
|
|
200
|
-
|
|
201
|
-
// Dark-only overrides (elements + context-aware foundation vars)
|
|
202
|
-
css += buildRule(`.scheme-dark ${selector}`, [...darkElementVars, ...darkFoundationCtx])
|
|
203
|
+
always.push(...paletteVars, ...foundationVars, ...compVars)
|
|
204
|
+
light.push(...buildElementVars(colors?.elements?.light), ...buildFoundationVars(ctxFoundation.light))
|
|
205
|
+
dark.push(...buildElementVars(colors?.elements?.dark), ...buildFoundationVars(ctxFoundation.dark))
|
|
203
206
|
} else {
|
|
204
|
-
// Single context: when toggle is off, always use 'light' bucket
|
|
205
|
-
// (overrides are context-independent); when toggle is on, use pinned context
|
|
206
207
|
const ctx = hasToggle ? (block.themeName || 'light') : 'light'
|
|
207
|
-
|
|
208
|
-
|
|
208
|
+
always.push(
|
|
209
|
+
...paletteVars,
|
|
210
|
+
...buildElementVars(colors?.elements?.[ctx]),
|
|
211
|
+
...foundationVars,
|
|
212
|
+
...compVars,
|
|
213
|
+
...buildFoundationVars(ctxFoundation[ctx])
|
|
214
|
+
)
|
|
215
|
+
}
|
|
216
|
+
} else {
|
|
217
|
+
always.push(...compVars)
|
|
218
|
+
}
|
|
209
219
|
|
|
210
|
-
|
|
211
|
-
|
|
220
|
+
// The section's `theme:` — theme.yml's keys, scoped to the section.
|
|
221
|
+
const theme = block.themeOverrides
|
|
222
|
+
const themeDark = []
|
|
223
|
+
if (theme) {
|
|
224
|
+
const { flat, contexts: ctxVars } = splitFoundationStyles(theme.vars)
|
|
225
|
+
always.push(...buildPaletteVars(theme.colors), ...buildFoundationVars(flat), ...buildElementVars(theme.tokens))
|
|
226
|
+
if (isAuto) {
|
|
227
|
+
light.push(...buildElementVars(theme.contexts?.light), ...buildFoundationVars(ctxVars.light))
|
|
228
|
+
themeDark.push(...buildElementVars(theme.contexts?.dark), ...buildFoundationVars(ctxVars.dark))
|
|
229
|
+
dark.push(...themeDark)
|
|
230
|
+
} else {
|
|
231
|
+
always.push(...buildElementVars(theme.contexts?.[block.themeName]), ...buildFoundationVars(ctxVars[block.themeName]))
|
|
212
232
|
}
|
|
213
233
|
}
|
|
214
234
|
|
|
215
|
-
return
|
|
235
|
+
return (
|
|
236
|
+
buildRule(selector, always) +
|
|
237
|
+
buildRule(`:root:not(.scheme-dark) ${selector}`, light) +
|
|
238
|
+
buildRule(`.scheme-dark ${selector}`, dark) +
|
|
239
|
+
// A site that follows the visitor's system goes dark through a media query before any
|
|
240
|
+
// class is set — as the theme's own dark tokens do (`generateDarkSchemeCSS`) — so the
|
|
241
|
+
// section's dark values follow it there too. Same specificity as the light rule, later.
|
|
242
|
+
(appearance.default === 'system' && themeDark.length > 0
|
|
243
|
+
? `@media (prefers-color-scheme: dark) {\n${buildRule(`:root:not(.scheme-light) ${selector}`, themeDark)}}\n`
|
|
244
|
+
: '')
|
|
245
|
+
)
|
|
216
246
|
}
|