geoidesic
geoidesic
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 git@github.com: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
TTyphonJS
Created by geoidesic on 7/4/2023 in #typhonjs-runtime
Drag & Drop broke in v11
Ok so something that broke for me when moving to v11 is drag&drop from both the items tab of the sidebar and from compendiums isn't working. The code I have is:
export default class SvelteDocumentSheet extends SvelteApplication {
async _onDropItem(event, data, actor) {
console.log('_onDropItem');
}
}
export default class SvelteDocumentSheet extends SvelteApplication {
async _onDropItem(event, data, actor) {
console.log('_onDropItem');
}
}
It works in v10 but in v11 it doesn't seem to. No errors but it doesn't trigger. Thoughts?
126 replies
TTyphonJS
Created by geoidesic on 6/8/2023 in #typhonjs-runtime
Storing a collection of Items in an Item?
Use cases would be: - containers could contain other Items - some items have prerequisites, which consist of other Items I'm trying to figure out the best way to represent that. It seems logical that adding Items to an item should be done via drag and drop from a compendium (or from the game items SideBar tab). I can use the BasicDocAppshell.svelte example from essenial-svelte-esm as a reference for drag and drop... but what do I do with the drop? Option 1 Add them as an embedded collection? As far as I can tell, one can't just arbitrarily add an embedded collection or Items to an Item? Option 2 I could just write the uuids or ids to an array in the Item's .system node. But I feel like that's probably expensive as it would involve a db lookup on each item? Option 3 ...?
2 replies
TTyphonJS
Created by geoidesic on 5/26/2023 in #typhonjs-runtime
TJSDialog how to use buttons and callback or return value?
I'm planning to use TJSDialog to act as an intervening Application. So... player clicks a button that would normally generate a ChatMessage. However, a flag causes instead a dialog to appear with several options for the player. Once the decision is made between the options, that information needs to be used by the component that opened the dialog to allow the ChatMessage to be generated at that point. Option 1 I can see that TJSDialog has a mechanism for something along these lines, but I haven't been able to figure out how to use it - managedPromise - seems to be a private property of TJSDialog without a setter. Option 2 It seems that using the prompt function is one way... but a simple binary choice won't be sufficient for my case. It will be more like a radio button with multiple options of which one must be selected. Option 3 Another option would be the onClose callback, provided that I could write a value to return from the dialog, which sounds plausible, except that I'm not sure how to provide buttons to the TJSDialog. It tells me that I can provide them as TJSDialogButtonData types but I can't find that type definition in the runtime codebase. Option 4 I suppose I could write the value to a svelte store, provide a custom button in the content, which writes to that store, then close the dialog when an option is clicked and trigger the onClose callback from there.
6 replies
TTyphonJS
Created by geoidesic on 5/8/2023 in #typhonjs-runtime
How can I create an embeddedCollection in a chat message?
I have this:
const messageDocument = game.messages.get(message._id);
const doc = new TJSDocument(messageDocument);
doc.embedded.create("Targets", targets);
const messageDocument = game.messages.get(message._id);
const doc = new TJSDocument(messageDocument);
doc.embedded.create("Targets", targets);
But I think that might be creating a clone rather than updating the original message?
2 replies