@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.
Files changed (131) hide show
  1. package/dist/_deprecated/old-constants.d.ts.map +1 -1
  2. package/dist/_deprecated/old-constants.js.map +1 -1
  3. package/dist/core/graph-engine.d.ts +3 -2
  4. package/dist/core/graph-engine.d.ts.map +1 -1
  5. package/dist/core/graph-engine.js +1 -0
  6. package/dist/core/graph-engine.js.map +1 -1
  7. package/dist/core/graph-layout.d.ts.map +1 -1
  8. package/dist/core/graph-layout.js.map +1 -1
  9. package/dist/core/interaction-manager.d.ts.map +1 -1
  10. package/dist/core/interaction-manager.js.map +1 -1
  11. package/dist/graph/arrow-graph.d.ts.map +1 -1
  12. package/dist/graph/arrow-graph.js.map +1 -1
  13. package/dist/graph/classic-graph.d.ts.map +1 -1
  14. package/dist/graph/classic-graph.js +1 -3
  15. package/dist/graph/classic-graph.js.map +1 -1
  16. package/dist/graph/functions/arrow-utils.d.ts.map +1 -1
  17. package/dist/graph/functions/arrow-utils.js +5 -3
  18. package/dist/graph/functions/arrow-utils.js.map +1 -1
  19. package/dist/graph/functions/create-graph-from-data.d.ts.map +1 -1
  20. package/dist/graph/functions/create-graph-from-data.js.map +1 -1
  21. package/dist/graph/graph-normalization.d.ts.map +1 -1
  22. package/dist/graph/graph-normalization.js.map +1 -1
  23. package/dist/graph-data/arrow-graph-data-builder.d.ts.map +1 -1
  24. package/dist/graph-data/arrow-graph-data-builder.js.map +1 -1
  25. package/dist/graph-data/graph-data-builder.d.ts.map +1 -1
  26. package/dist/graph-data/plain-graph-data-builder.d.ts.map +1 -1
  27. package/dist/graph-style-schema.cdn.js +1 -1
  28. package/dist/graph-style-schema.json +1 -1
  29. package/dist/index.cjs +332 -224
  30. package/dist/index.cjs.map +4 -4
  31. package/dist/index.d.ts +3 -3
  32. package/dist/index.d.ts.map +1 -1
  33. package/dist/index.js +2 -2
  34. package/dist/index.js.map +1 -1
  35. package/dist/layers/common-layers/grid-layer/grid-layer.d.ts.map +1 -1
  36. package/dist/layers/common-layers/grid-layer/grid-layer.js +6 -16
  37. package/dist/layers/common-layers/grid-layer/grid-layer.js.map +1 -1
  38. package/dist/layers/edge-attachment-helper.d.ts.map +1 -1
  39. package/dist/layers/edge-attachment-helper.js +1 -3
  40. package/dist/layers/edge-attachment-helper.js.map +1 -1
  41. package/dist/layers/edge-layer.js +4 -4
  42. package/dist/layers/edge-layer.js.map +1 -1
  43. package/dist/layers/edge-layers/arrow-2d-geometry.js +1 -8
  44. package/dist/layers/edge-layers/arrow-2d-geometry.js.map +1 -1
  45. package/dist/layers/graph-layer.d.ts +4 -3
  46. package/dist/layers/graph-layer.d.ts.map +1 -1
  47. package/dist/layers/graph-layer.js +20 -17
  48. package/dist/layers/graph-layer.js.map +1 -1
  49. package/dist/layouts/d3-dag/collapsable-d3-dag-layout.d.ts.map +1 -1
  50. package/dist/layouts/d3-dag/collapsable-d3-dag-layout.js.map +1 -1
  51. package/dist/layouts/d3-dag/d3-dag-layout.d.ts.map +1 -1
  52. package/dist/layouts/d3-dag/d3-dag-layout.js +9 -2
  53. package/dist/layouts/d3-dag/d3-dag-layout.js.map +1 -1
  54. package/dist/layouts/experimental/radial-layout.d.ts.map +1 -1
  55. package/dist/layouts/experimental/radial-layout.js.map +1 -1
  56. package/dist/layouts/simple-layout.d.ts.map +1 -1
  57. package/dist/layouts/simple-layout.js +4 -1
  58. package/dist/layouts/simple-layout.js.map +1 -1
  59. package/dist/loaders/dot-graph-loader.d.ts.map +1 -1
  60. package/dist/loaders/dot-graph-loader.js +10 -3
  61. package/dist/loaders/dot-graph-loader.js.map +1 -1
  62. package/dist/loaders/json-graph-loader.d.ts.map +1 -1
  63. package/dist/loaders/json-graph-loader.js +2 -2
  64. package/dist/loaders/json-graph-loader.js.map +1 -1
  65. package/dist/loaders/parsers/parse-json-graph.js +2 -1
  66. package/dist/loaders/parsers/parse-json-graph.js.map +1 -1
  67. package/dist/style/graph-layer-stylesheet.d.ts +14 -5
  68. package/dist/style/graph-layer-stylesheet.d.ts.map +1 -1
  69. package/dist/style/graph-layer-stylesheet.js +14 -8
  70. package/dist/style/graph-layer-stylesheet.js.map +1 -1
  71. package/dist/style/graph-style-engine.d.ts +4 -4
  72. package/dist/style/graph-style-engine.d.ts.map +1 -1
  73. package/dist/style/graph-style-engine.js +7 -5
  74. package/dist/style/graph-style-engine.js.map +1 -1
  75. package/dist/style/graph-stylesheet-schema.d.ts +13211 -0
  76. package/dist/style/graph-stylesheet-schema.d.ts.map +1 -0
  77. package/dist/style/graph-stylesheet-schema.js +346 -0
  78. package/dist/style/graph-stylesheet-schema.js.map +1 -0
  79. package/dist/style/style-property.d.ts.map +1 -1
  80. package/dist/style/style-property.js +17 -5
  81. package/dist/style/style-property.js.map +1 -1
  82. package/dist/style/stylesheet-engine.d.ts.map +1 -1
  83. package/dist/style/stylesheet-engine.js +1 -1
  84. package/dist/style/stylesheet-engine.js.map +1 -1
  85. package/dist/utils/collapsed-chains.d.ts.map +1 -1
  86. package/dist/utils/collapsed-chains.js.map +1 -1
  87. package/dist/utils/node-boundary.d.ts.map +1 -1
  88. package/dist/utils/node-boundary.js +1 -1
  89. package/dist/utils/node-boundary.js.map +1 -1
  90. package/dist/utils/rank-grid.d.ts.map +1 -1
  91. package/dist/utils/rank-grid.js +5 -2
  92. package/dist/utils/rank-grid.js.map +1 -1
  93. package/package.json +8 -8
  94. package/src/_deprecated/old-constants.ts +12 -6
  95. package/src/core/graph-engine.ts +7 -2
  96. package/src/core/graph-layout.ts +2 -6
  97. package/src/core/interaction-manager.ts +2 -1
  98. package/src/graph/arrow-graph.ts +17 -10
  99. package/src/graph/classic-graph.ts +8 -5
  100. package/src/graph/functions/arrow-utils.ts +8 -4
  101. package/src/graph/functions/create-graph-from-data.ts +2 -2
  102. package/src/graph/graph-normalization.ts +8 -2
  103. package/src/graph-data/arrow-graph-data-builder.ts +6 -3
  104. package/src/graph-data/graph-data-builder.ts +1 -1
  105. package/src/graph-data/plain-graph-data-builder.ts +1 -1
  106. package/src/index.ts +35 -17
  107. package/src/layers/common-layers/grid-layer/grid-layer.ts +26 -19
  108. package/src/layers/edge-attachment-helper.ts +54 -45
  109. package/src/layers/edge-layer.ts +4 -4
  110. package/src/layers/edge-layers/arrow-2d-geometry.ts +1 -8
  111. package/src/layers/graph-layer.ts +109 -99
  112. package/src/layouts/d3-dag/collapsable-d3-dag-layout.ts +14 -7
  113. package/src/layouts/d3-dag/d3-dag-layout.ts +31 -19
  114. package/src/layouts/experimental/radial-layout.ts +4 -1
  115. package/src/layouts/simple-layout.ts +6 -4
  116. package/src/loaders/dot-graph-loader.ts +19 -7
  117. package/src/loaders/json-graph-loader.ts +3 -5
  118. package/src/loaders/parsers/parse-json-graph.ts +2 -1
  119. package/src/style/graph-layer-stylesheet.ts +26 -19
  120. package/src/style/graph-style-engine.ts +30 -17
  121. package/src/style/graph-stylesheet-schema.ts +490 -0
  122. package/src/style/style-property.ts +26 -11
  123. package/src/style/stylesheet-engine.ts +44 -29
  124. package/src/utils/collapsed-chains.ts +6 -2
  125. package/src/utils/node-boundary.ts +2 -3
  126. package/src/utils/rank-grid.ts +31 -17
  127. package/dist/style/graph-stylesheet.schema.d.ts +0 -311
  128. package/dist/style/graph-stylesheet.schema.d.ts.map +0 -1
  129. package/dist/style/graph-stylesheet.schema.js +0 -238
  130. package/dist/style/graph-stylesheet.schema.js.map +0 -1
  131. 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 = GraphStylesheet<GraphNodeStyleType> & {
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 = GraphStylesheet<GraphEdgeDecoratorType>;
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
- | GraphStylesheet<EdgeStyleType>
26
- | (Omit<GraphStylesheet<EdgeStyleType>, 'type'> & {type?: EdgeStyleType})
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
- type: 'edge',
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
- ? [resolvedEdgeStyles]
83
- : DEFAULT_GRAPH_LAYER_STYLESHEET.edges;
84
-
85
- const edges: GraphLayerEdgeStyle[] = (edgeEntries)
86
- .filter(Boolean)
87
- .map((edgeStyleEntry) => ({
88
- ...edgeStyleEntry,
89
- type: ((edgeStyleEntry).type ?? 'edge'),
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
- GraphStylesheetSchema,
12
- type GraphStylesheet,
13
- type GraphStylesheetParsed
14
- } from './graph-stylesheet.schema';
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(style: GraphStylesheet, {stateUpdateTrigger}: {stateUpdateTrigger?: unknown} = {}) {
44
- const result = GraphStylesheetSchema.safeParse(style);
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 GraphStylesheet, {
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
- } from './graph-stylesheet.schema';
70
+ GraphStylesheetSchema,
71
+ GraphStyleRuleSchema
72
+ } from './graph-stylesheet-schema';
69
73
 
70
74
  export type {
71
75
  GraphStylesheet,
72
- GraphStylesheetInput,
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.schema';
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(style: GraphStylesheet, issues: ZodIssue[]): GraphStylesheetParsed {
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' ? (style as {type: string}).type : undefined;
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 = GraphStylesheetSchema.safeParse(sanitized);
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(target: Record<string, unknown> | unknown[], path: (string | number)[]) {
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>;