Question: Modifying class list of SvelteApplication

A question from @dorako:
so, my module hooks into renderApplication and modifies the html[0].classList to add a .dorako-ui class to most Applications, but this strategy does not work for Svelte Applications. I had suspected this would be the case, but I'm not sure why or how to fix it.
Would I need to submit some sort of update to the SvelteApplication to push my dorako-ui class to the options.classes?
22 Replies
Dorako
Dorako•2y ago
My logging suggests that hook is triggering my code, but manipulating the DOM isn't working. If I manually add the .dorako-ui class to the application frame, the results are as expected (broad styling changes, replacing the background image etc.)
No description
TyphonJS (Michael)
TyphonJS (Michael)OP•2y ago
And you can't add the class in the defaultOptions classes entry? Also there is a onSvelteMount callback that passes back the the element in an object.
onSvelteMount({ element })
{
element.classList.add('dorako-ui');
}
onSvelteMount({ element })
{
element.classList.add('dorako-ui');
}
This occurs after the render callbacks from Foundry, but not sure why you can't add a class to the ApplicationShell component per se. --- I suppose this brings up a possibility of making the optional classes entry data reactive. So you can add / remove optional classes and have the default application shells automatically update.
Dorako
Dorako•2y ago
Would this not need to be in the Svelte-based module itself? In this specific case I'm trying to affect the Item Piles module which uses TJS, but Dorako UI itself is just ol' boring JS and CSS
TyphonJS (Michael)
TyphonJS (Michael)OP•2y ago
Gotcha, so you are trying to provide a global theming module.
One of the catches with this approach is that you have to keep in mind in general that there is an option in the core Application to limit the callbacks that are generated: baseApplication. So renderApplication may not always trigger for every app. Is it perhaps CSS specificity that is causing a problem? Can you see the dorako-ui class added when you look at the DOM in browser dev tools?
Dorako
Dorako•2y ago
Yeah, lots of the pf2e system sheets don't trigger renderApplication which is a pain, so I have a list of those specific application names. It's not a question of CSS specificity, the class isn't in the DOM
No description
Dorako
Dorako•2y ago
If I add the class manually by editing the DOM in the inspector I see the expected results (my "base theme" styling applying)
No description
TyphonJS (Michael)
TyphonJS (Michael)OP•2y ago
I'll just take a minute to add a renderApplication hook in a demo and see what happens.
Dorako
Dorako•2y ago
Awesome, thanks
TyphonJS (Michael)
TyphonJS (Michael)OP•2y ago
So what is happening in this case is that the html JQuery reference that is passed back in that hook is the default Foundry outer application shell that is not used when mounting a Svelte component which controls the outer application shell. If you add the class in onSvelteMount it works fine. A workaround that may or may not be considered acceptable is using setTimeout in renderApplication like this:
Hooks.on('renderApplication, (app) =>
{
setTimeout(() => app.element[0].classList.add('doraku-ui'), 0);
});
Hooks.on('renderApplication, (app) =>
{
setTimeout(() => app.element[0].classList.add('doraku-ui'), 0);
});
Actually I just verified that you don't need the timeout. This works fine:
Hooks.on('renderApplication, (app) =>
{
app.element[0].classList.add('doraku-ui');
});
Hooks.on('renderApplication, (app) =>
{
app.element[0].classList.add('doraku-ui');
});
It also appears to work fine for normal Foundry applications.
Dorako
Dorako•2y ago
well now! Are there any potential implications of affecting the app's classlist through the element list, rather than through the jquery reference?
TyphonJS (Michael)
TyphonJS (Michael)OP•2y ago
It should be the same element / value actually except in the SvelteApplication loading case where html is the unused outer application shell. By that time element is the mounted Svelte component.
Dorako
Dorako•2y ago
Hooks.on("renderSvelteApplication", (app) => {
app.element[0].classList.add("dorako-ui");
});
Hooks.on("renderSvelteApplication", (app) => {
app.element[0].classList.add("dorako-ui");
});
Works great and shouldn't interfere with my existing stuff
TyphonJS (Michael)
TyphonJS (Michael)OP•2y ago
I'd say again you have to be careful in this approach as it won't universally work for any apps that define baseApplication. There shouldn't be any problems with the code w/ renderApplication and using app.element[0]. IE no need to add custom code for TRL handling.
Dorako
Dorako•2y ago
I'll probably use a strict list like I do for the system applications, so I'll only affect the stuff I know to be compatible
TyphonJS (Michael)
TyphonJS (Michael)OP•2y ago
If this is for particular systems to like PF2E then you have a bit more freedom in specific targeting vs a broad UI overhaul module.
Dorako
Dorako•2y ago
I primarily support PF2e, but SWADE is also supported
TyphonJS (Michael)
TyphonJS (Michael)OP•2y ago
Yeah in that case you can check game.system.id I believe and generate hooks dynamically for game system specific cases where baseApplication is defined.
// Unique app names that use `baseApplication` option.
const systemAppHooks = {
pf2e: ['PF2EActor', 'SomethingUnique'],
swade: [...]
}

Hooks.once('init', () =>
{
Hooks.on('renderApplication', (app) => app.element[0].classList.add('doraku-ui'));

const customApps = systemAppHooks[game.system.id] ?? [];
for (appName of customApps)
{
Hooks.on(`render${appName}`, (app) => app.element[0].classList.add('doraku-ui'));
}
});
// Unique app names that use `baseApplication` option.
const systemAppHooks = {
pf2e: ['PF2EActor', 'SomethingUnique'],
swade: [...]
}

Hooks.once('init', () =>
{
Hooks.on('renderApplication', (app) => app.element[0].classList.add('doraku-ui'));

const customApps = systemAppHooks[game.system.id] ?? [];
for (appName of customApps)
{
Hooks.on(`render${appName}`, (app) => app.element[0].classList.add('doraku-ui'));
}
});
Dorako
Dorako•2y ago
unrelated question, but to what extent can I assume that the specificity-raising selectors like in .item.active.underscore.svelte-14iev2w will remain the same?
TyphonJS (Michael)
TyphonJS (Michael)OP•2y ago
I wouldn't rely on it. The package author can modify the hash svelte-14iev2w, but it is also auto generated based on styles of the component, so it can change if the styles embedded in a component changes.
Dorako
Dorako•2y ago
Perfect, I can apply the styling how I want it now
No description
No description
TyphonJS (Michael)
TyphonJS (Michael)OP•2y ago
You could use a regex though for styles. Quite likely the svelte- part won't change unless the package author completely generates a custom hash which is not as likely. So... .item .active .underscore [class^="svelte-"] if you had to override specific styles defined by the component. Err.. You might have to play around with the regex. Not sure how that would work with chaining previous classes. It looks like you got things going though! 😄
Dorako
Dorako•2y ago
Yeah I just opted for minimal touches, and I avoided the specificity class by just using other classes instead. Thanks for the help! If I ever do up creating a module that contains applications I'll be sure to use TJS. Just moving the window around is a world of difference as always.
Want results from more Discord servers?
Add your server