geoidesic
geoidesic
TTyphonJS
Created by geoidesic on 10/15/2024 in #typhonjs-runtime
Is there any way to avoid 'game' is not defined lint error for vite build?
7:09:30 PM [vite-plugin-svelte] /Users/noeldacosta/code/foundryvtt-final-fantasy/src/components/organisms/item/shared/EffectsTab.svelte:172:768 'game' is not defined
170:
7:09:30 PM [vite-plugin-svelte] /Users/noeldacosta/code/foundryvtt-final-fantasy/src/components/organisms/item/shared/EffectsTab.svelte:172:768 'game' is not defined
170:
8 replies
TTyphonJS
Created by geoidesic on 9/26/2024 in #typhonjs-runtime
TJSGameSettings doesn't respect `onChange` option?
So if I have a standard settings registration:
function dontShowWelcome() {
game.settings.register(MODULE_ID, 'dontShowWelcome', {
name: game.i18n.localize('GAS.Setting.DontShowWelcome.Name'),
hint: game.i18n.localize('GAS.Setting.DontShowWelcome.Hint'),
scope: 'user',
config: true,
default: false,
type: Boolean,
onChange: () => {
alert('o');
}
});
function dontShowWelcome() {
game.settings.register(MODULE_ID, 'dontShowWelcome', {
name: game.i18n.localize('GAS.Setting.DontShowWelcome.Name'),
hint: game.i18n.localize('GAS.Setting.DontShowWelcome.Hint'),
scope: 'user',
config: true,
default: false,
type: Boolean,
onChange: () => {
alert('o');
}
});
The alert will trigger. However, if I wrap a setting via TJSGameSettings it won't trigger the onChange hook. E.g.
class trackerSettings extends TJSGameSettings {
this.register({
namespace,
key: "enable-tracker",
options: {
name: game.i18n.localize('Name'),
hint: game.i18n.localize('Hint'),
scope: "world",
config: true,
type: Boolean,
default: true,
onchange: () => {
alert('o');
}
}
});
class trackerSettings extends TJSGameSettings {
this.register({
namespace,
key: "enable-tracker",
options: {
name: game.i18n.localize('Name'),
hint: game.i18n.localize('Hint'),
scope: "world",
config: true,
type: Boolean,
default: true,
onchange: () => {
alert('o');
}
}
});
Am I doing it wrong?
3 replies
TTyphonJS
Created by geoidesic on 8/10/2024 in #typhonjs-runtime
How can I respond to the _onDrop event in the shell?
I'm working with a SvelteApplication. I can edit the _onDrop method on the sheet but how do I react to it in the svelte shell?
30 replies
TTyphonJS
Created by geoidesic on 8/1/2024 in #typhonjs-runtime
What's the best way to control default header items in a TJS application window?
No description
27 replies
TTyphonJS
Created by geoidesic on 7/24/2024 in #typhonjs-runtime
[vite] warning: Could not resolve import "#runtime/svelte/component/core"
I haven't seen this error before. WelcomeAppShell.svelte
import { ApplicationShell } from '#runtime/svelte/component/core';
import { ApplicationShell } from '#runtime/svelte/component/core';
Foundry v12, developing a new system. Any clues?
18 replies
TTyphonJS
Created by geoidesic on 6/28/2024 in #typhonjs-runtime
$actor.toObject() for a TJSDocument isn't reactive
I'm creating an actor in memory and assigning that to the TJSDocument on my application
export default class PCApplication extends SvelteApplication
{
/**
* Document store that monitors updates to any assigned document.
*
* @type {TJSDocument<foundry.abstract.Document>}
*/
#documentStore = new TJSDocument(void 0, { delete: this.close.bind(this) });

constructor(object) {
super(object);

// Define document store property
Object.defineProperty(this.reactive, "document", {
get: () => this.#documentStore.get(),
set: (document) => {
this.#documentStore.set(document);
},
});
this.reactive.document = object;
}

static get defaultOptions() {
const title = this.title;
return foundry.utils.mergeObject(super.defaultOptions, {
id: 'foundryvtt-actor-studio-pc-sheet',
title: game.i18n.localize('GAS.ActorStudio')+' - '+game.i18n.localize('GAS.PCTitle'),
classes: ['gas-actor-studio'],
width: 650,
height: 600,
headerIcon: 'modules/foundryvtt-actor-studio/assets/actor-studio-logo-dragon-white.svg',
minWidth: 500,
padding: 0,
resizable: true,
focusAuto: false,
minimizable: true,
svelte: {
class: PCAppShell,
target: document.body,
props: function () {
return { documentStore: this.#documentStore, document: this.reactive.document };
},
},
});
}
export default class PCApplication extends SvelteApplication
{
/**
* Document store that monitors updates to any assigned document.
*
* @type {TJSDocument<foundry.abstract.Document>}
*/
#documentStore = new TJSDocument(void 0, { delete: this.close.bind(this) });

constructor(object) {
super(object);

// Define document store property
Object.defineProperty(this.reactive, "document", {
get: () => this.#documentStore.get(),
set: (document) => {
this.#documentStore.set(document);
},
});
this.reactive.document = object;
}

static get defaultOptions() {
const title = this.title;
return foundry.utils.mergeObject(super.defaultOptions, {
id: 'foundryvtt-actor-studio-pc-sheet',
title: game.i18n.localize('GAS.ActorStudio')+' - '+game.i18n.localize('GAS.PCTitle'),
classes: ['gas-actor-studio'],
width: 650,
height: 600,
headerIcon: 'modules/foundryvtt-actor-studio/assets/actor-studio-logo-dragon-white.svg',
minWidth: 500,
padding: 0,
resizable: true,
focusAuto: false,
minimizable: true,
svelte: {
class: PCAppShell,
target: document.body,
props: function () {
return { documentStore: this.#documentStore, document: this.reactive.document };
},
},
});
}
Then to open the application:
new PCApplication(new Actor.implementation({ name: 'Name1', folder: folderName, type: actorType })).render(true, { focus: true });
new PCApplication(new Actor.implementation({ name: 'Name1', folder: folderName, type: actorType })).render(true, { focus: true });
PCAppShell does:
export let documentStore;
setContext("#doc", documentStore);
export let documentStore;
setContext("#doc", documentStore);
Then later in another componentI do this:
const doc = getContext('#doc')
$doc.name = "Name2"
console.log($doc.name) //<-- outputs "Name2"
console.log($doc.toObject().name) //<-- outputs "Name1", which is unexpected.
const doc = getContext('#doc')
$doc.name = "Name2"
console.log($doc.name) //<-- outputs "Name2"
console.log($doc.toObject().name) //<-- outputs "Name1", which is unexpected.
4 replies
TTyphonJS
Created by geoidesic on 6/21/2024 in #typhonjs-runtime
v12 seems to break item reactivity for createFilterQuery
I've been trying out my system on v12. Something I notice is that some of my reactive components are no longer reactive. Specifically where I've used createFilterQuery. I don't get any errors but when the items in the wildcard list are changed, the view doesn't update. I mean the filter select still works reactively but if any of the values of the items in the list are altered, or if the core list changes (e.g. item is added or deleted from the original unfiltered list) those changes aren't reactively rendered. I don't understand why that might be but I've tested the same code in both v11 and v12 and it's working in v11. My svelte component looks something like this:
$: typeSearch.set(typeFilterValue);
$: items = [...$wildcard];

/** @type {import('@typhonjs-fvtt/runtime/svelte/store').DynMapReducer<string, Item>} */
const wildcard = doc.embedded.create(Item, {
name: "wildcard",
filters: [nameSearch, typeSearch],
sort: (a, b) => a.name.localeCompare(b.name),
});
$: typeSearch.set(typeFilterValue);
$: items = [...$wildcard];

/** @type {import('@typhonjs-fvtt/runtime/svelte/store').DynMapReducer<string, Item>} */
const wildcard = doc.embedded.create(Item, {
name: "wildcard",
filters: [nameSearch, typeSearch],
sort: (a, b) => a.name.localeCompare(b.name),
});
<template>
<Select options {typeFilterOptions} bind:value={typeFilterValue} />
{#each items as item (item.id)}
.. various item properties
{/each}
<template>
<Select options {typeFilterOptions} bind:value={typeFilterValue} />
{#each items as item (item.id)}
.. various item properties
{/each}
It might not precisely be to do with createFilterQuery. I'm not sure yet why it's happening, but certainly, what was working in v11 is not working in v12.
4 replies
TTyphonJS
Created by geoidesic on 6/19/2024 in #typhonjs-runtime
How to avoid Foundry Globals from causing vite build warnings?
I'm getting a lot of warnings from vite-plugin-svelte for foundry globals like TextEditor.enrichHTML(item.system.description.value || '') . Any idea how I can make it ignore those or register them? E.g.:
1:00:29 PM [vite-plugin-svelte] /Users/me/path/ItemGrant.svelte:35:153 'TextEditor' is not defined
1:00:29 PM [vite-plugin-svelte] /Users/me/path/ItemGrant.svelte:35:153 'TextEditor' is not defined
26 replies
TTyphonJS
Created by geoidesic on 6/15/2024 in #typhonjs-runtime
Dynamic Imports work on dev server but not in build?
I'm having something weird. I'm doing dynamic async imports for certain dynamic components. It's working just find when run via a dev server (e.g. npm run dev) but once I build it, then the imports break. From the error message it seems that the import is done via URL, rather than via code. The URL exists and is browsable in the dev server, but not once built. Am I doing it wrong? Or are dynamic imports not available to the build? E.g.
const importComponent = async (importPath, componentName) => {
const { default: Component } = await import(
/* @vite-ignore */ `../${importPath}${componentName}.svelte`
);
return Component;
};

let importPath;

<div class="tab-content">
{#each tabs as tab}
{#if tab.id === activeTab}
{#if typeof tab.component === 'object'}
<svelte:component this={tab.component} />
{/if}
{#if typeof tab.component === 'string' && importPath}
{#await importComponent(importPath, tab.component)}
<i class="spinner fas fa-circle-notch fa-spin"></i>
{:then Component}
<svelte:component this={Component} />
{:catch error}
<p>Error loading component: {error.message}</p>
{/await}
{/if}
{/if}
{/each}
</div>
</div>
const importComponent = async (importPath, componentName) => {
const { default: Component } = await import(
/* @vite-ignore */ `../${importPath}${componentName}.svelte`
);
return Component;
};

let importPath;

<div class="tab-content">
{#each tabs as tab}
{#if tab.id === activeTab}
{#if typeof tab.component === 'object'}
<svelte:component this={tab.component} />
{/if}
{#if typeof tab.component === 'string' && importPath}
{#await importComponent(importPath, tab.component)}
<i class="spinner fas fa-circle-notch fa-spin"></i>
{:then Component}
<svelte:component this={Component} />
{:catch error}
<p>Error loading component: {error.message}</p>
{/await}
{/if}
{/if}
{/each}
</div>
</div>
So this works if I run the dev server. It seems to find it via URL:
http://localhost:30001/modules/foundryvtt-my-module/components/organisms/dnd5e/Tabs/Abilities.svelte
http://localhost:30001/modules/foundryvtt-my-module/components/organisms/dnd5e/Tabs/Abilities.svelte
However, once built, the path it looks for changes, leaving out the module id and reporting a 404:
http://localhost:3000/modules/components/organisms/dnd5e/Tabs/Abilities.svelte
http://localhost:3000/modules/components/organisms/dnd5e/Tabs/Abilities.svelte
Even if I correct the ommssion in the URL manually I still see a 404 Any ideas?
22 replies
TTyphonJS
Created by geoidesic on 6/10/2024 in #typhonjs-runtime
Can I use markdown with TJSProseMirror?
No description
2 replies
TTyphonJS
Created by geoidesic on 5/31/2024 in #typhonjs-runtime
What's the TJS way to extend FormApplication?
Specifically I want a custom type to register a component via game.settings.register e.g. a multi-select or checkbox list. E.g. I currently have this:
game.settings.registerMenu(MODULE_ID, SettingKeys.SOURCES, {
name: 'compendiums'),
label: 'Compendiums'),
icon: 'fas fa-atlas',
type: CompendiumSourcesSubmenu,
restricted: true,
});
game.settings.registerMenu(MODULE_ID, SettingKeys.SOURCES, {
name: 'compendiums'),
label: 'Compendiums'),
icon: 'fas fa-atlas',
type: CompendiumSourcesSubmenu,
restricted: true,
});
But I would like that CompendiumSourcesSubmenu to be a svelte component, rather than the TypeScript / Handlebars extension to FormApplication that it currently is (as it has been ported from an existing module)
9 replies
TTyphonJS
Created by geoidesic on 5/23/2024 in #typhonjs-runtime
dnd5e reactivity with race.advancement.byID
I'm having trouble when fetching a race byUuid with one particular reactive var:
const selectHandler = async (option) => {
race = await fromUuid(option);
console.log(source); //<-- works
console.log(adv); //<-- undefined
console.log(race.advancement.byId); //<-- works
}
$: source = race?.system?.source;
$: adv = race?.advancement?.byId;
const selectHandler = async (option) => {
race = await fromUuid(option);
console.log(source); //<-- works
console.log(adv); //<-- undefined
console.log(race.advancement.byId); //<-- works
}
$: source = race?.system?.source;
$: adv = race?.advancement?.byId;
Any ideas? Why adv is undefined? (The only special thing about byId is that it's a getter)
7 replies
TTyphonJS
Created by geoidesic on 5/21/2024 in #typhonjs-runtime
Error in $doc.update()?
I'm not quite sure if I'm doing it wrong. The error I'm getting is:
foundry.js:13637 Uncaught (in promise) Error: You must provide an _id for every object in the update data Array.
at #preUpdateDocumentArray (foundry.js:13637:32)
at ClientDatabaseBackend._updateDocuments (foundry.js:13449:73)
at ClientDatabaseBackend.update (commons.js:8677:19)
at async Actor5e.updateDocuments (commons.js:8001:23)
at async Actor5e.update (commons.js:8098:23)
foundry.js:13637 Uncaught (in promise) Error: You must provide an _id for every object in the update data Array.
at #preUpdateDocumentArray (foundry.js:13637:32)
at ClientDatabaseBackend._updateDocuments (foundry.js:13449:73)
at ClientDatabaseBackend.update (commons.js:8677:19)
at async Actor5e.updateDocuments (commons.js:8001:23)
at async Actor5e.update (commons.js:8098:23)
Here's the component
<script>
import { log, update } from "~/src/helpers/Utility";
import { Timing } from "@typhonjs-fvtt/runtime/util";
import { createEventDispatcher, getContext, onDestroy, onMount } from "svelte";

export let document = false;

const dispatch = createEventDispatcher();
const doc = document || getContext("#doc");
const updateDebounce = (path) => Timing.debounce($doc.update({[path]: event.target.value }), 300);

$: systemAbilities = game.system.config.abilities
$: systemAbilitiesArray = Object.entries(systemAbilities);

</script>

<template lang="pug">
.attribute-entry.mt-sm
+each("systemAbilitiesArray as ability, index")
.flexrow.mb-sm
.flex1 {ability[1].label}
.flex3.right
input(type="number" value="{$doc.system.abilities[ability[1].abbreviation].value}" on:input="{updateDebounce(`system.abilities.${ability[1].abbreviation}.value`)}" style="width: 40px")

</template>
<script>
import { log, update } from "~/src/helpers/Utility";
import { Timing } from "@typhonjs-fvtt/runtime/util";
import { createEventDispatcher, getContext, onDestroy, onMount } from "svelte";

export let document = false;

const dispatch = createEventDispatcher();
const doc = document || getContext("#doc");
const updateDebounce = (path) => Timing.debounce($doc.update({[path]: event.target.value }), 300);

$: systemAbilities = game.system.config.abilities
$: systemAbilitiesArray = Object.entries(systemAbilities);

</script>

<template lang="pug">
.attribute-entry.mt-sm
+each("systemAbilitiesArray as ability, index")
.flexrow.mb-sm
.flex1 {ability[1].label}
.flex3.right
input(type="number" value="{$doc.system.abilities[ability[1].abbreviation].value}" on:input="{updateDebounce(`system.abilities.${ability[1].abbreviation}.value`)}" style="width: 40px")

</template>
Normally (e.g. in my system, as opposed to this module) $doc.update() just works for me. I haven't seen this _id error before. It seems weird because update is being called on $doc, which is a TJSDocument instance of the actor, so it has the _id already I would expect.
5 replies
TTyphonJS
Created by geoidesic on 5/11/2024 in #typhonjs-runtime
local link of the runtime
Because the current runtime has some build issues and also because I am trying to debug something (i.e. application css overflow), I would like to be able to edit the runtime. I tried editing the runtime in node_modules but changes weren't seen (even after clearing vite-cache. Yarn offers yarn patch and yarn link which are potential solutions. However, when I tried to git clone [email protected]:typhonjs-fvtt-lib/typhonjs.git I got confused because it does not contain the same folders / files as in node_modules @typhonjs-fvtt/runtime. So the question is how do I get a local, editable copy of the runtime linked to my local module for debugging? Specifically I want to edit and debug in @typhonjs-fvtt/runtime/_dist/svelte/component/core/application/ApplicationShell
7 replies
TTyphonJS
Created by geoidesic on 5/10/2024 in #typhonjs-runtime
importing from the runtime
I see this in the template-svelte-esm example:
import { ApplicationShell } from '#runtime/svelte/component/core';
import { ApplicationShell } from '#runtime/svelte/component/core';
I'm not familiar with this syntax – i.e. the # here in the path. What does it mean and what enables it? I looked in vite.config.js and the # symbol doesn't appear in that file. I also couldn't find anything about that being standard sugar for ESM6 syntax.
5 replies
TTyphonJS
Created by geoidesic on 5/10/2024 in #typhonjs-runtime
lang localization in svelte template?
So far I've only managed to do this via data-tooltip, which picks up the localization string magically (presumably a FoundryVTT feature). What's the best way to use localization strings in a TJS-inspired svelte template directly? I tried this:
export const lang = game.i18n.localize;

<header> {lang("MY.langstring")} </header>
export const lang = game.i18n.localize;

<header> {lang("MY.langstring")} </header>
... but no go
33 replies
TTyphonJS
Created by geoidesic on 5/7/2024 in #typhonjs-runtime
How can I use typescript with `template-svelte-esm`?
Is there a way to get the template-svelte-esm HMR working with typescript? I had a go but wasn't able. Like it builds but the URL doesn't work, can't serve the built index.js file for some reason. I'm guessing that HMR is not possible if I'm using typescript? So I'd have to build each time?
2 replies
TTyphonJS
Created by geoidesic on 9/19/2023 in #typhonjs-runtime
How to get rid of funky Prosemirror overlap
No description
14 replies
TTyphonJS
Created by geoidesic on 7/10/2023 in #typhonjs-runtime
Update to ChatMessage outside of Svelte doesn't trigger reactivity on linked TJSDocument
I'm a bit confused about this... 1. When I render a ChatMessage via svelte, in the chat message svelte component I do:
let foundryChatMessageDocument = new TJSDocument(void 0, { delete: () => {} }),

onMount(async () => {
await foundryChatMessageDocument.set(await game.messages.get(messageId));
let foundryChatMessageDocument = new TJSDocument(void 0, { delete: () => {} }),

onMount(async () => {
await foundryChatMessageDocument.set(await game.messages.get(messageId));
2. At various points in the workflow I save updates to the chat message using:
await $foundryChatMessageDocument.update({
flags: {
surge: { data: { contest: contestsData } },
},
});
await $foundryChatMessageDocument.update({
flags: {
surge: { data: { contest: contestsData } },
},
});
Which works reactivly. 3. However, I then have a class, which is not a svelte component because it represents shared logic. In that class I also update the chat message like so:
const message = game.messages.get(messageId);
message.update({ flags: { surge: { data: { contest } } } })
const message = game.messages.get(messageId);
message.update({ flags: { surge: { data: { contest } } } })
These changes are not however picked up within foundryChatMessageDocument reactively. I assume that is expected. However, is there a way I can make the update to the chat message in point 3 be reactively picked up by the TJSDocument?
9 replies
TTyphonJS
Created by geoidesic on 7/6/2023 in #typhonjs-runtime
How do I get the elementRoot of a ChatMessage?
SvelteApplication provides elementRoot prop to components that implement it, which is very useful. I'm looking to get something similar for my Svelte chat message templates. I'm using this in index.js
Hooks.on('renderChatMessage, (message, html) => {
message._svelteComponent = new SurgeRoll(
{
target: html[0],
props: {
surgeMessage,
messageId: message._id
}
}
)
}
Hooks.on('renderChatMessage, (message, html) => {
message._svelteComponent = new SurgeRoll(
{
target: html[0],
props: {
surgeMessage,
messageId: message._id
}
}
)
}
SurgeRoll.svelte does this:
<script>
import * as ChatComponents from "~/view/chatmessage/rollchat";
export let surgeMessage;
</script>

<svelte:component this={ChatComponents[surgeMessage.chatTemplate]} {...$$props} />
<script>
import * as ChatComponents from "~/view/chatmessage/rollchat";
export let surgeMessage;
</script>

<svelte:component this={ChatComponents[surgeMessage.chatTemplate]} {...$$props} />
The svelte:component is the component in which I want to get hold of that root element. Specifically I want to be able to do something like:
elementRoot.style.setProperty("--sheet-color", owner.color);
elementRoot.style.setProperty("--sheet-color", owner.color);
... which I'm currently using successfully in my SvelteApplication ActorSheet component.
7 replies