@deck.gl-community/graph-layers 9.2.0-beta.6 → 9.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/dist/_deprecated/old-constants.d.ts.map +1 -1
- package/dist/_deprecated/old-constants.js.map +1 -1
- package/dist/core/graph-engine.d.ts +3 -2
- package/dist/core/graph-engine.d.ts.map +1 -1
- package/dist/core/graph-engine.js +1 -0
- package/dist/core/graph-engine.js.map +1 -1
- package/dist/core/graph-layout.d.ts.map +1 -1
- package/dist/core/graph-layout.js.map +1 -1
- package/dist/core/interaction-manager.d.ts.map +1 -1
- package/dist/core/interaction-manager.js.map +1 -1
- package/dist/graph/arrow-graph.d.ts.map +1 -1
- package/dist/graph/arrow-graph.js.map +1 -1
- package/dist/graph/classic-graph.d.ts.map +1 -1
- package/dist/graph/classic-graph.js +1 -3
- package/dist/graph/classic-graph.js.map +1 -1
- package/dist/graph/functions/arrow-utils.d.ts.map +1 -1
- package/dist/graph/functions/arrow-utils.js +5 -3
- package/dist/graph/functions/arrow-utils.js.map +1 -1
- package/dist/graph/functions/create-graph-from-data.d.ts.map +1 -1
- package/dist/graph/functions/create-graph-from-data.js.map +1 -1
- package/dist/graph/graph-normalization.d.ts.map +1 -1
- package/dist/graph/graph-normalization.js.map +1 -1
- package/dist/graph-data/arrow-graph-data-builder.d.ts.map +1 -1
- package/dist/graph-data/arrow-graph-data-builder.js.map +1 -1
- package/dist/graph-data/graph-data-builder.d.ts.map +1 -1
- package/dist/graph-data/plain-graph-data-builder.d.ts.map +1 -1
- package/dist/graph-style-schema.cdn.js +1 -1
- package/dist/graph-style-schema.json +1 -1
- package/dist/index.cjs +332 -224
- package/dist/index.cjs.map +4 -4
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/layers/common-layers/grid-layer/grid-layer.d.ts.map +1 -1
- package/dist/layers/common-layers/grid-layer/grid-layer.js +6 -16
- package/dist/layers/common-layers/grid-layer/grid-layer.js.map +1 -1
- package/dist/layers/edge-attachment-helper.d.ts.map +1 -1
- package/dist/layers/edge-attachment-helper.js +1 -3
- package/dist/layers/edge-attachment-helper.js.map +1 -1
- package/dist/layers/edge-layer.js +4 -4
- package/dist/layers/edge-layer.js.map +1 -1
- package/dist/layers/edge-layers/arrow-2d-geometry.js +1 -8
- package/dist/layers/edge-layers/arrow-2d-geometry.js.map +1 -1
- package/dist/layers/graph-layer.d.ts +4 -3
- package/dist/layers/graph-layer.d.ts.map +1 -1
- package/dist/layers/graph-layer.js +20 -17
- package/dist/layers/graph-layer.js.map +1 -1
- package/dist/layouts/d3-dag/collapsable-d3-dag-layout.d.ts.map +1 -1
- package/dist/layouts/d3-dag/collapsable-d3-dag-layout.js.map +1 -1
- package/dist/layouts/d3-dag/d3-dag-layout.d.ts.map +1 -1
- package/dist/layouts/d3-dag/d3-dag-layout.js +9 -2
- package/dist/layouts/d3-dag/d3-dag-layout.js.map +1 -1
- package/dist/layouts/experimental/radial-layout.d.ts.map +1 -1
- package/dist/layouts/experimental/radial-layout.js.map +1 -1
- package/dist/layouts/simple-layout.d.ts.map +1 -1
- package/dist/layouts/simple-layout.js +4 -1
- package/dist/layouts/simple-layout.js.map +1 -1
- package/dist/loaders/dot-graph-loader.d.ts.map +1 -1
- package/dist/loaders/dot-graph-loader.js +10 -3
- package/dist/loaders/dot-graph-loader.js.map +1 -1
- package/dist/loaders/json-graph-loader.d.ts.map +1 -1
- package/dist/loaders/json-graph-loader.js +2 -2
- package/dist/loaders/json-graph-loader.js.map +1 -1
- package/dist/loaders/parsers/parse-json-graph.js +2 -1
- package/dist/loaders/parsers/parse-json-graph.js.map +1 -1
- package/dist/style/graph-layer-stylesheet.d.ts +14 -5
- package/dist/style/graph-layer-stylesheet.d.ts.map +1 -1
- package/dist/style/graph-layer-stylesheet.js +14 -8
- package/dist/style/graph-layer-stylesheet.js.map +1 -1
- package/dist/style/graph-style-engine.d.ts +4 -4
- package/dist/style/graph-style-engine.d.ts.map +1 -1
- package/dist/style/graph-style-engine.js +7 -5
- package/dist/style/graph-style-engine.js.map +1 -1
- package/dist/style/graph-stylesheet-schema.d.ts +13211 -0
- package/dist/style/graph-stylesheet-schema.d.ts.map +1 -0
- package/dist/style/graph-stylesheet-schema.js +346 -0
- package/dist/style/graph-stylesheet-schema.js.map +1 -0
- package/dist/style/style-property.d.ts.map +1 -1
- package/dist/style/style-property.js +17 -5
- package/dist/style/style-property.js.map +1 -1
- package/dist/style/stylesheet-engine.d.ts.map +1 -1
- package/dist/style/stylesheet-engine.js +1 -1
- package/dist/style/stylesheet-engine.js.map +1 -1
- package/dist/utils/collapsed-chains.d.ts.map +1 -1
- package/dist/utils/collapsed-chains.js.map +1 -1
- package/dist/utils/node-boundary.d.ts.map +1 -1
- package/dist/utils/node-boundary.js +1 -1
- package/dist/utils/node-boundary.js.map +1 -1
- package/dist/utils/rank-grid.d.ts.map +1 -1
- package/dist/utils/rank-grid.js +5 -2
- package/dist/utils/rank-grid.js.map +1 -1
- package/package.json +8 -8
- package/src/_deprecated/old-constants.ts +12 -6
- package/src/core/graph-engine.ts +7 -2
- package/src/core/graph-layout.ts +2 -6
- package/src/core/interaction-manager.ts +2 -1
- package/src/graph/arrow-graph.ts +17 -10
- package/src/graph/classic-graph.ts +8 -5
- package/src/graph/functions/arrow-utils.ts +8 -4
- package/src/graph/functions/create-graph-from-data.ts +2 -2
- package/src/graph/graph-normalization.ts +8 -2
- package/src/graph-data/arrow-graph-data-builder.ts +6 -3
- package/src/graph-data/graph-data-builder.ts +1 -1
- package/src/graph-data/plain-graph-data-builder.ts +1 -1
- package/src/index.ts +35 -17
- package/src/layers/common-layers/grid-layer/grid-layer.ts +26 -19
- package/src/layers/edge-attachment-helper.ts +54 -45
- package/src/layers/edge-layer.ts +4 -4
- package/src/layers/edge-layers/arrow-2d-geometry.ts +1 -8
- package/src/layers/graph-layer.ts +109 -99
- package/src/layouts/d3-dag/collapsable-d3-dag-layout.ts +14 -7
- package/src/layouts/d3-dag/d3-dag-layout.ts +31 -19
- package/src/layouts/experimental/radial-layout.ts +4 -1
- package/src/layouts/simple-layout.ts +6 -4
- package/src/loaders/dot-graph-loader.ts +19 -7
- package/src/loaders/json-graph-loader.ts +3 -5
- package/src/loaders/parsers/parse-json-graph.ts +2 -1
- package/src/style/graph-layer-stylesheet.ts +26 -19
- package/src/style/graph-style-engine.ts +30 -17
- package/src/style/graph-stylesheet-schema.ts +490 -0
- package/src/style/style-property.ts +26 -11
- package/src/style/stylesheet-engine.ts +44 -29
- package/src/utils/collapsed-chains.ts +6 -2
- package/src/utils/node-boundary.ts +2 -3
- package/src/utils/rank-grid.ts +31 -17
- package/dist/style/graph-stylesheet.schema.d.ts +0 -311
- package/dist/style/graph-stylesheet.schema.d.ts.map +0 -1
- package/dist/style/graph-stylesheet.schema.js +0 -238
- package/dist/style/graph-stylesheet.schema.js.map +0 -1
- package/src/style/graph-stylesheet.schema.ts +0 -344
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// SPDX-License-Identifier: MIT
|
|
3
3
|
// Copyright (c) vis.gl contributors
|
|
4
4
|
|
|
5
|
-
import type {GraphStylesheet, GraphStyleType} from './graph-style-engine';
|
|
5
|
+
import type {GraphStylesheet, GraphStyleRule, GraphStyleType} from './graph-style-engine';
|
|
6
6
|
|
|
7
7
|
export type GraphNodeStyleType = Exclude<
|
|
8
8
|
GraphStyleType,
|
|
@@ -11,26 +11,26 @@ export type GraphNodeStyleType = Exclude<
|
|
|
11
11
|
|
|
12
12
|
export type GraphEdgeDecoratorType = Extract<GraphStyleType, 'edge-label' | 'flow' | 'arrow'>;
|
|
13
13
|
|
|
14
|
-
export type GraphLayerNodeStyle =
|
|
14
|
+
export type GraphLayerNodeStyle = Extract<GraphStyleRule, {type: GraphNodeStyleType}> & {
|
|
15
15
|
pickable?: boolean;
|
|
16
16
|
visible?: boolean;
|
|
17
17
|
data?: (nodes: any[]) => any;
|
|
18
18
|
};
|
|
19
19
|
|
|
20
|
-
export type GraphLayerEdgeDecoratorStyle =
|
|
20
|
+
export type GraphLayerEdgeDecoratorStyle = Extract<GraphStyleRule, {type: GraphEdgeDecoratorType}>;
|
|
21
21
|
|
|
22
22
|
type EdgeStyleType = Extract<GraphStyleType, 'Edge' | 'edge'>;
|
|
23
23
|
|
|
24
24
|
export type GraphLayerEdgeStyle = (
|
|
25
|
-
|
|
|
26
|
-
| (Omit<
|
|
25
|
+
| Extract<GraphStyleRule, {type: EdgeStyleType}>
|
|
26
|
+
| (Omit<Extract<GraphStyleRule, {type: EdgeStyleType}>, 'type'> & {type?: EdgeStyleType})
|
|
27
27
|
) & {
|
|
28
28
|
decorators?: GraphLayerEdgeDecoratorStyle[];
|
|
29
29
|
data?: (edges: any[]) => any;
|
|
30
30
|
visible?: boolean;
|
|
31
31
|
};
|
|
32
32
|
|
|
33
|
-
export type GraphLayerStylesheet = {
|
|
33
|
+
export type GraphLayerStylesheet = GraphStylesheet & {
|
|
34
34
|
nodes?: GraphLayerNodeStyle[];
|
|
35
35
|
edges?: GraphLayerEdgeStyle | GraphLayerEdgeStyle[];
|
|
36
36
|
};
|
|
@@ -42,10 +42,19 @@ export type NormalizedGraphLayerStylesheet = {
|
|
|
42
42
|
edges: GraphLayerEdgeStyle[];
|
|
43
43
|
};
|
|
44
44
|
|
|
45
|
+
export const DEFAULT_GRAPH_LAYER_STYLESHEET_INPUT: GraphLayerStylesheet = {
|
|
46
|
+
nodes: [],
|
|
47
|
+
edges: [
|
|
48
|
+
{
|
|
49
|
+
type: 'edge',
|
|
50
|
+
stroke: 'black',
|
|
51
|
+
strokeWidth: 1
|
|
52
|
+
}
|
|
53
|
+
]
|
|
54
|
+
};
|
|
55
|
+
|
|
45
56
|
const DEFAULT_EDGE_STYLE: GraphLayerEdgeStyle = {
|
|
46
|
-
|
|
47
|
-
stroke: 'black',
|
|
48
|
-
strokeWidth: 1,
|
|
57
|
+
...DEFAULT_GRAPH_LAYER_STYLESHEET_INPUT.edges[0],
|
|
49
58
|
decorators: []
|
|
50
59
|
};
|
|
51
60
|
|
|
@@ -79,16 +88,14 @@ export function normalizeGraphLayerStylesheet({
|
|
|
79
88
|
const edgeEntries = Array.isArray(resolvedEdgeStyles)
|
|
80
89
|
? resolvedEdgeStyles
|
|
81
90
|
: resolvedEdgeStyles
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
const edges: GraphLayerEdgeStyle[] = (
|
|
86
|
-
|
|
87
|
-
.
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
decorators: (edgeStyleEntry).decorators ?? []
|
|
91
|
-
})) as GraphLayerEdgeStyle[];
|
|
91
|
+
? [resolvedEdgeStyles]
|
|
92
|
+
: DEFAULT_GRAPH_LAYER_STYLESHEET.edges;
|
|
93
|
+
|
|
94
|
+
const edges: GraphLayerEdgeStyle[] = edgeEntries.filter(Boolean).map((edgeStyleEntry) => ({
|
|
95
|
+
...edgeStyleEntry,
|
|
96
|
+
type: edgeStyleEntry.type ?? 'edge',
|
|
97
|
+
decorators: edgeStyleEntry.decorators ?? []
|
|
98
|
+
})) as GraphLayerEdgeStyle[];
|
|
92
99
|
|
|
93
100
|
return {
|
|
94
101
|
nodes,
|
|
@@ -2,16 +2,16 @@
|
|
|
2
2
|
// SPDX-License-Identifier: MIT
|
|
3
3
|
// Copyright (c) vis.gl contributors
|
|
4
4
|
|
|
5
|
-
/* eslint-disable no-continue */
|
|
5
|
+
/* eslint-disable no-continue */
|
|
6
6
|
|
|
7
7
|
import {ZodError, type ZodIssue} from 'zod';
|
|
8
8
|
|
|
9
9
|
import {StylesheetEngine, type DeckGLUpdateTriggers} from './stylesheet-engine';
|
|
10
10
|
import {
|
|
11
|
-
|
|
12
|
-
type
|
|
13
|
-
type
|
|
14
|
-
} from './graph-stylesheet
|
|
11
|
+
GraphStyleRuleSchema,
|
|
12
|
+
type GraphStyleRule,
|
|
13
|
+
type GraphStyleRuleParsed
|
|
14
|
+
} from './graph-stylesheet-schema';
|
|
15
15
|
import {GRAPH_DECKGL_ACCESSOR_MAP} from './graph-style-accessor-map';
|
|
16
16
|
import {warn} from '../utils/log';
|
|
17
17
|
|
|
@@ -40,13 +40,16 @@ function formatStylesheetError(error: ZodError) {
|
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
export class GraphStylesheetEngine extends StylesheetEngine {
|
|
43
|
-
constructor(
|
|
44
|
-
|
|
43
|
+
constructor(
|
|
44
|
+
style: GraphStyleRule | GraphStyleRuleParsed,
|
|
45
|
+
{stateUpdateTrigger}: {stateUpdateTrigger?: unknown} = {}
|
|
46
|
+
) {
|
|
47
|
+
const result = GraphStyleRuleSchema.safeParse(style);
|
|
45
48
|
const parsedStyle = result.success
|
|
46
49
|
? result.data
|
|
47
50
|
: sanitizeStylesheet(style, result.error.issues);
|
|
48
51
|
|
|
49
|
-
super(parsedStyle as
|
|
52
|
+
super(parsedStyle as GraphStyleRule, {
|
|
50
53
|
deckglAccessorMap: GRAPH_DECKGL_ACCESSOR_MAP,
|
|
51
54
|
deckglUpdateTriggers: GRAPH_DECKGL_UPDATE_TRIGGERS,
|
|
52
55
|
stateUpdateTrigger
|
|
@@ -64,12 +67,14 @@ export {
|
|
|
64
67
|
GraphStyleLeafValueSchema,
|
|
65
68
|
GraphStyleStateMapSchema,
|
|
66
69
|
GraphStyleValueSchema,
|
|
67
|
-
GraphStylesheetSchema
|
|
68
|
-
|
|
70
|
+
GraphStylesheetSchema,
|
|
71
|
+
GraphStyleRuleSchema
|
|
72
|
+
} from './graph-stylesheet-schema';
|
|
69
73
|
|
|
70
74
|
export type {
|
|
71
75
|
GraphStylesheet,
|
|
72
|
-
|
|
76
|
+
GraphStyleRule,
|
|
77
|
+
GraphStyleRuleParsed,
|
|
73
78
|
GraphStylesheetParsed,
|
|
74
79
|
GraphStyleSelector,
|
|
75
80
|
GraphStyleType,
|
|
@@ -78,12 +83,15 @@ export type {
|
|
|
78
83
|
GraphStyleScale,
|
|
79
84
|
GraphStyleScaleType,
|
|
80
85
|
GraphStyleValue
|
|
81
|
-
} from './graph-stylesheet
|
|
86
|
+
} from './graph-stylesheet-schema';
|
|
82
87
|
|
|
83
88
|
export {GRAPH_DECKGL_ACCESSOR_MAP} from './graph-style-accessor-map';
|
|
84
89
|
|
|
85
90
|
// eslint-disable-next-line max-statements, complexity
|
|
86
|
-
function sanitizeStylesheet(
|
|
91
|
+
function sanitizeStylesheet(
|
|
92
|
+
style: GraphStyleRule | GraphStyleRuleParsed,
|
|
93
|
+
issues: ZodIssue[]
|
|
94
|
+
): GraphStyleRuleParsed {
|
|
87
95
|
if (issues.length) {
|
|
88
96
|
const details = issues
|
|
89
97
|
.map((issue) => {
|
|
@@ -95,7 +103,9 @@ function sanitizeStylesheet(style: GraphStylesheet, issues: ZodIssue[]): GraphSt
|
|
|
95
103
|
}
|
|
96
104
|
|
|
97
105
|
const fallbackTypeCandidate =
|
|
98
|
-
typeof (style as {type?: unknown}).type === 'string'
|
|
106
|
+
typeof (style as {type?: unknown}).type === 'string'
|
|
107
|
+
? (style as {type: string}).type
|
|
108
|
+
: undefined;
|
|
99
109
|
const fallbackCandidates = Array.from(
|
|
100
110
|
new Set(
|
|
101
111
|
[fallbackTypeCandidate, 'edge'].filter(
|
|
@@ -126,7 +136,7 @@ function sanitizeStylesheet(style: GraphStylesheet, issues: ZodIssue[]): GraphSt
|
|
|
126
136
|
if (rootKey === undefined || rootKey === 'type') {
|
|
127
137
|
continue;
|
|
128
138
|
}
|
|
129
|
-
|
|
139
|
+
|
|
130
140
|
if (typeof rootKey === 'string' && rootKey.startsWith(':')) {
|
|
131
141
|
removeNestedProperty(sanitized, path);
|
|
132
142
|
continue;
|
|
@@ -139,7 +149,7 @@ function sanitizeStylesheet(style: GraphStylesheet, issues: ZodIssue[]): GraphSt
|
|
|
139
149
|
delete sanitized[rootKey];
|
|
140
150
|
}
|
|
141
151
|
|
|
142
|
-
const result =
|
|
152
|
+
const result = GraphStyleRuleSchema.safeParse(sanitized);
|
|
143
153
|
if (result.success) {
|
|
144
154
|
return result.data;
|
|
145
155
|
}
|
|
@@ -170,7 +180,10 @@ function cloneValue<T>(value: T): T {
|
|
|
170
180
|
}
|
|
171
181
|
|
|
172
182
|
// eslint-disable-next-line max-statements, complexity
|
|
173
|
-
function removeNestedProperty(
|
|
183
|
+
function removeNestedProperty(
|
|
184
|
+
target: Record<string, unknown> | unknown[],
|
|
185
|
+
path: (string | number)[]
|
|
186
|
+
) {
|
|
174
187
|
if (path.length === 0) {
|
|
175
188
|
return;
|
|
176
189
|
}
|
|
@@ -0,0 +1,490 @@
|
|
|
1
|
+
// deck.gl-community
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
// Copyright (c) vis.gl contributors
|
|
4
|
+
|
|
5
|
+
/* eslint-disable no-continue */
|
|
6
|
+
|
|
7
|
+
import {z, type ZodTypeAny} from 'zod';
|
|
8
|
+
|
|
9
|
+
import {GRAPH_DECKGL_ACCESSOR_MAP} from './graph-style-accessor-map';
|
|
10
|
+
export {GRAPH_DECKGL_ACCESSOR_MAP};
|
|
11
|
+
|
|
12
|
+
const GraphStylePrimitiveSchema = z.union([
|
|
13
|
+
z.string(),
|
|
14
|
+
z.number(),
|
|
15
|
+
z.boolean(),
|
|
16
|
+
z.null(),
|
|
17
|
+
z.array(z.union([z.string(), z.number(), z.boolean(), z.null()]))
|
|
18
|
+
]);
|
|
19
|
+
|
|
20
|
+
const GraphStyleFunctionSchema = z.custom<(...args: unknown[]) => unknown>(
|
|
21
|
+
(value) => typeof value === 'function',
|
|
22
|
+
{
|
|
23
|
+
message: 'Style functions must be callable.'
|
|
24
|
+
}
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Supported scale identifiers for mapping data values to visual encodings.
|
|
29
|
+
*/
|
|
30
|
+
export const GraphStyleScaleTypeEnum = z.enum([
|
|
31
|
+
'linear',
|
|
32
|
+
'log',
|
|
33
|
+
'pow',
|
|
34
|
+
'sqrt',
|
|
35
|
+
'quantize',
|
|
36
|
+
'quantile',
|
|
37
|
+
'ordinal'
|
|
38
|
+
]);
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* TypeScript union of {@link GraphStyleScaleTypeEnum} values.
|
|
42
|
+
*/
|
|
43
|
+
export type GraphStyleScaleType = z.infer<typeof GraphStyleScaleTypeEnum>;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Configuration for data-driven style scaling. Supports deck.gl compatible numeric and
|
|
47
|
+
* categorical scaling with optional d3-scale like parameters.
|
|
48
|
+
*/
|
|
49
|
+
export const GraphStyleScaleSchema = z
|
|
50
|
+
.object({
|
|
51
|
+
type: GraphStyleScaleTypeEnum.optional(),
|
|
52
|
+
domain: z.array(z.union([z.number(), z.string()])).optional(),
|
|
53
|
+
range: z.array(z.any()).optional(),
|
|
54
|
+
clamp: z.boolean().optional(),
|
|
55
|
+
nice: z.union([z.boolean(), z.number()]).optional(),
|
|
56
|
+
base: z.number().optional(),
|
|
57
|
+
exponent: z.number().optional(),
|
|
58
|
+
unknown: z.any().optional()
|
|
59
|
+
})
|
|
60
|
+
.strict();
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* TypeScript view of {@link GraphStyleScaleSchema} after parsing.
|
|
64
|
+
*/
|
|
65
|
+
export type GraphStyleScale = z.infer<typeof GraphStyleScaleSchema>;
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Reference to node/edge attributes, optionally including fallback values and scale
|
|
69
|
+
* configuration for data-driven styling.
|
|
70
|
+
*/
|
|
71
|
+
export const GraphStyleAttributeReferenceSchema = z.union([
|
|
72
|
+
z
|
|
73
|
+
.string()
|
|
74
|
+
.regex(
|
|
75
|
+
/^@.+/,
|
|
76
|
+
'Attribute reference strings must start with "@" and include an attribute name.'
|
|
77
|
+
),
|
|
78
|
+
z
|
|
79
|
+
.object({
|
|
80
|
+
attribute: z.string().min(1, 'Attribute name is required.'),
|
|
81
|
+
fallback: GraphStylePrimitiveSchema.optional(),
|
|
82
|
+
scale: z.union([GraphStyleScaleSchema, GraphStyleFunctionSchema]).optional()
|
|
83
|
+
})
|
|
84
|
+
.strict()
|
|
85
|
+
]);
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Parsed value produced by {@link GraphStyleAttributeReferenceSchema}.
|
|
89
|
+
*/
|
|
90
|
+
export type GraphStyleAttributeReference = z.infer<typeof GraphStyleAttributeReferenceSchema>;
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Primitive value allowed in stylesheet definitions. Supports literal values, attribute
|
|
94
|
+
* references and imperative resolver functions.
|
|
95
|
+
*/
|
|
96
|
+
export const GraphStyleLeafValueSchema = z.union([
|
|
97
|
+
GraphStylePrimitiveSchema,
|
|
98
|
+
GraphStyleAttributeReferenceSchema,
|
|
99
|
+
GraphStyleFunctionSchema
|
|
100
|
+
]);
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Union of literal, attribute-driven and functional style values.
|
|
104
|
+
*/
|
|
105
|
+
export type GraphStyleLeafValue = z.infer<typeof GraphStyleLeafValueSchema>;
|
|
106
|
+
|
|
107
|
+
const RESERVED_STATE_KEYS = new Set(['attribute', 'fallback', 'scale']);
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Mapping of interaction or application state keys to leaf style values.
|
|
111
|
+
*/
|
|
112
|
+
export const GraphStyleStateMapSchema = z.record(
|
|
113
|
+
z
|
|
114
|
+
.string()
|
|
115
|
+
.refine((key) => !RESERVED_STATE_KEYS.has(key), 'State overrides must not use reserved keys.'),
|
|
116
|
+
GraphStyleLeafValueSchema
|
|
117
|
+
);
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Style value that may be either a simple leaf value or a keyed map of overrides.
|
|
121
|
+
*/
|
|
122
|
+
export const GraphStyleValueSchema = z.union([GraphStyleLeafValueSchema, GraphStyleStateMapSchema]);
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Parsed style property value that may include state overrides.
|
|
126
|
+
*/
|
|
127
|
+
export type GraphStyleValue = z.infer<typeof GraphStyleValueSchema>;
|
|
128
|
+
|
|
129
|
+
export type GraphStyleType = keyof typeof GRAPH_DECKGL_ACCESSOR_MAP;
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* CSS-like pseudo selector supported by the stylesheet for state overrides.
|
|
133
|
+
*/
|
|
134
|
+
export type GraphStyleSelector = `:${string}`;
|
|
135
|
+
|
|
136
|
+
const GraphStyleSelectorKeySchema = z.string().regex(/^:[^\s]+/, 'Selectors must start with ":".');
|
|
137
|
+
|
|
138
|
+
function createSelectorRefinement(allowedKeys: readonly string[], propertiesSchema: ZodTypeAny) {
|
|
139
|
+
const allowedKeySet = new Set<string>(allowedKeys);
|
|
140
|
+
|
|
141
|
+
return (value: unknown, ctx: z.RefinementCtx) => {
|
|
142
|
+
if (typeof value !== 'object' || value === null) {
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const record = value as Record<string, unknown>;
|
|
147
|
+
|
|
148
|
+
for (const key of Object.keys(record)) {
|
|
149
|
+
if (key === 'type') continue;
|
|
150
|
+
if (allowedKeySet.has(key)) continue;
|
|
151
|
+
|
|
152
|
+
if (!key.startsWith(':')) {
|
|
153
|
+
ctx.addIssue({
|
|
154
|
+
code: z.ZodIssueCode.custom,
|
|
155
|
+
path: [key],
|
|
156
|
+
message: `Unknown style property "${key}".`
|
|
157
|
+
});
|
|
158
|
+
continue;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
if (!GraphStyleSelectorKeySchema.safeParse(key).success) {
|
|
162
|
+
ctx.addIssue({
|
|
163
|
+
code: z.ZodIssueCode.custom,
|
|
164
|
+
path: [key],
|
|
165
|
+
message: 'Selectors must start with ":".'
|
|
166
|
+
});
|
|
167
|
+
continue;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
const selectorResult = propertiesSchema.safeParse(record[key]);
|
|
171
|
+
if (!selectorResult.success) {
|
|
172
|
+
for (const issue of selectorResult.error.issues) {
|
|
173
|
+
ctx.addIssue({
|
|
174
|
+
...issue,
|
|
175
|
+
path: [key, ...(issue.path ?? [])]
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
const CircleShape = {
|
|
184
|
+
offset: GraphStyleValueSchema.optional(),
|
|
185
|
+
opacity: GraphStyleValueSchema.optional(),
|
|
186
|
+
fill: GraphStyleValueSchema.optional(),
|
|
187
|
+
stroke: GraphStyleValueSchema.optional(),
|
|
188
|
+
strokeWidth: GraphStyleValueSchema.optional(),
|
|
189
|
+
radius: GraphStyleValueSchema.optional()
|
|
190
|
+
} as const;
|
|
191
|
+
|
|
192
|
+
const CirclePropertiesSchema = z.object(CircleShape).partial().strict();
|
|
193
|
+
|
|
194
|
+
const CircleStylesheetSchema = z
|
|
195
|
+
.object({
|
|
196
|
+
type: z.literal('circle'),
|
|
197
|
+
...CircleShape
|
|
198
|
+
})
|
|
199
|
+
.catchall(z.unknown())
|
|
200
|
+
.superRefine(createSelectorRefinement(Object.keys(CircleShape), CirclePropertiesSchema));
|
|
201
|
+
|
|
202
|
+
const RectangleShape = {
|
|
203
|
+
offset: GraphStyleValueSchema.optional(),
|
|
204
|
+
opacity: GraphStyleValueSchema.optional(),
|
|
205
|
+
width: GraphStyleValueSchema.optional(),
|
|
206
|
+
height: GraphStyleValueSchema.optional(),
|
|
207
|
+
fill: GraphStyleValueSchema.optional(),
|
|
208
|
+
stroke: GraphStyleValueSchema.optional(),
|
|
209
|
+
strokeWidth: GraphStyleValueSchema.optional()
|
|
210
|
+
} as const;
|
|
211
|
+
|
|
212
|
+
const RectanglePropertiesSchema = z.object(RectangleShape).partial().strict();
|
|
213
|
+
|
|
214
|
+
const RectangleStylesheetSchema = z
|
|
215
|
+
.object({
|
|
216
|
+
type: z.literal('rectangle'),
|
|
217
|
+
...RectangleShape
|
|
218
|
+
})
|
|
219
|
+
.catchall(z.unknown())
|
|
220
|
+
.superRefine(createSelectorRefinement(Object.keys(RectangleShape), RectanglePropertiesSchema));
|
|
221
|
+
|
|
222
|
+
const RoundedRectangleShape = {
|
|
223
|
+
offset: GraphStyleValueSchema.optional(),
|
|
224
|
+
opacity: GraphStyleValueSchema.optional(),
|
|
225
|
+
cornerRadius: GraphStyleValueSchema.optional(),
|
|
226
|
+
radius: GraphStyleValueSchema.optional(),
|
|
227
|
+
width: GraphStyleValueSchema.optional(),
|
|
228
|
+
height: GraphStyleValueSchema.optional(),
|
|
229
|
+
fill: GraphStyleValueSchema.optional(),
|
|
230
|
+
stroke: GraphStyleValueSchema.optional(),
|
|
231
|
+
strokeWidth: GraphStyleValueSchema.optional()
|
|
232
|
+
} as const;
|
|
233
|
+
|
|
234
|
+
const RoundedRectanglePropertiesSchema = z.object(RoundedRectangleShape).partial().strict();
|
|
235
|
+
|
|
236
|
+
const RoundedRectangleStylesheetSchema = z
|
|
237
|
+
.object({
|
|
238
|
+
type: z.literal('rounded-rectangle'),
|
|
239
|
+
...RoundedRectangleShape
|
|
240
|
+
})
|
|
241
|
+
.catchall(z.unknown())
|
|
242
|
+
.superRefine(
|
|
243
|
+
createSelectorRefinement(Object.keys(RoundedRectangleShape), RoundedRectanglePropertiesSchema)
|
|
244
|
+
);
|
|
245
|
+
|
|
246
|
+
const PathRoundedRectangleShape = {
|
|
247
|
+
offset: GraphStyleValueSchema.optional(),
|
|
248
|
+
opacity: GraphStyleValueSchema.optional(),
|
|
249
|
+
width: GraphStyleValueSchema.optional(),
|
|
250
|
+
height: GraphStyleValueSchema.optional(),
|
|
251
|
+
fill: GraphStyleValueSchema.optional(),
|
|
252
|
+
stroke: GraphStyleValueSchema.optional(),
|
|
253
|
+
strokeWidth: GraphStyleValueSchema.optional(),
|
|
254
|
+
cornerRadius: GraphStyleValueSchema.optional()
|
|
255
|
+
} as const;
|
|
256
|
+
|
|
257
|
+
const PathRoundedRectanglePropertiesSchema = z.object(PathRoundedRectangleShape).partial().strict();
|
|
258
|
+
|
|
259
|
+
const PathRoundedRectangleStylesheetSchema = z
|
|
260
|
+
.object({
|
|
261
|
+
type: z.literal('path-rounded-rectangle'),
|
|
262
|
+
...PathRoundedRectangleShape
|
|
263
|
+
})
|
|
264
|
+
.catchall(z.unknown())
|
|
265
|
+
.superRefine(
|
|
266
|
+
createSelectorRefinement(
|
|
267
|
+
Object.keys(PathRoundedRectangleShape),
|
|
268
|
+
PathRoundedRectanglePropertiesSchema
|
|
269
|
+
)
|
|
270
|
+
);
|
|
271
|
+
|
|
272
|
+
const LabelShape = {
|
|
273
|
+
offset: GraphStyleValueSchema.optional(),
|
|
274
|
+
opacity: GraphStyleValueSchema.optional(),
|
|
275
|
+
color: GraphStyleValueSchema.optional(),
|
|
276
|
+
text: GraphStyleValueSchema.optional(),
|
|
277
|
+
fontSize: GraphStyleValueSchema.optional(),
|
|
278
|
+
textAnchor: GraphStyleValueSchema.optional(),
|
|
279
|
+
alignmentBaseline: GraphStyleValueSchema.optional(),
|
|
280
|
+
angle: GraphStyleValueSchema.optional(),
|
|
281
|
+
scaleWithZoom: GraphStyleValueSchema.optional(),
|
|
282
|
+
textMaxWidth: GraphStyleValueSchema.optional(),
|
|
283
|
+
textWordBreak: GraphStyleValueSchema.optional(),
|
|
284
|
+
textSizeMinPixels: GraphStyleValueSchema.optional()
|
|
285
|
+
} as const;
|
|
286
|
+
|
|
287
|
+
const LabelPropertiesSchema = z.object(LabelShape).partial().strict();
|
|
288
|
+
|
|
289
|
+
const LabelStylesheetSchema = z
|
|
290
|
+
.object({
|
|
291
|
+
type: z.literal('label'),
|
|
292
|
+
...LabelShape
|
|
293
|
+
})
|
|
294
|
+
.catchall(z.unknown())
|
|
295
|
+
.superRefine(createSelectorRefinement(Object.keys(LabelShape), LabelPropertiesSchema));
|
|
296
|
+
|
|
297
|
+
const MarkerShape = {
|
|
298
|
+
offset: GraphStyleValueSchema.optional(),
|
|
299
|
+
opacity: GraphStyleValueSchema.optional(),
|
|
300
|
+
fill: GraphStyleValueSchema.optional(),
|
|
301
|
+
size: GraphStyleValueSchema.optional(),
|
|
302
|
+
marker: GraphStyleValueSchema.optional(),
|
|
303
|
+
scaleWithZoom: GraphStyleValueSchema.optional()
|
|
304
|
+
} as const;
|
|
305
|
+
|
|
306
|
+
const MarkerPropertiesSchema = z.object(MarkerShape).partial().strict();
|
|
307
|
+
|
|
308
|
+
const MarkerStylesheetSchema = z
|
|
309
|
+
.object({
|
|
310
|
+
type: z.literal('marker'),
|
|
311
|
+
...MarkerShape
|
|
312
|
+
})
|
|
313
|
+
.catchall(z.unknown())
|
|
314
|
+
.superRefine(createSelectorRefinement(Object.keys(MarkerShape), MarkerPropertiesSchema));
|
|
315
|
+
|
|
316
|
+
const EdgeUpperShape = {
|
|
317
|
+
stroke: GraphStyleValueSchema.optional(),
|
|
318
|
+
strokeWidth: GraphStyleValueSchema.optional()
|
|
319
|
+
} as const;
|
|
320
|
+
|
|
321
|
+
const EdgeUpperPropertiesSchema = z.object(EdgeUpperShape).partial().strict();
|
|
322
|
+
|
|
323
|
+
const EdgeUpperStylesheetSchema = z
|
|
324
|
+
.object({
|
|
325
|
+
type: z.literal('Edge'),
|
|
326
|
+
...EdgeUpperShape
|
|
327
|
+
})
|
|
328
|
+
.catchall(z.unknown())
|
|
329
|
+
.superRefine(createSelectorRefinement(Object.keys(EdgeUpperShape), EdgeUpperPropertiesSchema));
|
|
330
|
+
|
|
331
|
+
const EdgeLowerShape = {
|
|
332
|
+
stroke: GraphStyleValueSchema.optional(),
|
|
333
|
+
strokeWidth: GraphStyleValueSchema.optional()
|
|
334
|
+
} as const;
|
|
335
|
+
|
|
336
|
+
const EdgeLowerPropertiesSchema = z.object(EdgeLowerShape).partial().strict();
|
|
337
|
+
|
|
338
|
+
const EdgeLowerStylesheetSchema = z
|
|
339
|
+
.object({
|
|
340
|
+
type: z.literal('edge'),
|
|
341
|
+
...EdgeLowerShape
|
|
342
|
+
})
|
|
343
|
+
.catchall(z.unknown())
|
|
344
|
+
.superRefine(createSelectorRefinement(Object.keys(EdgeLowerShape), EdgeLowerPropertiesSchema));
|
|
345
|
+
|
|
346
|
+
const EdgeLabelShape = {
|
|
347
|
+
color: GraphStyleValueSchema.optional(),
|
|
348
|
+
text: GraphStyleValueSchema.optional(),
|
|
349
|
+
fontSize: GraphStyleValueSchema.optional(),
|
|
350
|
+
textAnchor: GraphStyleValueSchema.optional(),
|
|
351
|
+
alignmentBaseline: GraphStyleValueSchema.optional(),
|
|
352
|
+
scaleWithZoom: GraphStyleValueSchema.optional(),
|
|
353
|
+
textMaxWidth: GraphStyleValueSchema.optional(),
|
|
354
|
+
textWordBreak: GraphStyleValueSchema.optional(),
|
|
355
|
+
textSizeMinPixels: GraphStyleValueSchema.optional()
|
|
356
|
+
} as const;
|
|
357
|
+
|
|
358
|
+
const EdgeLabelPropertiesSchema = z.object(EdgeLabelShape).partial().strict();
|
|
359
|
+
|
|
360
|
+
const EdgeLabelStylesheetSchema = z
|
|
361
|
+
.object({
|
|
362
|
+
type: z.literal('edge-label'),
|
|
363
|
+
...EdgeLabelShape
|
|
364
|
+
})
|
|
365
|
+
.catchall(z.unknown())
|
|
366
|
+
.superRefine(createSelectorRefinement(Object.keys(EdgeLabelShape), EdgeLabelPropertiesSchema));
|
|
367
|
+
|
|
368
|
+
const FlowShape = {
|
|
369
|
+
color: GraphStyleValueSchema.optional(),
|
|
370
|
+
width: GraphStyleValueSchema.optional(),
|
|
371
|
+
speed: GraphStyleValueSchema.optional(),
|
|
372
|
+
tailLength: GraphStyleValueSchema.optional()
|
|
373
|
+
} as const;
|
|
374
|
+
|
|
375
|
+
const FlowPropertiesSchema = z.object(FlowShape).partial().strict();
|
|
376
|
+
|
|
377
|
+
const FlowStylesheetSchema = z
|
|
378
|
+
.object({
|
|
379
|
+
type: z.literal('flow'),
|
|
380
|
+
...FlowShape
|
|
381
|
+
})
|
|
382
|
+
.catchall(z.unknown())
|
|
383
|
+
.superRefine(createSelectorRefinement(Object.keys(FlowShape), FlowPropertiesSchema));
|
|
384
|
+
|
|
385
|
+
const ArrowShape = {
|
|
386
|
+
color: GraphStyleValueSchema.optional(),
|
|
387
|
+
size: GraphStyleValueSchema.optional(),
|
|
388
|
+
offset: GraphStyleValueSchema.optional()
|
|
389
|
+
} as const;
|
|
390
|
+
|
|
391
|
+
const ArrowPropertiesSchema = z.object(ArrowShape).partial().strict();
|
|
392
|
+
|
|
393
|
+
const ArrowStylesheetSchema = z
|
|
394
|
+
.object({
|
|
395
|
+
type: z.literal('arrow'),
|
|
396
|
+
...ArrowShape
|
|
397
|
+
})
|
|
398
|
+
.catchall(z.unknown())
|
|
399
|
+
.superRefine(createSelectorRefinement(Object.keys(ArrowShape), ArrowPropertiesSchema));
|
|
400
|
+
|
|
401
|
+
const GraphNodeStylesheetVariants = [
|
|
402
|
+
CircleStylesheetSchema,
|
|
403
|
+
RectangleStylesheetSchema,
|
|
404
|
+
RoundedRectangleStylesheetSchema,
|
|
405
|
+
PathRoundedRectangleStylesheetSchema,
|
|
406
|
+
LabelStylesheetSchema,
|
|
407
|
+
MarkerStylesheetSchema
|
|
408
|
+
];
|
|
409
|
+
|
|
410
|
+
const GraphEdgeStylesheetVariants = [
|
|
411
|
+
EdgeUpperStylesheetSchema,
|
|
412
|
+
EdgeLowerStylesheetSchema,
|
|
413
|
+
EdgeLabelStylesheetSchema,
|
|
414
|
+
FlowStylesheetSchema,
|
|
415
|
+
ArrowStylesheetSchema
|
|
416
|
+
];
|
|
417
|
+
|
|
418
|
+
const GraphStyleRuleVariants = [...GraphNodeStylesheetVariants, ...GraphEdgeStylesheetVariants];
|
|
419
|
+
|
|
420
|
+
type GraphStyleRuleVariantSchema = (typeof GraphStyleRuleVariants)[number];
|
|
421
|
+
|
|
422
|
+
/**
|
|
423
|
+
* Schema that validates stylesheet definitions for all graph style primitives.
|
|
424
|
+
*/
|
|
425
|
+
export const GraphStyleRuleSchema = z.discriminatedUnion(
|
|
426
|
+
'type',
|
|
427
|
+
GraphStyleRuleVariants as [GraphStyleRuleVariantSchema, ...GraphStyleRuleVariantSchema[]]
|
|
428
|
+
);
|
|
429
|
+
|
|
430
|
+
/**
|
|
431
|
+
* Runtime type accepted by {@link GraphStyleRuleSchema} before validation.
|
|
432
|
+
*/
|
|
433
|
+
export type GraphStyleRule = z.input<typeof GraphStyleRuleSchema>;
|
|
434
|
+
/**
|
|
435
|
+
* Type returned by {@link GraphStyleRuleSchema} after successful parsing.
|
|
436
|
+
*/
|
|
437
|
+
export type GraphStyleRuleParsed = z.infer<typeof GraphStyleRuleSchema>;
|
|
438
|
+
|
|
439
|
+
const GraphNodeStyleRuleSchema = z.discriminatedUnion(
|
|
440
|
+
'type',
|
|
441
|
+
GraphNodeStylesheetVariants as [
|
|
442
|
+
(typeof GraphNodeStylesheetVariants)[number],
|
|
443
|
+
...(typeof GraphNodeStylesheetVariants)[number][]
|
|
444
|
+
]
|
|
445
|
+
);
|
|
446
|
+
|
|
447
|
+
const GraphEdgeDecoratorRuleSchema = z.discriminatedUnion('type', [
|
|
448
|
+
EdgeLabelStylesheetSchema,
|
|
449
|
+
FlowStylesheetSchema,
|
|
450
|
+
ArrowStylesheetSchema
|
|
451
|
+
] as [
|
|
452
|
+
typeof EdgeLabelStylesheetSchema,
|
|
453
|
+
typeof FlowStylesheetSchema,
|
|
454
|
+
typeof ArrowStylesheetSchema,
|
|
455
|
+
...Array<
|
|
456
|
+
typeof EdgeLabelStylesheetSchema | typeof FlowStylesheetSchema | typeof ArrowStylesheetSchema
|
|
457
|
+
>
|
|
458
|
+
]);
|
|
459
|
+
|
|
460
|
+
const EdgeUpperWithDecoratorsSchema = EdgeUpperStylesheetSchema.safeExtend({
|
|
461
|
+
decorators: z.array(GraphEdgeDecoratorRuleSchema).optional()
|
|
462
|
+
});
|
|
463
|
+
|
|
464
|
+
const EdgeLowerWithDecoratorsSchema = EdgeLowerStylesheetSchema.safeExtend({
|
|
465
|
+
decorators: z.array(GraphEdgeDecoratorRuleSchema).optional()
|
|
466
|
+
});
|
|
467
|
+
|
|
468
|
+
const GraphEdgeRuleWithDecoratorsSchema = z.discriminatedUnion('type', [
|
|
469
|
+
EdgeUpperWithDecoratorsSchema,
|
|
470
|
+
EdgeLowerWithDecoratorsSchema
|
|
471
|
+
] as [typeof EdgeUpperWithDecoratorsSchema, typeof EdgeLowerWithDecoratorsSchema]);
|
|
472
|
+
|
|
473
|
+
/**
|
|
474
|
+
* Schema that validates a full graph stylesheet including nodes, edges, and decorators.
|
|
475
|
+
*/
|
|
476
|
+
export const GraphStylesheetSchema = z
|
|
477
|
+
.object({
|
|
478
|
+
nodes: z.array(GraphNodeStyleRuleSchema).optional(),
|
|
479
|
+
edges: z.array(GraphEdgeRuleWithDecoratorsSchema).optional()
|
|
480
|
+
})
|
|
481
|
+
.strict();
|
|
482
|
+
|
|
483
|
+
/**
|
|
484
|
+
* Runtime type accepted by {@link GraphStylesheetSchema} before validation.
|
|
485
|
+
*/
|
|
486
|
+
export type GraphStylesheet = z.input<typeof GraphStylesheetSchema>;
|
|
487
|
+
/**
|
|
488
|
+
* Type returned by {@link GraphStylesheetSchema} after successful parsing.
|
|
489
|
+
*/
|
|
490
|
+
export type GraphStylesheetParsed = z.infer<typeof GraphStylesheetSchema>;
|