flowweaver · Installera
Bädda in Flowweaver
Hur mycket ni behöver installera beror på vad ni vill ha ut, och för de flesta är det mindre än de tror. Sidan går i tre steg: svaren i inkorgen, visaren på er sida, och sist det som en utvecklare behöver. Många kan sluta läsa efter det första.
En sak att veta innan du kopplar in det: det här är byggt för den som redigerar, inte för den som installerar. Det avgör mer av det som följer än något tekniskt val gör.
Varje attribut, egenskap, metod och händelse står i API-referensen.
Steg 1 — vill ni bara få in svaren? Välj e-post
Ett formulär behöver någonstans att lämna svaren. Det stället finns redan hos er, och det är inkorgen.
I editorn låter redaktören guiden sluta i en nod som heter E-postresultat. Mottagare, ämne och brödtext skrivs en gång, med svaren insatta som variabler. När besökaren är framme fyller guiden i dem och lämnar ifrån sig ett färdigt meddelande. Ingen databas, ingen mottagare på en server, ingenting någon behöver bygga åt er.
Biblioteket skickar ingenting självt — och säger det rakt ut i editorn: Producerar e-postdata – skickar inte. Meddelandet lämnas över till sidan, som bestämmer vad som händer med det. Det billigaste svaret är att öppna besökarens eget e-postprogram med allt ifyllt; det gör webbläsaren åt er.
<script>
const guide = document.querySelector("guide-preview");
guide.addEventListener("preview-node-changed", () => {
// null ända tills guiden nått sin e-postnod
const brev = guide.getOutput();
if (!brev) return;
window.location.href =
"mailto:" + brev.resolved.to +
"?subject=" + encodeURIComponent(brev.resolved.subject) +
"&body=" + encodeURIComponent(brev.resolved.body);
});
</script>
Brödtexten går med som ren text — ett mailto: bär ingen
formatering. Vill ni ha den formaterad, eller vill ni skicka från er
egen server i stället för från besökarens program, är det samma data ni
läser: getOutput() lämnar mottagare, ämne och brödtext
färdigt ifyllda.
Exempelsidan för e-postresultat kör en sådan guide och visar meddelandet den producerar, rad för rad. Noden byggs i Advanced-editorn.
På väg, men inte färdigt än: mottagare som lämnar svaret direkt i WordPress, i en fil på ert webbhotell eller som en rad i ett kalkylark. De finns inte i dag. Tills de gör det är e-post vägen som inte kräver att någon installerar något åt er.
Steg 2 — en rad lägger visaren på vilken sida som helst
Visaren är en script-tagg. Den fungerar i ett CMS där man kan klistra in HTML, på en sida i ett publiceringsverktyg, i en fil på webbhotellet. Inget konto, ingen token, inget byggsteg.
<script src="https://flowweaver.se/lib/0.12/flowweaver-viewer.global.js"></script>
Resten är er egen guide. Redaktören exporterar den ur editorn som en fil, ni lägger filen bredvid sidan, och sidan hämtar den:
<link rel="stylesheet" href="https://flowweaver.se/lib/tokens.css">
<guide-preview></guide-preview>
<script src="https://flowweaver.se/lib/0.12/flowweaver-viewer.global.js"></script>
<script>
fetch("min-guide.json")
.then((svar) => svar.json())
.then((guide) => { document.querySelector("guide-preview").graph = guide; });
</script>
Filen är er. En äldre fil öppnas i en nyare visare — migreringarna körs när grafen sätts — så en guide ni exporterade i våras fungerar efter en uppdatering av biblioteket.
Det där är hela installationen för den som inte har en utvecklare. Resten av sidan är för den som har en.
Steg 3 — versionerna, npm och editorn
Flowweaver är två vanliga custom elements — <guide-preview> som kör en
färdig guide, och <guide-editor> som redaktören bygger den i. Inget
ramverk krävs. Härifrån och ned står det som en utvecklare behöver veta:
vilken version ni bör peka på, paketen, och editorn.
Två sätt att hämta biblioteket. Välj det första om du bara vill komma igång; det andra passar när du redan har ett byggsteg och vill versionshantera beroendet.
-
Script-tagg
Ladda filen direkt från den här sajten. Inget konto, ingen token, inget byggsteg.
-
npm-paket
@johanfuruskog-create/flowweaver-viewer(MIT) och…/flowweaver-editor(se nedan) från GitHub Packages. Kräver ett token medread:packages.
Visaren är MIT och får köras var som helst. Editorn får provas fritt för utveckling, test och utvärdering. Produktion är all annan användning, oavsett vilken server den körs på, och kräver en licens. Villkoren för den är inte satta än.
Väg 1 — script-tagg
Två filer: bundeln som registrerar elementen, och tokens.css med
temavariablerna. Sedan sätter du grafen på elementet. Samma uppsättning
som i steg 2, men med grafen skriven för hand i stället för hämtad ur en
exporterad fil.
Fungerar överallt, även i CMS:er där man bara kan klistra in en vanlig script-tagg.
Filen slutar på .global.js — det är det klassiska bygget.
Adresserna nedan är rullande. /lib/ byggs
om från main vid varje ändring, så ni får alltid det
senaste — även när det senaste bryter något. Bra för att prova, fel
för något ni kör i drift.
I produktion: peka på en linje. 0.12 är
varje 0.12.x-släpp. Den bär fram en rättelse till er utan att ni rör
något, och aldrig en brytande ändring — en sådan höjer numret. Vill ni
att ingenting alls ska röra sig, skriv hela versionen:
0.12.0.
<script src="https://flowweaver.se/lib/0.12/flowweaver-viewer.global.js"></script>
Byt siffran medvetet, och läs CHANGELOG först — den säger vad ni behöver göra när något bryter.
<link rel="stylesheet" href="https://flowweaver.se/lib/tokens.css">
<guide-preview></guide-preview>
<script src="https://flowweaver.se/lib/flowweaver-viewer.global.js"></script>
<script>
document.querySelector("guide-preview").graph = {
startNodeId: "q1",
nodes: [
{ id: "q1", type: "question", position: { x: 0, y: 0 }, data: {
title: "Har du fyllt 18 år?",
variableName: "isAdult",
options: [
{ id: "yes", label: "Ja", value: "yes" },
{ id: "no", label: "Nej", value: "no" },
] } },
{ id: "ok", type: "result", position: { x: 400, y: 0 }, data: {
title: "Du kan gå vidare" } },
],
connections: [
{ id: "c1", from: { nodeId: "q1", portId: "yes" }, to: { nodeId: "ok", portId: "input" } },
],
};
</script>
Ordningen mellan taggarna spelar ingen roll — sätter du grafen innan bundeln hunnit ladda plockas värdet upp när elementet registreras.
Det där är inte ett påhittat exempel — rutan nedan kör precis den koden, med bundeln hämtad från den här sajten.
Laddar …
Som ES-modul
Har du redan ett byggsteg, eller vill slippa ett globalt namn, finns samma bundle
utan .global:
<script type="module">
import "https://flowweaver.se/lib/flowweaver-viewer.js";
document.querySelector("guide-preview").graph = {
startNodeId: "q1",
nodes: [
{ id: "q1", type: "question", position: { x: 0, y: 0 }, data: {
title: "Har du fyllt 18 år?",
variableName: "isAdult",
options: [
{ id: "yes", label: "Ja", value: "yes" },
{ id: "no", label: "Nej", value: "no" },
] } },
{ id: "ok", type: "result", position: { x: 400, y: 0 }, data: {
title: "Du kan gå vidare" } },
],
connections: [
{ id: "c1", from: { nodeId: "q1", portId: "yes" }, to: { nodeId: "ok", portId: "input" } },
],
};
</script>
Filerna följer senaste versionen. Behöver du en låst version, peka på dess
mapp — till exempel /lib/0.12/ — eller lägg filerna på din egen sajt.
Väg 2 — npm
Paketet ligger på GitHub Packages. Peka scopet dit och lägg ett token med
read:packages i din .npmrc:
@johanfuruskog-create:registry=https://npm.pkg.github.com
//npm.pkg.github.com/:_authToken=DITT_TOKEN
npm install @johanfuruskog-create/flowweaver-viewer
npm install @johanfuruskog-create/flowweaver-editor
Installera antingen visaren eller editorn — editorn bäddar redan in
visaren för sin förhandsvisning, och drar in visarpaketet som beroende för sina typer
och tokens.css.
import "@johanfuruskog-create/flowweaver-viewer";
// eller
import "@johanfuruskog-create/flowweaver-editor";
TypeScript-typer följer med. GraphData och de övriga graftyperna
återexporteras från båda ingångarna.
Editorn
Samma mönster, men du lyssnar på ändringar och sparar dem själv.
feature-level styr hur mycket redaktören ser.
<guide-editor feature-level="advanced"></guide-editor>
<script type="module">
import "@johanfuruskog-create/flowweaver-editor";
const editor = document.querySelector("guide-editor");
editor.graph = existingGraph;
editor.addEventListener("graph-changed", (event) => save(event.detail));
</script>
basic ger den avskalade editorn, advanced är standardläget med
variabler och regler, och service är profilen för e-tjänster. Dolda fält tas
aldrig bort ur grafen — en avancerad guide kan öppnas i enkelt läge och sedan i avancerat
igen, utan dataförlust.
mode säger vad redaktören får göra — readonly är förvalet, och
en okänd inställning stannar där. mode-notice="off" tystar panelens ruta om
varför fälten är låsta. Sätt den bara om din egen yta redan säger det, till exempel en rad
ovanför editorn som namnger den som håller guiden: annars ser låsta fält trasiga ut i
stället för avsiktliga.
Byggt för redaktören, inte för utvecklaren
Tänk på vem som öppnar det här en vanlig tisdag. En regel ändrades i morse, någon väntar på ett svar, och guiden måste vara rätt innan den möter någon som behöver den. Det är inte kunskapen som saknas — de vet precis vad en besökare behöver bli tillfrågad om. Det som saknas är visshet om vad verktyget gör om de rör vid det.
Verktyg för det här jobbet byggs oftast för utvecklaren först, och det är sällan någons fel: de som skriver verktyget förstår modellen bäst, så den kortaste vägen är att exponera den och låta gränssnittet följa med. Det är glasklart för den som byggde det. Alla andra blir i tysthet ombedda att lära sig en datastruktur innan de får ställa en fråga.
Alltså blir man försiktig. Försiktighet ser ut som noggrannhet och kostar som väntetid: ändringen väntar på någon som inte är rädd för systemet, och guiden glider en bit till från reglerna den beskriver. En guide ingen vågar redigera är en guide som blir inaktuell.
Målet är inte att det ska gå att redigera. Det är att det ska kännas tryggt.
Det mesta av det handlar om en enda sak: det ska vara lätt att
backa. Pröva, titta på vad det gjorde, ta tillbaka det om det
blev fel. Varje ändring går att ångra. Dolda fält överlever ett byte av
feature-level, så man förlorar ingenting på att titta. Att
bocka av ett språk lämnar översättningarna kvar. Ingenting förstörs,
alltså behöver ingenting bekräftas — och det editorn visar är det som
sparas, vilket är löftet allt annat vilar på.
Exportera och importera
Verktygsraden skriver ut hela guiden som en JSON-fil och läser in en igen. Den finns av samma skäl som ångra, fast ett nummer större: en redaktör som kan ta en kopia före en stor ändring är en redaktör som gör ändringen.
Värt att visa era redaktörer tidigt, för kopian är deras snarare än er. De kan spara den, lämna den till en kollega, sova på den över en helg, eller ta tillbaka den efter ett experiment som inte ledde någonstans — utan att be någon om en databasåterläsning eller förklara vad som hände. Import kör samma versionsmigreringar som inläsning, så en fil ur en äldre utgåva öppnas i en nyare.
Språk
Tre inställningar, och de rör sig oberoende av varandra. De flesta misstag som görs mot det här biblioteket kommer av att behandla dem som en.
| Inställning | Vems | Sätts med |
|---|---|---|
| Verktygets språk — palett, panel, menyer | ert | editor-locale |
| Guidens innehåll — frågor, svar, resultat | redaktörens och översättarens | active-locale, och verktygsraden |
| Vilka språk som får erbjudas | ert | declareLocales() |
Att översätta innehållet till ett språk får aldrig kräva att verktyget översätts till samma språk. Berättelse 017, regeln de tre inställningarna finns för att hålla
En somalisk guide väntar inte på en somalisk palett — det är vad åtskillnaden köper er.
Svenska och engelska är inbyggda
Varje text paketet levererar — knappar, fältetiketter, valideringsmeddelanden, hela editorn — finns i båda, komplett. Ni registrerar dem inte och ni underhåller dem inte. Ingenting nedan behövs om de två är de språk ni erbjuder.
Deklarera vilka språk som finns
Editorn visar en kryssruta per deklarerat språk, och redaktören bockar för de språk just den guiden ska erbjudas på. Källspråket är alltid ibockat och går inte att bocka av.
import { init } from "@johanfuruskog-create/flowweaver-editor";
init(document.querySelector("guide-editor"), {
graph,
mode: "administrator",
languages: {
offer: ["sv", "en", "fi"], // vad redaktören får bocka i
source: "sv", // vad en NY guide skrivs på
content: "sv", // vilket språk editorn öppnar i
tool: "sv", // gränssnittets eget språk
},
onSave: (graph) => save(graph),
});
Att utelämna offer är inte samma sak som att inte erbjuda något. Redaktören ser då bara de språk guiden redan bär och kan inte lägga till något — vilket är rätt, för listan är er att bestämma, men det betyder också att ingen kan lägga till ett språk förrän ni sagt vilka som finns.
Ett tredje språk
För ett språk paketet inte levererar: skicka med texterna. Uppdelat efter vem som läser dem — viewer är vad en besökare läser,
editor är verktygets egna ord. Ni kan skicka det ena utan det andra — ett paket för besökaren är ofta allt som behövs.
const wiring = init(element, {
languages: { offer: ["sv", "en", "fi"], source: "sv" },
packs: {
fi: {
viewer: { "nav.next": "Seuraava", "nav.previous": "Edellinen" },
},
},
});
wiring.coverage.fi.viewer; // { filled: 2, total: 164, missing: [...] }
init lämnar tillbaka vad varje paket faktiskt täcker, så ni får veta att ett paket når 2 av 92 när ni lämnar över det i stället för när en besökare möter luckan. localeStrings("sv") ger er paketets egna texter som mall att översätta från.
Hela visaren, i en egen fil
Två nycklar inlinade är så det börjar. Ett språk ni faktiskt erbjuder vill ha alltihop, och det hör hemma i en fil ni kan lämna till en översättare och versionshantera, snarare än mitt i er uppsättningskod.
// locales/fi.js — en fil per språk, i ert eget repo.
export default {
viewer: {
"step.number": "Vaihe",
"step.result": "Tulos",
"nav.next": "Seuraava",
"nav.previous": "Edellinen",
"nav.restart": "Aloita alusta",
"validation.required": "Kenttä on pakollinen.",
// … 119 totalt
},
};
import fi from "./locales/fi.js";
const wiring = init(editor, {
languages: { offer: ["sv", "en", "fi"], source: "sv" },
packs: { fi },
});
wiring.coverage.fi.viewer; // { filled: 164, total: 164, missing: [] }
164 nycklar är hela ytan besökaren möter — knappar, fältetiketter, valideringsmeddelanden, alltihop. Be om listan innan ni börjar:
import { coverageOf } from "@johanfuruskog-create/flowweaver-editor";
coverageOf("fi").viewer.missing; // de 164 nycklarna, som en lista
coverageOf("fi").editor.missing; // verktygets egna 1097 — ett annat jobb
Den andra raden är den som är värd att läsa två gånger. Att översätta visaren är 164 texter och ger besökaren hela guiden på sitt språk. Att översätta editorn är 1097 och ger redaktören en finsk palett — värt att göra en dag, aldrig ett villkor för det första. Det är den uppdelningen paketets två halvor finns för att göra tydlig.
Vad en besökare ser när något saknas
Ingenting går sönder och ingen ruta är tom. En saknad text faller tillbaka, i den här ordningen:
det efterfrågade språket
→ dess basspråk (en-GB faller till en)
→ guidens egen källa (settings.sourceLocale)
→ engelska
→ vad texten nu har
Notera tredje steget: en finsk läsare av en svensk guide får svenska på det som inte översatts, inte engelska. Källan är den text författaren faktiskt skrev och den enda som garanterat är komplett.
Och det sägs i stället för att döljas. En besökare som bett om ett språk guiden inte har får läsa varför:
Guiden är inte översatt till finska. Den visas därför på svenska.
Notisen dyker upp på de steg där språket faktiskt bytte under dem, och väljer engelska före källan — hela dess syfte är att läsas av någon som inte kunde läsa guiden.
Kontrollera en uppsättning
checkSetup(element) rapporterar vad som saknas
och vad det leder till, inklusive språk en guide erbjuds på utan texter bakom sig.
import { checkSetup } from "@johanfuruskog-create/flowweaver-editor";
checkSetup(editor);
// { ok: false, findings: [{ id, severity, what, consequence }] }
Den levande versionen av allt det här finns på språksidan, som kör de riktiga anropen och skriver ut vad de gav.
Det här bygger ni hos er
Flowweaver är frontend. Sex ansvar går ut ur den, och bakom vart och ett står ett system som är ert — det är därför guiderna och svaren aldrig behöver lämna er. Varje ansvar har ett skrivet kontrakt som säger vad ni ska svara på, inte hur ni gör det, och Status säger hur långt vi själva kommit.
Detaljerna, och en guide som heter Så integrerar ni på en förmiddag, står i värdsystemskontraktet.
| Ansvar | Vad ni bygger | Status |
|---|---|---|
| Lagring | Arbetskopian, de frusna versionerna, pekaren på den publicerade och låset. Sex regler säger vad som får ändras — en version ändras aldrig, gallring är er och numren döps aldrig om — och var det ligger väljer ni. | Färdig |
| Inlämning | En väg som tar emot svaren och svarar med ett referensnummer. Guiden bär aldrig adressen — bara ett id som ni översätter på er sida, så en intern adress kan inte finnas i en guides JSON eller i besökarens nätverkstrafik. | Färdig |
| E-post | Utskicket är ert, och nyckeln stannar hos er. Besökaren kan också få öppna sitt eget e-postprogram utan någon server alls — men den vägen bifogar inga filer. | Delvis |
| Identitet | Vem redaktören är avgör ni. Kontraktet säger bara vad Authorization får vara — ett token ur er inloggning, eller en cookie. Besökarens identitet är ännu bara en skiss. |
Delvis |
| Uppslag | Fält som söker i era register frågar en BFF hos er, och den avgör vad som får synas. Visaren ställer frågan och ritar svaret; den känner inga register. | Färdig |
| Filer | Bilagor och gallringen av dem är era, eftersom det är era personuppgifter som annars ligger kvar. Guiden bär länkar till bilder, aldrig bilderna själva. | Delvis |
api.flowweaver.se är vår referensimplementation av alla sex. Node och
SQLite är val vi gjorde där, och varje del går att byta — ingenting behöver skickas
till en central Flowweaver-tjänst för att någon av sömmarna ska fungera.
Kontrakten i sin helhet är filer i repot, en per söm. Repot är privat i dag, så hör av er så visar vi dem — och säg gärna till om ni hellre läser dem som sidor här.
Vad din sida äger
Biblioteket är avsiktligt fritt från sidoeffekter utanför komponenterna. Tre saker gör det alltså inte åt dig:
| Ansvar | Vad du behöver göra |
|---|---|
| Lagring |
Editorn autosparar inte, och påstår det aldrig. Lyssna på graph-changed och spara grafen
där du vill ha den. Ctrl+S skickar ett avbrytbart save-request: anropa
preventDefault(), spara, och säg vad som hände — annars säger editorn bara att sidan sköter sparningen.
Vill du inte hitta på en egen modell finns den skriven: arbetskopia, frusna versioner
och en publicerad pekare, enligt lagringssömmen ovan.
|
| Versioner |
<guide-versions> ritar en guides versioner och skickar en avsikt när
någon vill något — den sparar ingenting och bestämmer ingenting. Var versionerna
ligger väljer du, och elementet erbjuder åtta handlingar du kan svara på: lista, läs,
lägg till, uppdatera, kopiera, byt namn, ta bort, anteckna. Du svarar på dem du har —
en värd som följer lagringssömmen ovan svarar på öppna och återställ, och låter
publiceringen skapa versionerna. Det finns färdiga exempel att utgå
från: versionssidan sparar i webbläsaren, och
SiteVision-modulen i repot lägger samma åtta över tre olika lagringar.
|
| Tema |
tokens.css följer operativsystemets ljusa/mörka läge. Vill du styra
det själv sätter du data-theme="dark" eller "light" på
<html>.
Typsnittet är --fw-font, operativsystemets eget (system-ui) tills du
pekar om det på taggarna: guide-editor, guide-preview, guide-versions { --fw-font: …; }.
Layouten prövas före varje släpp mot fyra typsnitt av olika bredd och radhöjd, ett av dem serif.
|
Storlek
Visaren är 53 kB gzip och editorn 127 kB. Bara visaren behöver laddas av slutanvändare — bundlarna är separata just därför.
Höjd
Editorns höjd styrs med CSS-variabler, om standardvärdena inte passar:
<guide-editor
style="--flowweaver-height: 800px; --flowweaver-min-height: 600px"
></guide-editor>
Vidare
Kom igång med editorn beskriver hur en guide byggs. Startsidan samlar fler exempel, från enkel guide till e-tjänst med beräkningar.