@oh-just-another/react-ui 0.57.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/CHANGELOG.md +22 -0
- package/LICENSE +21 -0
- package/README.md +54 -0
- package/dist/.tsbuildinfo +1 -0
- package/dist/bottom-sheet.d.ts +26 -0
- package/dist/bottom-sheet.d.ts.map +1 -0
- package/dist/bottom-sheet.js +87 -0
- package/dist/bottom-sheet.js.map +1 -0
- package/dist/button-group.d.ts +14 -0
- package/dist/button-group.d.ts.map +1 -0
- package/dist/button-group.js +3 -0
- package/dist/button-group.js.map +1 -0
- package/dist/color-palette.d.ts +34 -0
- package/dist/color-palette.d.ts.map +1 -0
- package/dist/color-palette.js +77 -0
- package/dist/color-palette.js.map +1 -0
- package/dist/color-swatch-picker.d.ts +29 -0
- package/dist/color-swatch-picker.d.ts.map +1 -0
- package/dist/color-swatch-picker.js +56 -0
- package/dist/color-swatch-picker.js.map +1 -0
- package/dist/command-palette.d.ts +13 -0
- package/dist/command-palette.d.ts.map +1 -0
- package/dist/command-palette.js +146 -0
- package/dist/command-palette.js.map +1 -0
- package/dist/comments-panel.d.ts +27 -0
- package/dist/comments-panel.d.ts.map +1 -0
- package/dist/comments-panel.js +139 -0
- package/dist/comments-panel.js.map +1 -0
- package/dist/constants.d.ts +112 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +119 -0
- package/dist/constants.js.map +1 -0
- package/dist/context-menu-controller.d.ts +41 -0
- package/dist/context-menu-controller.d.ts.map +1 -0
- package/dist/context-menu-controller.js +26 -0
- package/dist/context-menu-controller.js.map +1 -0
- package/dist/context-menu.d.ts +53 -0
- package/dist/context-menu.d.ts.map +1 -0
- package/dist/context-menu.js +333 -0
- package/dist/context-menu.js.map +1 -0
- package/dist/context.d.ts +44 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +95 -0
- package/dist/context.js.map +1 -0
- package/dist/diagram-bars.d.ts +21 -0
- package/dist/diagram-bars.d.ts.map +1 -0
- package/dist/diagram-bars.js +4 -0
- package/dist/diagram-bars.js.map +1 -0
- package/dist/diagram-canvas.d.ts +39 -0
- package/dist/diagram-canvas.d.ts.map +1 -0
- package/dist/diagram-canvas.js +9 -0
- package/dist/diagram-canvas.js.map +1 -0
- package/dist/diagram-root.d.ts +70 -0
- package/dist/diagram-root.d.ts.map +1 -0
- package/dist/diagram-root.js +180 -0
- package/dist/diagram-root.js.map +1 -0
- package/dist/diff-panel.d.ts +25 -0
- package/dist/diff-panel.d.ts.map +1 -0
- package/dist/diff-panel.js +77 -0
- package/dist/diff-panel.js.map +1 -0
- package/dist/edge-style-panel.d.ts +19 -0
- package/dist/edge-style-panel.d.ts.map +1 -0
- package/dist/edge-style-panel.js +120 -0
- package/dist/edge-style-panel.js.map +1 -0
- package/dist/frame-name-editor-overlay.d.ts +13 -0
- package/dist/frame-name-editor-overlay.d.ts.map +1 -0
- package/dist/frame-name-editor-overlay.js +84 -0
- package/dist/frame-name-editor-overlay.js.map +1 -0
- package/dist/frame-panel.d.ts +19 -0
- package/dist/frame-panel.d.ts.map +1 -0
- package/dist/frame-panel.js +66 -0
- package/dist/frame-panel.js.map +1 -0
- package/dist/help-button.d.ts +16 -0
- package/dist/help-button.d.ts.map +1 -0
- package/dist/help-button.js +14 -0
- package/dist/help-button.js.map +1 -0
- package/dist/help-dialog.d.ts +56 -0
- package/dist/help-dialog.d.ts.map +1 -0
- package/dist/help-dialog.js +142 -0
- package/dist/help-dialog.js.map +1 -0
- package/dist/hooks.d.ts +54 -0
- package/dist/hooks.d.ts.map +1 -0
- package/dist/hooks.js +85 -0
- package/dist/hooks.js.map +1 -0
- package/dist/icon-button.d.ts +28 -0
- package/dist/icon-button.d.ts.map +1 -0
- package/dist/icon-button.js +14 -0
- package/dist/icon-button.js.map +1 -0
- package/dist/index.d.ts +45 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +46 -0
- package/dist/index.js.map +1 -0
- package/dist/layer-panel.d.ts +13 -0
- package/dist/layer-panel.d.ts.map +1 -0
- package/dist/layer-panel.js +109 -0
- package/dist/layer-panel.js.map +1 -0
- package/dist/library-panel.d.ts +33 -0
- package/dist/library-panel.d.ts.map +1 -0
- package/dist/library-panel.js +37 -0
- package/dist/library-panel.js.map +1 -0
- package/dist/link-caption-editor.d.ts +8 -0
- package/dist/link-caption-editor.d.ts.map +1 -0
- package/dist/link-caption-editor.js +65 -0
- package/dist/link-caption-editor.js.map +1 -0
- package/dist/link-drop-shape-menu.d.ts +12 -0
- package/dist/link-drop-shape-menu.d.ts.map +1 -0
- package/dist/link-drop-shape-menu.js +55 -0
- package/dist/link-drop-shape-menu.js.map +1 -0
- package/dist/link-hover-popup.d.ts +2 -0
- package/dist/link-hover-popup.d.ts.map +1 -0
- package/dist/link-hover-popup.js +96 -0
- package/dist/link-hover-popup.js.map +1 -0
- package/dist/main-menu.d.ts +67 -0
- package/dist/main-menu.d.ts.map +1 -0
- package/dist/main-menu.js +243 -0
- package/dist/main-menu.js.map +1 -0
- package/dist/markdown.d.ts +10 -0
- package/dist/markdown.d.ts.map +1 -0
- package/dist/markdown.js +131 -0
- package/dist/markdown.js.map +1 -0
- package/dist/merge-dialog.d.ts +22 -0
- package/dist/merge-dialog.d.ts.map +1 -0
- package/dist/merge-dialog.js +46 -0
- package/dist/merge-dialog.js.map +1 -0
- package/dist/modal.d.ts +19 -0
- package/dist/modal.d.ts.map +1 -0
- package/dist/modal.js +87 -0
- package/dist/modal.js.map +1 -0
- package/dist/palette.d.ts +73 -0
- package/dist/palette.d.ts.map +1 -0
- package/dist/palette.js +330 -0
- package/dist/palette.js.map +1 -0
- package/dist/popover.d.ts +33 -0
- package/dist/popover.d.ts.map +1 -0
- package/dist/popover.js +107 -0
- package/dist/popover.js.map +1 -0
- package/dist/property-panel.d.ts +32 -0
- package/dist/property-panel.d.ts.map +1 -0
- package/dist/property-panel.js +728 -0
- package/dist/property-panel.js.map +1 -0
- package/dist/reset-to-content-button.d.ts +10 -0
- package/dist/reset-to-content-button.d.ts.map +1 -0
- package/dist/reset-to-content-button.js +62 -0
- package/dist/reset-to-content-button.js.map +1 -0
- package/dist/segmented-control.d.ts +23 -0
- package/dist/segmented-control.d.ts.map +1 -0
- package/dist/segmented-control.js +5 -0
- package/dist/segmented-control.js.map +1 -0
- package/dist/selection-floating-panel.d.ts +56 -0
- package/dist/selection-floating-panel.d.ts.map +1 -0
- package/dist/selection-floating-panel.js +251 -0
- package/dist/selection-floating-panel.js.map +1 -0
- package/dist/sidebar.d.ts +31 -0
- package/dist/sidebar.d.ts.map +1 -0
- package/dist/sidebar.js +66 -0
- package/dist/sidebar.js.map +1 -0
- package/dist/slider.d.ts +20 -0
- package/dist/slider.d.ts.map +1 -0
- package/dist/slider.js +9 -0
- package/dist/slider.js.map +1 -0
- package/dist/text-editor-overlay.d.ts +16 -0
- package/dist/text-editor-overlay.d.ts.map +1 -0
- package/dist/text-editor-overlay.js +112 -0
- package/dist/text-editor-overlay.js.map +1 -0
- package/dist/toast.d.ts +34 -0
- package/dist/toast.d.ts.map +1 -0
- package/dist/toast.js +89 -0
- package/dist/toast.js.map +1 -0
- package/dist/toolbar.d.ts +149 -0
- package/dist/toolbar.d.ts.map +1 -0
- package/dist/toolbar.js +282 -0
- package/dist/toolbar.js.map +1 -0
- package/dist/tooltip.d.ts +21 -0
- package/dist/tooltip.d.ts.map +1 -0
- package/dist/tooltip.js +217 -0
- package/dist/tooltip.js.map +1 -0
- package/dist/ui-layer.d.ts +22 -0
- package/dist/ui-layer.d.ts.map +1 -0
- package/dist/ui-layer.js +3 -0
- package/dist/ui-layer.js.map +1 -0
- package/dist/versioning.d.ts +32 -0
- package/dist/versioning.d.ts.map +1 -0
- package/dist/versioning.js +206 -0
- package/dist/versioning.js.map +1 -0
- package/package.json +81 -0
- package/src/styles.css +1502 -0
package/src/styles.css
ADDED
|
@@ -0,0 +1,1502 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Diagram UI stylesheet. Imported once by the host:
|
|
3
|
+
*
|
|
4
|
+
* import "@oh-just-another/react-ui/styles.css";
|
|
5
|
+
*
|
|
6
|
+
* Provides:
|
|
7
|
+
* • CSS variables for theme (`:root` + `[data-theme="dark"]`)
|
|
8
|
+
* • Utility classes prefixed `du-` ("diagram ui") so they don't
|
|
9
|
+
* collide with host's own styles.
|
|
10
|
+
* • Per-component blocks (.du-icon-button, .du-top-bar, ...).
|
|
11
|
+
*
|
|
12
|
+
* Hosts can override any variable in their own stylesheet for
|
|
13
|
+
* theming — every component reads colours / sizes through these
|
|
14
|
+
* variables, never hard-coded.
|
|
15
|
+
*
|
|
16
|
+
* Colour values mirror `@oh-just-another/tokens` — CSS can't import
|
|
17
|
+
* TypeScript, so values are hand-copied with comments pointing
|
|
18
|
+
* back to the token name. Keep this in sync when you change a
|
|
19
|
+
* value in `packages/tokens/src/colors.ts`.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
:root {
|
|
23
|
+
/* --- Surfaces (from UI_SURFACE.light) --- */
|
|
24
|
+
--du-canvas-bg: #f5f5f5; /* UI_SURFACE.light.canvas */
|
|
25
|
+
--du-ui-bg: rgba(255, 255, 255, 0.95); /* UI_SURFACE.light.bg */
|
|
26
|
+
--du-ui-bg-solid: #ffffff; /* UI_SURFACE.light.bgSolid */
|
|
27
|
+
--du-ui-border: rgba(0, 0, 0, 0.08); /* UI_SURFACE.light.border */
|
|
28
|
+
--du-ui-shadow: 0 1px 4px rgba(0, 0, 0, 0.08), 0 4px 12px rgba(0, 0, 0, 0.04);
|
|
29
|
+
|
|
30
|
+
/* --- Text (from UI_SURFACE.light) --- */
|
|
31
|
+
--du-text: #1a1a1a; /* UI_SURFACE.light.text */
|
|
32
|
+
--du-text-muted: #6b6b6b; /* UI_SURFACE.light.textMuted */
|
|
33
|
+
--du-text-on-accent: #ffffff;
|
|
34
|
+
|
|
35
|
+
/* --- Accent (from UI_ACCENT.light — Radix iris) --- */
|
|
36
|
+
--du-accent: #5b5bd6; /* UI_ACCENT.light.accent (iris.iris9) */
|
|
37
|
+
--du-accent-hover: #5151cd; /* UI_ACCENT.light.accentHover (iris.iris10) */
|
|
38
|
+
--du-danger: #e54d2e; /* UI_ACCENT.light.danger (tomato.tomato9) */
|
|
39
|
+
|
|
40
|
+
/* --- Selected (tonal, modern-style) --- */
|
|
41
|
+
/* Active toolbar / icon buttons get a *muted* tonal fill so they
|
|
42
|
+
read as "this state is selected" without hijacking the eye like
|
|
43
|
+
a saturated accent fill would. The icon switches to the accent
|
|
44
|
+
hue, the background stays close to the surface. */
|
|
45
|
+
--du-selected-bg: #e6e7ff; /* UI_ACCENT.light.selectedBg (iris.iris4) */
|
|
46
|
+
--du-selected-fg: #5753c6; /* UI_ACCENT.light.selectedFg (iris.iris11) */
|
|
47
|
+
|
|
48
|
+
/* --- Sizing --- */
|
|
49
|
+
--du-radius: 10px;
|
|
50
|
+
--du-radius-sm: 6px;
|
|
51
|
+
--du-radius-lg: 14px;
|
|
52
|
+
--du-button-size: 36px;
|
|
53
|
+
--du-button-size-sm: 32px;
|
|
54
|
+
--du-icon-size: 18px;
|
|
55
|
+
--du-gap: 8px;
|
|
56
|
+
--du-gap-sm: 4px;
|
|
57
|
+
--du-pad: 8px;
|
|
58
|
+
--du-pad-sm: 4px;
|
|
59
|
+
--du-hover-overlay: rgba(0, 0, 0, 0.05);
|
|
60
|
+
--du-bar-inset: 12px;
|
|
61
|
+
--du-z-canvas: 1;
|
|
62
|
+
--du-z-ui: 100;
|
|
63
|
+
--du-z-modal: 1000;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Theme resolution priority (highest wins):
|
|
68
|
+
* [data-theme="light"] — host forced light.
|
|
69
|
+
* [data-theme="dark"] — host forced dark.
|
|
70
|
+
* @media prefers-color-scheme: dark → :root — OS-derived dark when
|
|
71
|
+
* no data-theme is present.
|
|
72
|
+
* :root — light defaults.
|
|
73
|
+
*
|
|
74
|
+
* Hosts set `data-theme` via the Diagram component's `theme` prop
|
|
75
|
+
* ("light" / "dark" / "system" — "system" omits the attribute so
|
|
76
|
+
* the media query takes over).
|
|
77
|
+
*/
|
|
78
|
+
@media (prefers-color-scheme: dark) {
|
|
79
|
+
:root {
|
|
80
|
+
/* All values mirror UI_SURFACE.dark + UI_ACCENT.dark from
|
|
81
|
+
`@oh-just-another/tokens`. */
|
|
82
|
+
--du-canvas-bg: #121212; /* UI_SURFACE.dark.canvas */
|
|
83
|
+
--du-ui-bg: rgba(35, 35, 35, 0.95); /* UI_SURFACE.dark.bg */
|
|
84
|
+
--du-ui-bg-solid: #252525; /* UI_SURFACE.dark.bgSolid */
|
|
85
|
+
--du-ui-border: rgba(255, 255, 255, 0.08); /* UI_SURFACE.dark.border */
|
|
86
|
+
--du-ui-shadow: 0 1px 4px rgba(0, 0, 0, 0.4), 0 4px 12px rgba(0, 0, 0, 0.3);
|
|
87
|
+
--du-text: #e8e8e8; /* UI_SURFACE.dark.text */
|
|
88
|
+
--du-text-muted: #9a9a9a; /* UI_SURFACE.dark.textMuted */
|
|
89
|
+
--du-accent: #5b5bd6; /* UI_ACCENT.dark.accent (irisDark.iris9) */
|
|
90
|
+
--du-accent-hover: #6e6ade; /* UI_ACCENT.dark.accentHover (irisDark.iris10) */
|
|
91
|
+
--du-hover-overlay: rgba(255, 255, 255, 0.06); /* UI_SURFACE.dark.hoverOverlay */
|
|
92
|
+
--du-selected-bg: #262a65; /* UI_ACCENT.dark.selectedBg (irisDark.iris4) */
|
|
93
|
+
--du-selected-fg: #b1a9ff; /* UI_ACCENT.dark.selectedFg (irisDark.iris11) */
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
[data-theme="light"] {
|
|
98
|
+
/* Same as :root — explicit override so a host that toggles
|
|
99
|
+
`data-theme` between "light" / "dark" / unset still picks
|
|
100
|
+
up the light palette under all conditions. Mirrors
|
|
101
|
+
UI_SURFACE.light + UI_ACCENT.light. */
|
|
102
|
+
--du-canvas-bg: #f5f5f5;
|
|
103
|
+
--du-ui-bg: rgba(255, 255, 255, 0.95);
|
|
104
|
+
--du-ui-bg-solid: #ffffff;
|
|
105
|
+
--du-ui-border: rgba(0, 0, 0, 0.08);
|
|
106
|
+
--du-ui-shadow: 0 1px 4px rgba(0, 0, 0, 0.08), 0 4px 12px rgba(0, 0, 0, 0.04);
|
|
107
|
+
--du-text: #1a1a1a;
|
|
108
|
+
--du-text-muted: #6b6b6b;
|
|
109
|
+
--du-accent: #5b5bd6; /* iris.iris9 */
|
|
110
|
+
--du-accent-hover: #5151cd; /* iris.iris10 */
|
|
111
|
+
--du-hover-overlay: rgba(0, 0, 0, 0.05);
|
|
112
|
+
--du-selected-bg: #e6e7ff; /* iris.iris4 */
|
|
113
|
+
--du-selected-fg: #5753c6; /* iris.iris11 */
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/* ------------------------------------------------------------------ */
|
|
117
|
+
/* Legacy variable aliases — kept so the older components (MainMenu, */
|
|
118
|
+
/* ContextMenu, Modal, HelpDialog) that read `var(--panel)` / */
|
|
119
|
+
/* `var(--text)` / `var(--button-bg)` etc. still pick up the active */
|
|
120
|
+
/* theme without being rewritten to the `--du-*` namespace. */
|
|
121
|
+
/* */
|
|
122
|
+
/* Hosts can still override the legacy names individually — these */
|
|
123
|
+
/* are defaults that *forward* to the unified theme variables. */
|
|
124
|
+
/* ------------------------------------------------------------------ */
|
|
125
|
+
:root {
|
|
126
|
+
--bg: var(--du-canvas-bg);
|
|
127
|
+
--panel: var(--du-ui-bg-solid);
|
|
128
|
+
--surface: var(--du-ui-bg-solid);
|
|
129
|
+
--text: var(--du-text);
|
|
130
|
+
--muted: var(--du-text-muted);
|
|
131
|
+
--border: var(--du-ui-border);
|
|
132
|
+
--button-bg: var(--du-ui-bg-solid);
|
|
133
|
+
--button-hover-bg: var(--du-ui-bg);
|
|
134
|
+
--accent: var(--du-accent);
|
|
135
|
+
--menu-bg: var(--du-ui-bg-solid);
|
|
136
|
+
--menu-text: var(--du-text);
|
|
137
|
+
--menu-border: var(--du-ui-border);
|
|
138
|
+
--menu-divider: var(--du-ui-border);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
[data-theme="dark"] {
|
|
142
|
+
/* Mirrors UI_SURFACE.dark + UI_ACCENT.dark from `@oh-just-another/tokens`. */
|
|
143
|
+
--du-canvas-bg: #121212;
|
|
144
|
+
--du-ui-bg: rgba(35, 35, 35, 0.95);
|
|
145
|
+
--du-ui-bg-solid: #252525;
|
|
146
|
+
--du-ui-border: rgba(255, 255, 255, 0.08);
|
|
147
|
+
--du-ui-shadow: 0 1px 4px rgba(0, 0, 0, 0.4), 0 4px 12px rgba(0, 0, 0, 0.3);
|
|
148
|
+
--du-text: #e8e8e8;
|
|
149
|
+
--du-text-muted: #9a9a9a;
|
|
150
|
+
--du-accent: #5b5bd6; /* irisDark.iris9 */
|
|
151
|
+
--du-accent-hover: #6e6ade; /* irisDark.iris10 */
|
|
152
|
+
--du-hover-overlay: rgba(255, 255, 255, 0.06);
|
|
153
|
+
--du-selected-bg: #262a65; /* irisDark.iris4 */
|
|
154
|
+
--du-selected-fg: #b1a9ff; /* irisDark.iris11 */
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/* ------------------------------------------------------------------ */
|
|
158
|
+
/* UI layer — absolute overlay above the canvas surface. */
|
|
159
|
+
/* pointer-events: none on the wrapper, auto on children, so the */
|
|
160
|
+
/* canvas keeps receiving pointer events anywhere the UI isn't drawn. */
|
|
161
|
+
/* ------------------------------------------------------------------ */
|
|
162
|
+
.du-ui-layer {
|
|
163
|
+
position: absolute;
|
|
164
|
+
inset: 0;
|
|
165
|
+
pointer-events: none;
|
|
166
|
+
z-index: var(--du-z-ui);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
.du-ui-layer > * {
|
|
170
|
+
pointer-events: auto;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/* ------------------------------------------------------------------ */
|
|
174
|
+
/* Bars — top / bottom 3-zone layout (left / center / right). */
|
|
175
|
+
/* ------------------------------------------------------------------ */
|
|
176
|
+
.du-bar {
|
|
177
|
+
position: absolute;
|
|
178
|
+
left: var(--du-bar-inset);
|
|
179
|
+
right: var(--du-bar-inset);
|
|
180
|
+
display: flex;
|
|
181
|
+
justify-content: space-between;
|
|
182
|
+
align-items: center;
|
|
183
|
+
gap: var(--du-gap);
|
|
184
|
+
pointer-events: none;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
.du-bar > * {
|
|
188
|
+
pointer-events: auto;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
.du-bar-top {
|
|
192
|
+
top: var(--du-bar-inset);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
.du-bar-bottom {
|
|
196
|
+
bottom: var(--du-bar-inset);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
.du-bar-zone {
|
|
200
|
+
display: inline-flex;
|
|
201
|
+
align-items: center;
|
|
202
|
+
gap: var(--du-gap);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
.du-bar-zone-center {
|
|
206
|
+
margin: 0 auto;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/* ------------------------------------------------------------------ */
|
|
210
|
+
/* Icon button — square clickable. Two visual modes: */
|
|
211
|
+
/* 1. Standalone (outside `du-button-group`): full pill with */
|
|
212
|
+
/* surface, border, shadow. */
|
|
213
|
+
/* 2. Inside `du-button-group`: transparent surface, subtle radius, */
|
|
214
|
+
/* lets the group's pill chrome carry the framing. */
|
|
215
|
+
/* ------------------------------------------------------------------ */
|
|
216
|
+
.du-icon-button {
|
|
217
|
+
width: var(--du-button-size);
|
|
218
|
+
height: var(--du-button-size);
|
|
219
|
+
display: inline-flex;
|
|
220
|
+
align-items: center;
|
|
221
|
+
justify-content: center;
|
|
222
|
+
background: var(--du-ui-bg);
|
|
223
|
+
color: var(--du-text);
|
|
224
|
+
border: 1px solid var(--du-ui-border);
|
|
225
|
+
border-radius: var(--du-radius);
|
|
226
|
+
cursor: pointer;
|
|
227
|
+
font-size: 14px;
|
|
228
|
+
line-height: 1;
|
|
229
|
+
box-shadow: var(--du-ui-shadow);
|
|
230
|
+
transition: background 0.12s ease, color 0.12s ease, transform 0.05s ease;
|
|
231
|
+
padding: 0;
|
|
232
|
+
outline: none;
|
|
233
|
+
user-select: none;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
.du-icon-button:hover:not(:disabled) {
|
|
237
|
+
background: var(--du-ui-bg-solid);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
.du-icon-button:active:not(:disabled) {
|
|
241
|
+
transform: scale(0.96);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
.du-icon-button:disabled {
|
|
245
|
+
opacity: 0.4;
|
|
246
|
+
cursor: not-allowed;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
.du-icon-button:focus-visible {
|
|
250
|
+
outline: 2px solid var(--du-accent);
|
|
251
|
+
outline-offset: 2px;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
.du-icon-button[aria-pressed="true"],
|
|
255
|
+
.du-icon-button.is-active {
|
|
256
|
+
background: var(--du-selected-bg);
|
|
257
|
+
color: var(--du-selected-fg);
|
|
258
|
+
border-color: var(--du-selected-bg);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
.du-icon-button[aria-pressed="true"]:hover:not(:disabled),
|
|
262
|
+
.du-icon-button.is-active:hover:not(:disabled) {
|
|
263
|
+
/* Slight tint shift on hover — keeps the "selected" cue but
|
|
264
|
+
acknowledges the cursor. Same hue family, marginally darker. */
|
|
265
|
+
background: color-mix(in srgb, var(--du-selected-bg) 90%, var(--du-text) 10%);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
.du-icon-button-sm {
|
|
269
|
+
width: var(--du-button-size-sm);
|
|
270
|
+
height: var(--du-button-size-sm);
|
|
271
|
+
font-size: 12px;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* Flat modifier — strips the standalone pill chrome (background,
|
|
276
|
+
* border, shadow) and adopts the same look as an IconButton sitting
|
|
277
|
+
* inside a `du-button-group`. Use this when a button has to live
|
|
278
|
+
* inside a container that the descendant selector can't reach (e.g.
|
|
279
|
+
* the MainMenu trigger, which is wrapped in a positioning <div> so
|
|
280
|
+
* its dropdown can be `position: absolute`).
|
|
281
|
+
*/
|
|
282
|
+
.du-icon-button-flat {
|
|
283
|
+
background: transparent;
|
|
284
|
+
border: none;
|
|
285
|
+
box-shadow: none;
|
|
286
|
+
border-radius: var(--du-radius-sm);
|
|
287
|
+
width: var(--du-button-size-sm);
|
|
288
|
+
height: var(--du-button-size-sm);
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
.du-icon-button-flat:hover:not(:disabled) {
|
|
292
|
+
background: var(--du-hover-overlay);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
/* ------------------------------------------------------------------ */
|
|
296
|
+
/* Button group — pill that wraps one or more IconButtons. Group */
|
|
297
|
+
/* carries the surface, border, shadow; the buttons inside drop */
|
|
298
|
+
/* their own chrome so the row reads as one cohesive control. */
|
|
299
|
+
/* Padding + gap match standard's tool bar feel. */
|
|
300
|
+
/* ------------------------------------------------------------------ */
|
|
301
|
+
.du-button-group {
|
|
302
|
+
display: inline-flex;
|
|
303
|
+
align-items: center;
|
|
304
|
+
gap: var(--du-gap-sm);
|
|
305
|
+
background: var(--du-ui-bg);
|
|
306
|
+
border: 1px solid var(--du-ui-border);
|
|
307
|
+
border-radius: var(--du-radius);
|
|
308
|
+
box-shadow: var(--du-ui-shadow);
|
|
309
|
+
padding: var(--du-pad-sm);
|
|
310
|
+
/* No `overflow: hidden` — a child popup (MainMenu dropdown) must
|
|
311
|
+
be able to render outside the group's bounds. */
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
/* Vertical variant — the left creation dock. Stacks buttons in a
|
|
315
|
+
column; dividers (rendered inline by <Toolbar>) become horizontal. */
|
|
316
|
+
.du-button-group-vertical {
|
|
317
|
+
flex-direction: column;
|
|
318
|
+
align-items: stretch;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
.du-button-group > .du-icon-button {
|
|
322
|
+
border: none;
|
|
323
|
+
box-shadow: none;
|
|
324
|
+
border-radius: var(--du-radius-sm);
|
|
325
|
+
background: transparent;
|
|
326
|
+
width: var(--du-button-size-sm);
|
|
327
|
+
height: var(--du-button-size-sm);
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
/* Vertical dock buttons are square + centred (icon-only tools). */
|
|
331
|
+
.du-button-group-vertical > .du-icon-button {
|
|
332
|
+
width: var(--du-button-size-sm) !important;
|
|
333
|
+
min-width: var(--du-button-size-sm) !important;
|
|
334
|
+
padding: 0 !important;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
/* ------------------------------------------------------------------ */
|
|
338
|
+
/* Mobile / coarse-pointer chrome (keep the 640px breakpoint in sync */
|
|
339
|
+
/* with MOBILE_MAX_WIDTH_PX in constants.ts). */
|
|
340
|
+
/* ------------------------------------------------------------------ */
|
|
341
|
+
@media (pointer: coarse), (max-width: 640px) {
|
|
342
|
+
/* Bars clear the notch / home indicator + rounded corners. */
|
|
343
|
+
.du-bar-top {
|
|
344
|
+
top: calc(var(--du-bar-inset) + env(safe-area-inset-top, 0px));
|
|
345
|
+
}
|
|
346
|
+
.du-bar-bottom {
|
|
347
|
+
bottom: calc(var(--du-bar-inset) + env(safe-area-inset-bottom, 0px));
|
|
348
|
+
}
|
|
349
|
+
.du-bar {
|
|
350
|
+
left: calc(var(--du-bar-inset) + env(safe-area-inset-left, 0px));
|
|
351
|
+
right: calc(var(--du-bar-inset) + env(safe-area-inset-right, 0px));
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
/* Vertical creation dock: ≥44px touch targets; scroll inside the dock
|
|
355
|
+
when a short screen can't fit every tool. */
|
|
356
|
+
.du-button-group-vertical {
|
|
357
|
+
max-height: calc(
|
|
358
|
+
100vh - 2 * var(--du-bar-inset) - env(safe-area-inset-top, 0px) -
|
|
359
|
+
env(safe-area-inset-bottom, 0px)
|
|
360
|
+
);
|
|
361
|
+
overflow-y: auto;
|
|
362
|
+
scrollbar-width: none;
|
|
363
|
+
}
|
|
364
|
+
.du-button-group-vertical::-webkit-scrollbar {
|
|
365
|
+
display: none;
|
|
366
|
+
}
|
|
367
|
+
.du-button-group-vertical > .du-icon-button {
|
|
368
|
+
width: 44px !important;
|
|
369
|
+
min-width: 44px !important;
|
|
370
|
+
height: 44px !important;
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
.du-button-group > .du-icon-button:hover:not(:disabled) {
|
|
375
|
+
background: var(--du-hover-overlay);
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
.du-button-group > .du-icon-button[aria-pressed="true"],
|
|
379
|
+
.du-button-group > .du-icon-button.is-active {
|
|
380
|
+
background: var(--du-selected-bg);
|
|
381
|
+
color: var(--du-selected-fg);
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
.du-button-group > .du-icon-button[aria-pressed="true"]:hover:not(:disabled),
|
|
385
|
+
.du-button-group > .du-icon-button.is-active:hover:not(:disabled) {
|
|
386
|
+
background: color-mix(in srgb, var(--du-selected-bg) 90%, var(--du-text) 10%);
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
/* ------------------------------------------------------------------ */
|
|
390
|
+
/* Floating side panel — used by Library / SelectedShapeActions. */
|
|
391
|
+
/* Fixed-width, fixed-height-with-scroll, sits flush against the */
|
|
392
|
+
/* corresponding side of the canvas with a `du-bar-inset` margin. */
|
|
393
|
+
/* ------------------------------------------------------------------ */
|
|
394
|
+
.du-side-panel {
|
|
395
|
+
position: absolute;
|
|
396
|
+
top: calc(var(--du-bar-inset) + var(--du-button-size) + var(--du-gap));
|
|
397
|
+
bottom: calc(var(--du-bar-inset) + var(--du-button-size) + var(--du-gap));
|
|
398
|
+
width: 240px;
|
|
399
|
+
background: var(--du-ui-bg);
|
|
400
|
+
color: var(--du-text);
|
|
401
|
+
border: 1px solid var(--du-ui-border);
|
|
402
|
+
border-radius: var(--du-radius);
|
|
403
|
+
box-shadow: var(--du-ui-shadow);
|
|
404
|
+
display: flex;
|
|
405
|
+
flex-direction: column;
|
|
406
|
+
overflow: hidden;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
.du-side-panel-left {
|
|
410
|
+
left: var(--du-bar-inset);
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
.du-side-panel-right {
|
|
414
|
+
right: var(--du-bar-inset);
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
/* Sheet mode — fills the parent BottomSheet; the sheet provides the
|
|
418
|
+
surface, so drop the floating-pill position / border / shadow. */
|
|
419
|
+
.du-side-panel.du-side-panel-sheet {
|
|
420
|
+
position: static;
|
|
421
|
+
top: auto;
|
|
422
|
+
bottom: auto;
|
|
423
|
+
left: auto;
|
|
424
|
+
right: auto;
|
|
425
|
+
width: 100%;
|
|
426
|
+
height: 100%;
|
|
427
|
+
border: none;
|
|
428
|
+
border-radius: 0;
|
|
429
|
+
box-shadow: none;
|
|
430
|
+
background: transparent;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
.du-side-panel-header {
|
|
434
|
+
display: flex;
|
|
435
|
+
align-items: center;
|
|
436
|
+
justify-content: flex-end;
|
|
437
|
+
gap: var(--du-gap-sm);
|
|
438
|
+
padding: var(--du-pad-sm) var(--du-pad-sm) var(--du-pad-sm) var(--du-pad);
|
|
439
|
+
font-size: 12px;
|
|
440
|
+
font-weight: 600;
|
|
441
|
+
text-transform: uppercase;
|
|
442
|
+
letter-spacing: 0.5px;
|
|
443
|
+
color: var(--du-text-muted);
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
/* Hide the header when it's empty (no action buttons configured). */
|
|
447
|
+
.du-side-panel-header:empty {
|
|
448
|
+
display: none;
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
/* Auto-height variant — content hugs its natural height instead
|
|
452
|
+
of stretching from top to bottom of the canvas area. Used by
|
|
453
|
+
the Properties panel so it shrinks to whatever the inspector
|
|
454
|
+
sections need. The Library panel keeps the default full-height
|
|
455
|
+
so its long grid can scroll. */
|
|
456
|
+
.du-side-panel-auto-height {
|
|
457
|
+
bottom: auto;
|
|
458
|
+
max-height: calc(
|
|
459
|
+
100% - 2 * var(--du-bar-inset) - 2 * var(--du-button-size) - 2 * var(--du-gap)
|
|
460
|
+
);
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
.du-side-panel-body {
|
|
464
|
+
flex: 1;
|
|
465
|
+
overflow-y: auto;
|
|
466
|
+
padding: var(--du-pad);
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
/* Variant for hosts that lay out their own grid / list inside the
|
|
470
|
+
panel body (e.g. <Palette>) and would otherwise have to subtract
|
|
471
|
+
the body's padding from their own paddings. Keeps overflow + flex
|
|
472
|
+
behaviour. */
|
|
473
|
+
.du-side-panel-body-flush {
|
|
474
|
+
padding: 0;
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
/* ------------------------------------------------------------------ */
|
|
478
|
+
/* Palette (template library content) — sectioned grid of icon tiles. */
|
|
479
|
+
/* No per-tile borders, no per-section dividers — visual structure */
|
|
480
|
+
/* comes from spacing alone so the panel reads as one calm surface. */
|
|
481
|
+
/* ------------------------------------------------------------------ */
|
|
482
|
+
.du-palette {
|
|
483
|
+
display: flex;
|
|
484
|
+
flex-direction: column;
|
|
485
|
+
min-height: 0;
|
|
486
|
+
color: var(--du-text);
|
|
487
|
+
width: 100%;
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
.du-palette-body {
|
|
491
|
+
flex: 1 1 auto;
|
|
492
|
+
overflow-y: auto;
|
|
493
|
+
display: flex;
|
|
494
|
+
flex-direction: column;
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
.du-palette-section {
|
|
498
|
+
padding: 0 var(--du-pad) var(--du-pad-sm);
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
.du-palette-category {
|
|
502
|
+
width: 100%;
|
|
503
|
+
background: transparent;
|
|
504
|
+
color: var(--du-text-muted);
|
|
505
|
+
border: none;
|
|
506
|
+
padding: 10px 0 6px;
|
|
507
|
+
font: inherit;
|
|
508
|
+
font-size: 11px;
|
|
509
|
+
font-weight: 600;
|
|
510
|
+
text-transform: uppercase;
|
|
511
|
+
letter-spacing: 0.5px;
|
|
512
|
+
text-align: left;
|
|
513
|
+
cursor: pointer;
|
|
514
|
+
display: flex;
|
|
515
|
+
align-items: center;
|
|
516
|
+
justify-content: space-between;
|
|
517
|
+
gap: var(--du-gap-sm);
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
.du-palette-category-caret {
|
|
521
|
+
display: inline-flex;
|
|
522
|
+
align-items: center;
|
|
523
|
+
opacity: 0.6;
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
.du-palette-grid {
|
|
527
|
+
display: grid;
|
|
528
|
+
grid-template-columns: repeat(2, 1fr);
|
|
529
|
+
gap: var(--du-gap-sm);
|
|
530
|
+
align-content: start;
|
|
531
|
+
padding: 0 var(--du-pad) var(--du-pad-sm);
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
/* `.du-palette-section > .du-palette-grid` already gets padding via
|
|
535
|
+
.du-palette-section; remove the duplicate to avoid double margin. */
|
|
536
|
+
.du-palette-section > .du-palette-grid {
|
|
537
|
+
padding: 0;
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
/* Compact list layout (modern-style templates panel) — single column of
|
|
541
|
+
icon + name rows. Denser than the grid; the label reads left-aligned
|
|
542
|
+
beside a small icon. */
|
|
543
|
+
.du-palette-list {
|
|
544
|
+
display: flex;
|
|
545
|
+
flex-direction: column;
|
|
546
|
+
gap: 2px;
|
|
547
|
+
padding: 0 var(--du-pad) var(--du-pad-sm);
|
|
548
|
+
}
|
|
549
|
+
.du-palette-section > .du-palette-list {
|
|
550
|
+
padding: 0;
|
|
551
|
+
}
|
|
552
|
+
.du-palette-list .du-palette-item {
|
|
553
|
+
flex-direction: row;
|
|
554
|
+
align-items: center;
|
|
555
|
+
justify-content: flex-start;
|
|
556
|
+
aspect-ratio: auto;
|
|
557
|
+
gap: 8px;
|
|
558
|
+
padding: 5px 8px;
|
|
559
|
+
text-align: left;
|
|
560
|
+
font-size: 12px;
|
|
561
|
+
line-height: 1.2;
|
|
562
|
+
}
|
|
563
|
+
.du-palette-list .du-palette-item-icon {
|
|
564
|
+
width: 20px !important;
|
|
565
|
+
height: 20px !important;
|
|
566
|
+
flex: 0 0 auto;
|
|
567
|
+
}
|
|
568
|
+
.du-palette-list .du-palette-item-label {
|
|
569
|
+
flex: 1 1 auto;
|
|
570
|
+
white-space: nowrap;
|
|
571
|
+
overflow: hidden;
|
|
572
|
+
text-overflow: ellipsis;
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
.du-palette-empty {
|
|
576
|
+
padding: 24px 12px;
|
|
577
|
+
text-align: center;
|
|
578
|
+
font-size: 12px;
|
|
579
|
+
color: var(--du-text-muted);
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
.du-palette-item {
|
|
583
|
+
display: flex;
|
|
584
|
+
flex-direction: column;
|
|
585
|
+
align-items: center;
|
|
586
|
+
justify-content: center;
|
|
587
|
+
gap: 4px;
|
|
588
|
+
aspect-ratio: 1;
|
|
589
|
+
padding: 6px 4px;
|
|
590
|
+
background: transparent;
|
|
591
|
+
color: var(--du-text);
|
|
592
|
+
border: none;
|
|
593
|
+
border-radius: var(--du-radius-sm);
|
|
594
|
+
cursor: grab;
|
|
595
|
+
text-align: center;
|
|
596
|
+
font-size: 10px;
|
|
597
|
+
line-height: 1.1;
|
|
598
|
+
transition: background 0.12s ease;
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
.du-palette-item:hover {
|
|
602
|
+
background: var(--du-hover-overlay);
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
.du-palette-item:active {
|
|
606
|
+
cursor: grabbing;
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
.du-palette-item-icon {
|
|
610
|
+
display: inline-flex;
|
|
611
|
+
align-items: center;
|
|
612
|
+
justify-content: center;
|
|
613
|
+
color: var(--du-text);
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
.du-palette-item-icon svg {
|
|
617
|
+
width: 100%;
|
|
618
|
+
height: 100%;
|
|
619
|
+
display: block;
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
.du-palette-item-label {
|
|
623
|
+
/* Two-line clamp so long names don't push the tile out of square. */
|
|
624
|
+
display: -webkit-box;
|
|
625
|
+
-webkit-line-clamp: 2;
|
|
626
|
+
-webkit-box-orient: vertical;
|
|
627
|
+
overflow: hidden;
|
|
628
|
+
text-overflow: ellipsis;
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
/* ------------------------------------------------------------------ */
|
|
632
|
+
/* Property panel — modern-style sectioned inspector. */
|
|
633
|
+
/* Sections are stacked top-to-bottom; each one has a tiny uppercase */
|
|
634
|
+
/* label, then a row of controls (color swatches, segmented buttons, */
|
|
635
|
+
/* slider). No card chrome — visual structure comes from spacing. */
|
|
636
|
+
/* ------------------------------------------------------------------ */
|
|
637
|
+
.du-prop-panel {
|
|
638
|
+
display: flex;
|
|
639
|
+
flex-direction: column;
|
|
640
|
+
gap: 16px;
|
|
641
|
+
padding: 4px 0;
|
|
642
|
+
color: var(--du-text);
|
|
643
|
+
font-size: 12px;
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
.du-prop-section {
|
|
647
|
+
display: flex;
|
|
648
|
+
flex-direction: column;
|
|
649
|
+
gap: 6px;
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
.du-prop-section-label {
|
|
653
|
+
margin: 0;
|
|
654
|
+
font-size: 10px;
|
|
655
|
+
font-weight: 600;
|
|
656
|
+
text-transform: uppercase;
|
|
657
|
+
letter-spacing: 0.5px;
|
|
658
|
+
color: var(--du-text-muted);
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
.du-prop-row {
|
|
662
|
+
display: flex;
|
|
663
|
+
align-items: center;
|
|
664
|
+
gap: var(--du-gap-sm);
|
|
665
|
+
flex-wrap: wrap;
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
.du-prop-row-label {
|
|
669
|
+
font-size: 11px;
|
|
670
|
+
color: var(--du-text-muted);
|
|
671
|
+
min-width: 48px;
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
.du-prop-empty {
|
|
675
|
+
font-style: italic;
|
|
676
|
+
color: var(--du-text-muted);
|
|
677
|
+
font-size: 12px;
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
/* modern-style flat segmented control inside the panel:
|
|
681
|
+
no card chrome on the ButtonGroup wrapper. The buttons still
|
|
682
|
+
read as a row through their tonal `is-active` fill + hover. */
|
|
683
|
+
.du-prop-panel .du-button-group {
|
|
684
|
+
background: transparent;
|
|
685
|
+
border: none;
|
|
686
|
+
box-shadow: none;
|
|
687
|
+
padding: 0;
|
|
688
|
+
gap: 2px;
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
/* Tighter active state inside the panel (smaller buttons, same
|
|
692
|
+
tonal pair). Keeps the rest of the toolbar unaffected. */
|
|
693
|
+
.du-prop-panel .du-button-group > .du-icon-button {
|
|
694
|
+
width: var(--du-button-size-sm);
|
|
695
|
+
height: var(--du-button-size-sm);
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
/* Checkbox row — small native input + label. Used by Corners
|
|
699
|
+
"Auto radius" toggle. */
|
|
700
|
+
.du-prop-checkbox {
|
|
701
|
+
display: inline-flex;
|
|
702
|
+
align-items: center;
|
|
703
|
+
gap: 6px;
|
|
704
|
+
cursor: pointer;
|
|
705
|
+
font-size: 12px;
|
|
706
|
+
color: var(--du-text);
|
|
707
|
+
user-select: none;
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
.du-prop-checkbox input[type="checkbox"] {
|
|
711
|
+
width: 14px;
|
|
712
|
+
height: 14px;
|
|
713
|
+
margin: 0;
|
|
714
|
+
accent-color: var(--du-selected-fg);
|
|
715
|
+
cursor: pointer;
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
/* ------------------------------------------------------------------ */
|
|
719
|
+
/* Colour swatch grid — modern-style fixed 26 × 26 cell with a */
|
|
720
|
+
/* 24 × 24 fill that grows on hover to fill the cell. Selected cells */
|
|
721
|
+
/* get a 2 px tonal ring on the OUTER cell so the ring lands beside */
|
|
722
|
+
/* the colour, not over it. */
|
|
723
|
+
/* ------------------------------------------------------------------ */
|
|
724
|
+
.du-swatch-grid {
|
|
725
|
+
display: inline-flex;
|
|
726
|
+
flex-wrap: wrap;
|
|
727
|
+
gap: 4px;
|
|
728
|
+
max-width: 232px; /* 8 cells (26 × 8 = 208) + 7 gaps × 4 = ~232 */
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
.du-swatch {
|
|
732
|
+
position: relative;
|
|
733
|
+
width: 26px;
|
|
734
|
+
height: 26px;
|
|
735
|
+
padding: 0;
|
|
736
|
+
background: transparent;
|
|
737
|
+
border: none;
|
|
738
|
+
border-radius: var(--du-radius-sm);
|
|
739
|
+
cursor: pointer;
|
|
740
|
+
display: inline-flex;
|
|
741
|
+
align-items: center;
|
|
742
|
+
justify-content: center;
|
|
743
|
+
/* Reserve the ring space so width never changes on selection. */
|
|
744
|
+
box-shadow: inset 0 0 0 0 transparent;
|
|
745
|
+
transition: box-shadow 0.12s ease;
|
|
746
|
+
/* Suppress the UA tap-highlight on iOS so the cell looks clean
|
|
747
|
+
while the user drags through swatches. */
|
|
748
|
+
-webkit-tap-highlight-color: transparent;
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
.du-swatch:focus-visible {
|
|
752
|
+
outline: none;
|
|
753
|
+
box-shadow: inset 0 0 0 2px var(--du-accent);
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
.du-swatch[aria-checked="true"] {
|
|
757
|
+
box-shadow: inset 0 0 0 2px var(--du-selected-fg);
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
.du-swatch-fill {
|
|
761
|
+
display: inline-flex;
|
|
762
|
+
align-items: center;
|
|
763
|
+
justify-content: center;
|
|
764
|
+
width: 24px;
|
|
765
|
+
height: 24px;
|
|
766
|
+
border-radius: var(--du-radius-sm);
|
|
767
|
+
border: 1px solid var(--du-ui-border);
|
|
768
|
+
box-sizing: border-box;
|
|
769
|
+
transition: width 0.12s ease, height 0.12s ease, border-color 0.12s ease;
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
.du-swatch:hover .du-swatch-fill,
|
|
773
|
+
.du-swatch:focus-visible .du-swatch-fill {
|
|
774
|
+
width: 26px;
|
|
775
|
+
height: 26px;
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
/* Clear (×) + custom-picker (+) cells use the same chrome as a
|
|
779
|
+
regular swatch but with a neutral fill + glyph slot. */
|
|
780
|
+
.du-swatch-fill-blank {
|
|
781
|
+
background: var(--du-ui-bg-solid);
|
|
782
|
+
color: var(--du-text-muted);
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
.du-swatch-custom .du-swatch-fill {
|
|
786
|
+
background: var(--du-ui-bg-solid);
|
|
787
|
+
color: var(--du-text-muted);
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
.du-swatch-color-input {
|
|
791
|
+
position: absolute;
|
|
792
|
+
inset: 0;
|
|
793
|
+
opacity: 0;
|
|
794
|
+
cursor: pointer;
|
|
795
|
+
border: none;
|
|
796
|
+
padding: 0;
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
/* ------------------------------------------------------------------ */
|
|
800
|
+
/* Slider — themed native <input type=range> + value badge. */
|
|
801
|
+
/* ------------------------------------------------------------------ */
|
|
802
|
+
.du-slider {
|
|
803
|
+
display: flex;
|
|
804
|
+
align-items: center;
|
|
805
|
+
gap: 8px;
|
|
806
|
+
width: 100%;
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
.du-slider-track {
|
|
810
|
+
flex: 1;
|
|
811
|
+
-webkit-appearance: none;
|
|
812
|
+
appearance: none;
|
|
813
|
+
background: transparent;
|
|
814
|
+
height: 18px;
|
|
815
|
+
margin: 0;
|
|
816
|
+
padding: 0;
|
|
817
|
+
cursor: pointer;
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
.du-slider-track::-webkit-slider-runnable-track {
|
|
821
|
+
height: 4px;
|
|
822
|
+
background: var(--du-selected-bg);
|
|
823
|
+
border-radius: 2px;
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
.du-slider-track::-moz-range-track {
|
|
827
|
+
height: 4px;
|
|
828
|
+
background: var(--du-selected-bg);
|
|
829
|
+
border-radius: 2px;
|
|
830
|
+
border: none;
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
.du-slider-track::-webkit-slider-thumb {
|
|
834
|
+
-webkit-appearance: none;
|
|
835
|
+
appearance: none;
|
|
836
|
+
width: 14px;
|
|
837
|
+
height: 14px;
|
|
838
|
+
background: var(--du-selected-fg);
|
|
839
|
+
border-radius: 50%;
|
|
840
|
+
border: 2px solid var(--du-ui-bg-solid);
|
|
841
|
+
margin-top: -5px;
|
|
842
|
+
cursor: grab;
|
|
843
|
+
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
.du-slider-track::-moz-range-thumb {
|
|
847
|
+
width: 14px;
|
|
848
|
+
height: 14px;
|
|
849
|
+
background: var(--du-selected-fg);
|
|
850
|
+
border-radius: 50%;
|
|
851
|
+
border: 2px solid var(--du-ui-bg-solid);
|
|
852
|
+
cursor: grab;
|
|
853
|
+
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
.du-slider-track:focus {
|
|
857
|
+
outline: none;
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
.du-slider-track:focus-visible::-webkit-slider-thumb {
|
|
861
|
+
outline: 2px solid var(--du-accent);
|
|
862
|
+
outline-offset: 2px;
|
|
863
|
+
}
|
|
864
|
+
|
|
865
|
+
.du-slider-value {
|
|
866
|
+
min-width: 36px;
|
|
867
|
+
text-align: right;
|
|
868
|
+
font-variant-numeric: tabular-nums;
|
|
869
|
+
font-size: 11px;
|
|
870
|
+
color: var(--du-text-muted);
|
|
871
|
+
}
|
|
872
|
+
|
|
873
|
+
/* ------------------------------------------------------------------ */
|
|
874
|
+
/* Number input — small themed `<input type=number>`. */
|
|
875
|
+
/* ------------------------------------------------------------------ */
|
|
876
|
+
.du-number-input {
|
|
877
|
+
width: 64px;
|
|
878
|
+
height: 24px;
|
|
879
|
+
box-sizing: border-box;
|
|
880
|
+
background: var(--du-ui-bg-solid);
|
|
881
|
+
color: var(--du-text);
|
|
882
|
+
border: 1px solid var(--du-ui-border);
|
|
883
|
+
border-radius: var(--du-radius-sm);
|
|
884
|
+
padding: 0 6px;
|
|
885
|
+
font: inherit;
|
|
886
|
+
font-size: 11px;
|
|
887
|
+
font-variant-numeric: tabular-nums;
|
|
888
|
+
outline: none;
|
|
889
|
+
}
|
|
890
|
+
|
|
891
|
+
.du-number-input:focus {
|
|
892
|
+
border-color: var(--du-accent);
|
|
893
|
+
}
|
|
894
|
+
|
|
895
|
+
/* Search input row — sits between the header and the body. */
|
|
896
|
+
.du-side-panel-search {
|
|
897
|
+
position: relative;
|
|
898
|
+
padding: var(--du-pad-sm) var(--du-pad);
|
|
899
|
+
border-bottom: 1px solid var(--du-ui-border);
|
|
900
|
+
}
|
|
901
|
+
|
|
902
|
+
.du-side-panel-search input[type="search"] {
|
|
903
|
+
width: 100%;
|
|
904
|
+
height: 28px;
|
|
905
|
+
box-sizing: border-box;
|
|
906
|
+
background: var(--du-ui-bg-solid);
|
|
907
|
+
color: var(--du-text);
|
|
908
|
+
border: 1px solid var(--du-ui-border);
|
|
909
|
+
border-radius: var(--du-radius-sm);
|
|
910
|
+
padding: 0 8px 0 26px;
|
|
911
|
+
font: inherit;
|
|
912
|
+
font-size: 12px;
|
|
913
|
+
outline: none;
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
.du-side-panel-search input[type="search"]::placeholder {
|
|
917
|
+
color: var(--du-text-muted);
|
|
918
|
+
}
|
|
919
|
+
|
|
920
|
+
.du-side-panel-search input[type="search"]:focus {
|
|
921
|
+
border-color: var(--du-accent);
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
.du-side-panel-search-icon {
|
|
925
|
+
position: absolute;
|
|
926
|
+
left: calc(var(--du-pad) + 8px);
|
|
927
|
+
top: 50%;
|
|
928
|
+
transform: translateY(-50%);
|
|
929
|
+
color: var(--du-text-muted);
|
|
930
|
+
pointer-events: none;
|
|
931
|
+
}
|
|
932
|
+
|
|
933
|
+
/* ------------------------------------------------------------------ */
|
|
934
|
+
/* Toast for reset-to-content visibility hint. */
|
|
935
|
+
/* ------------------------------------------------------------------ */
|
|
936
|
+
.du-pill-button {
|
|
937
|
+
display: inline-flex;
|
|
938
|
+
align-items: center;
|
|
939
|
+
gap: var(--du-gap-sm);
|
|
940
|
+
padding: 0 12px;
|
|
941
|
+
height: var(--du-button-size);
|
|
942
|
+
background: var(--du-ui-bg);
|
|
943
|
+
color: var(--du-text);
|
|
944
|
+
border: 1px solid var(--du-ui-border);
|
|
945
|
+
border-radius: 999px;
|
|
946
|
+
box-shadow: var(--du-ui-shadow);
|
|
947
|
+
cursor: pointer;
|
|
948
|
+
font-size: 13px;
|
|
949
|
+
line-height: 1;
|
|
950
|
+
white-space: nowrap;
|
|
951
|
+
transition: background 0.15s ease, transform 0.05s ease;
|
|
952
|
+
}
|
|
953
|
+
|
|
954
|
+
.du-pill-button:hover {
|
|
955
|
+
background: var(--du-ui-bg-solid);
|
|
956
|
+
}
|
|
957
|
+
|
|
958
|
+
.du-pill-button:active {
|
|
959
|
+
transform: scale(0.96);
|
|
960
|
+
}
|
|
961
|
+
|
|
962
|
+
/* ------------------------------------------------------------------ */
|
|
963
|
+
/* Tooltip — singleton popup rendered via portal by <TooltipProvider>.*/
|
|
964
|
+
/* Pointer-events-none so it never blocks hover on neighbour buttons. */
|
|
965
|
+
/* ------------------------------------------------------------------ */
|
|
966
|
+
.du-tooltip {
|
|
967
|
+
background: var(--du-text);
|
|
968
|
+
color: var(--du-ui-bg-solid);
|
|
969
|
+
padding: 4px 8px;
|
|
970
|
+
border-radius: var(--du-radius-sm);
|
|
971
|
+
font-size: 12px;
|
|
972
|
+
line-height: 1.4;
|
|
973
|
+
white-space: nowrap;
|
|
974
|
+
box-shadow: var(--du-ui-shadow);
|
|
975
|
+
font-family: inherit;
|
|
976
|
+
max-width: 260px;
|
|
977
|
+
}
|
|
978
|
+
|
|
979
|
+
/* ------------------------------------------------------------------ */
|
|
980
|
+
/* Help dialog — modern-style hotkey cheatsheet. */
|
|
981
|
+
/* Each section is an "island" with bordered rows; each key is its */
|
|
982
|
+
/* own pill `<kbd>` rendered with the same tonal selected fill as */
|
|
983
|
+
/* active toolbar buttons so the visual language stays consistent. */
|
|
984
|
+
/* ------------------------------------------------------------------ */
|
|
985
|
+
.du-help-islands {
|
|
986
|
+
display: grid;
|
|
987
|
+
gap: 24px;
|
|
988
|
+
grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
|
|
989
|
+
}
|
|
990
|
+
|
|
991
|
+
.du-help-island {
|
|
992
|
+
display: flex;
|
|
993
|
+
flex-direction: column;
|
|
994
|
+
gap: 8px;
|
|
995
|
+
}
|
|
996
|
+
|
|
997
|
+
.du-help-island-title {
|
|
998
|
+
margin: 0;
|
|
999
|
+
font-size: 13px;
|
|
1000
|
+
font-weight: 600;
|
|
1001
|
+
color: var(--du-text);
|
|
1002
|
+
letter-spacing: 0.2px;
|
|
1003
|
+
}
|
|
1004
|
+
|
|
1005
|
+
.du-help-island-rows {
|
|
1006
|
+
border: 1px solid var(--du-ui-border);
|
|
1007
|
+
border-radius: var(--du-radius);
|
|
1008
|
+
overflow: hidden;
|
|
1009
|
+
}
|
|
1010
|
+
|
|
1011
|
+
.du-help-row {
|
|
1012
|
+
display: flex;
|
|
1013
|
+
align-items: center;
|
|
1014
|
+
justify-content: space-between;
|
|
1015
|
+
gap: 12px;
|
|
1016
|
+
padding: 8px 12px;
|
|
1017
|
+
font-size: 13px;
|
|
1018
|
+
color: var(--du-text);
|
|
1019
|
+
border-bottom: 1px solid var(--du-ui-border);
|
|
1020
|
+
}
|
|
1021
|
+
|
|
1022
|
+
.du-help-row:last-child {
|
|
1023
|
+
border-bottom: none;
|
|
1024
|
+
}
|
|
1025
|
+
|
|
1026
|
+
.du-help-row-label {
|
|
1027
|
+
/* Label may wrap on narrow viewports; keys stay on a single line. */
|
|
1028
|
+
min-width: 0;
|
|
1029
|
+
}
|
|
1030
|
+
|
|
1031
|
+
.du-help-keys {
|
|
1032
|
+
display: inline-flex;
|
|
1033
|
+
align-items: center;
|
|
1034
|
+
gap: 4px;
|
|
1035
|
+
flex-shrink: 0;
|
|
1036
|
+
}
|
|
1037
|
+
|
|
1038
|
+
.du-help-keys-separator {
|
|
1039
|
+
font-size: 11px;
|
|
1040
|
+
color: var(--du-text-muted);
|
|
1041
|
+
padding: 0 2px;
|
|
1042
|
+
}
|
|
1043
|
+
|
|
1044
|
+
.du-help-key {
|
|
1045
|
+
display: inline-flex;
|
|
1046
|
+
align-items: center;
|
|
1047
|
+
justify-content: center;
|
|
1048
|
+
min-width: 22px;
|
|
1049
|
+
height: 22px;
|
|
1050
|
+
padding: 0 6px;
|
|
1051
|
+
background: var(--du-selected-bg);
|
|
1052
|
+
color: var(--du-selected-fg);
|
|
1053
|
+
border-radius: var(--du-radius-sm);
|
|
1054
|
+
font-family: inherit;
|
|
1055
|
+
font-size: 11px;
|
|
1056
|
+
font-weight: 600;
|
|
1057
|
+
line-height: 1;
|
|
1058
|
+
white-space: nowrap;
|
|
1059
|
+
}
|
|
1060
|
+
|
|
1061
|
+
.du-help-platform-badge {
|
|
1062
|
+
font-size: 11px;
|
|
1063
|
+
color: var(--du-text-muted);
|
|
1064
|
+
text-transform: uppercase;
|
|
1065
|
+
letter-spacing: 0.5px;
|
|
1066
|
+
}
|
|
1067
|
+
|
|
1068
|
+
/* ------------------------------------------------------------------ */
|
|
1069
|
+
/* Selection floating panel — modern-style horizontal toolbar that */
|
|
1070
|
+
/* hovers above the selection bbox. Position is set inline via */
|
|
1071
|
+
/* `transform:translate(...)` by floating-ui — these rules cover only */
|
|
1072
|
+
/* the visual chrome (pill background, shadow, animation, layout of */
|
|
1073
|
+
/* inline controls + their popover triggers). */
|
|
1074
|
+
/* ------------------------------------------------------------------ */
|
|
1075
|
+
/* Fade-in is handled inline via the `positioned` state in
|
|
1076
|
+
<SelectionFloatingPanel> — a CSS animation here would override the
|
|
1077
|
+
inline `transform: translate(...)` floating-ui writes, causing
|
|
1078
|
+
the panel to flash at the (0, 0) origin before snapping into
|
|
1079
|
+
place. */
|
|
1080
|
+
|
|
1081
|
+
.du-sel-panel {
|
|
1082
|
+
display: inline-flex;
|
|
1083
|
+
align-items: center;
|
|
1084
|
+
gap: var(--du-gap-sm);
|
|
1085
|
+
background: var(--du-ui-bg-solid);
|
|
1086
|
+
border: 1px solid var(--du-ui-border);
|
|
1087
|
+
border-radius: var(--du-radius);
|
|
1088
|
+
box-shadow: var(--du-ui-shadow);
|
|
1089
|
+
padding: var(--du-pad-sm);
|
|
1090
|
+
font-size: 12px;
|
|
1091
|
+
color: var(--du-text);
|
|
1092
|
+
max-width: calc(100vw - 32px);
|
|
1093
|
+
/* Allow horizontal scroll within the pill when too many controls
|
|
1094
|
+
are visible; `shift` middleware clamps the outer position but
|
|
1095
|
+
a panel wider than viewport still needs internal overflow. */
|
|
1096
|
+
overflow-x: auto;
|
|
1097
|
+
overflow-y: visible;
|
|
1098
|
+
scrollbar-width: thin;
|
|
1099
|
+
}
|
|
1100
|
+
|
|
1101
|
+
/* ---- Mobile bottom-sheet property panel (modern-style) ---- */
|
|
1102
|
+
/* Fixed dock at the bottom edge; transparent container so only the
|
|
1103
|
+
panel itself catches touches. Honours the home-indicator safe area. */
|
|
1104
|
+
.du-sel-panel-dock {
|
|
1105
|
+
position: fixed;
|
|
1106
|
+
left: 0;
|
|
1107
|
+
right: 0;
|
|
1108
|
+
/* Sit ABOVE the bottom bar (zoom / help) + the home-indicator safe area
|
|
1109
|
+
so the two don't overlap. Mirrors the side-panel top offset. */
|
|
1110
|
+
bottom: calc(
|
|
1111
|
+
var(--du-bar-inset) + var(--du-button-size) + var(--du-gap) +
|
|
1112
|
+
env(safe-area-inset-bottom, 0px)
|
|
1113
|
+
);
|
|
1114
|
+
z-index: 1500;
|
|
1115
|
+
display: flex;
|
|
1116
|
+
justify-content: center;
|
|
1117
|
+
padding: 0 8px;
|
|
1118
|
+
pointer-events: none;
|
|
1119
|
+
}
|
|
1120
|
+
|
|
1121
|
+
/* Full-width sheet: a primary row + (when ⋮ is tapped) a wrapped
|
|
1122
|
+
overflow grid below. Overrides the floating pill's row/scroll chrome. */
|
|
1123
|
+
.du-sel-panel-mobile {
|
|
1124
|
+
pointer-events: auto;
|
|
1125
|
+
flex-direction: column;
|
|
1126
|
+
align-items: stretch;
|
|
1127
|
+
width: 100%;
|
|
1128
|
+
max-width: 560px;
|
|
1129
|
+
overflow: visible;
|
|
1130
|
+
gap: 6px;
|
|
1131
|
+
padding: 8px;
|
|
1132
|
+
}
|
|
1133
|
+
.du-sel-mobile-row {
|
|
1134
|
+
display: flex;
|
|
1135
|
+
align-items: center;
|
|
1136
|
+
gap: var(--du-gap-sm);
|
|
1137
|
+
width: 100%;
|
|
1138
|
+
}
|
|
1139
|
+
/* Primary controls scroll horizontally if they don't fit; the ⋮ button
|
|
1140
|
+
stays pinned to the right, always reachable. */
|
|
1141
|
+
.du-sel-mobile-primary {
|
|
1142
|
+
display: flex;
|
|
1143
|
+
align-items: center;
|
|
1144
|
+
gap: var(--du-gap-sm);
|
|
1145
|
+
flex: 1 1 auto;
|
|
1146
|
+
min-width: 0;
|
|
1147
|
+
overflow-x: auto;
|
|
1148
|
+
scrollbar-width: none;
|
|
1149
|
+
}
|
|
1150
|
+
.du-sel-mobile-primary::-webkit-scrollbar {
|
|
1151
|
+
display: none;
|
|
1152
|
+
}
|
|
1153
|
+
.du-sel-mobile-expand {
|
|
1154
|
+
flex: 0 0 auto;
|
|
1155
|
+
}
|
|
1156
|
+
.du-sel-mobile-overflow {
|
|
1157
|
+
display: flex;
|
|
1158
|
+
flex-wrap: wrap;
|
|
1159
|
+
align-items: center;
|
|
1160
|
+
gap: var(--du-gap-sm);
|
|
1161
|
+
border-top: 1px solid var(--du-ui-border);
|
|
1162
|
+
padding-top: 8px;
|
|
1163
|
+
}
|
|
1164
|
+
/* ≥44px touch targets on the mobile panel (Apple HIG). Standalone icon
|
|
1165
|
+
buttons + color triggers grow; grouped segmented buttons stay a touch
|
|
1166
|
+
smaller so wide controls (font-size S/M/L/XL) still fit one row. */
|
|
1167
|
+
.du-sel-panel-mobile .du-sel-icon-button,
|
|
1168
|
+
.du-sel-panel-mobile .du-sel-color-trigger {
|
|
1169
|
+
width: 44px;
|
|
1170
|
+
height: 44px;
|
|
1171
|
+
}
|
|
1172
|
+
.du-sel-panel-mobile .du-button-group > .du-icon-button {
|
|
1173
|
+
width: 38px;
|
|
1174
|
+
height: 38px;
|
|
1175
|
+
}
|
|
1176
|
+
|
|
1177
|
+
/* Flat segmented controls inside the floating panel — no group
|
|
1178
|
+
pill chrome (the outer panel already provides it). Reuses the
|
|
1179
|
+
button-group rules from PropertyPanel but with tighter gaps. */
|
|
1180
|
+
.du-sel-panel .du-button-group {
|
|
1181
|
+
background: transparent;
|
|
1182
|
+
border: none;
|
|
1183
|
+
box-shadow: none;
|
|
1184
|
+
padding: 0;
|
|
1185
|
+
gap: 2px;
|
|
1186
|
+
}
|
|
1187
|
+
|
|
1188
|
+
.du-sel-panel .du-button-group > .du-icon-button {
|
|
1189
|
+
width: var(--du-button-size-sm);
|
|
1190
|
+
height: var(--du-button-size-sm);
|
|
1191
|
+
}
|
|
1192
|
+
|
|
1193
|
+
/* Color swatch trigger — 28×28 with 20×20 colored square inside. */
|
|
1194
|
+
.du-sel-color-trigger {
|
|
1195
|
+
display: inline-flex;
|
|
1196
|
+
align-items: center;
|
|
1197
|
+
justify-content: center;
|
|
1198
|
+
width: var(--du-button-size-sm);
|
|
1199
|
+
height: var(--du-button-size-sm);
|
|
1200
|
+
padding: 0;
|
|
1201
|
+
background: transparent;
|
|
1202
|
+
border: none;
|
|
1203
|
+
border-radius: var(--du-radius-sm);
|
|
1204
|
+
cursor: pointer;
|
|
1205
|
+
-webkit-tap-highlight-color: transparent;
|
|
1206
|
+
}
|
|
1207
|
+
|
|
1208
|
+
.du-sel-color-trigger:hover:not(:disabled) {
|
|
1209
|
+
background: var(--du-hover-overlay);
|
|
1210
|
+
}
|
|
1211
|
+
|
|
1212
|
+
.du-sel-color-trigger:focus-visible {
|
|
1213
|
+
outline: 2px solid var(--du-accent);
|
|
1214
|
+
outline-offset: 1px;
|
|
1215
|
+
}
|
|
1216
|
+
|
|
1217
|
+
.du-sel-color-swatch {
|
|
1218
|
+
display: inline-block;
|
|
1219
|
+
width: 18px;
|
|
1220
|
+
height: 18px;
|
|
1221
|
+
border-radius: 4px;
|
|
1222
|
+
border: 1px solid var(--du-ui-border);
|
|
1223
|
+
box-sizing: border-box;
|
|
1224
|
+
}
|
|
1225
|
+
|
|
1226
|
+
/* Plain icon button used for corners / etc. Same chrome as
|
|
1227
|
+
color-trigger but icon inside. */
|
|
1228
|
+
.du-sel-icon-button {
|
|
1229
|
+
display: inline-flex;
|
|
1230
|
+
align-items: center;
|
|
1231
|
+
justify-content: center;
|
|
1232
|
+
width: var(--du-button-size-sm);
|
|
1233
|
+
height: var(--du-button-size-sm);
|
|
1234
|
+
padding: 0;
|
|
1235
|
+
background: transparent;
|
|
1236
|
+
border: none;
|
|
1237
|
+
border-radius: var(--du-radius-sm);
|
|
1238
|
+
cursor: pointer;
|
|
1239
|
+
color: var(--du-text);
|
|
1240
|
+
}
|
|
1241
|
+
|
|
1242
|
+
.du-sel-icon-button:hover:not(:disabled) {
|
|
1243
|
+
background: var(--du-hover-overlay);
|
|
1244
|
+
}
|
|
1245
|
+
|
|
1246
|
+
/* Pressed / on state for toggle buttons (Bold / Italic / Underline /
|
|
1247
|
+
Strikethrough in the text style popover). Without this the computed
|
|
1248
|
+
`is-active` class had no visual, so toggles never reflected the
|
|
1249
|
+
selection's current style. */
|
|
1250
|
+
.du-sel-icon-button.is-active {
|
|
1251
|
+
background: var(--du-accent-soft, rgba(80, 130, 255, 0.22));
|
|
1252
|
+
color: var(--du-accent, #5082ff);
|
|
1253
|
+
}
|
|
1254
|
+
|
|
1255
|
+
.du-sel-icon-button:focus-visible {
|
|
1256
|
+
outline: 2px solid var(--du-accent);
|
|
1257
|
+
outline-offset: 1px;
|
|
1258
|
+
}
|
|
1259
|
+
|
|
1260
|
+
/* Text-label button (opacity badge "75%"). */
|
|
1261
|
+
.du-sel-text-button {
|
|
1262
|
+
display: inline-flex;
|
|
1263
|
+
align-items: center;
|
|
1264
|
+
justify-content: center;
|
|
1265
|
+
height: var(--du-button-size-sm);
|
|
1266
|
+
min-width: var(--du-button-size-sm);
|
|
1267
|
+
padding: 0 8px;
|
|
1268
|
+
background: transparent;
|
|
1269
|
+
border: none;
|
|
1270
|
+
border-radius: var(--du-radius-sm);
|
|
1271
|
+
cursor: pointer;
|
|
1272
|
+
color: var(--du-text);
|
|
1273
|
+
font-size: 12px;
|
|
1274
|
+
font-variant-numeric: tabular-nums;
|
|
1275
|
+
}
|
|
1276
|
+
|
|
1277
|
+
.du-sel-text-button:hover:not(:disabled) {
|
|
1278
|
+
background: var(--du-hover-overlay);
|
|
1279
|
+
}
|
|
1280
|
+
|
|
1281
|
+
.du-sel-text-button:focus-visible {
|
|
1282
|
+
outline: 2px solid var(--du-accent);
|
|
1283
|
+
outline-offset: 1px;
|
|
1284
|
+
}
|
|
1285
|
+
|
|
1286
|
+
/* Visual divider between inline groups (z-order, actions). */
|
|
1287
|
+
.du-sel-divider {
|
|
1288
|
+
display: inline-block;
|
|
1289
|
+
width: 1px;
|
|
1290
|
+
height: 18px;
|
|
1291
|
+
background: var(--du-ui-border);
|
|
1292
|
+
margin: 0 2px;
|
|
1293
|
+
}
|
|
1294
|
+
|
|
1295
|
+
/* ------------------------------------------------------------------ */
|
|
1296
|
+
/* Popover — generic floating panel used by color picker / corners / */
|
|
1297
|
+
/* opacity slider inside the selection floating panel. */
|
|
1298
|
+
/* ------------------------------------------------------------------ */
|
|
1299
|
+
.du-popover {
|
|
1300
|
+
background: var(--du-ui-bg-solid);
|
|
1301
|
+
border: 1px solid var(--du-ui-border);
|
|
1302
|
+
border-radius: var(--du-radius);
|
|
1303
|
+
box-shadow: var(--du-ui-shadow);
|
|
1304
|
+
padding: var(--du-pad);
|
|
1305
|
+
font-size: 12px;
|
|
1306
|
+
color: var(--du-text);
|
|
1307
|
+
min-width: 120px;
|
|
1308
|
+
max-width: 320px;
|
|
1309
|
+
}
|
|
1310
|
+
|
|
1311
|
+
.du-sel-popover-section {
|
|
1312
|
+
display: flex;
|
|
1313
|
+
flex-direction: column;
|
|
1314
|
+
gap: 8px;
|
|
1315
|
+
min-width: 0;
|
|
1316
|
+
}
|
|
1317
|
+
|
|
1318
|
+
.du-sel-popover-label {
|
|
1319
|
+
margin: 0;
|
|
1320
|
+
font-size: 10px;
|
|
1321
|
+
font-weight: 600;
|
|
1322
|
+
text-transform: uppercase;
|
|
1323
|
+
letter-spacing: 0.5px;
|
|
1324
|
+
color: var(--du-text-muted);
|
|
1325
|
+
}
|
|
1326
|
+
|
|
1327
|
+
/* Vertical list row inside a selection popover (e.g. font-family
|
|
1328
|
+
picker). One full-width clickable row; `is-active` marks the
|
|
1329
|
+
current value. */
|
|
1330
|
+
.du-sel-menu-row {
|
|
1331
|
+
all: unset;
|
|
1332
|
+
display: block;
|
|
1333
|
+
width: 100%;
|
|
1334
|
+
box-sizing: border-box;
|
|
1335
|
+
padding: 6px 10px;
|
|
1336
|
+
border-radius: 4px;
|
|
1337
|
+
font-size: 13px;
|
|
1338
|
+
color: var(--du-text, #ddd);
|
|
1339
|
+
cursor: pointer;
|
|
1340
|
+
}
|
|
1341
|
+
|
|
1342
|
+
.du-sel-menu-row:hover {
|
|
1343
|
+
background: var(--du-ui-hover, #2a2a2a);
|
|
1344
|
+
}
|
|
1345
|
+
|
|
1346
|
+
.du-sel-menu-row.is-active {
|
|
1347
|
+
background: var(--du-accent-soft, rgba(80, 130, 255, 0.2));
|
|
1348
|
+
}
|
|
1349
|
+
|
|
1350
|
+
/* URL field inside the element-link popover. */
|
|
1351
|
+
.du-sel-link-input {
|
|
1352
|
+
width: 220px;
|
|
1353
|
+
max-width: 60vw;
|
|
1354
|
+
box-sizing: border-box;
|
|
1355
|
+
padding: 6px 8px;
|
|
1356
|
+
font-size: 13px;
|
|
1357
|
+
color: var(--du-text, #ddd);
|
|
1358
|
+
background: var(--du-ui-bg, #1a1a1a);
|
|
1359
|
+
border: 1px solid var(--du-ui-border, #333);
|
|
1360
|
+
border-radius: 4px;
|
|
1361
|
+
outline: none;
|
|
1362
|
+
}
|
|
1363
|
+
|
|
1364
|
+
.du-sel-link-input:focus-visible {
|
|
1365
|
+
outline: 2px solid var(--du-accent, #5082ff);
|
|
1366
|
+
outline-offset: -1px;
|
|
1367
|
+
}
|
|
1368
|
+
|
|
1369
|
+
/* Hover link popup (chip above a linked element). */
|
|
1370
|
+
.du-link-popup {
|
|
1371
|
+
z-index: 1400;
|
|
1372
|
+
margin-top: -6px;
|
|
1373
|
+
pointer-events: auto;
|
|
1374
|
+
}
|
|
1375
|
+
|
|
1376
|
+
.du-link-popup-url {
|
|
1377
|
+
display: inline-flex;
|
|
1378
|
+
align-items: center;
|
|
1379
|
+
gap: 6px;
|
|
1380
|
+
max-width: 280px;
|
|
1381
|
+
padding: 4px 8px;
|
|
1382
|
+
font: 12px system-ui, -apple-system, Segoe UI, Roboto, sans-serif;
|
|
1383
|
+
color: var(--du-accent, #5082ff);
|
|
1384
|
+
text-decoration: none;
|
|
1385
|
+
background: var(--menu-bg, #1a1a1a);
|
|
1386
|
+
border: 1px solid var(--menu-border, #333);
|
|
1387
|
+
border-radius: 6px;
|
|
1388
|
+
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.3);
|
|
1389
|
+
cursor: pointer;
|
|
1390
|
+
}
|
|
1391
|
+
|
|
1392
|
+
.du-link-popup-url:hover {
|
|
1393
|
+
background: var(--du-ui-hover, #2a2a2a);
|
|
1394
|
+
}
|
|
1395
|
+
|
|
1396
|
+
.du-link-popup-text {
|
|
1397
|
+
overflow: hidden;
|
|
1398
|
+
text-overflow: ellipsis;
|
|
1399
|
+
white-space: nowrap;
|
|
1400
|
+
max-width: 240px;
|
|
1401
|
+
}
|
|
1402
|
+
|
|
1403
|
+
/* Arrowhead picker popover (per-end). */
|
|
1404
|
+
.du-arrowhead-grid {
|
|
1405
|
+
display: grid;
|
|
1406
|
+
grid-template-columns: repeat(4, 1fr);
|
|
1407
|
+
gap: 2px;
|
|
1408
|
+
margin-top: 4px;
|
|
1409
|
+
}
|
|
1410
|
+
.du-arrowhead-option {
|
|
1411
|
+
display: inline-flex;
|
|
1412
|
+
align-items: center;
|
|
1413
|
+
justify-content: center;
|
|
1414
|
+
min-width: 30px;
|
|
1415
|
+
height: 26px;
|
|
1416
|
+
padding: 2px;
|
|
1417
|
+
border: 1px solid transparent;
|
|
1418
|
+
border-radius: 6px;
|
|
1419
|
+
background: transparent;
|
|
1420
|
+
cursor: pointer;
|
|
1421
|
+
color: var(--du-fg, #1c1c1e);
|
|
1422
|
+
}
|
|
1423
|
+
.du-arrowhead-option:hover {
|
|
1424
|
+
background: var(--du-hover, #f0f0f3);
|
|
1425
|
+
}
|
|
1426
|
+
.du-arrowhead-option--active {
|
|
1427
|
+
border-color: var(--du-accent, #5082ff);
|
|
1428
|
+
}
|
|
1429
|
+
.du-arrowhead-none {
|
|
1430
|
+
font-size: 13px;
|
|
1431
|
+
opacity: 0.6;
|
|
1432
|
+
}
|
|
1433
|
+
.du-arrowhead-erd-label {
|
|
1434
|
+
font-size: 9px;
|
|
1435
|
+
line-height: 1.05;
|
|
1436
|
+
text-align: center;
|
|
1437
|
+
}
|
|
1438
|
+
.du-arrowhead-erd-toggle {
|
|
1439
|
+
margin-top: 6px;
|
|
1440
|
+
width: 100%;
|
|
1441
|
+
text-align: left;
|
|
1442
|
+
border: none;
|
|
1443
|
+
background: transparent;
|
|
1444
|
+
cursor: pointer;
|
|
1445
|
+
font-size: 11px;
|
|
1446
|
+
color: var(--du-muted, #6b6b70);
|
|
1447
|
+
padding: 2px 0;
|
|
1448
|
+
}
|
|
1449
|
+
.du-arrowhead-erd-toggle:hover {
|
|
1450
|
+
color: var(--du-fg, #1c1c1e);
|
|
1451
|
+
}
|
|
1452
|
+
|
|
1453
|
+
/* Inline link caption editor. */
|
|
1454
|
+
.du-link-caption-input {
|
|
1455
|
+
min-width: 60px;
|
|
1456
|
+
max-width: 220px;
|
|
1457
|
+
padding: 2px 6px;
|
|
1458
|
+
font: 12px system-ui, sans-serif;
|
|
1459
|
+
text-align: center;
|
|
1460
|
+
color: var(--du-fg, #222);
|
|
1461
|
+
background: var(--du-panel-bg, #fff);
|
|
1462
|
+
border: 1px solid var(--du-accent, #5082ff);
|
|
1463
|
+
border-radius: 4px;
|
|
1464
|
+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.18);
|
|
1465
|
+
outline: none;
|
|
1466
|
+
}
|
|
1467
|
+
|
|
1468
|
+
/* Mini shape-picker shown after a link is dropped on empty canvas. */
|
|
1469
|
+
.du-link-drop-menu {
|
|
1470
|
+
display: flex;
|
|
1471
|
+
gap: 2px;
|
|
1472
|
+
padding: 4px;
|
|
1473
|
+
background: var(--du-panel-bg, #fff);
|
|
1474
|
+
border: 1px solid var(--du-border, #e3e3e6);
|
|
1475
|
+
border-radius: 8px;
|
|
1476
|
+
box-shadow: 0 6px 20px rgba(0, 0, 0, 0.18);
|
|
1477
|
+
}
|
|
1478
|
+
.du-link-drop-item {
|
|
1479
|
+
display: inline-flex;
|
|
1480
|
+
align-items: center;
|
|
1481
|
+
justify-content: center;
|
|
1482
|
+
width: 30px;
|
|
1483
|
+
height: 30px;
|
|
1484
|
+
padding: 4px;
|
|
1485
|
+
border: none;
|
|
1486
|
+
border-radius: 6px;
|
|
1487
|
+
background: transparent;
|
|
1488
|
+
cursor: pointer;
|
|
1489
|
+
color: var(--du-fg, #1c1c1e);
|
|
1490
|
+
}
|
|
1491
|
+
.du-link-drop-item:hover {
|
|
1492
|
+
background: var(--du-hover, #f0f0f3);
|
|
1493
|
+
}
|
|
1494
|
+
.du-link-drop-item svg {
|
|
1495
|
+
width: 100%;
|
|
1496
|
+
height: 100%;
|
|
1497
|
+
}
|
|
1498
|
+
|
|
1499
|
+
.du-sel-menu-row:focus-visible {
|
|
1500
|
+
outline: 2px solid var(--du-accent, #5082ff);
|
|
1501
|
+
outline-offset: -2px;
|
|
1502
|
+
}
|