@skygraph/styles 0.0.0-placeholder.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +92 -6
- package/components/autocomplete.css +33 -0
- package/components/avatar.css +37 -0
- package/components/badge.css +102 -0
- package/components/breadcrumb.css +29 -0
- package/components/button.css +181 -0
- package/components/calendar.css +408 -0
- package/components/carousel.css +102 -0
- package/components/cascader.css +354 -0
- package/components/charts.css +408 -0
- package/components/checkbox.css +114 -0
- package/components/collapse.css +166 -0
- package/components/colorpicker.css +252 -0
- package/components/context-menu.css +95 -0
- package/components/dashboard.css +299 -0
- package/components/datagrid.css +86 -0
- package/components/datepicker.css +601 -0
- package/components/descriptions.css +82 -0
- package/components/diagram.css +435 -0
- package/components/drawer.css +103 -0
- package/components/dropdown.css +93 -0
- package/components/empty.css +25 -0
- package/components/event-timeline.css +100 -0
- package/components/field.css +35 -0
- package/components/form.css +115 -0
- package/components/gantt.css +166 -0
- package/components/inline-edit.css +113 -0
- package/components/input-group.css +79 -0
- package/components/input-number.css +76 -0
- package/components/input-password.css +104 -0
- package/components/input.css +185 -0
- package/components/list.css +357 -0
- package/components/mentions.css +54 -0
- package/components/menu.css +309 -0
- package/components/modal.css +77 -0
- package/components/notification.css +128 -0
- package/components/pagination.css +162 -0
- package/components/pin-input.css +71 -0
- package/components/popconfirm.css +95 -0
- package/components/progress.css +116 -0
- package/components/radio.css +95 -0
- package/components/rate.css +34 -0
- package/components/resource-calendar.css +224 -0
- package/components/result.css +45 -0
- package/components/schema-form-editor.css +433 -0
- package/components/search-input.css +112 -0
- package/components/segmented.css +76 -0
- package/components/select.css +172 -0
- package/components/skeleton.css +68 -0
- package/components/slider.css +51 -0
- package/components/spin.css +86 -0
- package/components/steps.css +185 -0
- package/components/switch.css +75 -0
- package/components/table.css +1023 -0
- package/components/tabs.css +117 -0
- package/components/tag-input.css +94 -0
- package/components/tag.css +61 -0
- package/components/textarea.css +22 -0
- package/components/timeline.css +169 -0
- package/components/timepicker.css +213 -0
- package/components/tooltip.css +91 -0
- package/components/transfer.css +140 -0
- package/components/tree.css +574 -0
- package/components/treeselect.css +219 -0
- package/components/upload.css +124 -0
- package/index.css +69 -3
- package/index.d.ts +9 -0
- package/package.json +102 -18
- package/print.css +88 -0
- package/reset.css +17 -0
- package/themes/dark.css +17 -0
- package/themes/default.css +14 -0
- package/tokens.css +312 -0
- package/transitions.css +158 -0
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
.sg-descriptions {
|
|
2
|
+
font-size: var(--sg-font-size);
|
|
3
|
+
color: var(--sg-color-text);
|
|
4
|
+
width: 100%;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
.sg-descriptions-title {
|
|
8
|
+
font-size: var(--sg-font-size-lg);
|
|
9
|
+
font-weight: 600;
|
|
10
|
+
color: var(--sg-color-text);
|
|
11
|
+
margin-bottom: var(--sg-margin-md);
|
|
12
|
+
line-height: var(--sg-line-height);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
.sg-descriptions-table {
|
|
16
|
+
width: 100%;
|
|
17
|
+
border-collapse: collapse;
|
|
18
|
+
table-layout: auto;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.sg-descriptions-row {
|
|
22
|
+
vertical-align: top;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.sg-descriptions-item-label {
|
|
26
|
+
font-weight: 500;
|
|
27
|
+
color: var(--sg-color-text-secondary);
|
|
28
|
+
white-space: nowrap;
|
|
29
|
+
text-align: left;
|
|
30
|
+
padding: var(--sg-padding-sm) var(--sg-padding-md) var(--sg-padding-sm) 0;
|
|
31
|
+
line-height: var(--sg-line-height);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.sg-descriptions-item-content {
|
|
35
|
+
color: var(--sg-color-text);
|
|
36
|
+
padding: var(--sg-padding-sm) var(--sg-padding-md) var(--sg-padding-sm) 0;
|
|
37
|
+
line-height: var(--sg-line-height);
|
|
38
|
+
word-break: break-word;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
.sg-descriptions-colon {
|
|
42
|
+
margin-right: var(--sg-margin-sm);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/* Bordered */
|
|
46
|
+
.sg-descriptions-bordered .sg-descriptions-table {
|
|
47
|
+
border: 1px solid var(--sg-color-border-secondary);
|
|
48
|
+
border-radius: var(--sg-border-radius);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.sg-descriptions-bordered .sg-descriptions-item-label,
|
|
52
|
+
.sg-descriptions-bordered .sg-descriptions-item-content {
|
|
53
|
+
padding: var(--sg-padding-sm) var(--sg-padding-lg);
|
|
54
|
+
border-bottom: 1px solid var(--sg-color-border-secondary);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.sg-descriptions-bordered .sg-descriptions-item-label {
|
|
58
|
+
background: var(--sg-color-bg-secondary);
|
|
59
|
+
border-right: 1px solid var(--sg-color-border-secondary);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.sg-descriptions-bordered .sg-descriptions-row:last-child .sg-descriptions-item-label,
|
|
63
|
+
.sg-descriptions-bordered .sg-descriptions-row:last-child .sg-descriptions-item-content {
|
|
64
|
+
border-bottom: none;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/* Sizes */
|
|
68
|
+
.sg-descriptions-small .sg-descriptions-item-label,
|
|
69
|
+
.sg-descriptions-small .sg-descriptions-item-content {
|
|
70
|
+
padding: var(--sg-padding-xs) var(--sg-padding-sm) var(--sg-padding-xs) 0;
|
|
71
|
+
font-size: var(--sg-font-size-sm);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
.sg-descriptions-small.sg-descriptions-bordered .sg-descriptions-item-label,
|
|
75
|
+
.sg-descriptions-small.sg-descriptions-bordered .sg-descriptions-item-content {
|
|
76
|
+
padding: var(--sg-padding-xs) var(--sg-padding-md);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
.sg-descriptions-middle .sg-descriptions-item-label,
|
|
80
|
+
.sg-descriptions-middle .sg-descriptions-item-content {
|
|
81
|
+
padding: var(--sg-padding-sm) var(--sg-padding-md) var(--sg-padding-sm) 0;
|
|
82
|
+
}
|
|
@@ -0,0 +1,435 @@
|
|
|
1
|
+
/* Diagram — visual layer for GraphEngine.
|
|
2
|
+
*
|
|
3
|
+
* All chrome (canvas, grid, nodes, edges, lasso, hover toolbar) goes
|
|
4
|
+
* through `--sg-diagram-*` semantic tokens defined in `tokens.css`. Dark
|
|
5
|
+
* theme overrides those tokens, so every visual surface here re-themes
|
|
6
|
+
* automatically without per-rule duplication.
|
|
7
|
+
*
|
|
8
|
+
* Hover / selected / dragging states use existing `data-*` attributes
|
|
9
|
+
* emitted by `Diagram.tsx` (`data-selected`, `data-sg-dragging`,
|
|
10
|
+
* `data-selection-mode`). No new class names are introduced — the visual
|
|
11
|
+
* polish lives entirely in this file.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
.sg-diagram {
|
|
15
|
+
/*
|
|
16
|
+
* Component-local CSS variables. `<Diagram>` overrides `--sg-grid-size`
|
|
17
|
+
* via inline-style (`style={{ '--sg-grid-size': '20px' }}`) when
|
|
18
|
+
* snap-to-grid is active so the background pattern stays in sync with
|
|
19
|
+
* the snap step (and the current zoom). Defaults are declared here so
|
|
20
|
+
* `var()` always resolves to a real value — required by `check:tokens`.
|
|
21
|
+
*/
|
|
22
|
+
--sg-grid-size: 20px;
|
|
23
|
+
|
|
24
|
+
/* Local aliases that delegate to the new semantic tokens. They keep
|
|
25
|
+
* back-compat for any consumer who pinned to the old name and let
|
|
26
|
+
* us redirect the visual treatment globally by overriding the
|
|
27
|
+
* semantic token only. */
|
|
28
|
+
--sg-diagram-shadow-md: var(--sg-diagram-node-shadow-hover);
|
|
29
|
+
--sg-diagram-edge-hover-stroke: var(--sg-diagram-edge-color-hover);
|
|
30
|
+
--sg-diagram-selected-ring: var(--sg-diagram-edge-color-selected);
|
|
31
|
+
--sg-diagram-lasso-bg: var(--sg-diagram-lasso-fill);
|
|
32
|
+
--sg-diagram-lasso-border: var(--sg-diagram-lasso-stroke);
|
|
33
|
+
|
|
34
|
+
position: relative;
|
|
35
|
+
background-color: var(--sg-diagram-canvas-bg);
|
|
36
|
+
/* Subtle dot-pattern that gives the empty canvas a sense of "infinite
|
|
37
|
+
* surface" without the noise of full grid lines. The strong-color dot
|
|
38
|
+
* sits at every 32px; combined with the grid overlay (`.sg-diagram-grid`)
|
|
39
|
+
* this creates a clean two-tier rhythm. We use radial-gradients so the
|
|
40
|
+
* pattern stays pin-sharp at any zoom and never bleeds onto nodes
|
|
41
|
+
* (nodes have their own opaque background). */
|
|
42
|
+
background-image: radial-gradient(
|
|
43
|
+
circle at 1px 1px,
|
|
44
|
+
var(--sg-diagram-grid-line-color) 1px,
|
|
45
|
+
transparent 1.5px
|
|
46
|
+
);
|
|
47
|
+
background-size: 20px 20px;
|
|
48
|
+
border: 1px solid var(--sg-color-border);
|
|
49
|
+
border-radius: var(--sg-border-radius);
|
|
50
|
+
/* Make selection feedback feel snappy but not jarring on dense graphs. */
|
|
51
|
+
transition: border-color var(--sg-transition-medium);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.sg-diagram:focus-within {
|
|
55
|
+
border-color: var(--sg-color-primary);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/* While the user is mid-lasso, hint that a multi-select is in progress
|
|
59
|
+
* by lifting the canvas border to the primary color. */
|
|
60
|
+
.sg-diagram[data-selection-mode='lasso']:hover {
|
|
61
|
+
cursor: crosshair;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/* Suppress native scroll/pinch when lasso selection is active — the
|
|
65
|
+
* wrapper owns those gestures via Pointer Events. Single-selection
|
|
66
|
+
* canvases keep native scroll behaviour because they don't intercept
|
|
67
|
+
* empty-canvas drags. */
|
|
68
|
+
.sg-diagram[data-selection-mode='lasso'],
|
|
69
|
+
.sg-diagram[data-selection-mode='multi'] {
|
|
70
|
+
touch-action: none;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/* When the canvas accepts DnD drops (palette → canvas) and the user is
|
|
74
|
+
* mid-drag, highlight the border so the drop target is obvious. The
|
|
75
|
+
* `data-sg-drop="true"` attribute is set by `<Diagram>` whenever an
|
|
76
|
+
* `onDropNode` / `@drop-node` listener is attached.
|
|
77
|
+
*
|
|
78
|
+
* The wide outline uses the primary-token so dark mode inverts
|
|
79
|
+
* automatically. */
|
|
80
|
+
.sg-diagram[data-sg-drop='true'] {
|
|
81
|
+
/* nothing extra in the rest state — keep the diagram looking calm */
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.sg-diagram[data-sg-drop='true'].sg-diagram-drag-over,
|
|
85
|
+
.sg-diagram[data-sg-drop='true']:has(.sg-diagram-drag-indicator) {
|
|
86
|
+
/* Reserved for future preview / drop indicator. */
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/* Snap-to-grid hook — applied when `<Diagram snapToGrid={N}>` is set.
|
|
90
|
+
* The two-line gradient overlays the dot-pattern from `.sg-diagram` to
|
|
91
|
+
* give a proper grid reading. The strong color is used for "every Nth"
|
|
92
|
+
* line by relying on the larger background-size on the wrapper. */
|
|
93
|
+
.sg-diagram-grid {
|
|
94
|
+
background-image:
|
|
95
|
+
linear-gradient(to right, var(--sg-diagram-grid-line-color-strong) 1px, transparent 1px),
|
|
96
|
+
linear-gradient(to bottom, var(--sg-diagram-grid-line-color-strong) 1px, transparent 1px),
|
|
97
|
+
radial-gradient(circle at 1px 1px, var(--sg-diagram-grid-line-color) 1px, transparent 1.5px);
|
|
98
|
+
background-size:
|
|
99
|
+
var(--sg-grid-size) var(--sg-grid-size),
|
|
100
|
+
var(--sg-grid-size) var(--sg-grid-size),
|
|
101
|
+
calc(var(--sg-grid-size) / 2) calc(var(--sg-grid-size) / 2);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
.sg-diagram-canvas {
|
|
105
|
+
/* Inner transform host — `<Diagram>` writes translate/scale here so
|
|
106
|
+
* pan + zoom are applied to nodes and edges as one unit. */
|
|
107
|
+
transform-origin: 0 0;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/* ─── Nodes ──────────────────────────────────────────────────────────── */
|
|
111
|
+
|
|
112
|
+
.sg-diagram-node {
|
|
113
|
+
background: var(--sg-color-bg-elevated);
|
|
114
|
+
border: 1px solid var(--sg-color-border);
|
|
115
|
+
border-radius: var(--sg-border-radius);
|
|
116
|
+
display: flex;
|
|
117
|
+
align-items: center;
|
|
118
|
+
justify-content: center;
|
|
119
|
+
font-size: var(--sg-font-size);
|
|
120
|
+
color: var(--sg-color-text);
|
|
121
|
+
box-shadow: var(--sg-diagram-node-shadow);
|
|
122
|
+
user-select: none;
|
|
123
|
+
/* `touch-action: none` is essential for Pointer Events + touch: it
|
|
124
|
+
* tells the browser to suppress the default scroll / pinch-zoom
|
|
125
|
+
* gesture on this element so our drag handler keeps receiving
|
|
126
|
+
* `pointermove` events past the first ~10 px. Without it touchscreens
|
|
127
|
+
* eat the drag the moment they decide it "looks like" a scroll. */
|
|
128
|
+
touch-action: none;
|
|
129
|
+
/* `transform` is animated for the dragging-lift effect; keep the
|
|
130
|
+
* box-shadow + border-color transitions in lock-step so the change
|
|
131
|
+
* feels like a single response rather than three discrete swaps. */
|
|
132
|
+
transition:
|
|
133
|
+
box-shadow var(--sg-transition-medium),
|
|
134
|
+
transform var(--sg-transition-medium),
|
|
135
|
+
border-color var(--sg-transition-medium);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
.sg-diagram-node:hover {
|
|
139
|
+
border-color: var(--sg-color-text-secondary);
|
|
140
|
+
box-shadow: var(--sg-diagram-node-shadow-hover);
|
|
141
|
+
/* Tiny lift to convey interactivity without jumping the layout. */
|
|
142
|
+
transform: translateY(-1px);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
.sg-diagram-node[data-sg-dragging='true'] {
|
|
146
|
+
box-shadow: var(--sg-diagram-node-shadow-dragging);
|
|
147
|
+
cursor: grabbing;
|
|
148
|
+
/* Pop further out of the canvas while moving. Combined with the
|
|
149
|
+
* heavier shadow this reads as "this node is now floating above
|
|
150
|
+
* the rest". */
|
|
151
|
+
transform: scale(1.04) translateY(-2px);
|
|
152
|
+
border-color: var(--sg-color-primary);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
.sg-diagram-node-selected,
|
|
156
|
+
.sg-diagram-node[data-selected='true'] {
|
|
157
|
+
border-color: var(--sg-diagram-selected-ring);
|
|
158
|
+
box-shadow: var(--sg-diagram-node-shadow-selected);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/* When a selected node is also being dragged, the dragging shadow wins
|
|
162
|
+
* (deeper elevation), but we keep the primary border so the selection
|
|
163
|
+
* is still legible on the moving copy. */
|
|
164
|
+
.sg-diagram-node-selected[data-sg-dragging='true'],
|
|
165
|
+
.sg-diagram-node[data-selected='true'][data-sg-dragging='true'] {
|
|
166
|
+
box-shadow: var(--sg-diagram-node-shadow-dragging);
|
|
167
|
+
border-color: var(--sg-color-primary);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
.sg-diagram-node-rect {
|
|
171
|
+
/* default; nothing extra */
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
.sg-diagram-node-ellipse {
|
|
175
|
+
border-radius: 50%;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
.sg-diagram-node-polygon,
|
|
179
|
+
.sg-diagram-node-path {
|
|
180
|
+
/* For non-rect outlines the bbox-sized DIV is just a label container — the
|
|
181
|
+
* actual shape lives in the SVG overlay (or a custom renderer). */
|
|
182
|
+
background: transparent;
|
|
183
|
+
border: 1px dashed var(--sg-color-border);
|
|
184
|
+
box-shadow: none;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
.sg-diagram-node-polygon:hover,
|
|
188
|
+
.sg-diagram-node-path:hover {
|
|
189
|
+
/* The label container is purely decorative for non-rect shapes; the
|
|
190
|
+
* lift effect from the base rule would clip against the underlying
|
|
191
|
+
* SVG, so we suppress it. */
|
|
192
|
+
transform: none;
|
|
193
|
+
box-shadow: none;
|
|
194
|
+
border-color: var(--sg-color-text-secondary);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
.sg-diagram-node-label {
|
|
198
|
+
padding: 0 var(--sg-padding-md);
|
|
199
|
+
white-space: nowrap;
|
|
200
|
+
overflow: hidden;
|
|
201
|
+
text-overflow: ellipsis;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
.sg-diagram-node-draggable {
|
|
205
|
+
/* legacy hook kept for tests + back-compat — visual transitions live on
|
|
206
|
+
* `.sg-diagram-node` itself now so they apply equally to non-draggable
|
|
207
|
+
* nodes that still get hover / selected feedback. */
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
.sg-diagram-node-draggable:active {
|
|
211
|
+
cursor: grabbing;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/* ─── Edges ──────────────────────────────────────────────────────────── */
|
|
215
|
+
|
|
216
|
+
.sg-diagram-edges {
|
|
217
|
+
/* sits behind nodes; per-edge groups override pointer-events when
|
|
218
|
+
* interactivity is enabled. */
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
.sg-diagram-edge {
|
|
222
|
+
stroke: var(--sg-diagram-edge-color);
|
|
223
|
+
stroke-width: 1.5;
|
|
224
|
+
fill: none;
|
|
225
|
+
/* `linejoin: round` smooths orthogonal corners. `linecap: butt`
|
|
226
|
+
* means the path tip ends flush — combined with the marker-end
|
|
227
|
+
* sitting at `refX/refY = 0`, the arrow glyph picks up exactly
|
|
228
|
+
* where the line stops, with no visible "pill" cap protruding
|
|
229
|
+
* beyond the arrowhead. Round caps used to leak a half-circle
|
|
230
|
+
* over the marker base and that was visible on every screenshot
|
|
231
|
+
* the user shared. */
|
|
232
|
+
stroke-linejoin: round;
|
|
233
|
+
stroke-linecap: butt;
|
|
234
|
+
transition:
|
|
235
|
+
stroke var(--sg-transition-fast),
|
|
236
|
+
stroke-width var(--sg-transition-fast);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/* Bezier edges read better with a touch more weight — the curve
|
|
240
|
+
* naturally thins at the inflection point, which makes the same
|
|
241
|
+
* stroke-width look lighter than its orthogonal counterpart. */
|
|
242
|
+
.sg-diagram-edge-bezier {
|
|
243
|
+
stroke-width: 1.75;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/* Dashed for manual-routed waypoints — visually distinguishes a hand-
|
|
247
|
+
* drawn polyline from auto-routed ones. */
|
|
248
|
+
.sg-diagram-edge-manual {
|
|
249
|
+
stroke-dasharray: 6 4;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
.sg-diagram-edge-hit:hover + .sg-diagram-edge,
|
|
253
|
+
g[data-edge-id]:hover .sg-diagram-edge {
|
|
254
|
+
stroke: var(--sg-diagram-edge-hover-stroke);
|
|
255
|
+
stroke-width: 2.25;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/* Highlight edges connected to a selected node when the selection is
|
|
259
|
+
* driven via the data-attr API. The DOM doesn't tag edges by selection
|
|
260
|
+
* (they're SVG paths), so this is best-effort: we emphasise the
|
|
261
|
+
* `selected` color on `:focus-within` of the SVG group. */
|
|
262
|
+
g[data-edge-id]:focus-within .sg-diagram-edge {
|
|
263
|
+
stroke: var(--sg-diagram-edge-color-selected);
|
|
264
|
+
stroke-width: 2.25;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/* ─── Arrow markers ─────────────────────────────────────────────────── */
|
|
268
|
+
/*
|
|
269
|
+
* The arrowhead is an "open V" — two strokes meeting at the marker
|
|
270
|
+
* anchor, not a filled triangle. That gives the arrow visual cohesion
|
|
271
|
+
* with the line (same stroke), keeps it readable on dense graphs, and
|
|
272
|
+
* matches the look used by React Flow / draw.io / Lucidchart.
|
|
273
|
+
*
|
|
274
|
+
* SVG markers don't inherit `stroke` from the path automatically. We
|
|
275
|
+
* use `context-stroke` in the marker so modern browsers paint the arrow
|
|
276
|
+
* with the line colour, and rely on `currentColor` below as a fallback
|
|
277
|
+
* for Firefox / Safari versions that don't yet support context-stroke.
|
|
278
|
+
*
|
|
279
|
+
* `.sg-diagram-edges { color: ... }` is the lever per-edge state hooks
|
|
280
|
+
* (`:hover`) modulate so the arrow lights up together with the line.
|
|
281
|
+
*/
|
|
282
|
+
.sg-diagram-edges {
|
|
283
|
+
color: var(--sg-diagram-edge-color);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/* Marker glyph: stroke takes the inherited `currentColor` so old
|
|
287
|
+
* browsers without context-stroke still render the arrow in the right
|
|
288
|
+
* colour. `fill: none` is essential — the marker is an open polyline,
|
|
289
|
+
* not a triangle. */
|
|
290
|
+
.sg-diagram-arrow-fill {
|
|
291
|
+
stroke: currentColor;
|
|
292
|
+
fill: none;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
g[data-edge-id]:hover {
|
|
296
|
+
color: var(--sg-diagram-edge-hover-stroke);
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
/* ─── Hover mini-toolbar ─────────────────────────────────────────────── */
|
|
300
|
+
|
|
301
|
+
.sg-diagram-hover-actions {
|
|
302
|
+
display: inline-flex;
|
|
303
|
+
align-items: center;
|
|
304
|
+
gap: var(--sg-padding-sm);
|
|
305
|
+
padding: var(--sg-padding-xs) var(--sg-padding-sm);
|
|
306
|
+
background: var(--sg-color-bg-elevated);
|
|
307
|
+
border: 1px solid var(--sg-color-border);
|
|
308
|
+
border-radius: var(--sg-border-radius);
|
|
309
|
+
box-shadow: var(--sg-shadow-lg);
|
|
310
|
+
font-size: var(--sg-font-size-sm);
|
|
311
|
+
white-space: nowrap;
|
|
312
|
+
/* Smooth opacity-in via the parent toolkit; transition lives here so
|
|
313
|
+
* appearance stays consistent across NodeHoverActions / EdgeHoverActions. */
|
|
314
|
+
transition: box-shadow var(--sg-transition-medium);
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
.sg-diagram-hover-action {
|
|
318
|
+
display: inline-flex;
|
|
319
|
+
align-items: center;
|
|
320
|
+
justify-content: center;
|
|
321
|
+
min-width: 24px;
|
|
322
|
+
height: 24px;
|
|
323
|
+
padding: 0 var(--sg-padding-xs);
|
|
324
|
+
background: transparent;
|
|
325
|
+
border: 1px solid transparent;
|
|
326
|
+
border-radius: var(--sg-border-radius);
|
|
327
|
+
color: var(--sg-color-text);
|
|
328
|
+
font: inherit;
|
|
329
|
+
cursor: pointer;
|
|
330
|
+
transition:
|
|
331
|
+
background var(--sg-transition-fast),
|
|
332
|
+
border-color var(--sg-transition-fast),
|
|
333
|
+
color var(--sg-transition-fast);
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
.sg-diagram-hover-action:hover {
|
|
337
|
+
background: var(--sg-color-bg-hover);
|
|
338
|
+
border-color: var(--sg-color-border);
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
.sg-diagram-hover-action:focus-visible {
|
|
342
|
+
outline: 2px solid var(--sg-color-primary);
|
|
343
|
+
outline-offset: 1px;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
.sg-diagram-hover-action:active {
|
|
347
|
+
background: var(--sg-color-bg-secondary);
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
/* ─── Palette items (optional consumer hook) ─────────────────────────── */
|
|
351
|
+
|
|
352
|
+
/*
|
|
353
|
+
* `.sg-diagram-palette-item` is a reusable hook for "palette" entries
|
|
354
|
+
* that the consumer can drag onto the canvas (HTML5 DnD). The class is
|
|
355
|
+
* opt-in — `<Diagram>` itself doesn't render the palette, but consumers
|
|
356
|
+
* (`workflow-editor` showcase, etc.) can pick this up so the palette
|
|
357
|
+
* matches the diagram visual rhythm and behaves consistently.
|
|
358
|
+
*
|
|
359
|
+
* Combine with `draggable="true"` and `onDragStart` setting
|
|
360
|
+
* `dataTransfer.setData('application/x-sg-node', ...)` for the canvas
|
|
361
|
+
* to recognise the drop.
|
|
362
|
+
*/
|
|
363
|
+
.sg-diagram-palette {
|
|
364
|
+
display: flex;
|
|
365
|
+
flex-direction: column;
|
|
366
|
+
gap: var(--sg-padding-xs);
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
.sg-diagram-palette-item {
|
|
370
|
+
display: flex;
|
|
371
|
+
align-items: center;
|
|
372
|
+
gap: var(--sg-padding-sm);
|
|
373
|
+
width: 100%;
|
|
374
|
+
padding: var(--sg-padding-sm) var(--sg-padding-md);
|
|
375
|
+
border: 1px solid var(--sg-color-border);
|
|
376
|
+
border-radius: var(--sg-border-radius);
|
|
377
|
+
background: var(--sg-color-bg-elevated);
|
|
378
|
+
color: var(--sg-color-text);
|
|
379
|
+
font-size: var(--sg-font-size);
|
|
380
|
+
text-align: left;
|
|
381
|
+
cursor: grab;
|
|
382
|
+
user-select: none;
|
|
383
|
+
transition:
|
|
384
|
+
background var(--sg-transition-fast),
|
|
385
|
+
border-color var(--sg-transition-fast),
|
|
386
|
+
box-shadow var(--sg-transition-fast),
|
|
387
|
+
transform var(--sg-transition-fast);
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
.sg-diagram-palette-item:hover {
|
|
391
|
+
border-color: var(--sg-color-primary);
|
|
392
|
+
background: var(--sg-color-bg-hover);
|
|
393
|
+
box-shadow: var(--sg-diagram-node-shadow-hover);
|
|
394
|
+
transform: translateY(-1px);
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
.sg-diagram-palette-item:active {
|
|
398
|
+
cursor: grabbing;
|
|
399
|
+
transform: scale(0.98);
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
.sg-diagram-palette-item:focus-visible {
|
|
403
|
+
outline: 2px solid var(--sg-color-primary);
|
|
404
|
+
outline-offset: 2px;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
/* Icon slot inside the palette item (emoji / SVG / character glyph). */
|
|
408
|
+
.sg-diagram-palette-icon {
|
|
409
|
+
display: inline-flex;
|
|
410
|
+
align-items: center;
|
|
411
|
+
justify-content: center;
|
|
412
|
+
min-width: 24px;
|
|
413
|
+
font-size: var(--sg-font-size-lg, 16px);
|
|
414
|
+
color: var(--sg-color-text-secondary);
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
/* ─── Lasso rubber-band ──────────────────────────────────────────────── */
|
|
418
|
+
|
|
419
|
+
.sg-diagram-lasso {
|
|
420
|
+
background: var(--sg-diagram-lasso-bg);
|
|
421
|
+
border: 1px dashed var(--sg-diagram-lasso-border);
|
|
422
|
+
border-radius: 2px;
|
|
423
|
+
/* Backdrop blur on the lasso surface helps pick out which nodes fall
|
|
424
|
+
* inside on dense graphs (the desaturation gives a "cut-out" feel).
|
|
425
|
+
* `backdrop-filter` is gracefully ignored where unsupported — the
|
|
426
|
+
* dashed border + tinted fill remain the source of truth. */
|
|
427
|
+
backdrop-filter: saturate(0.85);
|
|
428
|
+
-webkit-backdrop-filter: saturate(0.85);
|
|
429
|
+
/* Inner glow + outer shadow add weight without hardcoding a colour:
|
|
430
|
+
* both reuse the primary-bg semantic token, so dark theme inverts
|
|
431
|
+
* automatically. */
|
|
432
|
+
box-shadow:
|
|
433
|
+
inset 0 0 0 1px var(--sg-color-primary-bg),
|
|
434
|
+
0 1px 4px var(--sg-color-primary-bg);
|
|
435
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
.sg-drawer-root {
|
|
2
|
+
position: fixed;
|
|
3
|
+
inset: 0;
|
|
4
|
+
z-index: var(--sg-z-modal);
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
.sg-drawer-mask {
|
|
8
|
+
position: absolute;
|
|
9
|
+
inset: 0;
|
|
10
|
+
background: var(--sg-color-overlay);
|
|
11
|
+
animation: sg-drawer-fade-in var(--sg-transition-duration) var(--sg-transition-timing);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
@keyframes sg-drawer-fade-in {
|
|
15
|
+
from { opacity: 0; }
|
|
16
|
+
to { opacity: 1; }
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.sg-drawer {
|
|
20
|
+
position: absolute;
|
|
21
|
+
display: flex;
|
|
22
|
+
flex-direction: column;
|
|
23
|
+
background: var(--sg-color-bg-elevated);
|
|
24
|
+
box-shadow: var(--sg-shadow-lg);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.sg-drawer-right {
|
|
28
|
+
top: 0;
|
|
29
|
+
right: 0;
|
|
30
|
+
bottom: 0;
|
|
31
|
+
animation: sg-drawer-slide-right var(--sg-transition-duration) var(--sg-transition-timing);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.sg-drawer-left {
|
|
35
|
+
top: 0;
|
|
36
|
+
left: 0;
|
|
37
|
+
bottom: 0;
|
|
38
|
+
animation: sg-drawer-slide-left var(--sg-transition-duration) var(--sg-transition-timing);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
.sg-drawer-top {
|
|
42
|
+
top: 0;
|
|
43
|
+
left: 0;
|
|
44
|
+
right: 0;
|
|
45
|
+
animation: sg-drawer-slide-top var(--sg-transition-duration) var(--sg-transition-timing);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.sg-drawer-bottom {
|
|
49
|
+
bottom: 0;
|
|
50
|
+
left: 0;
|
|
51
|
+
right: 0;
|
|
52
|
+
animation: sg-drawer-slide-bottom var(--sg-transition-duration) var(--sg-transition-timing);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
@keyframes sg-drawer-slide-right {
|
|
56
|
+
from { transform: translateX(100%); }
|
|
57
|
+
to { transform: translateX(0); }
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
@keyframes sg-drawer-slide-left {
|
|
61
|
+
from { transform: translateX(-100%); }
|
|
62
|
+
to { transform: translateX(0); }
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
@keyframes sg-drawer-slide-top {
|
|
66
|
+
from { transform: translateY(-100%); }
|
|
67
|
+
to { transform: translateY(0); }
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
@keyframes sg-drawer-slide-bottom {
|
|
71
|
+
from { transform: translateY(100%); }
|
|
72
|
+
to { transform: translateY(0); }
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.sg-drawer-header {
|
|
76
|
+
display: flex;
|
|
77
|
+
align-items: center;
|
|
78
|
+
justify-content: space-between;
|
|
79
|
+
padding: var(--sg-padding-md) var(--sg-padding-xl);
|
|
80
|
+
border-bottom: 1px solid var(--sg-color-border-secondary);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
.sg-drawer-title {
|
|
84
|
+
font-size: var(--sg-font-size-lg);
|
|
85
|
+
font-weight: 500;
|
|
86
|
+
color: var(--sg-color-text);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.sg-drawer-close {
|
|
90
|
+
color: var(--sg-color-text-tertiary);
|
|
91
|
+
font-size: var(--sg-font-size-xl);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
.sg-drawer-body {
|
|
95
|
+
flex: 1;
|
|
96
|
+
padding: var(--sg-padding-xl);
|
|
97
|
+
overflow: auto;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
.sg-drawer-footer {
|
|
101
|
+
padding: var(--sg-padding-md) var(--sg-padding-xl);
|
|
102
|
+
border-top: 1px solid var(--sg-color-border-secondary);
|
|
103
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
.sg-dropdown-wrapper {
|
|
2
|
+
position: relative;
|
|
3
|
+
display: inline-block;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
.sg-dropdown-trigger {
|
|
7
|
+
cursor: pointer;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
.sg-dropdown {
|
|
11
|
+
position: absolute;
|
|
12
|
+
z-index: var(--sg-z-dropdown);
|
|
13
|
+
min-width: 120px;
|
|
14
|
+
padding: var(--sg-padding-xs) 0;
|
|
15
|
+
background: var(--sg-color-bg-elevated);
|
|
16
|
+
border-radius: var(--sg-border-radius-lg);
|
|
17
|
+
box-shadow: var(--sg-shadow-lg);
|
|
18
|
+
border: 1px solid var(--sg-color-border-secondary);
|
|
19
|
+
animation: sg-dropdown-in var(--sg-transition-duration) var(--sg-transition-timing);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
@keyframes sg-dropdown-in {
|
|
23
|
+
from { opacity: 0; transform: scaleY(0.8); }
|
|
24
|
+
to { opacity: 1; transform: scaleY(1); }
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/* Placement variants — both camelCase (legacy, generated as
|
|
28
|
+
* `sg-dropdown-${placement}` from a camelCase prop) and kebab-case (preferred
|
|
29
|
+
* canonical name) are accepted. Keep both selectors in sync. */
|
|
30
|
+
.sg-dropdown-bottomLeft,
|
|
31
|
+
.sg-dropdown-bottom-left {
|
|
32
|
+
top: calc(100% + 4px);
|
|
33
|
+
left: 0;
|
|
34
|
+
transform-origin: top left;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.sg-dropdown-bottomRight,
|
|
38
|
+
.sg-dropdown-bottom-right {
|
|
39
|
+
top: calc(100% + 4px);
|
|
40
|
+
right: 0;
|
|
41
|
+
transform-origin: top right;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.sg-dropdown-topLeft,
|
|
45
|
+
.sg-dropdown-top-left {
|
|
46
|
+
bottom: calc(100% + 4px);
|
|
47
|
+
left: 0;
|
|
48
|
+
transform-origin: bottom left;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.sg-dropdown-topRight,
|
|
52
|
+
.sg-dropdown-top-right {
|
|
53
|
+
bottom: calc(100% + 4px);
|
|
54
|
+
right: 0;
|
|
55
|
+
transform-origin: bottom right;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.sg-dropdown-item {
|
|
59
|
+
padding: var(--sg-padding-xs) var(--sg-padding-md);
|
|
60
|
+
font-size: var(--sg-font-size);
|
|
61
|
+
color: var(--sg-color-text);
|
|
62
|
+
cursor: pointer;
|
|
63
|
+
transition: background var(--sg-transition-duration) var(--sg-transition-timing);
|
|
64
|
+
line-height: var(--sg-line-height);
|
|
65
|
+
white-space: nowrap;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.sg-dropdown-item:hover {
|
|
69
|
+
background: var(--sg-color-bg-hover);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.sg-dropdown-item-disabled {
|
|
73
|
+
color: var(--sg-color-text-disabled);
|
|
74
|
+
cursor: not-allowed;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.sg-dropdown-item-disabled:hover {
|
|
78
|
+
background: none;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
.sg-dropdown-item-danger {
|
|
82
|
+
color: var(--sg-color-error);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
.sg-dropdown-item-danger:hover {
|
|
86
|
+
background: var(--sg-color-error-bg);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.sg-dropdown-divider {
|
|
90
|
+
height: 1px;
|
|
91
|
+
margin: var(--sg-margin-xs) 0;
|
|
92
|
+
background: var(--sg-color-border-secondary);
|
|
93
|
+
}
|