Index

mmo-theme-config

1 symbol · generated 5 Oct 2026

element

mmo-theme-config

mmo-theme-config.jhs:1

The theme configurator: every value the theme's .scs token sources declare, editable, previewed live, and written back as Simple CSS.

<mmo-theme-config source="" section="" filter=""></mmo-theme-config>
Extends
CustomShadowElement
It is a face for `MMO\client\ThemeConfigurator`, reached through `MMO\client\controllers\ThemeController` -- the element draws a hint and nothing else when the application did not register that controller, so a page can carry it unconditionally. ### What it edits Not a list of colours: the *expressions* the sources are written with. A row whose value reads `$palette.n50` is a token derived from the neutral ramp, and it keeps that derivation until someone types something else in it -- which is why moving `$brand.s500` moves every token built on the brand. Anything an `.scs` value may be can be typed in a row. ### Reading it Two halves, side by side when there is room: the rows on the left say what a value *is*, the sample on the right says what it *does*, and the sample stays put while the rows are edited. Below that width they stack, with the sample on top. The rows are one **group** at a time -- the groups the sources declare, as tabs with the count of what the filter kept -- because a source of 170 values listed in full is a page nobody reads to the end. Searching and **Changed** look across every group of the source, and the strip says so by falling back to `All`; picking a group drops the search, since that is what a tab click means. ### Seeing what a change implies Every keystroke asks the server to compile the candidate theme, and the answer carries three things this element shows at once: - the **css**, hung in the document's head, so the page and the sample below are painted by a real compilation rather than by an approximation of one; - the **sample**: the real components, in this element's light dom, which is the only place the document's stylesheet can reach them -- a row says what a value *is*, the sample says what it *does*; - the **value of every token** under that theme, which is what lets a token nobody touched be recognised as one that *followed* something that was: those rows are marked apart from the ones that were edited, counted next to the buttons, and **Changed** narrows the list down to just the two. A theme's tokens only paint their own half of it, so the sample carries a light/dark switch: editing the dark map while the page is light changes nothing anyone can see. **Live** stops showing the candidate theme without stopping the compilation -- the rows keep the new values while the page shows the saved ones, which is how the two are compared. Apply** is the only thing that writes: it stores the configuration, regenerates the `.scs` and recompiles the application's stylesheet, then swaps the document's own `<link>` so the page shows the saved theme without reloading. ```html <mmo-theme-config></mmo-theme-config> <!-- a project that would rather see its own components move --> <mmo-theme-config source="dark"> <div class="autogrid">...</div> </mmo-theme-config> ```

Index

sourcethe token source whose groups are shown (the tab), ex: tokens, dark.
sectionthe group of that source to open on; empty opens on all of them
filterwhat the search box holds; a row matches on its name, its custom property, the expression it carries or the value that expression produces
PREVIEW_DELAY statichow long a keystroke waits before the candidate theme is compiled
PREVIEW_ID staticthe id of the <style> this element hangs the previewed theme from, in the document's head
ViewDefault static readonly accessor
constructor()
init()
mountSample()Put the sample where the document's stylesheet can paint it.
readScheme()Read the scheme the page is really showing, so the switch says what is on screen.
setScheme(scheme)Show the theme's other half.
toggleSample()Fold the sample away, for a screen that is all rows.
toggleLive()Stop (or resume) showing the theme being edited.
toggleOnly()Show only what changed and what follows it, or everything again.
disconnectedCallback()Drop the previewed theme when the element goes away: it lives in the document, not in this root.
request(path, method, overrides)Call one of the theme routes.
load()Read the model and the stored configuration.
save()Store the configuration, regenerate the theme and recompile the stylesheet.
resetAll()Drop every override, on the server: the theme goes back to what its sources declare.
revert()Throw away what is not saved and read the stored configuration again.
preview()Compile the candidate theme and show it, writing nothing.
setPayload(data)Render a payload: the sections, their entries, and where the configuration is written.
readEntry(entry)One model entry, as this element renders it.
applyFilter()Show the sections of the chosen source, and inside them the rows the filter keeps.
selectSource(namespace)Show the source whose tab was clicked, on its own first group.
selectSection(key)Show one group, or all of them.
firstGroup(source)
message(state, text)
collect()The overrides to send: every row that no longer says what its source says.
countDirty()Count the rows that differ from their source, for the badge on the apply button.
touch()A row was typed in: count it, and compile the candidate theme once the typing stops.
pick(view, event)Write the colour a picker was moved to into the row's own value.
revertEntry(view)Put back the expression the source declares for one row.
setResolved(resolved, overrides)Show what the server really compiled each row to, and what that change implied.
markRows()Stamp, on every row, what happened to it.
countStates()Say, next to the buttons, how many values were changed and how many followed them.
batch(fn)Run a bulk update of the view as one.
showPreview(css)Hang the previewed token layer in the document's head.
clearPreview(pending)Remove the previewed theme, so the page goes back to the stylesheet it really loaded.
reloadStylesheet(url)Point the document's stylesheet at the css that was just compiled.
ToHex(value) staticRead any css colour as the #rrggbb a native colour picker takes.
(default)the sample the preview paints.

Attributes3

source

mmo-theme-config.jhs

the token source whose groups are shown (the tab), ex: tokens, dark. Empty opens on the first source the server answers with.

source=""

section

mmo-theme-config.jhs

the group of that source to open on; empty opens on all of them

section=""

filter

mmo-theme-config.jhs

what the search box holds; a row matches on its name, its custom property, the expression it carries or the value that expression produces

filter=""

Constants2

PREVIEW_DELAY

staticmmo-theme-config.jhs:362

how long a keystroke waits before the candidate theme is compiled

static PREVIEW_DELAY = 400;

PREVIEW_ID

staticmmo-theme-config.jhs:364

the id of the <style> this element hangs the previewed theme from, in the document's head

static PREVIEW_ID = 'mmo-theme-preview';

Properties1

Methods35

mountSample()

mmo-theme-config.jhs:416

Put the sample where the document's stylesheet can paint it.

mountSample()A page that brought its own markup keeps it -- the sample is a default, not a fixture, and a project is better served seeing *its* components move than this one's. Otherwise the one written in this file is moved out of the shadow root into the light dom, which is the only place `.button`, `.card` and the rest exist.

readScheme()

mmo-theme-config.jhs:429

Read the scheme the page is really showing, so the switch says what is on screen.

readScheme()

setScheme(scheme)

mmo-theme-config.jhs:442

Show the theme's other half.

setScheme(scheme)It goes through `<mmo-app>` when there is one, so the shell's own switch and what it remembers stay in step; an element used outside a shell stamps the attribute itself.
schemestring- light or dark

toggleLive()

mmo-theme-config.jhs:460

Stop (or resume) showing the theme being edited.

toggleLive()The compilation keeps running either way -- what a change moves is still counted and still shown in the rows -- so this is a *comparison*: off is the theme that is saved, on is the one being written.

disconnectedCallback()

mmo-theme-config.jhs:474

Drop the previewed theme when the element goes away: it lives in the document, not in this root.

disconnectedCallback()

request(path, method, overrides)

mmo-theme-config.jhs:495

Call one of the theme routes.

request(path, method = 'GET', overrides = null)`MMO.fetchJSON` throws before the body is read, and the body is exactly what says *why* a theme was refused -- which value, and what the compiler made of it. So the response is read here either way, and a refusal is raised with the server's own message.
pathstring- themeConfig or themePreview
method = 'GET'string- GET, PUT, POST or DELETE
overrides = null?object- the configuration to send, when the route takes one
returnsPromisethe route's payload

save()

mmo-theme-config.jhs:524

Store the configuration, regenerate the theme and recompile the stylesheet.

save()
returnsPromise

resetAll()

mmo-theme-config.jhs:539

Drop every override, on the server: the theme goes back to what its sources declare.

resetAll()

setPayload(data)

mmo-theme-config.jhs:582

Render a payload: the sections, their entries, and where the configuration is written.

setPayload(data)
dataobject- what a theme route answered

readEntry(entry)

mmo-theme-config.jhs:636

One model entry, as this element renders it.

readEntry(entry)
entryobject- an entry of the payload
returnsobject

applyFilter()

mmo-theme-config.jhs:665

Show the sections of the chosen source, and inside them the rows the filter keeps.

applyFilter()A row matches on everything it shows -- its own name, the custom property it is emitted as, the expression it carries and the value that expression produces -- so searching `#2F62F0` finds the ramp step a colour comes from as readily as searching `brand` does.

selectSource(namespace)

mmo-theme-config.jhs:713

Show the source whose tab was clicked, on its own first group.

selectSource(namespace)
namespacestring- a source's namespace, which is its file name

selectSection(key)

mmo-theme-config.jhs:726

Show one group, or all of them.

selectSection(key)Reading is what the tabs are for and searching is what the box is for, so picking a group drops the filter rather than narrowing inside it -- otherwise a tab click would appear to do nothing.
keystring- a section key, or '' for every group of the source

firstGroup(source)

mmo-theme-config.jhs:738
firstGroup(source = null)
source = null?string- the source to look in, defaulting to the one on screen
returnsstringthe key of its first group that has something to edit -- the compiler's own settings are a group too, and landing on a locked row says nothing

message(state, text)

mmo-theme-config.jhs:749
message(state, text)
statestring- busy, ok, error, or empty for nothing at all
textstring- what to say next to the buttons

collect()

mmo-theme-config.jhs:764

The overrides to send: every row that no longer says what its source says.

collect()A row emptied by hand carries no override at all, which is how a value goes back to the one the source declares -- the server reads an empty value the same way.
returnsobjectentry key => expression

countDirty()

mmo-theme-config.jhs:778

Count the rows that differ from their source, for the badge on the apply button.

countDirty()

touch()

mmo-theme-config.jhs:785

A row was typed in: count it, and compile the candidate theme once the typing stops.

touch()

pick(view, event)

mmo-theme-config.jhs:803

Write the colour a picker was moved to into the row's own value.

pick(view, event)Only a real gesture counts. Writing `hex` back after a preview sets the picker's value, and setting an input's value in this framework dispatches `input` (`MMO.core.dom.setAttribute`) -- without this guard, showing a row what its expression compiled to would replace that expression with the literal, and a token would silently stop being derived.
viewMMO.elements.View- the row's view
eventEvent- the event the picker fired

setResolved(resolved, overrides)

mmo-theme-config.jhs:829

Show what the server really compiled each row to, and what that change implied.

setResolved(resolved, overrides)This is where a configuration becomes readable as a *consequence*: the answer carries the value of every token under the candidate theme, so a token nobody touched whose value no longer matches the saved one is a token that **followed** something that was touched -- which is exactly what a row cannot say about itself.
resolvedobject- entry key => the value the compiler produced
overridesobject- what was sent

markRows()

mmo-theme-config.jhs:860

Stamp, on every row, what happened to it.

markRows()One pass over the rows rather than a binding per row: what happened to a row is not a property of that row, it is the answer the server just gave about all of them at once, and it changes on every keystroke.

countStates()

mmo-theme-config.jhs:872

Say, next to the buttons, how many values were changed and how many followed them.

countStates()

batch(fn)

mmo-theme-config.jhs:895

Run a bulk update of the view as one.

batch(fn)Every write to the map queues its listeners on the next animation frame, and the queue is not meant to be added to while it is being drained: this configurator writes hundreds of values at a time -- a filter touches every row, a preview re-reads every value -- so the queue is held shut for the duration and drained once, instead of racing with itself.
fnFunction- the writes to run

showPreview(css)

mmo-theme-config.jhs:911

Hang the previewed token layer in the document's head.

showPreview(css)It is appended last and it is the theme in full, so it wins over the stylesheet's own `:root` without having to know anything about it -- including for the dark theme, whose rules it carries too.
cssstring- the compiled token layer

clearPreview(pending)

mmo-theme-config.jhs:931

Remove the previewed theme, so the page goes back to the stylesheet it really loaded.

clearPreview(pending = true)
pending = trueboolean- false to leave a compilation that is already on its way alone, which is what the live toggle wants: it hides the preview, it does not cancel it

reloadStylesheet(url)

mmo-theme-config.jhs:948

Point the document's stylesheet at the css that was just compiled.

reloadStylesheet(url)The url carries the new file's timestamp, so this is a real reload rather than a cached one -- and a page that has just applied a theme shows it without losing what it was doing.
urlstring- the stylesheet's url, with its cache buster
returnsbooleanfalse when the document links no such stylesheet

ToHex(value)

staticmmo-theme-config.jhs:971

Read any css colour as the #rrggbb a native colour picker takes.

static ToHex(value)Anything the browser understands is understood here, because the browser is what reads it: a value it refuses is not a colour, and the row simply has no picker.
valuestring- a css colour, ex: #EEF3FF, rgba(13, 18, 27, .55), rebeccapurple
returnsstringthe colour as #rrggbb, or an empty string

Slots1

(default)

mmo-theme-config.jhs

the sample the preview paints. A page that provides none gets the one this element ships.

<slot>