@openpen/module-api 1.1.0 → 1.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.
Files changed (98) hide show
  1. package/CHANGELOG.md +43 -0
  2. package/dist/_chunks/AppButtonDropdown.vue_vue_type_style_index_0_lang-DBVFUpxc.js +245 -0
  3. package/dist/_chunks/AppButtonDropdown.vue_vue_type_style_index_0_lang-DBVFUpxc.js.map +1 -0
  4. package/dist/_chunks/inject-keys-CRXCpN-M.js +196 -0
  5. package/dist/_chunks/inject-keys-CRXCpN-M.js.map +1 -0
  6. package/dist/_chunks/module-context-registry-Cn1IWYu9.js +16 -0
  7. package/dist/_chunks/module-context-registry-Cn1IWYu9.js.map +1 -0
  8. package/dist/_chunks/passthrough-DKU7JYuQ.js +6 -0
  9. package/dist/_chunks/passthrough-DKU7JYuQ.js.map +1 -0
  10. package/dist/cursors.d.ts +83 -0
  11. package/dist/define-module.d.ts +17 -0
  12. package/dist/host/color-utils.d.ts +11 -0
  13. package/{src/host/event-bus.ts → dist/host/event-bus.d.ts} +7 -5
  14. package/dist/host/host-commands.d.ts +1 -0
  15. package/dist/host/index.d.ts +24 -0
  16. package/dist/host/index.js +49 -0
  17. package/dist/host/index.js.map +1 -0
  18. package/{src/host/module-context-registry.ts → dist/host/module-context-registry.d.ts} +5 -19
  19. package/dist/host/passthrough.d.ts +2 -0
  20. package/dist/host/popup-anchor.d.ts +3 -0
  21. package/dist/host/registry.d.ts +39 -0
  22. package/dist/host/registry.js +37 -0
  23. package/dist/host/registry.js.map +1 -0
  24. package/dist/host/slot-entries.d.ts +2 -0
  25. package/dist/host/stroke-store.d.ts +5 -0
  26. package/dist/host/stroke-style.d.ts +3 -0
  27. package/dist/host/types.d.ts +164 -0
  28. package/dist/index.d.ts +28 -0
  29. package/dist/index.js +349 -0
  30. package/dist/index.js.map +1 -0
  31. package/{src/inject-keys.ts → dist/inject-keys.d.ts} +37 -66
  32. package/{src/locale.ts → dist/locale.d.ts} +3 -22
  33. package/dist/slots.d.ts +57 -0
  34. package/dist/types/contributions.d.ts +288 -0
  35. package/dist/types/control-bar-layout.d.ts +227 -0
  36. package/dist/types/module.d.ts +208 -0
  37. package/{src/types/notification.ts → dist/types/notification.d.ts} +12 -14
  38. package/dist/types/tool.d.ts +77 -0
  39. package/dist/uikit/components/AppBanner.vue.d.ts +34 -0
  40. package/dist/uikit/components/AppButton.vue.d.ts +30 -0
  41. package/dist/uikit/components/AppButtonDropdown.vue.d.ts +52 -0
  42. package/dist/uikit/components/AppDialog.vue.d.ts +53 -0
  43. package/dist/uikit/components/AppPopover.vue.d.ts +43 -0
  44. package/dist/uikit/components/AppSegmented.vue.d.ts +19 -0
  45. package/dist/uikit/components/AppSelect.vue.d.ts +26 -0
  46. package/dist/uikit/components/AppSlider.vue.d.ts +43 -0
  47. package/dist/uikit/components/AppTabs.vue.d.ts +35 -0
  48. package/dist/uikit/components/AppToggle.vue.d.ts +13 -0
  49. package/dist/uikit/components/AppTooltip.vue.d.ts +27 -0
  50. package/dist/uikit/components/DialogHost.vue.d.ts +3 -0
  51. package/{src/uikit/composables/dialog-internal-keys.ts → dist/uikit/composables/dialog-internal-keys.d.ts} +3 -5
  52. package/dist/uikit/composables/useDialog.d.ts +399 -0
  53. package/dist/uikit/composables/useDialogPluginComponent.d.ts +9 -0
  54. package/dist/uikit/index.d.ts +42 -0
  55. package/dist/uikit/index.js +884 -0
  56. package/dist/uikit/index.js.map +1 -0
  57. package/{src/uikit/internal.ts → dist/uikit/internal.d.ts} +1 -1
  58. package/dist/uikit/internal.js +157 -0
  59. package/dist/uikit/internal.js.map +1 -0
  60. package/dist/uikit/module-api.css +851 -0
  61. package/dist/uikit/primitives.d.ts +42 -0
  62. package/{src/use-module-context.ts → dist/use-module-context.d.ts} +2 -15
  63. package/{src/validation.ts → dist/validation.d.ts} +2 -6
  64. package/package.json +26 -12
  65. package/packages/module-api/CHANGELOG.md +0 -27
  66. package/src/cursors.ts +0 -369
  67. package/src/define-module.ts +0 -55
  68. package/src/host/color-utils.ts +0 -18
  69. package/src/host/host-commands.ts +0 -9
  70. package/src/host/index.ts +0 -53
  71. package/src/host/passthrough.ts +0 -10
  72. package/src/host/popup-anchor.ts +0 -14
  73. package/src/host/slot-entries.ts +0 -9
  74. package/src/host/stroke-store.ts +0 -20
  75. package/src/host/stroke-style.ts +0 -15
  76. package/src/index.ts +0 -131
  77. package/src/slots.ts +0 -135
  78. package/src/types/contributions.ts +0 -333
  79. package/src/types/control-bar-layout.ts +0 -174
  80. package/src/types/module.ts +0 -225
  81. package/src/types/tool.ts +0 -82
  82. package/src/uikit/components/.gitkeep +0 -0
  83. package/src/uikit/components/AppBanner.vue +0 -131
  84. package/src/uikit/components/AppButton.vue +0 -135
  85. package/src/uikit/components/AppDialog.vue +0 -393
  86. package/src/uikit/components/AppPopover.vue +0 -268
  87. package/src/uikit/components/AppSegmented.vue +0 -128
  88. package/src/uikit/components/AppSelect.vue +0 -235
  89. package/src/uikit/components/AppSlider.vue +0 -204
  90. package/src/uikit/components/AppTabs.vue +0 -163
  91. package/src/uikit/components/AppToggle.vue +0 -96
  92. package/src/uikit/components/AppTooltip.vue +0 -118
  93. package/src/uikit/components/DialogHost.vue +0 -272
  94. package/src/uikit/composables/useDialog.ts +0 -141
  95. package/src/uikit/composables/useDialogPluginComponent.ts +0 -27
  96. package/src/uikit/index.ts +0 -79
  97. package/src/uikit/primitives.ts +0 -150
  98. /package/{src → dist}/uikit/tokens.css +0 -0
@@ -0,0 +1,851 @@
1
+
2
+ .openpen-popover-content {
3
+ background: var(--openpen-color-surface-popup);
4
+ border: 1px solid var(--openpen-color-popover-frame);
5
+ border-radius: var(--openpen-radius-lg);
6
+ padding: 14px 16px;
7
+ color: var(--openpen-color-text-primary);
8
+ font-size: 13px;
9
+ box-shadow: var(--openpen-shadow);
10
+ backdrop-filter: var(--openpen-blur);
11
+ -webkit-backdrop-filter: var(--openpen-blur);
12
+ z-index: 100;
13
+ /* Prevent pointer events from leaking through transparent gaps. */
14
+ pointer-events: auto;
15
+ }
16
+ .openpen-popover-arrow {
17
+ fill: var(--openpen-color-popover-frame);
18
+ }
19
+
20
+ /* ── Open / close animations ────────────────────────────────────────────────
21
+ Reka UI's Presence keeps the element in the DOM until the running CSS
22
+ animation ends, so animations targeting [data-state="closed"] DO play
23
+ on close. transform-origin tracks data-side so the popover scales out
24
+ from the trigger instead of from its own center.
25
+
26
+ Timings: 200ms easeOutBack enter, 150ms ease leave. */
27
+ .openpen-popover-content[data-state='open'] {
28
+ animation: openpen-popover-in 200ms cubic-bezier(0.34, 1.56, 0.64, 1);
29
+ }
30
+ .openpen-popover-content[data-state='closed'] {
31
+ animation: openpen-popover-out 150ms ease forwards;
32
+ }
33
+ .openpen-popover-content[data-side='bottom'] { transform-origin: top center;
34
+ }
35
+ .openpen-popover-content[data-side='top'] { transform-origin: bottom center;
36
+ }
37
+ .openpen-popover-content[data-side='left'] { transform-origin: right center;
38
+ }
39
+ .openpen-popover-content[data-side='right'] { transform-origin: left center;
40
+ }
41
+ @keyframes openpen-popover-in {
42
+ from { opacity: 0; transform: scale(0.92);
43
+ }
44
+ to { opacity: 1; transform: scale(1);
45
+ }
46
+ }
47
+ @keyframes openpen-popover-out {
48
+ from { opacity: 1; transform: scale(1);
49
+ }
50
+ to { opacity: 0; transform: scale(0.92);
51
+ }
52
+ }
53
+
54
+ /* ── Root container ────────────────────────────────────────────────────────── */
55
+ .app-slider-root[data-v-946ec6af] {
56
+ position: relative;
57
+ display: flex;
58
+ align-items: center;
59
+ user-select: none;
60
+ touch-action: none;
61
+ flex-shrink: 0;
62
+ cursor: pointer;
63
+ }
64
+ .app-slider-root[data-orientation='horizontal'][data-v-946ec6af] {
65
+ height: var(--track-height, 4px);
66
+ }
67
+ .app-slider-root[data-orientation='vertical'][data-v-946ec6af] {
68
+ flex-direction: column;
69
+ width: var(--track-height, 4px);
70
+ }
71
+
72
+ /* ── Track ─────────────────────────────────────────────────────────────────── */
73
+ .app-slider-track[data-v-946ec6af] {
74
+ position: relative;
75
+ flex-grow: 1;
76
+ border-radius: var(--track-radius, 2px);
77
+ background: var(--openpen-color-border-hi);
78
+ }
79
+ .app-slider-root[data-orientation='horizontal'] .app-slider-track[data-v-946ec6af] {
80
+ height: var(--track-height, 4px);
81
+ }
82
+ .app-slider-root[data-orientation='vertical'] .app-slider-track[data-v-946ec6af] {
83
+ width: var(--track-height, 4px);
84
+ }
85
+
86
+ /* ── Range (filled portion) ─────────────────────────────────────────────────── */
87
+ .app-slider-range[data-v-946ec6af] {
88
+ position: absolute;
89
+ border-radius: var(--track-radius, 2px);
90
+ background: var(--openpen-color-accent);
91
+ }
92
+ .app-slider-root[data-orientation='horizontal'] .app-slider-range[data-v-946ec6af] {
93
+ height: 100%;
94
+ top: 0;
95
+ left: 0;
96
+ }
97
+ .app-slider-root[data-orientation='vertical'] .app-slider-range[data-v-946ec6af] {
98
+ width: 100%;
99
+ bottom: 0;
100
+ left: 0;
101
+ }
102
+
103
+ /* ── Thumb ─────────────────────────────────────────────────────────────────── */
104
+ .app-slider-thumb[data-v-946ec6af] {
105
+ display: block;
106
+ width: var(--thumb-w, 14px);
107
+ height: var(--thumb-h, 14px);
108
+ border-radius: var(--thumb-r, 50%);
109
+ background: #fff;
110
+ box-shadow: 0 1px 6px rgba(0, 0, 0, 0.50);
111
+ cursor: pointer;
112
+ outline: none;
113
+ transition: transform var(--openpen-duration-fast) var(--openpen-easing-standard);
114
+ }
115
+ .app-slider-thumb[data-v-946ec6af]:hover {
116
+ transform: scale(1.2);
117
+ }
118
+ .app-slider-thumb[data-v-946ec6af]:focus-visible {
119
+ box-shadow: 0 0 0 3px var(--openpen-color-accent-glow);
120
+ }
121
+
122
+ /* Root — the toggle track */
123
+ .app-toggle[data-v-3bad8ac7] {
124
+ width: 40px;
125
+ height: 24px;
126
+ border-radius: 12px;
127
+ border: none;
128
+ cursor: pointer;
129
+ position: relative;
130
+ flex-shrink: 0;
131
+ background: var(--openpen-color-toggle-off);
132
+ transition: background var(--openpen-duration-base) var(--openpen-easing-standard);
133
+ /* Remove default button styles */
134
+ padding: 0;
135
+ appearance: none;
136
+ -webkit-appearance: none;
137
+ display: inline-flex;
138
+ align-items: center;
139
+ }
140
+ .app-toggle.on[data-v-3bad8ac7] {
141
+ background: var(--openpen-color-accent);
142
+ }
143
+
144
+ /* Thumb — the white circular knob */
145
+ .app-toggle-thumb[data-v-3bad8ac7] {
146
+ position: absolute;
147
+ top: 3px;
148
+ left: 3px;
149
+ width: 18px;
150
+ height: 18px;
151
+ border-radius: 50%;
152
+ background: #fff;
153
+ box-shadow: 0 1px 4px rgba(0, 0, 0, 0.35);
154
+ transition: left var(--openpen-duration-bounce) var(--openpen-easing-bounce);
155
+ display: block;
156
+ pointer-events: none;
157
+ }
158
+ .app-toggle.on .app-toggle-thumb[data-v-3bad8ac7],
159
+ .app-toggle[data-state='checked'] .app-toggle-thumb[data-v-3bad8ac7] {
160
+ left: 19px;
161
+ }
162
+
163
+ .app-seg[data-v-a0348ad4] {
164
+ display: flex;
165
+ gap: var(--openpen-space-xs);
166
+ }
167
+ .app-seg-btn[data-v-a0348ad4] {
168
+ flex: 1;
169
+ display: flex;
170
+ align-items: center;
171
+ justify-content: center;
172
+ gap: 6px;
173
+ padding: 6px var(--openpen-space-lg);
174
+ border: 1.5px solid var(--openpen-color-border-hi);
175
+ border-radius: var(--openpen-radius-sm);
176
+ background: var(--openpen-color-input-bg);
177
+ color: var(--openpen-color-text-dim);
178
+ font-size: 12px;
179
+ font-weight: 600;
180
+ cursor: pointer;
181
+ white-space: nowrap;
182
+ transition:
183
+ background var(--openpen-duration-fast) var(--openpen-easing-standard),
184
+ color var(--openpen-duration-fast) var(--openpen-easing-standard),
185
+ border-color var(--openpen-duration-fast) var(--openpen-easing-standard);
186
+ }
187
+ .app-seg-icon[data-v-a0348ad4] {
188
+ display: inline-flex;
189
+ align-items: center;
190
+ justify-content: center;
191
+ line-height: 0;
192
+ }
193
+ .app-seg-btn[data-v-a0348ad4]:hover {
194
+ color: var(--openpen-color-text-primary);
195
+ background: var(--openpen-color-control-hover);
196
+ }
197
+ .app-seg-btn.active[data-v-a0348ad4] {
198
+ background: var(--openpen-color-accent-bg);
199
+ color: var(--openpen-color-accent);
200
+ border-color: color-mix(in srgb, var(--openpen-color-accent) 40%, transparent);
201
+ }
202
+ .app-seg--disabled[data-v-a0348ad4] {
203
+ opacity: 0.45;
204
+ pointer-events: none;
205
+ cursor: not-allowed;
206
+ }
207
+
208
+ /* ── Overlay (transparent click absorber, NOT a dim backdrop) ─────────────────
209
+ OpenPen's overlay window is transparent + frameless. A traditional dim/blur
210
+ backdrop renders as a small dark patch only over the visible chrome — visually
211
+ jarring. The overlay is therefore kept fully transparent here; its only job
212
+ is to absorb outside clicks (so Reka can dispatch interact-outside → close
213
+ when not persistent) and to protect the canvas from stray clicks while the
214
+ dialog is open. Host containers (e.g. ControlBar) render their own "locked"
215
+ visual state via HOST_DIALOG_OPEN_COUNT_KEY. */
216
+ .openpen-modal-overlay {
217
+ position: fixed;
218
+ inset: 0;
219
+ background: transparent;
220
+ z-index: 200;
221
+ pointer-events: auto;
222
+ }
223
+
224
+ /* ── Dialog content panel ────────────────────────────────────────────────── */
225
+ .openpen-modal-content {
226
+ position: fixed;
227
+ top: 50%;
228
+ left: 50%;
229
+ transform: translate(-50%, -50%);
230
+ z-index: 201;
231
+ min-width: 320px;
232
+ max-width: min(480px, calc(100vw - 48px));
233
+ max-height: calc(100vh - 96px);
234
+ overflow-y: auto;
235
+
236
+ background: var(--openpen-color-surface-popup);
237
+ border: 1px solid var(--openpen-color-border-hi);
238
+ border-radius: var(--openpen-radius-lg);
239
+ box-shadow: var(--openpen-shadow);
240
+ backdrop-filter: var(--openpen-blur);
241
+ -webkit-backdrop-filter: var(--openpen-blur);
242
+
243
+ color: var(--openpen-color-text-primary);
244
+ font-size: 13px;
245
+ padding: var(--openpen-space-lg);
246
+ pointer-events: auto;
247
+ }
248
+
249
+ /* ── Title ───────────────────────────────────────────────────────────────── */
250
+ .openpen-modal-title {
251
+ font-size: 15px;
252
+ font-weight: 600;
253
+ color: var(--openpen-color-text-primary);
254
+ margin: 0 0 var(--openpen-space-md) 0;
255
+ padding-right: 28px; /* leave room for close button */
256
+ line-height: 1.4;
257
+ }
258
+
259
+ /* ── Visually hidden description (a11y) ──────────────────────────────────── */
260
+ .openpen-modal-description.sr-only {
261
+ position: absolute;
262
+ width: 1px;
263
+ height: 1px;
264
+ padding: 0;
265
+ margin: -1px;
266
+ overflow: hidden;
267
+ clip: rect(0, 0, 0, 0);
268
+ white-space: nowrap;
269
+ border-width: 0;
270
+ }
271
+
272
+ /* ── Body ────────────────────────────────────────────────────────────────── */
273
+ .openpen-modal-body {
274
+ color: var(--openpen-color-text-primary);
275
+ }
276
+
277
+ /* ── Footer ──────────────────────────────────────────────────────────────── */
278
+ .openpen-modal-footer {
279
+ display: flex;
280
+ justify-content: flex-end;
281
+ gap: var(--openpen-space-sm);
282
+ margin-top: var(--openpen-space-lg);
283
+ padding-top: var(--openpen-space-md);
284
+ border-top: 1px solid var(--openpen-color-border);
285
+ }
286
+
287
+ /* ── Close button ────────────────────────────────────────────────────────── */
288
+ .openpen-modal-close {
289
+ position: absolute;
290
+ top: var(--openpen-space-md);
291
+ right: var(--openpen-space-md);
292
+ width: 24px;
293
+ height: 24px;
294
+ display: flex;
295
+ align-items: center;
296
+ justify-content: center;
297
+ border: none;
298
+ background: transparent;
299
+ color: var(--openpen-color-text-dim);
300
+ border-radius: var(--openpen-radius-sm);
301
+ cursor: pointer;
302
+ transition: background var(--openpen-duration-fast), color var(--openpen-duration-fast);
303
+ }
304
+ .openpen-modal-close:hover {
305
+ background: var(--openpen-color-control-hover);
306
+ color: var(--openpen-color-text-primary);
307
+ }
308
+
309
+ /* ── Open / close animations ─────────────────────────────────────────────────
310
+ Reka UI's Presence keeps the element in the DOM until the CSS animation
311
+ ends, so [data-state="closed"] animations DO play on close.
312
+ Pattern matches AppPopover keyframes (200ms bounce enter, 150ms ease leave). */
313
+
314
+ /* Overlay is always transparent — no fade-in/out animation needed.
315
+ Only the dialog content panel animates. */
316
+ .openpen-modal-content[data-state='open'] {
317
+ animation: openpen-modal-in 200ms cubic-bezier(0.34, 1.56, 0.64, 1);
318
+ }
319
+ .openpen-modal-content[data-state='closed'] {
320
+ animation: openpen-modal-out 150ms ease forwards;
321
+ }
322
+ @keyframes openpen-modal-in {
323
+ from { opacity: 0; transform: translate(-50%, -50%) scale(0.92);
324
+ }
325
+ to { opacity: 1; transform: translate(-50%, -50%) scale(1);
326
+ }
327
+ }
328
+ @keyframes openpen-modal-out {
329
+ from { opacity: 1; transform: translate(-50%, -50%) scale(1);
330
+ }
331
+ to { opacity: 0; transform: translate(-50%, -50%) scale(0.92);
332
+ }
333
+ }
334
+
335
+ /* ── Trigger ─────────────────────────────────────────────────────────────── */
336
+ .openpen-select-trigger {
337
+ display: inline-flex;
338
+ align-items: center;
339
+ justify-content: space-between;
340
+ gap: var(--openpen-space-sm);
341
+ min-width: 120px;
342
+ height: 32px;
343
+ padding: 0 var(--openpen-space-md);
344
+ background: var(--openpen-color-input-bg);
345
+ border: 1px solid var(--openpen-color-border-hi);
346
+ border-radius: var(--openpen-radius-md);
347
+ color: var(--openpen-color-text-primary);
348
+ font-size: 13px;
349
+ cursor: pointer;
350
+ transition:
351
+ background var(--openpen-duration-fast),
352
+ border-color var(--openpen-duration-fast);
353
+ outline: none;
354
+ white-space: nowrap;
355
+ user-select: none;
356
+ }
357
+ .openpen-select-trigger:hover {
358
+ background: var(--openpen-color-control-hover);
359
+ border-color: var(--openpen-color-border-hi);
360
+ }
361
+ .openpen-select-trigger:focus-visible {
362
+ border-color: var(--openpen-color-accent);
363
+ box-shadow: 0 0 0 2px var(--openpen-color-accent-glow);
364
+ }
365
+ .openpen-select-trigger[data-disabled] {
366
+ opacity: 0.45;
367
+ cursor: not-allowed;
368
+ }
369
+
370
+ /* ── Trigger icon (chevron) ──────────────────────────────────────────────── */
371
+ .openpen-select-icon {
372
+ color: var(--openpen-color-text-dim);
373
+ flex-shrink: 0;
374
+ display: flex;
375
+ align-items: center;
376
+ transition: transform var(--openpen-duration-fast);
377
+ }
378
+ .openpen-select-trigger[data-state='open'] .openpen-select-icon {
379
+ transform: rotate(180deg);
380
+ }
381
+
382
+ /* ── Dropdown content ────────────────────────────────────────────────────── */
383
+ .openpen-select-content {
384
+ background: var(--openpen-color-surface-popup);
385
+ border: 1px solid var(--openpen-color-border-hi);
386
+ border-radius: var(--openpen-radius-md);
387
+ box-shadow: var(--openpen-shadow);
388
+ backdrop-filter: var(--openpen-blur);
389
+ -webkit-backdrop-filter: var(--openpen-blur);
390
+ z-index: 100;
391
+ pointer-events: auto;
392
+ /* Match trigger width */
393
+ min-width: var(--reka-select-trigger-width, 120px);
394
+ max-height: 240px;
395
+ overflow: hidden;
396
+ }
397
+
398
+ /* ── Viewport scrollable area ────────────────────────────────────────────── */
399
+ .openpen-select-viewport {
400
+ padding: var(--openpen-space-xs);
401
+ }
402
+
403
+ /* ── Individual items ────────────────────────────────────────────────────── */
404
+ .openpen-select-item {
405
+ display: flex;
406
+ align-items: center;
407
+ gap: var(--openpen-space-sm);
408
+ height: 30px;
409
+ padding: 0 var(--openpen-space-md);
410
+ padding-left: 28px; /* indent to align text past indicator */
411
+ border-radius: var(--openpen-radius-sm);
412
+ font-size: 13px;
413
+ color: var(--openpen-color-text-primary);
414
+ cursor: pointer;
415
+ position: relative;
416
+ user-select: none;
417
+ outline: none;
418
+ transition: background var(--openpen-duration-fast);
419
+ }
420
+ .openpen-select-item[data-highlighted] {
421
+ background: var(--openpen-color-control-hover);
422
+ color: var(--openpen-color-text-primary);
423
+ }
424
+ .openpen-select-item[data-state='checked'] {
425
+ color: var(--openpen-color-accent);
426
+ }
427
+ .openpen-select-item[data-disabled] {
428
+ opacity: 0.45;
429
+ cursor: not-allowed;
430
+ }
431
+
432
+ /* ── Selected item indicator (checkmark) ─────────────────────────────────── */
433
+ .openpen-select-item-indicator {
434
+ position: absolute;
435
+ left: var(--openpen-space-sm);
436
+ display: flex;
437
+ align-items: center;
438
+ justify-content: center;
439
+ color: var(--openpen-color-accent);
440
+ }
441
+
442
+ /* ── Open / close animations ─────────────────────────────────────────────────
443
+ Pattern matches AppPopover keyframes (200ms bounce enter, 150ms ease leave). */
444
+ .openpen-select-content[data-state='open'] {
445
+ animation: openpen-select-in 200ms cubic-bezier(0.34, 1.56, 0.64, 1);
446
+ }
447
+ .openpen-select-content[data-state='closed'] {
448
+ animation: openpen-select-out 150ms ease forwards;
449
+ }
450
+ @keyframes openpen-select-in {
451
+ from { opacity: 0; transform: scale(0.95);
452
+ }
453
+ to { opacity: 1; transform: scale(1);
454
+ }
455
+ }
456
+ @keyframes openpen-select-out {
457
+ from { opacity: 1; transform: scale(1);
458
+ }
459
+ to { opacity: 0; transform: scale(0.95);
460
+ }
461
+ }
462
+
463
+ .openpen-tooltip-content {
464
+ background: var(--openpen-color-tooltip-bg);
465
+ border: 1px solid var(--openpen-color-border-hi);
466
+ border-radius: var(--openpen-radius-sm);
467
+ padding: 5px 9px;
468
+ color: var(--openpen-color-tooltip-text);
469
+ font-size: 12px;
470
+ line-height: 1.4;
471
+ /* Prevent text wrap for short tooltip labels */
472
+ white-space: nowrap;
473
+ box-shadow: var(--openpen-shadow-sm);
474
+ z-index: 200;
475
+ pointer-events: none;
476
+ }
477
+ .openpen-tooltip-arrow {
478
+ fill: var(--openpen-color-tooltip-bg);
479
+ }
480
+
481
+ /* ── Open / close animations ────────────────────────────────────────────────
482
+ Reka UI Presence keeps the element in the DOM until the CSS animation ends,
483
+ so data-state="delayed-open" / "instant-open" / "closed" all animate. */
484
+ .openpen-tooltip-content[data-state='delayed-open'],
485
+ .openpen-tooltip-content[data-state='instant-open'] {
486
+ animation: openpen-tooltip-in var(--openpen-duration-fast) var(--openpen-easing-standard);
487
+ }
488
+ .openpen-tooltip-content[data-state='closed'] {
489
+ animation: openpen-tooltip-out var(--openpen-duration-fast) ease forwards;
490
+ }
491
+ @keyframes openpen-tooltip-in {
492
+ from { opacity: 0; transform: scale(0.95);
493
+ }
494
+ to { opacity: 1; transform: scale(1);
495
+ }
496
+ }
497
+ @keyframes openpen-tooltip-out {
498
+ from { opacity: 1; transform: scale(1);
499
+ }
500
+ to { opacity: 0; transform: scale(0.95);
501
+ }
502
+ }
503
+
504
+ /* ── Tab root ───────────────────────────────────────────────────────────────── */
505
+ .openpen-tabs[data-v-5bab1555] {
506
+ display: flex;
507
+ flex-direction: column;
508
+ gap: var(--openpen-space-sm);
509
+ }
510
+
511
+ /* ── Tab list (trigger bar) ─────────────────────────────────────────────────── */
512
+ .openpen-tabs-list[data-v-5bab1555] {
513
+ display: flex;
514
+ flex-direction: row;
515
+ gap: 2px;
516
+ padding: 3px;
517
+ background: var(--openpen-color-control-group);
518
+ border: 1px solid var(--openpen-color-border);
519
+ border-radius: var(--openpen-radius-md);
520
+ }
521
+
522
+ /* ── Individual trigger ─────────────────────────────────────────────────────── */
523
+ .openpen-tabs-trigger[data-v-5bab1555] {
524
+ flex: 1;
525
+ padding: var(--openpen-space-xs) var(--openpen-space-sm);
526
+ border: none;
527
+ border-radius: calc(var(--openpen-radius-md) - 3px);
528
+ background: transparent;
529
+ color: var(--openpen-color-text-dim);
530
+ font-size: 13px;
531
+ font-weight: 500;
532
+ cursor: pointer;
533
+ transition:
534
+ background var(--openpen-duration-fast) var(--openpen-easing-standard),
535
+ color var(--openpen-duration-fast) var(--openpen-easing-standard);
536
+ white-space: nowrap;
537
+ /* Remove default button outline; focus-visible ring below handles a11y. */
538
+ outline: none;
539
+ }
540
+ .openpen-tabs-trigger[data-v-5bab1555]:hover {
541
+ background: var(--openpen-color-control-hover);
542
+ color: var(--openpen-color-text-primary);
543
+ }
544
+ .openpen-tabs-trigger[data-state='active'][data-v-5bab1555] {
545
+ background: var(--openpen-color-accent-bg);
546
+ color: var(--openpen-color-accent);
547
+ box-shadow: 0 0 0 1px var(--openpen-color-accent-glow);
548
+ }
549
+ .openpen-tabs-trigger[data-v-5bab1555]:focus-visible {
550
+ box-shadow: 0 0 0 2px var(--openpen-color-accent);
551
+ }
552
+
553
+ /* ── Tab content ────────────────────────────────────────────────────────────── */
554
+ .openpen-tabs-content[data-v-5bab1555] {
555
+ /* Content area has no chrome by default; plugin authors add their own. */
556
+ outline: none;
557
+ }
558
+ .openpen-tabs-content[data-v-5bab1555]:focus-visible {
559
+ box-shadow: 0 0 0 2px var(--openpen-color-accent);
560
+ border-radius: var(--openpen-radius-sm);
561
+ }
562
+
563
+ .app-banner[data-v-c68deb55] {
564
+ display: flex;
565
+ align-items: flex-start;
566
+ gap: 10px;
567
+ padding: 10px 14px;
568
+ border-radius: var(--openpen-radius-md, 10px);
569
+ border: 1px solid;
570
+ font-size: 13px;
571
+ line-height: 1.55;
572
+ }
573
+ .app-banner-inline[data-v-c68deb55] {
574
+ padding: 7px 12px;
575
+ align-items: center;
576
+ font-size: 12px;
577
+ }
578
+ .app-banner-icon[data-v-c68deb55] {
579
+ flex-shrink: 0;
580
+ display: flex;
581
+ align-items: center;
582
+ margin-top: 1px;
583
+ }
584
+ .app-banner-inline .app-banner-icon[data-v-c68deb55] { margin-top: 0;
585
+ }
586
+ .app-banner-body[data-v-c68deb55] {
587
+ flex: 1;
588
+ min-width: 0;
589
+ }
590
+ .app-banner-actions[data-v-c68deb55] {
591
+ display: flex;
592
+ align-items: center;
593
+ gap: 6px;
594
+ flex-shrink: 0;
595
+ margin-left: auto;
596
+ }
597
+
598
+ /* Variants */
599
+ .app-banner-info[data-v-c68deb55] {
600
+ background: var(--openpen-color-state-info-bg);
601
+ border-color: var(--openpen-color-state-info-border);
602
+ color: var(--openpen-color-state-info-text);
603
+ }
604
+ .app-banner-info .app-banner-icon[data-v-c68deb55] {
605
+ color: var(--openpen-color-state-info-icon);
606
+ }
607
+ .app-banner-warning[data-v-c68deb55] {
608
+ background: var(--openpen-color-state-warning-bg);
609
+ border-color: var(--openpen-color-state-warning-border);
610
+ color: var(--openpen-color-state-warning-text);
611
+ }
612
+ .app-banner-warning .app-banner-icon[data-v-c68deb55] {
613
+ color: var(--openpen-color-state-warning-icon);
614
+ }
615
+ .app-banner-success[data-v-c68deb55] {
616
+ background: var(--openpen-color-state-success-bg);
617
+ border-color: var(--openpen-color-state-success-border);
618
+ color: var(--openpen-color-state-success-text);
619
+ }
620
+ .app-banner-success .app-banner-icon[data-v-c68deb55] {
621
+ color: var(--openpen-color-state-success-icon);
622
+ }
623
+ .app-banner-error[data-v-c68deb55] {
624
+ background: var(--openpen-color-state-error-bg);
625
+ border-color: var(--openpen-color-state-error-border);
626
+ color: var(--openpen-color-state-error-text);
627
+ }
628
+ .app-banner-error .app-banner-icon[data-v-c68deb55] {
629
+ color: var(--openpen-color-state-error-icon);
630
+ }
631
+
632
+ .app-btn[data-v-2d853b64] {
633
+ display: flex;
634
+ align-items: center;
635
+ justify-content: center;
636
+ width: 36px;
637
+ height: 36px;
638
+ border: none;
639
+ border-radius: var(--openpen-radius-md);
640
+ background: transparent;
641
+ color: var(--openpen-color-text-dim);
642
+ cursor: pointer;
643
+ transition: background var(--openpen-duration-fast), color var(--openpen-duration-fast), transform var(--openpen-duration-fast);
644
+ position: relative;
645
+ flex-shrink: 0;
646
+ padding: 0;
647
+ }
648
+
649
+ /* Vertical bars shrink the button to 34×34 to match the host's
650
+ `.control-bar.is-vertical .cb-btn` rule. */
651
+ .app-btn.app-btn--vertical[data-v-2d853b64] {
652
+ width: 34px;
653
+ height: 34px;
654
+ }
655
+ .app-btn[data-v-2d853b64]:hover {
656
+ background: var(--openpen-color-control-hover);
657
+ color: var(--openpen-color-text-primary);
658
+ }
659
+ .app-btn[data-v-2d853b64]:active {
660
+ transform: scale(0.88);
661
+ }
662
+ .app-btn.active[data-v-2d853b64] {
663
+ background: var(--openpen-color-accent-bg);
664
+ color: var(--openpen-color-accent);
665
+ box-shadow: 0 0 0 1px var(--openpen-color-accent-glow);
666
+ }
667
+ .app-btn.danger[data-v-2d853b64] {
668
+ color: var(--openpen-color-danger);
669
+ }
670
+ .app-btn.danger[data-v-2d853b64]:hover {
671
+ background: var(--openpen-color-danger-hover-bg);
672
+ color: var(--openpen-color-danger-hover);
673
+ }
674
+
675
+ /* Disabled: keeps pointer events alive so the tooltip ::after hover still fires. */
676
+ .app-btn.app-btn-disabled[data-v-2d853b64] {
677
+ cursor: not-allowed;
678
+ }
679
+
680
+ /* Dim only the button content — tooltip pseudo-element stays at full opacity. */
681
+ .app-btn.app-btn-disabled[data-v-2d853b64] > * {
682
+ opacity: 0.30;
683
+ }
684
+
685
+ /* Tooltip — horizontal mode default (above the button). */
686
+ .app-btn[data-tip][data-v-2d853b64]::after {
687
+ content: attr(data-tip);
688
+ position: absolute;
689
+ bottom: calc(100% + 8px);
690
+ left: 50%;
691
+ transform: translateX(-50%);
692
+ background: var(--openpen-color-tooltip-bg);
693
+ border: 1px solid var(--openpen-color-tooltip-border);
694
+ color: var(--openpen-color-tooltip-text);
695
+ font-size: 11.5px;
696
+ font-weight: 500;
697
+ white-space: nowrap;
698
+ padding: 5px 10px;
699
+ border-radius: var(--openpen-radius-sm);
700
+ pointer-events: none;
701
+ opacity: 0;
702
+ transition: opacity var(--openpen-duration-fast);
703
+ box-shadow: var(--openpen-shadow-sm);
704
+ z-index: 41;
705
+ }
706
+
707
+ /* Horizontal mode near workArea top: tooltip flips below the button so
708
+ it does not extend off-screen. The host sets TOOLTIP_FLIP_DOWN_KEY when
709
+ the ball is within ~60 px of the top edge. */
710
+ .app-btn.app-btn--tooltip-top-flip[data-tip][data-v-2d853b64]::after {
711
+ bottom: auto;
712
+ top: calc(100% + 8px);
713
+ }
714
+
715
+ /* Vertical bar, snap-left or vbar-free: tooltip points right (inward). */
716
+ .app-btn.app-btn--tooltip-right[data-tip][data-v-2d853b64]::after {
717
+ top: 50%;
718
+ bottom: auto;
719
+ left: calc(100% + 8px);
720
+ right: auto;
721
+ transform: translateY(-50%);
722
+ }
723
+
724
+ /* Vertical bar, snap-right: tooltip points left (inward). */
725
+ .app-btn.app-btn--tooltip-left[data-tip][data-v-2d853b64]::after {
726
+ top: 50%;
727
+ bottom: auto;
728
+ left: auto;
729
+ right: calc(100% + 8px);
730
+ transform: translateY(-50%);
731
+ }
732
+ .app-btn[data-tip][data-v-2d853b64]:hover::after {
733
+ opacity: 1;
734
+ }
735
+
736
+ /* Structural classes ship UNSCOPED on purpose so host CSS can apply
737
+ contextual overrides (e.g. `.cb-group--inset .app-btn-dropdown-caret`
738
+ shrinks the caret inside inset groups in the host control bar). The
739
+ classes are deliberately prefixed `app-btn-dropdown-*` to avoid
740
+ collisions in plugin code. */
741
+ .app-btn-dropdown-wrap {
742
+ display: flex;
743
+ align-items: center;
744
+ gap: 0;
745
+ -webkit-app-region: no-drag;
746
+ }
747
+ .app-btn-dropdown-wrap--vertical {
748
+ flex-direction: column;
749
+ gap: 2px;
750
+ }
751
+ .app-btn-dropdown-caret {
752
+ display: flex;
753
+ align-items: center;
754
+ justify-content: center;
755
+ width: 16px;
756
+ height: 36px;
757
+ border: none;
758
+ background: transparent;
759
+ color: var(--openpen-color-text-dim);
760
+ cursor: pointer;
761
+ padding: 0;
762
+ border-radius: 8px;
763
+ transition: color var(--openpen-duration-fast), background var(--openpen-duration-fast);
764
+ }
765
+ .app-btn-dropdown-caret--vertical {
766
+ width: 30px;
767
+ height: 14px;
768
+ }
769
+ .app-btn-dropdown-caret:hover {
770
+ color: var(--openpen-color-text-primary);
771
+ background: var(--openpen-color-control-hover);
772
+ }
773
+ .app-btn-dropdown-caret.active {
774
+ color: var(--openpen-color-accent);
775
+ background: var(--openpen-color-accent-bg);
776
+ }
777
+ .app-btn-dropdown-caret--disabled {
778
+ cursor: not-allowed;
779
+ }
780
+ .app-btn-dropdown-caret--disabled > * {
781
+ opacity: 0.30;
782
+ }
783
+ .app-btn-dropdown-caret-icon {
784
+ transition: transform 180ms cubic-bezier(0.34, 1.56, 0.64, 1);
785
+ }
786
+ .app-btn-dropdown-caret-icon--down { transform: rotate(0deg);
787
+ }
788
+ .app-btn-dropdown-caret-icon--up { transform: rotate(180deg);
789
+ }
790
+ .app-btn-dropdown-caret-icon--right { transform: rotate(-90deg);
791
+ }
792
+ .app-btn-dropdown-caret-icon--left { transform: rotate(90deg);
793
+ }
794
+
795
+ /* ── DialogHost utility styles ───────────────────────────────────────────── */
796
+ .openpen-dialog-host-message {
797
+ margin: 0 0 var(--openpen-space-md, 12px) 0;
798
+ color: var(--openpen-color-text-primary, #fff);
799
+ line-height: 1.5;
800
+ }
801
+ .openpen-dialog-host-input {
802
+ display: block;
803
+ width: 100%;
804
+ box-sizing: border-box;
805
+ padding: 6px 10px;
806
+ border: 1px solid var(--openpen-color-border-hi, rgba(255,255,255,0.2));
807
+ border-radius: var(--openpen-radius-sm, 6px);
808
+ background: var(--openpen-color-control, rgba(255,255,255,0.08));
809
+ color: var(--openpen-color-text-primary, #fff);
810
+ font-size: 13px;
811
+ outline: none;
812
+ }
813
+ .openpen-dialog-host-input:focus {
814
+ border-color: var(--accent, #7c7cff);
815
+ box-shadow: 0 0 0 2px var(--accent-bg, rgba(124,124,255,0.18));
816
+ }
817
+
818
+ /* ── DialogHost button styles ─────────────────────────────────────────────── */
819
+ .openpen-btn {
820
+ display: inline-flex;
821
+ align-items: center;
822
+ justify-content: center;
823
+ padding: 6px 16px;
824
+ border-radius: var(--openpen-radius-sm, 6px);
825
+ font-size: 13px;
826
+ font-weight: 500;
827
+ cursor: pointer;
828
+ border: none;
829
+ transition: background var(--openpen-duration-fast, 120ms), color var(--openpen-duration-fast, 120ms);
830
+ }
831
+ .openpen-btn-secondary {
832
+ background: var(--openpen-color-control, rgba(255,255,255,0.08));
833
+ color: var(--openpen-color-text-primary, #fff);
834
+ }
835
+ .openpen-btn-secondary:hover {
836
+ background: var(--openpen-color-control-hover, rgba(255,255,255,0.14));
837
+ }
838
+ .openpen-btn-primary {
839
+ background: var(--accent, #7c7cff);
840
+ color: #fff;
841
+ }
842
+ .openpen-btn-primary:hover {
843
+ opacity: 0.9;
844
+ }
845
+ .openpen-btn-danger {
846
+ background: var(--openpen-color-danger, #e05252);
847
+ color: #fff;
848
+ }
849
+ .openpen-btn-danger:hover {
850
+ opacity: 0.9;
851
+ }