@bazous/ui 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +150 -0
- package/dist/answers/AnswerPicture.d.ts +13 -0
- package/dist/answers/contract.d.ts +160 -0
- package/dist/answers/draw.d.ts +16 -0
- package/dist/answers/index.d.ts +6 -0
- package/dist/answers/messages.d.ts +3 -0
- package/dist/answers.js +10 -0
- package/dist/answers.js.map +1 -0
- package/dist/canvas/index.d.ts +32 -0
- package/dist/canvas.js +285 -0
- package/dist/canvas.js.map +1 -0
- package/dist/contract/snapshot.d.ts +173 -0
- package/dist/engine/scenario.d.ts +40 -0
- package/dist/format/index.d.ts +37 -0
- package/dist/i18n/index.d.ts +25 -0
- package/dist/i18n/shared.d.ts +3 -0
- package/dist/index-yeBMtDf1.js +649 -0
- package/dist/index-yeBMtDf1.js.map +1 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.js +1258 -0
- package/dist/index.js.map +1 -0
- package/dist/modules/Question.d.ts +18 -0
- package/dist/modules/available-now/index.d.ts +8 -0
- package/dist/modules/due-before-payday/index.d.ts +9 -0
- package/dist/modules/low-point/index.d.ts +12 -0
- package/dist/modules/margin-after-payday/index.d.ts +9 -0
- package/dist/modules/monthly-structure/index.d.ts +24 -0
- package/dist/modules/next-actions/index.d.ts +13 -0
- package/dist/modules/pay-cycles/index.d.ts +31 -0
- package/dist/modules/registry.d.ts +7 -0
- package/dist/modules/types.d.ts +77 -0
- package/dist/modules/what-if/index.d.ts +6 -0
- package/dist/primitives/CashflowChart.d.ts +22 -0
- package/dist/primitives/index.d.ts +57 -0
- package/dist/styles.css +1 -0
- package/package.json +84 -0
- package/schema/answers.schema.json +719 -0
- package/schema/canvas.json +181 -0
- package/schema/snapshot.schema.json +821 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Bazous and contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
# Bazous UI
|
|
2
|
+
|
|
3
|
+
**Le kit d’interface open source de [Bazous](https://bazous.com).** Chaque question d’argent — *combien ai-je maintenant ? que dois-je payer avant le salaire ? jusqu’où puis-je descendre ?* — est un module indépendant, rendu en cinq langues à partir d’un contrat de données public. La communauté peut en ajouter, les améliorer ou les traduire sans jamais toucher à un compte, une clé ou une donnée réelle.
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/@bazous/ui) [Galerie en ligne](https://bazousdotcom.github.io/ui/) · [La matrice des questions](docs/matrix.md) · [Contribuer](CONTRIBUTING.md) · [English below](#english)
|
|
6
|
+
|
|
7
|
+
## Ce qu’il y a dedans
|
|
8
|
+
|
|
9
|
+
| Dossier | Rôle |
|
|
10
|
+
| --- | --- |
|
|
11
|
+
| `schema/snapshot.schema.json` | Le contrat : la réponse de l’API Bazous (`GET /api/v1/cockpit`), la seule chose que le kit connaît. |
|
|
12
|
+
| `schema/canvas.json` | Le contrat du canevas Capture : balises, classes et intentions qu’une IA a le droit d’écrire. |
|
|
13
|
+
| `src/modules/<id>/` | Un module = une question. Une fonction pure `select(snapshot)` et une vue React. |
|
|
14
|
+
| `src/primitives/` | Carte, tuile, ligne, bouton, courbe de trésorerie. |
|
|
15
|
+
| `src/i18n/`, `src/format/` | Cinq langues (FR, DE, IT, RM, EN) et les chiffres suisses : `3’420.50` partout. |
|
|
16
|
+
| `src/engine/scenario.ts` | Le seul calcul du kit : rejouer les échéances quand on active un levier « et si ». |
|
|
17
|
+
| `src/canvas/` | Le CSS et le pont du canevas Capture (iframe isolée, aucune requête réseau). |
|
|
18
|
+
| `fixtures/` | Trois ménages fictifs produits par le vrai moteur Bazous, et leurs réponses (`answers-*.json`). |
|
|
19
|
+
| `src/answers/` | Les dessins des réponses : une fonction `drawVisual()` sans React, et le composant `<AnswerPicture>`. |
|
|
20
|
+
| `schema/answers.schema.json` | Le contrat des réponses et de leur bloc `visual`. |
|
|
21
|
+
| `gallery/` | La galerie publique : tous les modules, les réponses dessinées et la matrice, cinq langues, deux thèmes. |
|
|
22
|
+
| `docs/matrix.md` | La matrice : les 16 questions, leur module, leur dessin, et celles qui attendent le leur. |
|
|
23
|
+
|
|
24
|
+
## Les modules
|
|
25
|
+
|
|
26
|
+
**Une question, une réponse d’expert.** On ne demande pas à la personne de savoir quoi demander : chaque module arrive avec la réponse. Un module réussi se lit en une phrase — un verdict, sa tonalité (tout va bien, attention, risque) et, si besoin, le « parce que ».
|
|
27
|
+
|
|
28
|
+
| id | Question | Taille | Lit dans le contrat | Montre aujourd’hui | Intentions émises | Réponse d’expert ? | Ce qui manque | Verdict visé (exemple fictif) |
|
|
29
|
+
| --- | --- | --- | --- | --- | --- | --- | --- | --- |
|
|
30
|
+
| `available-now` | Combien ai-je maintenant ? | tuile | `opening_balance`, `accounts`, `data_quality` | Le disponible, et « N comptes sans solde » | — | ✅ oui | La fraîcheur du chiffre | « 3’420.50 CHF disponibles · 1 compte sans solde, chiffre incomplet » |
|
|
31
|
+
| `due-before-payday` | Que dois-je payer avant le salaire ? | tuile | `due_before_next_income`, `gap_before_next_income`, `opening_balance`, `next_income_date` | « Couvert · il reste X » ou « Il manque X avant le revenu » | — | ✅ oui, le modèle à suivre | — | déjà en place |
|
|
32
|
+
| `low-point` | Jusqu’où puis-je descendre ? | tuile | `low_point`, `next_income_date`, `second_income_date` | Point bas prévu et sa date, « N jours avant le revenu » | — | ✅ en grande partie | Une tonalité : +50 et −1’200 se ressemblent | « Point bas −1’240 le 20.10 · découvert 4 jours avant le salaire » |
|
|
33
|
+
| `margin-after-payday` | Que me restera-t-il ? | tuile | `end_of_horizon`, `second_income_date`, `data_quality` | La marge à une date, signalée si des récurrences n’ont pas de montant | — | ✅ oui | — | déjà en place |
|
|
34
|
+
| `monthly-structure` | Combien me coûte un mois ? | étroite | `structure`, `debts`, `data_quality` | Charges fixes / revenus, taux, marge structurelle, dettes | — | ⚠️ surtout des chiffres | Un jugement : ce taux est-il sain ? | « Vos charges fixes prennent 76 % du revenu : il reste ≈ 2’200 CHF / mois » |
|
|
35
|
+
| `next-actions` | Que faire ensuite ? | large | `actions`, `next_income_date` | « N décisions · M min », groupées et accompagnées d’un conseil | `mark_paid`, `reschedule`, `classify_transaction`, `review_obligation`, `open` | ✅ oui, le plus « expert » | — | déjà en place |
|
|
36
|
+
| `pay-cycles` | Qu’est-ce qui tombe à chaque salaire ? | pleine largeur | `cycles`, `events`, `next_income_date`, `horizon_end` | La liste des échéances par cycle de paie | `mark_paid`, `open` | ⚠️ une liste, pas de conclusion | Dire quel cycle est serré | « Le cycle 24.10 → 24.11 est le plus serré : 5’600 sortent pour 4’800 entrés » |
|
|
37
|
+
| `what-if` | Et si je décale un paiement ? | pleine largeur | `points`, `events`, `main_cycle`, `low_point`, `end_of_horizon`… (11 champs) | Courbe, horizon, « Pourquoi ? », leviers à activer, « Enregistrer comme scénario » | `set_horizon`, `save_scenario` | ❌ demande à la personne d’explorer | Proposer d’emblée le meilleur levier | « Le meilleur geste : reporter le loyer au 24.10 → aucun jour sous zéro » |
|
|
38
|
+
|
|
39
|
+
**Bilan de la 0.1 :** 5 modules répondent, 2 affichent des données, 1 demande d’explorer. Aucun module ne renvoie `null` : face à des données incomplètes, ils répondent en partie et le signalent.
|
|
40
|
+
|
|
41
|
+
**Prochaine étape (0.2) :** rendre la réponse obligatoire dans le contrat — chaque module fournira un verdict d’une phrase avec sa tonalité, testé dans les cinq langues — puis donner un verdict à `monthly-structure` et `pay-cycles`, et faire de `what-if` « le meilleur geste », recommandation d’abord. Les contributions sur ces trois modules sont les bienvenues.
|
|
42
|
+
|
|
43
|
+
## Les réponses dessinées
|
|
44
|
+
|
|
45
|
+
Bazous répond aussi en phrases (`GET /api/v1/answers`, et l’outil MCP `get_household_answers` pour Claude et ChatGPT). Une réponse peut porter un bloc `visual` : la forme du dessin, les chiffres à dessiner et une légende qui dit la même réponse sous un autre angle. Tout est calculé par le moteur ; le kit dessine.
|
|
46
|
+
|
|
47
|
+
| `kind` | Question | Ce que le dessin montre |
|
|
48
|
+
| --- | --- | --- |
|
|
49
|
+
| `runway` | Que dois-je payer avant le salaire ? | La piste jusqu’au jour de paie, les factures en chemin, le disponible face à ce qui est dû |
|
|
50
|
+
| `valley` | Jusqu’où puis-je descendre ? | La vallée du solde, la zone sous zéro, le point bas |
|
|
51
|
+
| `shift` | Et si je décale un paiement ? | Avant / après : la facture déplacée au jour de paie, les deux courbes rejouées par le moteur |
|
|
52
|
+
| `days` | Combien de temps tiendrais-je sans revenu ? | Les jours de charges fixes couverts, sur les 90 conseillés |
|
|
53
|
+
| `balance` | Qu’est-ce qui tombe à chaque salaire ? | Ce qui entre face à ce qui sort, et le trou |
|
|
54
|
+
| `countdown` | Ma prime d’assurance maladie augmente-t-elle ? | Le compte à rebours jusqu’à l’échéance, la marche de la prime |
|
|
55
|
+
| `horizon` | Que me restera-t-il ? | La courbe jusqu’à la fin de la période, la ligne d’arrivée et ce qu’elle représente en jours de charges fixes |
|
|
56
|
+
| `calendar` | Quelle grosse dépense de l’année arrive bientôt ? | Les 90 prochains jours et les factures annuelles qui y tombent |
|
|
57
|
+
| `leak` | Est-ce que je paie des frais évitables ? | Ce que les frais font sur 10 ans |
|
|
58
|
+
| `jar` | Ai-je mis de côté pour mes impôts ? | Douze mois à remplir face au bordereau, ce que cela fait par jour |
|
|
59
|
+
| `gauge` | Puis-je encore verser sur mon 3e pilier ? | Versé et encore possible jusqu’au plafond, et les jours jusqu’au 31.12 |
|
|
60
|
+
| `deadline` | Un contrat doit-il être résilié bientôt ? | Aujourd’hui, le jour où la lettre doit arriver, le renouvellement |
|
|
61
|
+
|
|
62
|
+
```tsx
|
|
63
|
+
import { AnswerPicture, type Answers } from "@bazous/ui";
|
|
64
|
+
|
|
65
|
+
function Answer({ answer, locale }: { answer: Answers["answers"][number]; locale: "fr" }) {
|
|
66
|
+
return (
|
|
67
|
+
<article>
|
|
68
|
+
<p>{answer.question}</p>
|
|
69
|
+
<AnswerPicture visual={answer.visual} locale={locale} />
|
|
70
|
+
{answer.visual && <p>{answer.visual.caption}</p>}
|
|
71
|
+
<p>{answer.answer}</p>
|
|
72
|
+
</article>
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Sans React (une page statique, la carte des assistants) : `import { drawVisual } from "@bazous/ui/answers"` renvoie un `SVGSVGElement`, ou `null` quand il n’y a rien à dessiner. Le dessin suit le thème par les jetons `--bz-*`.
|
|
78
|
+
|
|
79
|
+
Les questions encore sans dessin (« Combien ai-je maintenant ? », « Que faire ensuite ? », « Combien me coûte un mois ? », « Et si l’un des revenus manquait ? ») sont ouvertes aux contributions : ouvrez une issue avec votre angle. La [matrice](docs/matrix.md) (et sa [version vivante](https://bazousdotcom.github.io/ui/#view=matrix)) montre où en est chaque question.
|
|
80
|
+
|
|
81
|
+
## Les règles qui ne bougent pas
|
|
82
|
+
|
|
83
|
+
1. **Aucun réseau.** Un module ne fait ni requête, ni stockage, ni cookie. Il émet une intention (`mark_paid`, `reschedule`, `open`…) que l’application exécute. Un test parcourt `src/` et échoue sinon.
|
|
84
|
+
2. **Le moteur calcule, le kit montre.** Les modules sélectionnent et mettent en forme des chiffres déjà calculés côté serveur. Exception assumée : le rejeu des leviers, qui sans levier reproduit la courbe du moteur au centime (testé).
|
|
85
|
+
3. **Cinq langues ou rien.** Chaque clé existe dans les cinq langues, chaque module est rendu dans les cinq langues et les trois ménages de test sans clé manquante, `NaN` ou `undefined`.
|
|
86
|
+
4. **Chiffres suisses.** `3’420.50` dans toutes les langues, vrai signe moins, dates courtes `24.09`. Les nombres ne passent jamais par `Intl` (les navigateurs ne s’accordent pas sur fr-CH et it-CH).
|
|
87
|
+
5. **Données fictives uniquement** dans ce dépôt.
|
|
88
|
+
|
|
89
|
+
## Utiliser le kit
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
npm install @bazous/ui
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
```tsx
|
|
96
|
+
import "@bazous/ui/styles.css";
|
|
97
|
+
import { Dashboard, MODULES, type ModuleAction, type Snapshot } from "@bazous/ui";
|
|
98
|
+
|
|
99
|
+
function Cockpit({ snapshot }: { snapshot: Snapshot }) {
|
|
100
|
+
const onAction = (action: ModuleAction) => {
|
|
101
|
+
// l’application appelle son API avec le jeton de l’utilisateur, puis recharge le snapshot
|
|
102
|
+
};
|
|
103
|
+
return <Dashboard modules={MODULES} snapshot={snapshot} locale="fr" theme="dark" onAction={onAction} />;
|
|
104
|
+
}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Les polices ne sont pas embarquées : chargez Playfair Display (500, 600) et Montserrat (400, 500, 600).
|
|
108
|
+
|
|
109
|
+
## Développer
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
npm install
|
|
113
|
+
npm run dev # galerie sur http://localhost:5173
|
|
114
|
+
npm run check # types, tests, build
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## Traductions
|
|
118
|
+
|
|
119
|
+
Le romanche suit le Rumantsch Grischun ; une relecture par un·e locuteur·rice natif·ve est la bienvenue (étiquette `langue:rm`).
|
|
120
|
+
|
|
121
|
+
## Licence
|
|
122
|
+
|
|
123
|
+
MIT. Le kit est libre ; la marque Bazous, son logo et le service Bazous Cloud ne sont pas couverts par cette licence.
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
## English
|
|
128
|
+
|
|
129
|
+
**Bazous UI is the open-source interface kit of [Bazous](https://bazous.com).** Every money question is a self-contained module rendered in five languages (French, German, Italian, Romansh, English) from a public data contract (`schema/snapshot.schema.json`). Modules never touch the network: they select numbers the Bazous engine already computed and emit intents the host app executes. Fixtures are fictitious and generated by the real engine. Install with `npm install @bazous/ui`. The [question matrix](docs/matrix.md) lists every question, its module and its picture. See [CONTRIBUTING.md](CONTRIBUTING.md) to add a question; `npm run check` must pass. Licensed MIT; the Bazous name and logo are not.
|
|
130
|
+
|
|
131
|
+
### The modules at a glance
|
|
132
|
+
|
|
133
|
+
One question, one expert answer: people should not have to know what to ask. Each module should read as a single sentence — a verdict, its tone (fine, watch out, risk) and, when useful, the reason.
|
|
134
|
+
|
|
135
|
+
| id | Question | Expert answer today? | What is missing |
|
|
136
|
+
| --- | --- | --- | --- |
|
|
137
|
+
| `available-now` | How much do I have now? | ✅ yes | How fresh the figure is |
|
|
138
|
+
| `due-before-payday` | What do I owe before payday? | ✅ yes — the model to follow | — |
|
|
139
|
+
| `low-point` | How low might I go? | ✅ mostly | A tone: +50 and −1’200 look alike |
|
|
140
|
+
| `margin-after-payday` | What will be left? | ✅ yes | — |
|
|
141
|
+
| `monthly-structure` | What does a month cost me? | ⚠️ mostly figures | A judgement: is this ratio healthy? |
|
|
142
|
+
| `next-actions` | What next? | ✅ yes — the most "expert" | — |
|
|
143
|
+
| `pay-cycles` | What falls due each pay cycle? | ⚠️ a list, no conclusion | Which cycle is tight |
|
|
144
|
+
| `what-if` | What if I move a payment? | ❌ asks the person to explore | Lead with the best lever |
|
|
145
|
+
|
|
146
|
+
Next (0.2): make the answer part of the contract (a one-sentence verdict with a tone, tested in all five languages), then give `monthly-structure` and `pay-cycles` a verdict and turn `what-if` into "the best move". Contributions on these three modules are welcome.
|
|
147
|
+
|
|
148
|
+
### Answers with pictures
|
|
149
|
+
|
|
150
|
+
Bazous also answers in sentences (`GET /api/v1/answers`, and the MCP tool `get_household_answers` for Claude and ChatGPT). An answer may carry a `visual` block: the kind of picture (`runway`, `valley`, `shift`, `days`, `balance`, `countdown`, `horizon`, `calendar`, `leak`, `jar`, `gauge`, `deadline`), the figures to draw and a caption that says the same answer from another angle. The engine computes everything; the kit draws it, with `<AnswerPicture>` in React or `drawVisual()` from `@bazous/ui/answers` anywhere else. The contract is `schema/answers.schema.json`. Questions without a picture yet (available now, next actions, monthly structure, income loss) are open for contributions.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Locale } from "../i18n";
|
|
2
|
+
import type { AnswerVisual } from "./contract";
|
|
3
|
+
export type AnswerPictureProps = {
|
|
4
|
+
visual: AnswerVisual | null | undefined;
|
|
5
|
+
locale: Locale;
|
|
6
|
+
className?: string;
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* The picture of an answer, drawn by the same code as in the assistants' card. Nothing when there is none.
|
|
10
|
+
* It is laid out at the width of its container and redrawn when that width changes, so the labels keep
|
|
11
|
+
* their size on a phone.
|
|
12
|
+
*/
|
|
13
|
+
export declare function AnswerPicture({ visual, locale, className }: AnswerPictureProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import type { Decimal, IsoDate } from "../contract/snapshot";
|
|
2
|
+
/**
|
|
3
|
+
* The answers Bazous gives (`GET /api/v1/answers`, and the MCP tool `get_household_answers`),
|
|
4
|
+
* as far as a view needs them. The engine computes everything, including the `visual` block:
|
|
5
|
+
* the kind of picture, the figures to draw and a caption that says the answer from that angle.
|
|
6
|
+
* Published as schema/answers.schema.json.
|
|
7
|
+
*/
|
|
8
|
+
/** A balance at the end of a day: [iso date, balance]. */
|
|
9
|
+
export type BalancePoint = [IsoDate, Decimal];
|
|
10
|
+
type Visual<K extends string, T> = {
|
|
11
|
+
kind: K;
|
|
12
|
+
caption: string;
|
|
13
|
+
} & T;
|
|
14
|
+
/** « Que dois-je payer avant le salaire ? » — a runway from today to payday, bills on the way. */
|
|
15
|
+
export type RunwayVisual = Visual<"runway", {
|
|
16
|
+
today: IsoDate;
|
|
17
|
+
payday: IsoDate;
|
|
18
|
+
available: Decimal;
|
|
19
|
+
due: Decimal;
|
|
20
|
+
/** available − due: negative when something is missing. */
|
|
21
|
+
gap: Decimal;
|
|
22
|
+
bills: {
|
|
23
|
+
label: string;
|
|
24
|
+
amount: Decimal;
|
|
25
|
+
date: IsoDate;
|
|
26
|
+
}[];
|
|
27
|
+
/** Days before payday with the balance below zero. */
|
|
28
|
+
short_days: number;
|
|
29
|
+
}>;
|
|
30
|
+
/** « Jusqu’où puis-je descendre ? » — the valley of the balance. */
|
|
31
|
+
export type ValleyVisual = Visual<"valley", {
|
|
32
|
+
series: BalancePoint[];
|
|
33
|
+
low: {
|
|
34
|
+
date: IsoDate;
|
|
35
|
+
balance: Decimal;
|
|
36
|
+
};
|
|
37
|
+
days_below_zero: number;
|
|
38
|
+
incomes: IsoDate[];
|
|
39
|
+
}>;
|
|
40
|
+
/** « Et si je décale un paiement ? » — before and after moving one bill (both curves by the engine). */
|
|
41
|
+
export type ShiftVisual = Visual<"shift", {
|
|
42
|
+
before: BalancePoint[];
|
|
43
|
+
after: BalancePoint[];
|
|
44
|
+
move: {
|
|
45
|
+
label: string;
|
|
46
|
+
amount: Decimal;
|
|
47
|
+
from: IsoDate;
|
|
48
|
+
to: IsoDate;
|
|
49
|
+
};
|
|
50
|
+
low_before: Decimal;
|
|
51
|
+
low_after: Decimal;
|
|
52
|
+
}>;
|
|
53
|
+
/** « Combien de temps tiendrais-je sans revenu ? » — days of fixed costs covered, out of the advised ones. */
|
|
54
|
+
export type DaysVisual = Visual<"days", {
|
|
55
|
+
covered: number;
|
|
56
|
+
target: number;
|
|
57
|
+
balance?: Decimal;
|
|
58
|
+
}>;
|
|
59
|
+
/** « Qu’est-ce qui tombe à chaque salaire ? » — what comes in against what goes out in a pay cycle. */
|
|
60
|
+
export type BalanceVisual = Visual<"balance", {
|
|
61
|
+
in: Decimal;
|
|
62
|
+
out: Decimal;
|
|
63
|
+
gap: Decimal;
|
|
64
|
+
start: IsoDate;
|
|
65
|
+
end: IsoDate;
|
|
66
|
+
}>;
|
|
67
|
+
/** « Ma prime d’assurance maladie augmente-t-elle ? » — a countdown to a deadline, and the premium step. */
|
|
68
|
+
export type CountdownVisual = Visual<"countdown", {
|
|
69
|
+
deadline: IsoDate;
|
|
70
|
+
days_left: number;
|
|
71
|
+
window_days: number;
|
|
72
|
+
current?: Decimal | null;
|
|
73
|
+
next?: Decimal | null;
|
|
74
|
+
increase_per_year?: Decimal | null;
|
|
75
|
+
}>;
|
|
76
|
+
/** « Que me restera-t-il ? » — the curve to the end of the period, and where it finishes. */
|
|
77
|
+
export type HorizonVisual = Visual<"horizon", {
|
|
78
|
+
series: BalancePoint[];
|
|
79
|
+
end: {
|
|
80
|
+
date: IsoDate;
|
|
81
|
+
balance: Decimal;
|
|
82
|
+
};
|
|
83
|
+
/** When the end is below zero: how many days of fixed costs the hole represents. */
|
|
84
|
+
days_of_fixed_costs: number | null;
|
|
85
|
+
}>;
|
|
86
|
+
/** « Quelle grosse dépense de l’année arrive bientôt ? » — the next 90 days and the yearly bills in them. */
|
|
87
|
+
export type CalendarVisual = Visual<"calendar", {
|
|
88
|
+
today: IsoDate;
|
|
89
|
+
until: IsoDate;
|
|
90
|
+
items: {
|
|
91
|
+
label: string;
|
|
92
|
+
amount: Decimal;
|
|
93
|
+
date: IsoDate;
|
|
94
|
+
days: number;
|
|
95
|
+
per_month: Decimal;
|
|
96
|
+
}[];
|
|
97
|
+
}>;
|
|
98
|
+
/** « Est-ce que je paie des frais évitables ? » — what the fees add up to, year after year. */
|
|
99
|
+
export type LeakVisual = Visual<"leak", {
|
|
100
|
+
per_year: Decimal;
|
|
101
|
+
years: number;
|
|
102
|
+
total: Decimal;
|
|
103
|
+
items: {
|
|
104
|
+
label: string;
|
|
105
|
+
}[];
|
|
106
|
+
}>;
|
|
107
|
+
/** « Ai-je mis de côté pour mes impôts ? » — twelve months to fill before the bill. */
|
|
108
|
+
export type JarVisual = Visual<"jar", {
|
|
109
|
+
bill: Decimal;
|
|
110
|
+
needed_per_month: Decimal;
|
|
111
|
+
set_aside_per_month: Decimal;
|
|
112
|
+
per_day: Decimal;
|
|
113
|
+
}>;
|
|
114
|
+
/** « Puis-je encore verser sur mon 3e pilier ? » — paid and still possible, up to the legal limit, until 31.12. */
|
|
115
|
+
export type GaugeVisual = Visual<"gauge", {
|
|
116
|
+
year: number;
|
|
117
|
+
limit: Decimal;
|
|
118
|
+
paid: Decimal;
|
|
119
|
+
left: Decimal;
|
|
120
|
+
deadline: IsoDate;
|
|
121
|
+
days_left: number;
|
|
122
|
+
}>;
|
|
123
|
+
/** « Un contrat doit-il être résilié bientôt ? » — today, the day the letter must arrive, the renewal. */
|
|
124
|
+
export type DeadlineVisual = Visual<"deadline", {
|
|
125
|
+
today: IsoDate;
|
|
126
|
+
contracts: {
|
|
127
|
+
name: string;
|
|
128
|
+
ends_on: IsoDate;
|
|
129
|
+
cancel_before: IsoDate;
|
|
130
|
+
days_left: number;
|
|
131
|
+
}[];
|
|
132
|
+
}>;
|
|
133
|
+
export type AnswerVisual = RunwayVisual | ValleyVisual | ShiftVisual | DaysVisual | BalanceVisual | CountdownVisual | HorizonVisual | CalendarVisual | LeakVisual | JarVisual | GaugeVisual | DeadlineVisual;
|
|
134
|
+
export type VisualKind = AnswerVisual["kind"];
|
|
135
|
+
export declare const VISUAL_KINDS: readonly ["runway", "valley", "shift", "days", "balance", "countdown", "horizon", "calendar", "leak", "jar", "gauge", "deadline"];
|
|
136
|
+
export type AnswerTone = "risk" | "warn" | "info";
|
|
137
|
+
export type Answer = {
|
|
138
|
+
id: string;
|
|
139
|
+
question: string;
|
|
140
|
+
answer: string;
|
|
141
|
+
tone: AnswerTone;
|
|
142
|
+
because: string | null;
|
|
143
|
+
source: "kit" | "expert";
|
|
144
|
+
figures: Record<string, unknown>;
|
|
145
|
+
needs: string[];
|
|
146
|
+
visual?: AnswerVisual;
|
|
147
|
+
};
|
|
148
|
+
export type Answers = {
|
|
149
|
+
as_of: IsoDate;
|
|
150
|
+
currency: string;
|
|
151
|
+
language: string;
|
|
152
|
+
headline: string;
|
|
153
|
+
answers: Answer[];
|
|
154
|
+
all_clear: {
|
|
155
|
+
id: string;
|
|
156
|
+
question: string;
|
|
157
|
+
short: string;
|
|
158
|
+
}[];
|
|
159
|
+
};
|
|
160
|
+
export {};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type Locale } from "../i18n";
|
|
2
|
+
import type { AnswerVisual } from "./contract";
|
|
3
|
+
/**
|
|
4
|
+
* The picture is laid out at the width it is shown (one unit = one pixel), so its 11px labels stay
|
|
5
|
+
* 11px on a phone instead of being shrunk with the drawing. Below 260 it is scaled down, above 320 up.
|
|
6
|
+
*/
|
|
7
|
+
export declare const MIN_WIDTH = 260;
|
|
8
|
+
export declare const MAX_WIDTH = 320;
|
|
9
|
+
/** Long labels are shortened so they never leave the picture. */
|
|
10
|
+
export declare const shorten: (label: string, max?: number) => string;
|
|
11
|
+
export type DrawOptions = {
|
|
12
|
+
/** The width the picture is shown at, in CSS pixels (its container's width). 320 by default. */
|
|
13
|
+
width?: number;
|
|
14
|
+
};
|
|
15
|
+
/** The picture of one answer, or null when there is none (or it cannot be drawn). */
|
|
16
|
+
export declare function drawVisual(visual: AnswerVisual | null | undefined, locale: Locale, doc?: Document, options?: DrawOptions): SVGSVGElement | null;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/** Answer pictures without React: for pages that are not React apps (such as the assistants' card). */
|
|
2
|
+
export type * from "./contract";
|
|
3
|
+
export { VISUAL_KINDS } from "./contract";
|
|
4
|
+
export { MAX_WIDTH, MIN_WIDTH, drawVisual, shorten } from "./draw";
|
|
5
|
+
export type { DrawOptions } from "./draw";
|
|
6
|
+
export { answerMessages } from "./messages";
|
package/dist/answers.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"answers.js","sources":[],"sourcesContent":[],"names":[],"mappings":";"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Capture canvas: the public contract between an AI model and the Bazous UI.
|
|
3
|
+
*
|
|
4
|
+
* A model writes an HTML fragment for a captured bill. The server rejects any tag,
|
|
5
|
+
* attribute, class or intent outside these lists, the fragment runs in a sandboxed
|
|
6
|
+
* iframe with a CSP that forbids the network, and buttons only emit named intents.
|
|
7
|
+
* The same lists are enforced server-side; a test keeps them identical.
|
|
8
|
+
*/
|
|
9
|
+
export declare const CANVAS_TAGS: readonly ["section", "article", "header", "footer", "div", "span", "p", "h1", "h2", "h3", "h4", "ul", "ol", "li", "dl", "dt", "dd", "table", "thead", "tbody", "tr", "th", "td", "strong", "em", "b", "i", "small", "br", "hr", "button", "label", "input", "select", "option", "textarea", "figure", "figcaption", "blockquote", "code", "time", "mark"];
|
|
10
|
+
export declare const CANVAS_ATTRIBUTES: readonly ["class", "id", "type", "name", "value", "placeholder", "for", "checked", "selected", "disabled", "min", "max", "step", "rows", "datetime", "title", "aria-label", "role", "data-intent", "data-field", "data-payload", "colspan", "scope", "data-pct"];
|
|
11
|
+
export declare const CANVAS_INTENTS: readonly ["confirm", "discard", "answer", "reschedule", "mark_internal_transfer", "open_cockpit"];
|
|
12
|
+
export type CanvasIntent = (typeof CANVAS_INTENTS)[number];
|
|
13
|
+
export declare const CANVAS_FIELDS: readonly ["label", "amount", "currency", "due_date", "category"];
|
|
14
|
+
export declare const CANVAS_CLASSES: readonly ["page", "eyebrow", "title", "lead", "muted", "small", "card", "card-head", "tile", "tile-dark", "tile-value", "amount", "neg", "pos", "row", "date", "list", "grid-2", "grid-3", "chip", "chip-warn", "chip-ok", "banner", "banner-warn", "impact", "impact-before", "impact-after", "arrow", "question", "field", "actions", "button", "button-primary", "button-ghost", "source", "confidence", "timeline", "timeline-item", "table", "kv", "kpis", "kpi-label", "kpi-value", "kpi-note", "bars", "bar", "bar-label", "bar-track", "bar-fill", "bar-fill-2", "bar-fill-3", "bar-fill-4", "bar-value", "meter", "meter-fill", "stack", "stack-seg-1", "stack-seg-2", "stack-seg-3", "stack-seg-4", "legend", "legend-item", "swatch-1", "swatch-2", "swatch-3", "swatch-4", "spark", "spark-col", "spark-col-warn", "delta", "delta-up", "delta-down", "timeline-h", "timeline-h-item", "timeline-h-item-now", "timeline-h-item-warn", "gauge", "gauge-fill"];
|
|
15
|
+
/** Classes whose width (height for spark columns) comes from `data-pct="0..100"`, never from `style`. */
|
|
16
|
+
export declare const CANVAS_SIZED_CLASSES: readonly ["bar-fill", "bar-fill-2", "bar-fill-3", "bar-fill-4", "meter-fill", "gauge-fill", "stack-seg-1", "stack-seg-2", "stack-seg-3", "stack-seg-4", "spark-col", "spark-col-warn"];
|
|
17
|
+
export declare const CANVAS_CSS = "\n:root,[data-theme=dark]{color-scheme:dark;--ground:#0B0B0B;--ground-2:#1f1e1b;--card:#1A1A1A;--line:#3a3833;--line-2:#2a2926;--ink:#F5F3ED;--ink-2:#D9D6CE;--ink-3:#B7B5AE;--muted:#9a978f;--ember:#FF9292;--ember-2:#FFB4B4;--ember-bg:#392425;--ember-line:#6b3a3a;--gold:#DAAF37;--gold-2:#E8C46E;--leaf:#76CCA1;--leaf-bg:#1d3a2c;--contrast-bg:#0B0B0B;--contrast-line:#DAAF37;--contrast-ink:#F5F3ED;--contrast-muted:#B7B5AE;--quote:#23211d;--mark:#5a4a1c;--sans:\"Montserrat\",system-ui,-apple-system,\"Segoe UI\",sans-serif;--serif:\"Playfair Display\",Georgia,serif}\n[data-theme=light]{color-scheme:light;--ground:#F5F3ED;--ground-2:#eae8e1;--card:#FFFFFF;--line:#cdd0d2;--line-2:#e2e3e2;--ink:#15191F;--ink-2:#323943;--ink-3:#555E6B;--muted:#838a93;--ember:#B33535;--ember-2:#8c2b2b;--ember-bg:#fff0f0;--ember-line:#e4b2b2;--gold:#896313;--gold-2:#DAAF37;--leaf:#1B704A;--leaf-bg:#e3f3ea;--contrast-bg:#0B0B0B;--contrast-line:#0B0B0B;--contrast-ink:#F5F3ED;--contrast-muted:#B7B5AE;--quote:#fbf8ee;--mark:#fbf3dd}\n*{box-sizing:border-box}\nhtml,body{margin:0;background:var(--ground);color:var(--ink);font-family:var(--sans);font-size:15px;line-height:1.45}\n.page{display:flex;flex-direction:column;gap:16px;padding:8px 4px 24px}\nh1,h2,h3,h4{font-family:var(--serif);font-weight:600;margin:0;letter-spacing:-.01em}\nh1,.title{font-size:1.7rem;line-height:1.1}h2{font-size:1.2rem}h3{font-size:1.05rem}\np{margin:0}\n.eyebrow{color:var(--gold);letter-spacing:.14em;font-size:.72rem;font-weight:600;text-transform:uppercase}\n.lead{font-size:1.02rem;color:var(--ink-3)}\n.muted{color:var(--ink-3)}.small{font-size:.8rem}\n.card{background:var(--card);border:1px solid var(--line);border-radius:14px;padding:18px 20px;display:flex;flex-direction:column;gap:10px}\n.card-head{display:flex;align-items:baseline;justify-content:space-between;gap:12px;flex-wrap:wrap}\n.tile{background:var(--card);border:1px solid var(--line);border-radius:14px;padding:16px 18px;display:flex;flex-direction:column;gap:6px}\n.tile-dark{background:var(--contrast-bg);border-color:var(--contrast-line);color:var(--contrast-ink)}\n.tile-dark .eyebrow,.tile-dark .muted{color:var(--contrast-muted)}\n.tile-value{font-family:var(--serif);font-size:2rem;font-weight:600;letter-spacing:-.02em;line-height:1;font-variant-numeric:tabular-nums}\n.tile-dark .tile-value{color:var(--gold-2)}\n.amount{font-variant-numeric:tabular-nums;font-weight:600;white-space:nowrap}\n.neg{color:var(--ember)}.pos{color:var(--leaf)}\n.grid-2{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px}\n.grid-3{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:12px}\n.list{display:flex;flex-direction:column}\n.row{display:flex;align-items:center;gap:12px;padding:10px 0;border-top:1px solid var(--line-2);font-size:.9rem}\n.row:first-child{border-top:0}\n.date{width:48px;flex:none;color:var(--muted);font-variant-numeric:tabular-nums}\n.chip{display:inline-block;font-size:.74rem;font-weight:600;padding:4px 10px;border-radius:999px;background:var(--ground-2);color:var(--ink-2)}\n.chip-warn{background:var(--ember-bg);color:var(--ember-2)}\n.chip-ok{background:var(--leaf-bg);color:var(--leaf)}\n.banner{padding:12px 16px;border-radius:12px;background:var(--ground-2);font-size:.9rem}\n.banner-warn{background:var(--ember-bg);border:1px solid var(--ember-line);color:var(--ember-2)}\n.impact{display:flex;align-items:center;gap:14px;padding:14px 18px;background:var(--contrast-bg);border:1px solid var(--contrast-line);color:var(--contrast-ink);border-radius:12px;font-variant-numeric:tabular-nums;flex-wrap:wrap}\n.impact-before{color:var(--contrast-muted);font-size:1.05rem}\n.impact-after{color:var(--gold-2);font-family:var(--serif);font-size:1.6rem;font-weight:600}\n.arrow{color:var(--contrast-muted);font-size:1.2rem}\n.question{padding:12px 14px;background:var(--quote);border:1px solid var(--line);border-radius:10px;display:flex;flex-direction:column;gap:8px;font-size:.92rem}\n.field{display:flex;flex-direction:column;gap:4px;font-size:.78rem;font-weight:600;color:var(--muted);letter-spacing:.04em;text-transform:uppercase}\n.field input,.field select,.field textarea{font:500 15px var(--sans);color:var(--ink);border:1px solid var(--line);border-radius:8px;padding:9px 11px;background:var(--card);text-transform:none;letter-spacing:0}\n.field input:focus,.field select:focus,.field textarea:focus{outline:2px solid var(--gold);border-color:var(--gold)}\n.actions{display:flex;gap:10px;flex-wrap:wrap;align-items:center}\n.button{font:600 13px var(--sans);border:1px solid var(--line);border-radius:10px;padding:0 14px;height:38px;background:var(--card);color:var(--ink);cursor:pointer}\n.button-primary{background:var(--gold-2);border-color:var(--gold-2);color:#0B0B0B}\n.button-ghost{background:transparent;color:var(--gold)}\n.button:hover{filter:brightness(.97)}\n.source{font-size:.82rem;color:var(--ink-3);border-left:3px solid var(--gold);padding:6px 12px;background:var(--quote);border-radius:0 8px 8px 0;font-style:italic}\n.confidence{font-size:.78rem;color:var(--muted)}\n.timeline{display:flex;flex-direction:column;gap:0}\n.timeline-item{display:flex;gap:12px;padding:8px 0;border-left:2px solid var(--line);padding-left:14px;font-size:.88rem;position:relative}\n.timeline-item::before{content:\"\";position:absolute;left:-6px;top:14px;width:10px;height:10px;border-radius:50%;background:var(--ink)}\n.table{width:100%;border-collapse:collapse;font-size:.88rem}\n.table th,.table td{text-align:left;padding:8px 6px;border-bottom:1px solid var(--line-2)}\n.table th{font-size:.74rem;letter-spacing:.06em;text-transform:uppercase;color:var(--muted)}\n.kv{display:grid;grid-template-columns:auto 1fr;gap:6px 16px;font-size:.9rem}\n.kv dt{color:var(--muted)}.kv dd{margin:0;font-weight:500}\nhr{border:0;border-top:1px solid var(--line-2);margin:4px 0}\n/* dashboard primitives \u2014 sized by data-pct, applied by the bridge */\n.kpis{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:12px}\n.kpi-label{font-size:.7rem;font-weight:600;letter-spacing:.08em;text-transform:uppercase;color:var(--muted)}\n.tile-dark .kpi-label{color:var(--contrast-muted)}\n.kpi-value{font-family:var(--serif);font-size:1.75rem;font-weight:600;letter-spacing:-.02em;line-height:1.05;font-variant-numeric:tabular-nums}\n.tile-dark .kpi-value{color:var(--gold-2)}\n.kpi-note{font-size:.78rem;color:var(--ink-3)}\n.tile-dark .kpi-note{color:var(--contrast-muted)}\n.bars{display:flex;flex-direction:column;gap:8px}\n.bar{display:grid;grid-template-columns:minmax(90px,38%) 1fr auto;align-items:center;gap:10px;font-size:.86rem}\n.bar-label{color:var(--ink-2);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n.bar-track{display:block;height:9px;border-radius:5px;background:var(--ground-2);overflow:hidden}\n.bar-fill,.bar-fill-2,.bar-fill-3,.bar-fill-4{display:block;height:100%;border-radius:5px;width:0;transition:width .35s ease}\n.bar-fill{background:var(--gold-2)}.bar-fill-2{background:var(--ink)}.bar-fill-3{background:var(--ink-2)}.bar-fill-4{background:var(--muted)}\n.bar-value{font-variant-numeric:tabular-nums;font-weight:600;white-space:nowrap}\n.meter,.gauge{display:block;height:8px;border-radius:4px;background:var(--ground-2);overflow:hidden}\n.meter-fill,.gauge-fill{display:block;height:100%;border-radius:4px;width:0;background:var(--leaf);transition:width .35s ease}\n.gauge{height:14px;border-radius:7px}.gauge-fill{background:var(--gold)}\n.stack{display:flex;height:14px;border-radius:7px;overflow:hidden;background:var(--ground-2)}\n.stack-seg-1,.stack-seg-2,.stack-seg-3,.stack-seg-4{display:block;height:100%;width:0}\n.stack-seg-1{background:var(--gold-2)}.stack-seg-2{background:var(--ink)}.stack-seg-3{background:var(--ink-2)}.stack-seg-4{background:var(--muted)}\n.legend{display:flex;flex-wrap:wrap;gap:6px 16px;font-size:.8rem;color:var(--ink-3)}\n.legend-item{display:inline-flex;align-items:center;gap:6px}\n.swatch-1,.swatch-2,.swatch-3,.swatch-4{display:inline-block;width:10px;height:10px;border-radius:2px}\n.swatch-1{background:var(--gold-2)}.swatch-2{background:var(--ink)}.swatch-3{background:var(--ink-2)}.swatch-4{background:var(--muted)}\n.spark{display:flex;align-items:flex-end;gap:3px;height:56px;padding:4px 0;border-bottom:1px solid var(--line)}\n.spark-col,.spark-col-warn{display:block;flex:1;min-width:6px;height:0;border-radius:2px 2px 0 0;background:var(--ink)}\n.spark-col-warn{background:var(--ember)}\n.delta{display:inline-block;font-size:.8rem;font-weight:600;padding:2px 8px;border-radius:999px;background:var(--ground-2);font-variant-numeric:tabular-nums}\n.delta-up{background:var(--leaf-bg);color:var(--leaf)}.delta-down{background:var(--ember-bg);color:var(--ember-2)}\n.timeline-h{display:flex;gap:0;overflow:hidden;border-radius:10px;border:1px solid var(--line);background:var(--card)}\n.timeline-h-item{flex:1;padding:10px 12px;font-size:.8rem;color:var(--ink-3);border-left:1px solid var(--line-2);position:relative;min-width:0}\n.timeline-h-item:first-child{border-left:0}\n.timeline-h-item::before{content:\"\";display:block;width:8px;height:8px;border-radius:50%;background:var(--muted);margin-bottom:6px}\n.timeline-h-item-now{color:var(--gold);font-weight:600}.timeline-h-item-now::before{background:var(--gold)}\n.timeline-h-item-warn{background:var(--ember-bg);color:var(--ember-2);font-weight:600}.timeline-h-item-warn::before{background:var(--ember)}\nmark{background:var(--mark);padding:0 3px;border-radius:3px}\n@media (max-width:640px){.grid-2,.grid-3{grid-template-columns:1fr}.tile-value{font-size:1.6rem}.kpi-value{font-size:1.4rem}.timeline-h{flex-direction:column}.timeline-h-item{border-left:0;border-top:1px solid var(--line-2)}.timeline-h-item:first-child{border-top:0}}\n";
|
|
18
|
+
/** Runs inside the sandbox: sizes data-pct elements and forwards intents and field values to the host. */
|
|
19
|
+
export declare const CANVAS_BRIDGE = "\n(function(){\n function fields(){var o={};document.querySelectorAll('[data-field]').forEach(function(el){o[el.getAttribute('data-field')]=el.value;});return o;}\n document.addEventListener('click',function(ev){\n var btn=ev.target.closest('[data-intent]');if(!btn)return;ev.preventDefault();\n var payload=btn.getAttribute('data-payload');\n var q=btn.closest('.question');var answer=null;\n if(q){var inp=q.querySelector('input,select,textarea');if(inp)answer=inp.value;}\n parent.postMessage({source:'billminder-canvas',intent:btn.getAttribute('data-intent'),payload:payload,answer:answer,fields:fields()},'*');\n });\n function size(){document.querySelectorAll('[data-pct]').forEach(function(el){var p=Math.max(0,Math.min(100,parseInt(el.getAttribute('data-pct'),10)||0));var c=el.className||'';if(c.indexOf('spark-col')>=0){el.style.height=p+'%';}else{el.style.width=p+'%';}});}\n size();\n function report(){parent.postMessage({source:'billminder-canvas',intent:'resize',height:document.documentElement.scrollHeight},'*');}\n new ResizeObserver(report).observe(document.documentElement);report();\n})();\n";
|
|
20
|
+
export type CanvasMessage = {
|
|
21
|
+
source: "billminder-canvas";
|
|
22
|
+
intent: CanvasIntent;
|
|
23
|
+
payload: string | null;
|
|
24
|
+
answer: string | null;
|
|
25
|
+
fields: Record<string, string>;
|
|
26
|
+
} | {
|
|
27
|
+
source: "billminder-canvas";
|
|
28
|
+
intent: "resize";
|
|
29
|
+
height: number;
|
|
30
|
+
};
|
|
31
|
+
/** A complete sandboxed document for `<iframe sandbox="allow-scripts" srcdoc=…>`. */
|
|
32
|
+
export declare function canvasDocument(fragment: string, theme?: "dark" | "light", lang?: string): string;
|