@pixerate/editor-svelte 0.121.0 → 0.122.0
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/dist/chart/ChartDataGrid.svelte +4 -1
- package/dist/chart/ChartInspector.svelte +11 -0
- package/dist/chart/ChartLinksGrid.svelte +62 -0
- package/dist/chart/ChartLinksGrid.svelte.d.ts +10 -0
- package/dist/chart/index.d.ts +1 -0
- package/dist/chart/index.js +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/persistence/editorAutosave.svelte.d.ts +8 -2
- package/dist/persistence/editorAutosave.svelte.js +12 -4
- package/dist/style/StyleFindings.svelte +71 -0
- package/dist/style/StyleFindings.svelte.d.ts +13 -0
- package/dist/style/index.d.ts +5 -0
- package/dist/style/index.js +2 -0
- package/dist/style/style.svelte.d.ts +26 -0
- package/dist/style/style.svelte.js +89 -0
- package/package.json +2 -2
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { chartColorInputValue, chartSeriesColor, chartTreeFromSeries, formatChartNumber, type ChartController } from '@pixerate/editor/chart';
|
|
3
3
|
import ChartCommitInput from './ChartCommitInput.svelte';
|
|
4
|
+
import ChartLinksGrid from './ChartLinksGrid.svelte';
|
|
4
5
|
import ChartTreeGrid from './ChartTreeGrid.svelte';
|
|
5
6
|
import { chartStateOf } from './createChartEditor.svelte.js';
|
|
6
7
|
import { chartButtonClass, chartCellClass, chartIconButtonClass, chartInputClass } from './styles.js';
|
|
@@ -32,7 +33,9 @@
|
|
|
32
33
|
};
|
|
33
34
|
</script>
|
|
34
35
|
|
|
35
|
-
{#if spec.
|
|
36
|
+
{#if spec.links.length || spec.type === 'sankey'}
|
|
37
|
+
<ChartLinksGrid {controller} {readOnly} class={className} />
|
|
38
|
+
{:else if spec.tree.length}
|
|
36
39
|
<ChartTreeGrid {controller} {readOnly} class={className} />
|
|
37
40
|
{:else}
|
|
38
41
|
<div class="overflow-auto rounded-md border border-border {className}" data-chart-grid="">
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
CHART_COLOR_SCHEMES,
|
|
13
13
|
CHART_CURVES,
|
|
14
14
|
CHART_RADAR_GRATICULES,
|
|
15
|
+
CHART_SANKEY_LINK_COLORS,
|
|
15
16
|
CHART_ERROR_BAR_DIRECTIONS,
|
|
16
17
|
CHART_ERROR_BAR_LABELS,
|
|
17
18
|
CHART_ERROR_BAR_TYPES,
|
|
@@ -423,6 +424,16 @@
|
|
|
423
424
|
</div>
|
|
424
425
|
</div>
|
|
425
426
|
{/if}
|
|
427
|
+
{#if spec.type === 'sankey'}
|
|
428
|
+
<div class="flex items-center gap-2">
|
|
429
|
+
<label for="{idPrefix}-sankey-color" class="{chartLabelClass} w-20 shrink-0">Flows</label>
|
|
430
|
+
<select id="{idPrefix}-sankey-color" class={chartInputClass} value={spec.sankeyLinkColor} data-option="sankeyLinkColor" onchange={(e) => controller.update({ sankeyLinkColor: e.currentTarget.value as (typeof CHART_SANKEY_LINK_COLORS)[number] })}>
|
|
431
|
+
{#each CHART_SANKEY_LINK_COLORS as c (c)}
|
|
432
|
+
<option value={c}>{c === 'source' ? 'Coloured by source' : c === 'target' ? 'Coloured by target' : 'Grey'}</option>
|
|
433
|
+
{/each}
|
|
434
|
+
</select>
|
|
435
|
+
</div>
|
|
436
|
+
{/if}
|
|
426
437
|
{#if spec.type === 'sunburst'}
|
|
427
438
|
<div class="flex items-center gap-2">
|
|
428
439
|
<label for="{idPrefix}-sunburst-label" class="{chartLabelClass} w-20 shrink-0">Caption</label>
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { addChartLink, setChartLinkField, type ChartController } from '@pixerate/editor/chart';
|
|
3
|
+
import ChartCommitInput from './ChartCommitInput.svelte';
|
|
4
|
+
import { chartStateOf } from './createChartEditor.svelte.js';
|
|
5
|
+
import { chartButtonClass, chartCellClass, chartIconButtonClass } from './styles.js';
|
|
6
|
+
|
|
7
|
+
interface Props {
|
|
8
|
+
controller: ChartController;
|
|
9
|
+
/** Hide the add / delete buttons. */
|
|
10
|
+
readOnly?: boolean;
|
|
11
|
+
class?: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
let { controller, readOnly = false, class: className = '' }: Props = $props();
|
|
15
|
+
|
|
16
|
+
const view = chartStateOf(() => controller);
|
|
17
|
+
const links = $derived(view.current.spec.links);
|
|
18
|
+
const commit = (next: unknown) => controller.setLinks(next).ok;
|
|
19
|
+
const fields = ['source', 'target'] as const;
|
|
20
|
+
</script>
|
|
21
|
+
|
|
22
|
+
<!-- Flows as a table: source, target and value per row. Edits are checked as a whole (no loops, no repeated pairs). -->
|
|
23
|
+
<div class="overflow-auto rounded-md border border-border {className}" data-chart-grid="" data-chart-links-grid="">
|
|
24
|
+
<table class="w-full border-collapse text-xs">
|
|
25
|
+
<thead class="bg-muted/50">
|
|
26
|
+
<tr>
|
|
27
|
+
<th class="border-b border-r border-border px-2 py-1 text-left font-medium text-muted-foreground">Source</th>
|
|
28
|
+
<th class="border-b border-r border-border px-2 py-1 text-left font-medium text-muted-foreground">Target</th>
|
|
29
|
+
<th class="border-b border-r border-border px-2 py-1 text-right font-medium text-muted-foreground">Value</th>
|
|
30
|
+
{#if !readOnly}<th class="w-8 border-b border-border"></th>{/if}
|
|
31
|
+
</tr>
|
|
32
|
+
</thead>
|
|
33
|
+
<tbody>
|
|
34
|
+
{#each links as link, i (i)}
|
|
35
|
+
<tr data-link-row={i}>
|
|
36
|
+
{#each fields as field (field)}
|
|
37
|
+
<td class="border-b border-r border-border p-0">
|
|
38
|
+
<ChartCommitInput value={link[field]} aria-label="{field === 'source' ? 'Source' : 'Target'} of flow {i + 1}" data-link-cell="{i}:{field}" readonly={readOnly} oncommit={(text) => commit(setChartLinkField(links, i, field, text))} class="{chartCellClass} text-left" />
|
|
39
|
+
</td>
|
|
40
|
+
{/each}
|
|
41
|
+
<td class="border-b border-r border-border p-0">
|
|
42
|
+
<ChartCommitInput value={String(link.value)} inputmode="decimal" aria-label="Value of {link.source} → {link.target}" data-link-cell="{i}:value" readonly={readOnly} oncommit={(text) => commit(setChartLinkField(links, i, 'value', text))} class={chartCellClass} />
|
|
43
|
+
</td>
|
|
44
|
+
{#if !readOnly}
|
|
45
|
+
<td class="border-b border-border px-1">
|
|
46
|
+
<button type="button" class={chartIconButtonClass} title="Delete flow" aria-label="Delete {link.source} → {link.target}" data-action="link-remove" onclick={() => controller.removeLink(i)}>×</button>
|
|
47
|
+
</td>
|
|
48
|
+
{/if}
|
|
49
|
+
</tr>
|
|
50
|
+
{/each}
|
|
51
|
+
</tbody>
|
|
52
|
+
</table>
|
|
53
|
+
{#if !readOnly}
|
|
54
|
+
<div class="flex flex-wrap gap-1 p-1">
|
|
55
|
+
<button type="button" class="{chartButtonClass} h-6 border-dashed" data-action="link-add" onclick={() => commit(addChartLink(links))}>+ Add flow</button>
|
|
56
|
+
<span class="flex-1"></span>
|
|
57
|
+
{#if links.length}
|
|
58
|
+
<button type="button" class="{chartButtonClass} h-6" data-action="links-clear" title="Keep how much passes through each node as plain data" onclick={() => controller.setLinks([])}>Remove flows</button>
|
|
59
|
+
{/if}
|
|
60
|
+
</div>
|
|
61
|
+
{/if}
|
|
62
|
+
</div>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type ChartController } from '@pixerate/editor/chart';
|
|
2
|
+
interface Props {
|
|
3
|
+
controller: ChartController;
|
|
4
|
+
/** Hide the add / delete buttons. */
|
|
5
|
+
readOnly?: boolean;
|
|
6
|
+
class?: string;
|
|
7
|
+
}
|
|
8
|
+
declare const ChartLinksGrid: import("svelte").Component<Props, {}, "">;
|
|
9
|
+
type ChartLinksGrid = ReturnType<typeof ChartLinksGrid>;
|
|
10
|
+
export default ChartLinksGrid;
|
package/dist/chart/index.d.ts
CHANGED
|
@@ -9,6 +9,7 @@ export { default as ChartEditor } from "./ChartEditor.svelte";
|
|
|
9
9
|
export { default as ChartCanvas } from "./ChartCanvas.svelte";
|
|
10
10
|
export { default as ChartDataGrid } from "./ChartDataGrid.svelte";
|
|
11
11
|
export { default as ChartTreeGrid } from "./ChartTreeGrid.svelte";
|
|
12
|
+
export { default as ChartLinksGrid } from "./ChartLinksGrid.svelte";
|
|
12
13
|
export { default as ChartInspector } from "./ChartInspector.svelte";
|
|
13
14
|
export { default as ChartCommitInput } from "./ChartCommitInput.svelte";
|
|
14
15
|
export { default as ChartMarks } from "./ChartMarks.svelte";
|
package/dist/chart/index.js
CHANGED
|
@@ -2,6 +2,7 @@ export { default as ChartEditor } from "./ChartEditor.svelte";
|
|
|
2
2
|
export { default as ChartCanvas } from "./ChartCanvas.svelte";
|
|
3
3
|
export { default as ChartDataGrid } from "./ChartDataGrid.svelte";
|
|
4
4
|
export { default as ChartTreeGrid } from "./ChartTreeGrid.svelte";
|
|
5
|
+
export { default as ChartLinksGrid } from "./ChartLinksGrid.svelte";
|
|
5
6
|
export { default as ChartInspector } from "./ChartInspector.svelte";
|
|
6
7
|
export { default as ChartCommitInput } from "./ChartCommitInput.svelte";
|
|
7
8
|
export { default as ChartMarks } from "./ChartMarks.svelte";
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -1,8 +1,14 @@
|
|
|
1
|
-
import { type EditorDocument, type EditorDocumentFile, type LoadReport } from "@pixerate/editor/persistence";
|
|
1
|
+
import { type EditorAssetGarbageOptions, type EditorDocument, type EditorDocumentFile, type LoadReport } from "@pixerate/editor/persistence";
|
|
2
2
|
import { type CreateAutosaveOptions, type SvelteAutosave } from "./autosave.svelte.js";
|
|
3
3
|
export interface CreateEditorAutosaveOptions extends Omit<CreateAutosaveOptions<EditorDocumentFile>, "key" | "getSnapshot" | "serialize" | "deserialize" | "history"> {
|
|
4
4
|
/** Snapshot key (default the document's `kind`). */
|
|
5
5
|
key?: string;
|
|
6
|
+
/**
|
|
7
|
+
* For documents with `assets`: after `markClean` or `discard` retire a snapshot, delete the
|
|
8
|
+
* stored assets nothing refers to any more (`collectEditorAssetGarbage`, best effort, keeping
|
|
9
|
+
* the assets the document uses now; default `true`). Needs `storage.keys`; `false` turns it off.
|
|
10
|
+
*/
|
|
11
|
+
collectAssetGarbage?: boolean | Omit<EditorAssetGarbageOptions, "dryRun" | "only">;
|
|
6
12
|
}
|
|
7
13
|
export interface SvelteEditorAutosave extends Omit<SvelteAutosave<EditorDocumentFile>, "restore"> {
|
|
8
14
|
/** Loads the recovered snapshot into the document and starts autosaving. */
|
|
@@ -14,4 +20,4 @@ export interface SvelteEditorAutosave extends Omit<SvelteAutosave<EditorDocument
|
|
|
14
20
|
* `EditorDocumentFile` after each change, and `restore` loads a recovered
|
|
15
21
|
* snapshot straight into the editor. Status and recovery stay reactive.
|
|
16
22
|
*/
|
|
17
|
-
export declare function createEditorAutosave(doc: EditorDocument, options: CreateEditorAutosaveOptions): SvelteEditorAutosave;
|
|
23
|
+
export declare function createEditorAutosave(doc: EditorDocument, { collectAssetGarbage, ...options }: CreateEditorAutosaveOptions): SvelteEditorAutosave;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { parseEditorDocument, toEditorDocumentFile, withEditorAssets, } from "@pixerate/editor/persistence";
|
|
1
|
+
import { collectRetiredEditorAssets, parseEditorDocument, toEditorDocumentFile, withEditorAssets, } from "@pixerate/editor/persistence";
|
|
2
2
|
import { createAutosave } from "./autosave.svelte.js";
|
|
3
3
|
/**
|
|
4
4
|
* `createAutosave` for any editor's `EditorDocument` (e.g.
|
|
@@ -6,7 +6,9 @@ import { createAutosave } from "./autosave.svelte.js";
|
|
|
6
6
|
* `EditorDocumentFile` after each change, and `restore` loads a recovered
|
|
7
7
|
* snapshot straight into the editor. Status and recovery stay reactive.
|
|
8
8
|
*/
|
|
9
|
-
export function createEditorAutosave(doc, options) {
|
|
9
|
+
export function createEditorAutosave(doc, { collectAssetGarbage, ...options }) {
|
|
10
|
+
// Retiring a snapshot can leave assets nothing refers to any more.
|
|
11
|
+
const collect = () => collectRetiredEditorAssets(options.storage, doc, collectAssetGarbage);
|
|
10
12
|
const autosave = createAutosave({
|
|
11
13
|
...options,
|
|
12
14
|
// Image and paint documents hold asset references: their bytes are saved and read with them.
|
|
@@ -30,10 +32,16 @@ export function createEditorAutosave(doc, options) {
|
|
|
30
32
|
const snapshot = autosave.restore();
|
|
31
33
|
return snapshot ? doc.loadDocument(snapshot, { history: "reset" }) : undefined;
|
|
32
34
|
},
|
|
33
|
-
discard
|
|
35
|
+
async discard() {
|
|
36
|
+
await autosave.discard();
|
|
37
|
+
await collect();
|
|
38
|
+
},
|
|
34
39
|
ready: () => autosave.ready(),
|
|
35
40
|
flushNow: () => autosave.flushNow(),
|
|
36
|
-
markClean
|
|
41
|
+
async markClean() {
|
|
42
|
+
await autosave.markClean();
|
|
43
|
+
await collect();
|
|
44
|
+
},
|
|
37
45
|
notifyChange: () => autosave.notifyChange(),
|
|
38
46
|
checked: autosave.checked,
|
|
39
47
|
controller: autosave.controller,
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { StyleCheckReport, StyleFinding } from "@pixerate/editor/tools";
|
|
3
|
+
|
|
4
|
+
interface Props {
|
|
5
|
+
/** A check report (`useStyleFindings(...).report`, or a `check_*_style` tool result). Renders nothing while `null`. */
|
|
6
|
+
report: StyleCheckReport | null | undefined;
|
|
7
|
+
/** Called when a finding with a `target` is clicked, e.g. to select that series in the chart. */
|
|
8
|
+
onSelect?: (finding: StyleFinding) => void;
|
|
9
|
+
/** Heading (default "House style"). */
|
|
10
|
+
title?: string;
|
|
11
|
+
class?: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
let { report, onSelect, title = "House style", class: className = "" }: Props = $props();
|
|
15
|
+
|
|
16
|
+
const SEVERITY_CLASS: Record<StyleFinding["severity"], string> = {
|
|
17
|
+
error: "text-destructive",
|
|
18
|
+
warning: "text-amber-600",
|
|
19
|
+
info: "text-muted-foreground",
|
|
20
|
+
};
|
|
21
|
+
</script>
|
|
22
|
+
|
|
23
|
+
{#snippet body(finding: StyleFinding)}
|
|
24
|
+
<span data-style-severity={finding.severity} class="shrink-0 font-semibold uppercase text-[10px] {SEVERITY_CLASS[finding.severity]}">
|
|
25
|
+
{finding.severity}
|
|
26
|
+
</span>
|
|
27
|
+
<span class="flex min-w-0 flex-col">
|
|
28
|
+
<span data-style-message="">{finding.message}</span>
|
|
29
|
+
<span class="text-[10px] text-muted-foreground"><code>{finding.check}</code>{#if finding.layer} · {finding.layer}{/if}</span>
|
|
30
|
+
</span>
|
|
31
|
+
{/snippet}
|
|
32
|
+
|
|
33
|
+
{#if report}
|
|
34
|
+
<section data-style-findings="" aria-label={title} class="flex flex-col gap-1.5 text-xs text-foreground {className}">
|
|
35
|
+
<h3 class="text-[11px] font-semibold uppercase tracking-wide text-muted-foreground">{title}</h3>
|
|
36
|
+
{#if report.findings.length > 0}
|
|
37
|
+
<ul class="flex flex-col gap-1">
|
|
38
|
+
{#each report.findings as finding, i (`${finding.check}-${i}`)}
|
|
39
|
+
<li data-style-finding={finding.check}>
|
|
40
|
+
{#if finding.target !== undefined && onSelect}
|
|
41
|
+
<button
|
|
42
|
+
type="button"
|
|
43
|
+
class="flex w-full items-start gap-2 rounded border border-border px-2 py-1 text-left hover:bg-muted"
|
|
44
|
+
onclick={() => onSelect?.(finding)}
|
|
45
|
+
>
|
|
46
|
+
{@render body(finding)}
|
|
47
|
+
</button>
|
|
48
|
+
{:else}
|
|
49
|
+
<div class="flex items-start gap-2 rounded border border-border px-2 py-1">{@render body(finding)}</div>
|
|
50
|
+
{/if}
|
|
51
|
+
</li>
|
|
52
|
+
{/each}
|
|
53
|
+
</ul>
|
|
54
|
+
{/if}
|
|
55
|
+
{#if report.findings.length === 0 && report.ran.length > 0}
|
|
56
|
+
<p data-style-clear="" class="text-emerald-600">
|
|
57
|
+
All clear: {report.ran.length} {report.ran.length === 1 ? "check" : "checks"} passed.
|
|
58
|
+
</p>
|
|
59
|
+
{/if}
|
|
60
|
+
{#if report.findings.length === 0 && report.ran.length === 0 && report.skipped.length === 0}
|
|
61
|
+
<p class="text-muted-foreground">No house-style checks apply.</p>
|
|
62
|
+
{/if}
|
|
63
|
+
{#if report.skipped.length > 0}
|
|
64
|
+
<ul data-style-skipped="" aria-label="Skipped checks" class="flex flex-col gap-0.5 text-muted-foreground">
|
|
65
|
+
{#each report.skipped as s (s.check)}
|
|
66
|
+
<li data-style-skipped-check={s.check}>Skipped <code>{s.check}</code>: {s.reason}</li>
|
|
67
|
+
{/each}
|
|
68
|
+
</ul>
|
|
69
|
+
{/if}
|
|
70
|
+
</section>
|
|
71
|
+
{/if}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { StyleCheckReport, StyleFinding } from "@pixerate/editor/tools";
|
|
2
|
+
interface Props {
|
|
3
|
+
/** A check report (`useStyleFindings(...).report`, or a `check_*_style` tool result). Renders nothing while `null`. */
|
|
4
|
+
report: StyleCheckReport | null | undefined;
|
|
5
|
+
/** Called when a finding with a `target` is clicked, e.g. to select that series in the chart. */
|
|
6
|
+
onSelect?: (finding: StyleFinding) => void;
|
|
7
|
+
/** Heading (default "House style"). */
|
|
8
|
+
title?: string;
|
|
9
|
+
class?: string;
|
|
10
|
+
}
|
|
11
|
+
declare const StyleFindings: import("svelte").Component<Props, {}, "">;
|
|
12
|
+
type StyleFindings = ReturnType<typeof StyleFindings>;
|
|
13
|
+
export default StyleFindings;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { ComponentProps } from "svelte";
|
|
2
|
+
import type StyleFindingsComponent from "./StyleFindings.svelte";
|
|
3
|
+
export { default as StyleFindings } from "./StyleFindings.svelte";
|
|
4
|
+
export * from "./style.svelte.js";
|
|
5
|
+
export type StyleFindingsProps = ComponentProps<typeof StyleFindingsComponent>;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { ResolvedStyle, StyleCheckReport, StyleResolver } from "@pixerate/editor/tools";
|
|
2
|
+
type MaybeGetter<T> = T | (() => T);
|
|
3
|
+
export interface SvelteStyle {
|
|
4
|
+
/** The resolved house style for the domain, or `null` before the first resolve (or without a resolver) (reactive). */
|
|
5
|
+
readonly style: ResolvedStyle | null;
|
|
6
|
+
/** Why the last resolve failed (e.g. an unknown domain), or `null` (reactive). */
|
|
7
|
+
readonly error: string | null;
|
|
8
|
+
}
|
|
9
|
+
export interface SvelteStyleFindings extends SvelteStyle {
|
|
10
|
+
/** The last check report for `state`, or `null` before the first check (or without a resolver) (reactive). */
|
|
11
|
+
readonly report: StyleCheckReport | null;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Svelte 5 rune: the house style for one domain (`chart`, `tokens`, ...), merged across the
|
|
15
|
+
* resolver's layers; re-resolves when a style store or the token source changes. Call it during
|
|
16
|
+
* component initialisation; pass getters to react to changes. Parity with React's `useStyle`.
|
|
17
|
+
*/
|
|
18
|
+
export declare function useStyle(styles: MaybeGetter<StyleResolver | null | undefined>, domain: MaybeGetter<string>): SvelteStyle;
|
|
19
|
+
/**
|
|
20
|
+
* Svelte 5 rune: runs the domain's house-style checks against `subject`, the domain's state (e.g. a chart spec),
|
|
21
|
+
* whenever the value a getter returns changes by reference, the domain or resolver changes, or
|
|
22
|
+
* the resolver notifies. Results of older runs that settle late are ignored. Feed `report` to
|
|
23
|
+
* `<StyleFindings>`. Call it during component initialisation. Parity with React's `useStyleFindings`.
|
|
24
|
+
*/
|
|
25
|
+
export declare function useStyleFindings(styles: MaybeGetter<StyleResolver | null | undefined>, domain: MaybeGetter<string>, subject: MaybeGetter<unknown>): SvelteStyleFindings;
|
|
26
|
+
export {};
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
const read = (value) => (typeof value === "function" ? value() : value);
|
|
2
|
+
const message = (error) => (error instanceof Error ? error.message : String(error));
|
|
3
|
+
/**
|
|
4
|
+
* Runs `run` in an effect (re-run when anything `inputs` reads changes) and whenever the
|
|
5
|
+
* resolver notifies, delivering only the newest result.
|
|
6
|
+
*/
|
|
7
|
+
function resolverTask(inputs, run, deliver) {
|
|
8
|
+
$effect(() => {
|
|
9
|
+
const { styles, input } = inputs();
|
|
10
|
+
if (!styles) {
|
|
11
|
+
deliver({ value: null, error: null });
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
let latest = 0;
|
|
15
|
+
let active = true;
|
|
16
|
+
const go = () => {
|
|
17
|
+
const call = ++latest;
|
|
18
|
+
run(styles, input).then((value) => {
|
|
19
|
+
if (active && call === latest)
|
|
20
|
+
deliver({ value, error: null });
|
|
21
|
+
}, (error) => {
|
|
22
|
+
if (active && call === latest)
|
|
23
|
+
deliver({ value: null, error: message(error) });
|
|
24
|
+
});
|
|
25
|
+
};
|
|
26
|
+
go();
|
|
27
|
+
const unsubscribe = styles.subscribe(go);
|
|
28
|
+
return () => {
|
|
29
|
+
active = false;
|
|
30
|
+
unsubscribe();
|
|
31
|
+
};
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Svelte 5 rune: the house style for one domain (`chart`, `tokens`, ...), merged across the
|
|
36
|
+
* resolver's layers; re-resolves when a style store or the token source changes. Call it during
|
|
37
|
+
* component initialisation; pass getters to react to changes. Parity with React's `useStyle`.
|
|
38
|
+
*/
|
|
39
|
+
export function useStyle(styles, domain) {
|
|
40
|
+
let style = $state.raw(null);
|
|
41
|
+
let error = $state.raw(null);
|
|
42
|
+
resolverTask(() => ({ styles: read(styles), input: read(domain) }), (s, d) => s.resolve(d), (result) => {
|
|
43
|
+
style = result.value;
|
|
44
|
+
error = result.error;
|
|
45
|
+
});
|
|
46
|
+
return {
|
|
47
|
+
get style() {
|
|
48
|
+
return style;
|
|
49
|
+
},
|
|
50
|
+
get error() {
|
|
51
|
+
return error;
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Svelte 5 rune: runs the domain's house-style checks against `subject`, the domain's state (e.g. a chart spec),
|
|
57
|
+
* whenever the value a getter returns changes by reference, the domain or resolver changes, or
|
|
58
|
+
* the resolver notifies. Results of older runs that settle late are ignored. Feed `report` to
|
|
59
|
+
* `<StyleFindings>`. Call it during component initialisation. Parity with React's `useStyleFindings`.
|
|
60
|
+
*/
|
|
61
|
+
export function useStyleFindings(styles, domain, subject) {
|
|
62
|
+
let report = $state.raw(null);
|
|
63
|
+
let style = $state.raw(null);
|
|
64
|
+
let error = $state.raw(null);
|
|
65
|
+
resolverTask(() => ({ styles: read(styles), input: { domain: read(domain), value: read(subject) } }), (s, { domain: d, value }) => s.check(d, value), (result) => {
|
|
66
|
+
if (!result.value) {
|
|
67
|
+
report = null;
|
|
68
|
+
style = null;
|
|
69
|
+
error = result.error;
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
const { style: resolved, ...rest } = result.value;
|
|
73
|
+
report = rest;
|
|
74
|
+
style = resolved;
|
|
75
|
+
error = null;
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
return {
|
|
79
|
+
get report() {
|
|
80
|
+
return report;
|
|
81
|
+
},
|
|
82
|
+
get style() {
|
|
83
|
+
return style;
|
|
84
|
+
},
|
|
85
|
+
get error() {
|
|
86
|
+
return error;
|
|
87
|
+
},
|
|
88
|
+
};
|
|
89
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pixerate/editor-svelte",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.122.0",
|
|
4
4
|
"description": "Svelte bindings and prompt/rich-text components for @pixerate/editor",
|
|
5
5
|
"author": "Pixerate",
|
|
6
6
|
"license": "MIT",
|
|
@@ -168,7 +168,7 @@
|
|
|
168
168
|
"@tiptap/extension-bubble-menu": "^2.27.3",
|
|
169
169
|
"@tiptap/extension-placeholder": "^2.27.3",
|
|
170
170
|
"@tiptap/starter-kit": "^2.27.3",
|
|
171
|
-
"@pixerate/editor": "0.
|
|
171
|
+
"@pixerate/editor": "0.165.0"
|
|
172
172
|
},
|
|
173
173
|
"peerDependencies": {
|
|
174
174
|
"@dagrejs/dagre": "^1.1.4",
|