@fjader/svelte 0.2.3 → 0.2.5
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/README.md +3 -1
- package/dist/animation/EntranceGate.d.ts +52 -0
- package/dist/animation/EntranceGate.js +93 -0
- package/dist/animation/TransitionClock.d.ts +61 -30
- package/dist/animation/TransitionClock.js +67 -29
- package/dist/animation/transition-log.d.ts +41 -0
- package/dist/animation/transition-log.js +57 -0
- package/dist/components/axes/AxisBottom.svelte +27 -8
- package/dist/components/axes/AxisBottom.svelte.d.ts +10 -0
- package/dist/components/axes/AxisCenter.svelte +4 -2
- package/dist/components/axes/AxisLeft.svelte +81 -10
- package/dist/components/axes/AxisLeft.svelte.d.ts +17 -0
- package/dist/components/axes/BandAxisTicks.svelte +4 -3
- package/dist/components/axes/axis-title.d.ts +30 -0
- package/dist/components/axes/axis-title.js +77 -0
- package/dist/components/charts/ChartCell.svelte +33 -6
- package/dist/components/charts/ChartCell.svelte.d.ts +9 -0
- package/dist/components/charts/ChartContainer.svelte +55 -5
- package/dist/components/charts/ChartContainer.svelte.d.ts +14 -1
- package/dist/components/charts/ChartHover.svelte.d.ts +14 -0
- package/dist/components/charts/ChartHover.svelte.js +22 -0
- package/dist/components/charts/ChartVisibility.svelte.d.ts +43 -0
- package/dist/components/charts/ChartVisibility.svelte.js +67 -0
- package/dist/components/guides/Grid.svelte +12 -1
- package/dist/components/guides/legend/ContinuousColorLegend.svelte +7 -1
- package/dist/components/guides/legend/OrdinalColorLegend.svelte +8 -5
- package/dist/components/marks/AreaMarkX.svelte +18 -4
- package/dist/components/marks/AreaMarkY.svelte +18 -4
- package/dist/components/marks/BarMarkX.svelte +20 -4
- package/dist/components/marks/BarMarkY.svelte +20 -4
- package/dist/components/marks/DotsMark.svelte +8 -3
- package/dist/components/marks/LineMark.svelte +13 -6
- package/dist/components/marks/ParallelCoordinatesMark.svelte +11 -2
- package/dist/components/marks/ParallelCoordinatesMark.svelte.d.ts +4 -0
- package/dist/components/marks/RectMark.svelte +8 -3
- package/dist/components/marks/RectXMark.svelte +9 -3
- package/dist/components/marks/RectYMark.svelte +9 -3
- package/dist/components/marks/RuleMarkX.svelte +31 -25
- package/dist/components/marks/RuleMarkY.svelte +31 -25
- package/dist/components/marks/TextMark.svelte +52 -14
- package/dist/components/marks/lifecycle/MarkLifecycleV2.svelte.d.ts +22 -1
- package/dist/components/marks/lifecycle/MarkLifecycleV2.svelte.js +579 -66
- package/dist/components/marks/lifecycle/domain-queries.d.ts +13 -2
- package/dist/components/marks/lifecycle/domain-queries.js +43 -11
- package/dist/components/marks/lifecycle/domain-registration.d.ts +6 -1
- package/dist/components/marks/lifecycle/domain-registration.js +17 -20
- package/dist/components/marks/lifecycle/other-rows.svelte.d.ts +112 -0
- package/dist/components/marks/lifecycle/other-rows.svelte.js +193 -0
- package/dist/components/marks/lifecycle/other-split.d.ts +80 -0
- package/dist/components/marks/lifecycle/other-split.js +112 -0
- package/dist/components/marks/lifecycle/query-builder.d.ts +53 -3
- package/dist/components/marks/lifecycle/query-builder.js +46 -23
- package/dist/components/marks/utils/MarkColor.svelte.d.ts +3 -1
- package/dist/components/marks/utils/MarkColor.svelte.js +33 -3
- package/dist/components/marks/utils/MarkSeries.svelte.d.ts +14 -1
- package/dist/components/marks/utils/MarkSeries.svelte.js +25 -1
- package/dist/components/marks/utils/MarkSize.svelte.js +4 -0
- package/dist/components/marks/utils/reactive-config.d.ts +1 -1
- package/dist/components/marks/utils/reactive-config.js +9 -0
- package/dist/components/marks/utils/tooltip-helpers.d.ts +4 -1
- package/dist/components/marks/utils/tooltip-helpers.js +2 -1
- package/dist/components/rendering/Areas.svelte +57 -19
- package/dist/components/rendering/Areas.svelte.d.ts +12 -0
- package/dist/components/rendering/BaseGPURenderer.svelte.d.ts +3 -1
- package/dist/components/rendering/BaseGPURenderer.svelte.js +4 -2
- package/dist/components/rendering/Dots.svelte +23 -3
- package/dist/components/rendering/Dots.svelte.d.ts +6 -0
- package/dist/components/rendering/GridLine.svelte +13 -1
- package/dist/components/rendering/GridLine.svelte.d.ts +5 -0
- package/dist/components/rendering/Lines.svelte +48 -13
- package/dist/components/rendering/Lines.svelte.d.ts +12 -0
- package/dist/components/rendering/ParallelLines.svelte +5 -5
- package/dist/components/rendering/Rects.svelte +164 -30
- package/dist/components/rendering/Rects.svelte.d.ts +23 -2
- package/dist/components/rendering/RuleX.svelte +1 -1
- package/dist/components/rendering/RuleY.svelte +1 -1
- package/dist/components/rendering/WebGPUCanvas.svelte +4 -2
- package/dist/components/rendering/activity-reads.d.ts +47 -12
- package/dist/components/rendering/activity-reads.js +61 -19
- package/dist/components/rendering/uniform-sizes.d.ts +1 -1
- package/dist/components/rendering/uniform-sizes.js +1 -1
- package/dist/config/ChartConfig.svelte.d.ts +10 -1
- package/dist/config/ChartConfig.svelte.js +17 -0
- package/dist/gpu/GPUCoordinator.svelte.d.ts +31 -1
- package/dist/gpu/GPUCoordinator.svelte.js +164 -7
- package/dist/gpu/MorphedChannels.d.ts +11 -28
- package/dist/gpu/MorphedChannels.js +72 -8
- package/dist/gpu/ScaleTemplateSystem.d.ts +20 -2
- package/dist/gpu/ScaleTemplateSystem.js +83 -6
- package/dist/index.d.ts +19 -4
- package/dist/index.js +22 -4
- package/dist/interactors/Interval1D.svelte +6 -1
- package/dist/interactors/Interval2D.svelte +6 -1
- package/dist/interactors/ParallelAxisSource.svelte +10 -1
- package/dist/interactors/Toggle.svelte +32 -3
- package/dist/interactors/Tooltip.svelte +138 -41
- package/dist/interactors/TooltipManager.svelte.d.ts +20 -5
- package/dist/interactors/TooltipManager.svelte.js +46 -12
- package/dist/interactors/other-tooltip.d.ts +16 -0
- package/dist/interactors/other-tooltip.js +22 -0
- package/dist/query-engine/CrossfilterSelection.svelte.d.ts +4 -2
- package/dist/query-engine/CrossfilterSelection.svelte.js +2 -0
- package/dist/query-engine/FieldActivity.svelte.d.ts +49 -1
- package/dist/query-engine/FieldActivity.svelte.js +175 -5
- package/dist/query-engine/FilterGroup.svelte.d.ts +23 -1
- package/dist/query-engine/FilterGroup.svelte.js +43 -3
- package/dist/query-engine/FilterGroupRegistry.svelte.d.ts +31 -3
- package/dist/query-engine/FilterGroupRegistry.svelte.js +62 -15
- package/dist/query-engine/MarkHandle.svelte.d.ts +28 -1
- package/dist/query-engine/MarkHandle.svelte.js +33 -1
- package/dist/query-engine/QueryEngine.d.ts +225 -5
- package/dist/query-engine/QueryEngine.js +697 -47
- package/dist/query-engine/categorical-identity.d.ts +41 -0
- package/dist/query-engine/categorical-identity.js +145 -65
- package/dist/query-engine/debug/query-log.d.ts +39 -0
- package/dist/query-engine/debug/query-log.js +90 -0
- package/dist/query-engine/duckdb.d.ts +55 -8
- package/dist/query-engine/duckdb.js +82 -30
- package/dist/query-engine/index.d.ts +7 -4
- package/dist/query-engine/index.js +3 -3
- package/dist/query-engine/preagg/BuildQueue.d.ts +33 -13
- package/dist/query-engine/preagg/BuildQueue.js +51 -15
- package/dist/query-engine/preagg/Preagg.d.ts +46 -3
- package/dist/query-engine/preagg/Preagg.js +159 -31
- package/dist/query-engine/preagg/plan.d.ts +33 -1
- package/dist/query-engine/preagg/plan.js +158 -14
- package/dist/query-engine/sliced-lane.d.ts +108 -0
- package/dist/query-engine/sliced-lane.js +299 -0
- package/dist/query-engine/source-routing.d.ts +106 -0
- package/dist/query-engine/source-routing.js +189 -0
- package/dist/query-engine/toggle-predicate.d.ts +21 -0
- package/dist/query-engine/toggle-predicate.js +29 -1
- package/dist/scales/ActivityTable.d.ts +5 -1
- package/dist/scales/ActivityTable.js +12 -3
- package/dist/scales/BandScaleState.svelte.d.ts +22 -9
- package/dist/scales/BandScaleState.svelte.js +39 -21
- package/dist/scales/ChartScales.svelte.d.ts +3 -0
- package/dist/scales/ChartScales.svelte.js +26 -8
- package/dist/scales/ColorScaleState.svelte.d.ts +18 -2
- package/dist/scales/ColorScaleState.svelte.js +138 -26
- package/dist/scales/LinearScaleState.svelte.d.ts +7 -10
- package/dist/scales/LinearScaleState.svelte.js +21 -39
- package/dist/scales/ScaleGeneration.svelte.d.ts +48 -0
- package/dist/scales/ScaleGeneration.svelte.js +42 -0
- package/dist/scales/ScaleRegistry.svelte.js +3 -1
- package/dist/scales/SlotTransition.d.ts +15 -1
- package/dist/scales/SlotTransition.js +33 -4
- package/dist/scales/TimeScaleState.svelte.d.ts +7 -3
- package/dist/scales/TimeScaleState.svelte.js +7 -7
- package/dist/scales/color-utils.d.ts +0 -3
- package/dist/scales/color-utils.js +0 -3
- package/dist/scales/entered.d.ts +8 -0
- package/dist/scales/entered.js +10 -0
- package/dist/spec/LazyQueryEngine.js +2 -19
- package/dist/spec/MarkRegistry.d.ts +3 -1
- package/dist/spec/MarkRegistry.js +13 -1
- package/dist/spec/PlotFromSpec.svelte +1 -0
- package/dist/spec/export.js +11 -2
- package/dist/spec/types.d.ts +43 -13
- package/dist/sql/bin.d.ts +25 -0
- package/dist/sql/bin.js +108 -5
- package/dist/theme.css +5 -4
- package/dist/transforms/TransformCompiler.d.ts +47 -2
- package/dist/transforms/TransformCompiler.js +70 -1
- package/dist/transforms/index.js +176 -42
- package/dist/types.d.ts +177 -2
- package/package.json +4 -3
|
@@ -62,7 +62,7 @@ export class TimeScaleState extends LinearScaleState {
|
|
|
62
62
|
* Register a mark's datetime extent.
|
|
63
63
|
* Computes t0, converts all extents to offsets, updates parent.
|
|
64
64
|
*/
|
|
65
|
-
addDatetimeExtent(datetimeRange, markId) {
|
|
65
|
+
addDatetimeExtent(datetimeRange, markId, options = {}) {
|
|
66
66
|
const minDate = toDate(datetimeRange[0]);
|
|
67
67
|
const maxDate = toDate(datetimeRange[1]);
|
|
68
68
|
this.#datetimeExtents.set(markId, [minDate, maxDate]);
|
|
@@ -77,21 +77,21 @@ export class TimeScaleState extends LinearScaleState {
|
|
|
77
77
|
}
|
|
78
78
|
this.#suppressUpdate = false;
|
|
79
79
|
// Single update with time-aware nice
|
|
80
|
-
this.updateExtentFromExtents();
|
|
80
|
+
this.updateExtentFromExtents(true, options.instant);
|
|
81
81
|
}
|
|
82
82
|
/**
|
|
83
83
|
* Register a mark's extent using offset values (seconds from t0).
|
|
84
84
|
* Useful when data is already in offset form (e.g., from binned queries).
|
|
85
85
|
* Converts offsets back to datetimes and delegates to addDatetimeExtent.
|
|
86
86
|
*/
|
|
87
|
-
addOffsetExtent(offsetRange, markId) {
|
|
87
|
+
addOffsetExtent(offsetRange, markId, options = {}) {
|
|
88
88
|
if (!this.#t0) {
|
|
89
89
|
console.warn(`[TimeScaleState] Cannot add offset extent: t0 not set yet`);
|
|
90
90
|
return;
|
|
91
91
|
}
|
|
92
92
|
const minDate = this.offsetToDate(offsetRange[0]);
|
|
93
93
|
const maxDate = this.offsetToDate(offsetRange[1]);
|
|
94
|
-
this.addDatetimeExtent([minDate, maxDate], markId);
|
|
94
|
+
this.addDatetimeExtent([minDate, maxDate], markId, options);
|
|
95
95
|
}
|
|
96
96
|
/**
|
|
97
97
|
* Remove a mark's datetime extent.
|
|
@@ -110,12 +110,12 @@ export class TimeScaleState extends LinearScaleState {
|
|
|
110
110
|
* Override: apply time-aware nice instead of linear nice.
|
|
111
111
|
* Called by super.addMark via polymorphism.
|
|
112
112
|
*/
|
|
113
|
-
updateExtentFromExtents(nice = true) {
|
|
113
|
+
updateExtentFromExtents(nice = true, instant = false) {
|
|
114
114
|
if (this.#suppressUpdate)
|
|
115
115
|
return;
|
|
116
116
|
// If no datetime extents, fall through to linear behavior
|
|
117
117
|
if (this.#datetimeExtents.size === 0) {
|
|
118
|
-
super.updateExtentFromExtents(nice);
|
|
118
|
+
super.updateExtentFromExtents(nice, instant);
|
|
119
119
|
return;
|
|
120
120
|
}
|
|
121
121
|
// Compute global datetime range
|
|
@@ -141,7 +141,7 @@ export class TimeScaleState extends LinearScaleState {
|
|
|
141
141
|
this._setExtent(minOffset, maxOffset);
|
|
142
142
|
}
|
|
143
143
|
this.resetDomainLimits();
|
|
144
|
-
this.resetZoom();
|
|
144
|
+
this.resetZoom(instant);
|
|
145
145
|
}
|
|
146
146
|
// ===========================================================================
|
|
147
147
|
// VIEWMANAGER INTEGRATION
|
|
@@ -26,9 +26,6 @@ export declare function getInterpolator(scheme: string): Interpolator | null;
|
|
|
26
26
|
* Get the color array for an ordinal scheme.
|
|
27
27
|
*/
|
|
28
28
|
export declare function getOrdinalColors(scheme: string): readonly string[] | null;
|
|
29
|
-
/**
|
|
30
|
-
* Determine if a scheme is ordinal (discrete) or continuous.
|
|
31
|
-
*/
|
|
32
29
|
/**
|
|
33
30
|
* All available scheme names, grouped by type.
|
|
34
31
|
*/
|
|
@@ -327,9 +327,6 @@ export function getOrdinalColors(scheme) {
|
|
|
327
327
|
const key = scheme.toLowerCase();
|
|
328
328
|
return ORDINAL_SCHEMES[key] || null;
|
|
329
329
|
}
|
|
330
|
-
/**
|
|
331
|
-
* Determine if a scheme is ordinal (discrete) or continuous.
|
|
332
|
-
*/
|
|
333
330
|
/**
|
|
334
331
|
* All available scheme names, grouped by type.
|
|
335
332
|
*/
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Whether a scale's domain is ready to show: a continuous scale only once a
|
|
3
|
+
* chart drawing it has its marks' first data in (LinearScaleState.entered).
|
|
4
|
+
* Before that its domain is a placeholder, and an axis or grid drawn from it
|
|
5
|
+
* shows [0, 100] for a moment. Scales without the notion (band, point) are
|
|
6
|
+
* always shown.
|
|
7
|
+
*/
|
|
8
|
+
export declare function hasEntered(scale: unknown): boolean;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Whether a scale's domain is ready to show: a continuous scale only once a
|
|
3
|
+
* chart drawing it has its marks' first data in (LinearScaleState.entered).
|
|
4
|
+
* Before that its domain is a placeholder, and an axis or grid drawn from it
|
|
5
|
+
* shows [0, 100] for a moment. Scales without the notion (band, point) are
|
|
6
|
+
* always shown.
|
|
7
|
+
*/
|
|
8
|
+
export function hasEntered(scale) {
|
|
9
|
+
return scale?.entered !== false;
|
|
10
|
+
}
|
|
@@ -8,10 +8,7 @@
|
|
|
8
8
|
* DuckDB runs in the browser via @duckdb/duckdb-wasm, loaded from jsDelivr.
|
|
9
9
|
*/
|
|
10
10
|
import { QueryEngine } from '../query-engine/QueryEngine';
|
|
11
|
-
|
|
12
|
-
// Configuration (must be set before first getOrCreateQueryEngine call)
|
|
13
|
-
// ---------------------------------------------------------------------------
|
|
14
|
-
/** Inline WASM bytes + worker code (for environments where separate assets can't be served). */
|
|
11
|
+
import { initDuckDB } from '../query-engine/duckdb';
|
|
15
12
|
// ---------------------------------------------------------------------------
|
|
16
13
|
// Singleton QueryEngine
|
|
17
14
|
// ---------------------------------------------------------------------------
|
|
@@ -35,24 +32,10 @@ export async function getOrCreateQueryEngine(userEngine) {
|
|
|
35
32
|
return _enginePromise;
|
|
36
33
|
}
|
|
37
34
|
async function initEngine() {
|
|
38
|
-
_engine = new QueryEngine(await
|
|
35
|
+
_engine = new QueryEngine(await initDuckDB());
|
|
39
36
|
return _engine;
|
|
40
37
|
}
|
|
41
38
|
// ---------------------------------------------------------------------------
|
|
42
|
-
// WASM init (standard CDN bundles)
|
|
43
|
-
// ---------------------------------------------------------------------------
|
|
44
|
-
async function initFromWasm() {
|
|
45
|
-
const duckdb = await import('@duckdb/duckdb-wasm');
|
|
46
|
-
const bundles = duckdb.getJsDelivrBundles();
|
|
47
|
-
const bundle = await duckdb.selectBundle(bundles);
|
|
48
|
-
const workerUrl = URL.createObjectURL(new Blob([`importScripts("${bundle.mainWorker}");`], { type: 'text/javascript' }));
|
|
49
|
-
const worker = new Worker(workerUrl);
|
|
50
|
-
const db = new duckdb.AsyncDuckDB(new duckdb.VoidLogger(), worker);
|
|
51
|
-
await db.instantiate(bundle.mainModule, bundle.pthreadWorker);
|
|
52
|
-
URL.revokeObjectURL(workerUrl);
|
|
53
|
-
return (await db.connect());
|
|
54
|
-
}
|
|
55
|
-
// ---------------------------------------------------------------------------
|
|
56
39
|
// Data loading (shared across all render calls)
|
|
57
40
|
// ---------------------------------------------------------------------------
|
|
58
41
|
const _loadedTables = new Set();
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* and resolves mark spec objects into component props.
|
|
4
4
|
*/
|
|
5
5
|
import type { Component } from 'svelte';
|
|
6
|
-
import type { MarkSpec } from './types';
|
|
6
|
+
import type { MarkSpec, ColorFieldSpec } from './types';
|
|
7
7
|
export declare const MARK_REGISTRY: Record<string, Component<any>>;
|
|
8
8
|
/** Channel prop names that hold FieldSpec values and need resolution. */
|
|
9
9
|
export declare const FIELD_CHANNELS: Set<string>;
|
|
@@ -11,6 +11,8 @@ export declare const FIELD_CHANNELS: Set<string>;
|
|
|
11
11
|
export declare const STROKE_AS_FIELD_MARKS: Set<string>;
|
|
12
12
|
/** Internal mark type → spec mark type. Used by both resolveMarkEntry and exportSpec. */
|
|
13
13
|
export declare const SPEC_MARK_TYPES: Record<string, string>;
|
|
14
|
+
/** A colour channel with explicit `domain`/`range`, which is not a FieldSpec. */
|
|
15
|
+
export declare function isColorFieldSpec(value: unknown): value is ColorFieldSpec;
|
|
14
16
|
/**
|
|
15
17
|
* Convert a MarkSpec into { component, props } for svelte:component rendering.
|
|
16
18
|
* Resolves FieldSpecs, transforms, and selection references.
|
|
@@ -44,6 +44,13 @@ export const SPEC_MARK_TYPES = {
|
|
|
44
44
|
rectx: 'rectX',
|
|
45
45
|
text: 'text'
|
|
46
46
|
};
|
|
47
|
+
/** A colour channel with explicit `domain`/`range`, which is not a FieldSpec. */
|
|
48
|
+
export function isColorFieldSpec(value) {
|
|
49
|
+
return (typeof value === 'object' &&
|
|
50
|
+
value !== null &&
|
|
51
|
+
typeof value.field === 'string' &&
|
|
52
|
+
('domain' in value || 'range' in value));
|
|
53
|
+
}
|
|
47
54
|
/**
|
|
48
55
|
* Convert a MarkSpec into { component, props } for svelte:component rendering.
|
|
49
56
|
* Resolves FieldSpecs, transforms, and selection references.
|
|
@@ -62,11 +69,16 @@ export function resolveMarkEntry(markSpec) {
|
|
|
62
69
|
// Numbers are constants (e.g. r=3), not field references — skip resolution
|
|
63
70
|
if (typeof props[key] === 'number')
|
|
64
71
|
continue;
|
|
72
|
+
// Explicit colours pass through as the colour prop's object form
|
|
73
|
+
if (isColorFieldSpec(props[key]))
|
|
74
|
+
continue;
|
|
65
75
|
props[key] = resolveFieldSpec(props[key]);
|
|
66
76
|
}
|
|
67
77
|
}
|
|
68
78
|
// stroke is data-driven (FieldSpec) on lines, but a CSS constant on areas
|
|
69
|
-
if (STROKE_AS_FIELD_MARKS.has(markSpec.mark) &&
|
|
79
|
+
if (STROKE_AS_FIELD_MARKS.has(markSpec.mark) &&
|
|
80
|
+
props.stroke != null &&
|
|
81
|
+
!isColorFieldSpec(props.stroke)) {
|
|
70
82
|
props.stroke = resolveFieldSpec(props.stroke);
|
|
71
83
|
}
|
|
72
84
|
// Resolve transforms
|
package/dist/spec/export.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* back to spec format using the same types as the spec renderer.
|
|
6
6
|
*/
|
|
7
7
|
import { fieldRefToSpec } from './ExpressionParser';
|
|
8
|
-
import { SPEC_MARK_TYPES, FIELD_CHANNELS, STROKE_AS_FIELD_MARKS } from './MarkRegistry';
|
|
8
|
+
import { SPEC_MARK_TYPES, FIELD_CHANNELS, STROKE_AS_FIELD_MARKS, isColorFieldSpec } from './MarkRegistry';
|
|
9
9
|
/** Props handled specially (not passthrough) or internal-only (skip entirely). */
|
|
10
10
|
const SKIP_PROPS = new Set([
|
|
11
11
|
// Internal — not part of the spec
|
|
@@ -67,13 +67,22 @@ function entryToMarkSpec(entry) {
|
|
|
67
67
|
const val = entry[ch];
|
|
68
68
|
if (val == null)
|
|
69
69
|
continue;
|
|
70
|
+
// Explicit colours: the colour prop's object form is already spec-shaped
|
|
71
|
+
if (isColorFieldSpec(val)) {
|
|
72
|
+
spec[ch] = { ...val };
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
70
75
|
const converted = fieldRefToSpec(val);
|
|
71
76
|
if (converted != null)
|
|
72
77
|
spec[ch] = converted;
|
|
73
78
|
}
|
|
74
79
|
// stroke: data-driven on lines, CSS constant on areas
|
|
75
80
|
if (entry.stroke != null) {
|
|
76
|
-
|
|
81
|
+
const stroke = entry.stroke;
|
|
82
|
+
if (STROKE_AS_FIELD_MARKS.has(entry.markType) && isColorFieldSpec(stroke)) {
|
|
83
|
+
spec.stroke = { ...stroke };
|
|
84
|
+
}
|
|
85
|
+
else if (STROKE_AS_FIELD_MARKS.has(entry.markType)) {
|
|
77
86
|
const converted = fieldRefToSpec(entry.stroke);
|
|
78
87
|
if (converted != null)
|
|
79
88
|
spec.stroke = converted;
|
package/dist/spec/types.d.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Fjader Spec Schema — TypeScript interfaces defining the JSON contract
|
|
3
3
|
* between spec producers (Python wrapper, JS API) and the spec renderer.
|
|
4
4
|
*/
|
|
5
|
-
import type { ColorScheme, CurveType, ScaleType, SortConfig } from '../types';
|
|
5
|
+
import type { ColorDomainValue, ColorScheme, CurveType, EntranceMode, ScaleType, SortConfig } from '../types';
|
|
6
6
|
import type { QueryEngine } from '../query-engine/QueryEngine';
|
|
7
7
|
/** A layout item: either a single plot or a nested layout. */
|
|
8
8
|
export type LayoutItem = PlotSpec | {
|
|
@@ -64,6 +64,8 @@ export interface PlotSpec {
|
|
|
64
64
|
xDisableZoom?: boolean;
|
|
65
65
|
yDisableZoom?: boolean;
|
|
66
66
|
legend?: LegendSpec | boolean;
|
|
67
|
+
/** How the marks enter when data first draws; see ChartContainer. Default 'auto'. */
|
|
68
|
+
entrance?: EntranceMode;
|
|
67
69
|
}
|
|
68
70
|
export type InteractorSpec = IntervalXSpec | IntervalYSpec | Interval2DSpec | ToggleSpec | DerivedIntervalSpec;
|
|
69
71
|
export interface IntervalXSpec {
|
|
@@ -97,6 +99,17 @@ export interface DerivedIntervalSpec {
|
|
|
97
99
|
}
|
|
98
100
|
/** A column name, aggregate shorthand ("count()"), or structured object. */
|
|
99
101
|
export type FieldSpec = string | AggregateFieldSpec | BinFieldSpec | WindowFieldSpec | RawSqlFieldSpec;
|
|
102
|
+
/**
|
|
103
|
+
* A colour channel with explicit ordinal colours, as on the Svelte colour prop:
|
|
104
|
+
* `{ "field": "won", "domain": [0, 1], "range": ["#d62728", "#2ca02c"] }`.
|
|
105
|
+
*/
|
|
106
|
+
export interface ColorFieldSpec {
|
|
107
|
+
field: string;
|
|
108
|
+
domain?: ColorDomainValue[];
|
|
109
|
+
range?: string[];
|
|
110
|
+
}
|
|
111
|
+
/** What a colour channel (fill, a line's stroke) accepts. */
|
|
112
|
+
export type ColorChannelSpec = FieldSpec | ColorFieldSpec;
|
|
100
113
|
export interface AggregateFieldSpec {
|
|
101
114
|
aggregate: 'count' | 'sum' | 'avg' | 'min' | 'max' | 'median';
|
|
102
115
|
field?: string;
|
|
@@ -134,7 +147,11 @@ interface BaseMarkSpec {
|
|
|
134
147
|
table: string;
|
|
135
148
|
selection?: string;
|
|
136
149
|
/** How the mark responds to selections in its group; see BaseMarkProps. Default 'auto'. */
|
|
137
|
-
selectionResponse?: 'auto' | 'filter';
|
|
150
|
+
selectionResponse?: 'auto' | 'filter' | 'ignore';
|
|
151
|
+
/** What the mark does with NULL in its categorical channels; see BaseMarkProps. Default 'keep'. */
|
|
152
|
+
nulls?: 'keep' | 'drop';
|
|
153
|
+
/** Whether the chart's entrance waits for this mark's first data; see BaseMarkProps. Default true. */
|
|
154
|
+
holdsEntrance?: boolean;
|
|
138
155
|
scheme?: ColorScheme;
|
|
139
156
|
limit?: number;
|
|
140
157
|
transforms?: TransformSpec[];
|
|
@@ -143,7 +160,10 @@ interface BaseMarkSpec {
|
|
|
143
160
|
x?: string[];
|
|
144
161
|
y?: string[];
|
|
145
162
|
} | null;
|
|
146
|
-
tooltip
|
|
163
|
+
/** Hover tooltips, or options; see BaseMarkProps.tooltip. */
|
|
164
|
+
tooltip?: boolean | {
|
|
165
|
+
sortTable?: boolean;
|
|
166
|
+
};
|
|
147
167
|
tooltipProximity?: 'x' | 'y' | 'xy';
|
|
148
168
|
tip?: (string | '*' | AggregateFieldSpec | LabeledTipFieldSpec)[] | false;
|
|
149
169
|
fitDomain?: 'x' | 'y' | boolean;
|
|
@@ -156,7 +176,7 @@ export interface DotMarkSpec extends BaseMarkSpec, ContinuousScaleTypeSpec {
|
|
|
156
176
|
mark: 'dot';
|
|
157
177
|
x: FieldSpec;
|
|
158
178
|
y: FieldSpec;
|
|
159
|
-
fill?:
|
|
179
|
+
fill?: ColorChannelSpec | null;
|
|
160
180
|
opacity?: number;
|
|
161
181
|
r?: number | FieldSpec;
|
|
162
182
|
radiusRange?: [number, number];
|
|
@@ -167,7 +187,7 @@ export interface BarXMarkSpec extends BaseMarkSpec {
|
|
|
167
187
|
x1?: FieldSpec;
|
|
168
188
|
x2?: FieldSpec;
|
|
169
189
|
y: FieldSpec;
|
|
170
|
-
fill?:
|
|
190
|
+
fill?: ColorChannelSpec | null;
|
|
171
191
|
opacity?: number;
|
|
172
192
|
padding?: number;
|
|
173
193
|
paddingInner?: number;
|
|
@@ -175,6 +195,11 @@ export interface BarXMarkSpec extends BaseMarkSpec {
|
|
|
175
195
|
inset?: number;
|
|
176
196
|
dx?: number;
|
|
177
197
|
dy?: number;
|
|
198
|
+
/**
|
|
199
|
+
* `false`: follow the band axis the other marks on it decide, adding no
|
|
200
|
+
* categories to it; see BaseMarkProps. Default `true`.
|
|
201
|
+
*/
|
|
202
|
+
contributeDomain?: boolean;
|
|
178
203
|
}
|
|
179
204
|
export interface BarYMarkSpec extends BaseMarkSpec {
|
|
180
205
|
mark: 'barY';
|
|
@@ -182,7 +207,7 @@ export interface BarYMarkSpec extends BaseMarkSpec {
|
|
|
182
207
|
y: FieldSpec;
|
|
183
208
|
y1?: FieldSpec;
|
|
184
209
|
y2?: FieldSpec;
|
|
185
|
-
fill?:
|
|
210
|
+
fill?: ColorChannelSpec | null;
|
|
186
211
|
opacity?: number;
|
|
187
212
|
padding?: number;
|
|
188
213
|
paddingInner?: number;
|
|
@@ -190,12 +215,17 @@ export interface BarYMarkSpec extends BaseMarkSpec {
|
|
|
190
215
|
inset?: number;
|
|
191
216
|
dx?: number;
|
|
192
217
|
dy?: number;
|
|
218
|
+
/**
|
|
219
|
+
* `false`: follow the band axis the other marks on it decide, adding no
|
|
220
|
+
* categories to it; see BaseMarkProps. Default `true`.
|
|
221
|
+
*/
|
|
222
|
+
contributeDomain?: boolean;
|
|
193
223
|
}
|
|
194
224
|
export interface LineMarkSpec extends BaseMarkSpec, ContinuousScaleTypeSpec {
|
|
195
225
|
mark: 'line';
|
|
196
226
|
x: FieldSpec;
|
|
197
227
|
y: FieldSpec;
|
|
198
|
-
stroke?:
|
|
228
|
+
stroke?: ColorChannelSpec | null;
|
|
199
229
|
z?: FieldSpec | null;
|
|
200
230
|
strokeWidth?: number;
|
|
201
231
|
dotRadius?: number;
|
|
@@ -220,7 +250,7 @@ export interface AreaYMarkSpec extends BaseMarkSpec, ContinuousScaleTypeSpec {
|
|
|
220
250
|
y: FieldSpec;
|
|
221
251
|
y1?: FieldSpec;
|
|
222
252
|
y2?: FieldSpec;
|
|
223
|
-
fill?:
|
|
253
|
+
fill?: ColorChannelSpec | null;
|
|
224
254
|
z?: FieldSpec | null;
|
|
225
255
|
fillOpacity?: number;
|
|
226
256
|
stroke?: string | null;
|
|
@@ -235,7 +265,7 @@ export interface AreaXMarkSpec extends BaseMarkSpec, ContinuousScaleTypeSpec {
|
|
|
235
265
|
x: FieldSpec;
|
|
236
266
|
x1?: FieldSpec;
|
|
237
267
|
x2?: FieldSpec;
|
|
238
|
-
fill?:
|
|
268
|
+
fill?: ColorChannelSpec | null;
|
|
239
269
|
z?: FieldSpec | null;
|
|
240
270
|
fillOpacity?: number;
|
|
241
271
|
stroke?: string | null;
|
|
@@ -252,7 +282,7 @@ export interface RectMarkSpec extends BaseMarkSpec, ContinuousScaleTypeSpec {
|
|
|
252
282
|
y?: FieldSpec | null;
|
|
253
283
|
y1?: FieldSpec | null;
|
|
254
284
|
y2?: FieldSpec | null;
|
|
255
|
-
fill?:
|
|
285
|
+
fill?: ColorChannelSpec | null;
|
|
256
286
|
opacity?: number;
|
|
257
287
|
padding?: number;
|
|
258
288
|
paddingInner?: number;
|
|
@@ -269,7 +299,7 @@ export interface RectXMarkSpec extends BaseMarkSpec {
|
|
|
269
299
|
y?: FieldSpec | null;
|
|
270
300
|
y1?: FieldSpec | null;
|
|
271
301
|
y2?: FieldSpec | null;
|
|
272
|
-
fill?:
|
|
302
|
+
fill?: ColorChannelSpec | null;
|
|
273
303
|
opacity?: number;
|
|
274
304
|
inset?: number;
|
|
275
305
|
dx?: number;
|
|
@@ -285,7 +315,7 @@ export interface RectYMarkSpec extends BaseMarkSpec {
|
|
|
285
315
|
y: FieldSpec;
|
|
286
316
|
y1?: FieldSpec;
|
|
287
317
|
y2?: FieldSpec;
|
|
288
|
-
fill?:
|
|
318
|
+
fill?: ColorChannelSpec | null;
|
|
289
319
|
opacity?: number;
|
|
290
320
|
inset?: number;
|
|
291
321
|
dx?: number;
|
|
@@ -298,7 +328,7 @@ export interface TextMarkSpec extends BaseMarkSpec, ContinuousScaleTypeSpec {
|
|
|
298
328
|
x: FieldSpec;
|
|
299
329
|
y: FieldSpec;
|
|
300
330
|
text: FieldSpec;
|
|
301
|
-
fill?:
|
|
331
|
+
fill?: ColorChannelSpec | null;
|
|
302
332
|
fontSize?: number;
|
|
303
333
|
fontWeight?: string;
|
|
304
334
|
fontFamily?: string | null;
|
package/dist/sql/bin.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { ExprNode, BinHistogramOptions, BinDateOptions } from '@uwdata/mosaic-sql';
|
|
2
|
+
import type { BinPadding } from '../types';
|
|
2
3
|
type BinOptions = BinHistogramOptions & BinDateOptions;
|
|
3
4
|
interface FieldStats {
|
|
4
5
|
column: string;
|
|
@@ -9,14 +10,38 @@ interface FieldInfo {
|
|
|
9
10
|
max?: number;
|
|
10
11
|
type?: string;
|
|
11
12
|
}
|
|
13
|
+
/**
|
|
14
|
+
* The edge of numeric bin `index` (SQL), `min + alpha * (index + offset)`, in
|
|
15
|
+
* DOUBLE arithmetic. The one formula both `bin()` and `dense()`'s padding
|
|
16
|
+
* write, so a bin's edge is the same bits whichever produced it: a padded row
|
|
17
|
+
* then merges with a real one, and a mark's rows are the same bits whether
|
|
18
|
+
* they came from the base table or a preagg table.
|
|
19
|
+
*/
|
|
20
|
+
export declare function numericBinEdgeSQL(min: number, alpha: number, offset: number, index: string): string;
|
|
12
21
|
export declare function bin(field: string | ExprNode, options?: BinOptions): AutoBinNode;
|
|
13
22
|
export declare class AutoBinNode {
|
|
23
|
+
#private;
|
|
14
24
|
field: string | ExprNode;
|
|
15
25
|
options: BinOptions;
|
|
16
26
|
isAutoBinNode: true;
|
|
17
27
|
constructor(field: string | ExprNode, options?: BinOptions);
|
|
18
28
|
get stats(): FieldStats;
|
|
19
29
|
resolve(fieldInfo: Record<string, FieldInfo>, scaleType: string, timeOffset?: number | null, currentDomain?: [number, number] | null, binStepMultiplier?: number): ExprNode;
|
|
30
|
+
/**
|
|
31
|
+
* The bins `resolve` produces with the same arguments: every bin a value of
|
|
32
|
+
* the field can fall in. What `dense()` pads a histogram from, so a bin
|
|
33
|
+
* emptied by a filter stays as a zero row and the bars can morph.
|
|
34
|
+
*
|
|
35
|
+
* Numeric bins as numbers, edge k at `min + alpha * (k + offset)`. Time
|
|
36
|
+
* buckets as the interval `time_bucket` steps by, and the field's extent;
|
|
37
|
+
* those need `t0`, the time scale's origin in epoch seconds, because a time
|
|
38
|
+
* channel is drawn as seconds from it, and are null without it (before the
|
|
39
|
+
* scale has one, the channel is not rewritten either).
|
|
40
|
+
*
|
|
41
|
+
* Null for a field with a single value, which binHistogram floors instead
|
|
42
|
+
* of binning.
|
|
43
|
+
*/
|
|
44
|
+
padding(fieldInfo: Record<string, FieldInfo>, scaleType: string, currentDomain?: [number, number] | null, binStepMultiplier?: number, t0?: number | null): BinPadding | null;
|
|
20
45
|
withOffset(offset: number): AutoBinNode;
|
|
21
46
|
}
|
|
22
47
|
export declare function isBinExpression(expr: unknown): expr is AutoBinNode;
|
package/dist/sql/bin.js
CHANGED
|
@@ -1,5 +1,43 @@
|
|
|
1
|
-
import { binDate, binHistogram, column } from '@uwdata/mosaic-sql';
|
|
1
|
+
import { binDate, binHistogram, binSpec, column, interval, sql, timeInterval } from '@uwdata/mosaic-sql';
|
|
2
2
|
import { isTemporalScale } from '../scales/scale-categories';
|
|
3
|
+
/**
|
|
4
|
+
* Numeric bins over [min, max]: binHistogram's own derivation (binSpec, with
|
|
5
|
+
* the linear transform it is given), as the first edge and the width.
|
|
6
|
+
*/
|
|
7
|
+
function numericBins(min, max, options) {
|
|
8
|
+
const b = binSpec(min, max, options);
|
|
9
|
+
return { min: b.min, alpha: (b.max - b.min) / b.steps || 1 };
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* The edge of numeric bin `index` (SQL), `min + alpha * (index + offset)`, in
|
|
13
|
+
* DOUBLE arithmetic. The one formula both `bin()` and `dense()`'s padding
|
|
14
|
+
* write, so a bin's edge is the same bits whichever produced it: a padded row
|
|
15
|
+
* then merges with a real one, and a mark's rows are the same bits whether
|
|
16
|
+
* they came from the base table or a preagg table.
|
|
17
|
+
*/
|
|
18
|
+
export function numericBinEdgeSQL(min, alpha, offset, index) {
|
|
19
|
+
return `(${sqlDouble(min)} + ${sqlDouble(alpha)} * (${index} + ${offset}))`;
|
|
20
|
+
}
|
|
21
|
+
/** A JS number as a DOUBLE literal: a bare 0.1 would be read as a DECIMAL. */
|
|
22
|
+
function sqlDouble(n) {
|
|
23
|
+
return `CAST(${JSON.stringify(n)} AS DOUBLE)`;
|
|
24
|
+
}
|
|
25
|
+
/** Engine-built SQL text as an expression node. Never user input. */
|
|
26
|
+
function sqlFragment(text) {
|
|
27
|
+
return sql([text]);
|
|
28
|
+
}
|
|
29
|
+
/** A time unit's typical length, for estimating a bucket count. */
|
|
30
|
+
const UNIT_MS = {
|
|
31
|
+
year: 365 * 86_400_000,
|
|
32
|
+
quarter: 91 * 86_400_000,
|
|
33
|
+
month: 30 * 86_400_000,
|
|
34
|
+
day: 86_400_000,
|
|
35
|
+
hour: 3_600_000,
|
|
36
|
+
minute: 60_000,
|
|
37
|
+
second: 1000,
|
|
38
|
+
millisecond: 1,
|
|
39
|
+
microsecond: 0.001
|
|
40
|
+
};
|
|
3
41
|
export function bin(field, options = {}) {
|
|
4
42
|
return new AutoBinNode(field, options);
|
|
5
43
|
}
|
|
@@ -19,6 +57,70 @@ export class AutoBinNode {
|
|
|
19
57
|
};
|
|
20
58
|
}
|
|
21
59
|
resolve(fieldInfo, scaleType, timeOffset = null, currentDomain = null, binStepMultiplier = 1.0) {
|
|
60
|
+
const { col, min, max, isTemporal, binOptions } = this.#plan(fieldInfo, scaleType, currentDomain, binStepMultiplier);
|
|
61
|
+
if (isTemporal)
|
|
62
|
+
return binDate(col, [min, max], binOptions);
|
|
63
|
+
// A single value: binHistogram floors it rather than binning.
|
|
64
|
+
if (max === min)
|
|
65
|
+
return binHistogram(col, [min, max], binOptions);
|
|
66
|
+
// binHistogram's bins, written with the formula dense() pads with, so a
|
|
67
|
+
// real row's edge and a padded row's are the same bits (see
|
|
68
|
+
// numericBinEdgeSQL).
|
|
69
|
+
const { min: lo, alpha } = numericBins(min, max, binOptions);
|
|
70
|
+
const index = `floor((CAST(${col} AS DOUBLE) - ${sqlDouble(lo)}) / ${sqlDouble(alpha)})`;
|
|
71
|
+
return sqlFragment(numericBinEdgeSQL(lo, alpha, binOptions.offset ?? 0, index));
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* The bins `resolve` produces with the same arguments: every bin a value of
|
|
75
|
+
* the field can fall in. What `dense()` pads a histogram from, so a bin
|
|
76
|
+
* emptied by a filter stays as a zero row and the bars can morph.
|
|
77
|
+
*
|
|
78
|
+
* Numeric bins as numbers, edge k at `min + alpha * (k + offset)`. Time
|
|
79
|
+
* buckets as the interval `time_bucket` steps by, and the field's extent;
|
|
80
|
+
* those need `t0`, the time scale's origin in epoch seconds, because a time
|
|
81
|
+
* channel is drawn as seconds from it, and are null without it (before the
|
|
82
|
+
* scale has one, the channel is not rewritten either).
|
|
83
|
+
*
|
|
84
|
+
* Null for a field with a single value, which binHistogram floors instead
|
|
85
|
+
* of binning.
|
|
86
|
+
*/
|
|
87
|
+
padding(fieldInfo, scaleType, currentDomain = null, binStepMultiplier = 1.0, t0 = null) {
|
|
88
|
+
const { col, min, max, isTemporal, binOptions } = this.#plan(fieldInfo, scaleType, currentDomain, binStepMultiplier);
|
|
89
|
+
const offset = binOptions.offset ?? 0;
|
|
90
|
+
const source = String(col);
|
|
91
|
+
if (isTemporal) {
|
|
92
|
+
if (t0 === null)
|
|
93
|
+
return null;
|
|
94
|
+
// binDate's own choice of unit and step.
|
|
95
|
+
const { unit, step = 1 } = binOptions.interval
|
|
96
|
+
? { unit: binOptions.interval, step: binOptions.step }
|
|
97
|
+
: timeInterval(min, max, binOptions.steps || 40);
|
|
98
|
+
const width = (UNIT_MS[unit] ?? UNIT_MS.day) * step;
|
|
99
|
+
return {
|
|
100
|
+
kind: 'time',
|
|
101
|
+
source,
|
|
102
|
+
interval: String(interval(unit, step)),
|
|
103
|
+
minMs: min,
|
|
104
|
+
maxMs: max,
|
|
105
|
+
t0,
|
|
106
|
+
count: Math.ceil((max - min) / width) + 2,
|
|
107
|
+
offset
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
if (max === min)
|
|
111
|
+
return null;
|
|
112
|
+
const { min: lo, alpha } = numericBins(min, max, binOptions);
|
|
113
|
+
return {
|
|
114
|
+
kind: 'number',
|
|
115
|
+
source,
|
|
116
|
+
min: lo,
|
|
117
|
+
alpha,
|
|
118
|
+
count: Math.floor((max - lo) / alpha) + 1,
|
|
119
|
+
offset
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
/** The column, extent and options both `resolve` and `padding` bin with. */
|
|
123
|
+
#plan(fieldInfo, scaleType, currentDomain, binStepMultiplier) {
|
|
22
124
|
const fieldName = typeof this.field === 'string' ? this.field : this.field.toString();
|
|
23
125
|
const info = fieldInfo[fieldName] || {};
|
|
24
126
|
const { min, max, type } = info;
|
|
@@ -50,12 +152,13 @@ export class AutoBinNode {
|
|
|
50
152
|
binOptions.steps = Math.max(1, Math.round(binOptions.steps * binStepMultiplier));
|
|
51
153
|
}
|
|
52
154
|
if (binOptions.step) {
|
|
53
|
-
|
|
155
|
+
// A time interval counts whole units: `INTERVAL 6.78 day` is not SQL.
|
|
156
|
+
binOptions.step = binOptions.interval
|
|
157
|
+
? Math.max(1, Math.round(binOptions.step / binStepMultiplier))
|
|
158
|
+
: binOptions.step / binStepMultiplier;
|
|
54
159
|
}
|
|
55
160
|
}
|
|
56
|
-
return isTemporal
|
|
57
|
-
? binDate(col, [min, max], binOptions)
|
|
58
|
-
: binHistogram(col, [min, max], binOptions);
|
|
161
|
+
return { col, min, max, isTemporal, binOptions };
|
|
59
162
|
}
|
|
60
163
|
withOffset(offset) {
|
|
61
164
|
return new AutoBinNode(this.field, {
|
package/dist/theme.css
CHANGED
|
@@ -7,6 +7,11 @@
|
|
|
7
7
|
* Or copy and customize the variables below in your own CSS.
|
|
8
8
|
* All variables are optional — Fjader components have sensible
|
|
9
9
|
* inline fallbacks and work without any CSS imports.
|
|
10
|
+
*
|
|
11
|
+
* The tooltip is not set here: it follows the color-scheme it inherits (the
|
|
12
|
+
* one below, or the app's own) by itself, in contrast or follow mode
|
|
13
|
+
* (data-fjader-tooltip on any ancestor, or ChartContainer's tooltipScheme).
|
|
14
|
+
* Set --fjader-tooltip-bg and --fjader-tooltip-text to override both modes.
|
|
10
15
|
*/
|
|
11
16
|
|
|
12
17
|
:where(:root) {
|
|
@@ -16,8 +21,6 @@
|
|
|
16
21
|
--fjader-bg: #ffffff;
|
|
17
22
|
--fjader-primary: #3b82f6;
|
|
18
23
|
--fjader-accent: #93c5fd;
|
|
19
|
-
--fjader-tooltip-bg: rgba(0, 0, 0, 0.88);
|
|
20
|
-
--fjader-tooltip-text: #ffffff;
|
|
21
24
|
--fjader-palette-bg: rgba(0, 0, 0, 0.92);
|
|
22
25
|
--fjader-palette-text: #ffffff;
|
|
23
26
|
--fjader-palette-text-secondary: rgba(255, 255, 255, 0.5);
|
|
@@ -34,8 +37,6 @@
|
|
|
34
37
|
--fjader-bg: #111827;
|
|
35
38
|
--fjader-primary: #60a5fa;
|
|
36
39
|
--fjader-accent: #3b82f6;
|
|
37
|
-
--fjader-tooltip-bg: rgba(255, 255, 255, 0.92);
|
|
38
|
-
--fjader-tooltip-text: #111827;
|
|
39
40
|
--fjader-palette-bg: rgba(255, 255, 255, 0.95);
|
|
40
41
|
--fjader-palette-text: #111827;
|
|
41
42
|
--fjader-palette-text-secondary: rgba(17, 24, 39, 0.5);
|