@dtducas/wh-forge-viewer 1.0.9-beta0 → 2.0.0-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.esm.js +349 -132
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +349 -132
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2552,6 +2552,14 @@ var MarkupConverterService = /*#__PURE__*/function () {
|
|
|
2552
2552
|
if (shape === null || shape === void 0 ? void 0 : shape.text) {
|
|
2553
2553
|
attrs += " text=\"".concat(this.escapeXml(shape.text), "\"");
|
|
2554
2554
|
}
|
|
2555
|
+
// Add text-data for stamp/image types.
|
|
2556
|
+
// Forge's MarkupStamp.loadSvgData() reads style['text-data'] as the image SVG source.
|
|
2557
|
+
// Without this, Forge creates a blank (invisible) stamp when loadMarkups() + enterEditMode()
|
|
2558
|
+
// is used to restore stamps into the edit canvas (used by reloadEditCanvasWithMergedMarkups).
|
|
2559
|
+
if (forgeType === 'stamp' && (shape === null || shape === void 0 ? void 0 : shape.imageData)) {
|
|
2560
|
+
var svgData = "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 1 1\" width=\"1\" height=\"1\"><image width=\"1\" height=\"1\" href=\"".concat(shape.imageData, "\"/></svg>");
|
|
2561
|
+
attrs += " text-data=\"".concat(this.escapeXml(svgData), "\"");
|
|
2562
|
+
}
|
|
2555
2563
|
// Add font attributes.
|
|
2556
2564
|
// CRITICAL: The <metadata><markup_element font-size="..."/> is parsed by Forge's
|
|
2557
2565
|
// loadMarkups() as a COORDINATE-SPACE value (model units), NOT SVG pixel units.
|
|
@@ -2777,7 +2785,12 @@ var MarkupConverterService = /*#__PURE__*/function () {
|
|
|
2777
2785
|
var _h3 = size[1];
|
|
2778
2786
|
var x = -_w2 / 2;
|
|
2779
2787
|
var y = -_h3 / 2;
|
|
2780
|
-
|
|
2788
|
+
// Forge's markup SVG canvas uses a Y-up coordinate system.
|
|
2789
|
+
// Raster <image> pixels are always Y-down (screen space), so they appear
|
|
2790
|
+
// upside-down without a counter-flip. Append scale(1,-1) to flip the image
|
|
2791
|
+
// content back to the correct screen orientation for User B's overlay.
|
|
2792
|
+
// The hitarea rect does not need a flip — it is transparent and just tracks hits.
|
|
2793
|
+
return "<image href=\"".concat(imgData, "\" x=\"").concat(x, "\" y=\"").concat(y, "\" width=\"").concat(_w2, "\" height=\"").concat(_h3, "\" transform=\"").concat(transform, " scale(1,-1)\"/>") + "<rect id=\"hitarea\" fill=\"transparent\" stroke=\"transparent\" x=\"".concat(x, "\" y=\"").concat(y, "\" width=\"").concat(_w2, "\" height=\"").concat(_h3, "\" transform=\"").concat(transform, "\"/>");
|
|
2781
2794
|
}
|
|
2782
2795
|
if (imgData === '__pending__') {
|
|
2783
2796
|
// Render a placeholder rectangle while image chunks are still arriving
|
|
@@ -34106,33 +34119,81 @@ function updateShapeAttributes(svgElement, element) {
|
|
|
34106
34119
|
}
|
|
34107
34120
|
// ========== Shape Creation Functions ==========
|
|
34108
34121
|
/**
|
|
34109
|
-
* Create arrow SVG element
|
|
34122
|
+
* Create arrow SVG element matching Forge Viewer's native arrow format.
|
|
34123
|
+
*
|
|
34124
|
+
* Forge Viewer renders arrows as a single filled <path> (shaft + arrowhead merged)
|
|
34125
|
+
* centered at the midpoint of the two endpoints and rotated to the correct angle.
|
|
34126
|
+
* This matches the native SVG:
|
|
34127
|
+
* <path d="M -hl -hh l (2hl-al) 0 l -ni -(ahh-hh) l (al+ni) ahh l -(al+ni) ahh l ni -(ahh-hh) l -(2hl-al) 0 z"
|
|
34128
|
+
* transform="translate(cx, cy) rotate(angleDeg)" stroke-width="sw" fill="strokeColor" stroke="strokeColor"/>
|
|
34129
|
+
*
|
|
34130
|
+
* Geometry constants (in Forge coordinate units):
|
|
34131
|
+
* sw = stroke-width
|
|
34132
|
+
* hl = totalLength / 2 (half the arrow length, placed symmetrically)
|
|
34133
|
+
* hh = sw / 2 (shaft half-height)
|
|
34134
|
+
* ahh = 1.5 * sw (arrowhead half-height)
|
|
34135
|
+
* al = 3 * sw (arrowhead length along x-axis)
|
|
34136
|
+
* ni = 0.3 * sw (neck inset — small notch where shaft meets arrowhead)
|
|
34137
|
+
*
|
|
34110
34138
|
* @private
|
|
34111
34139
|
*/
|
|
34112
34140
|
function createArrowElement(element, ns) {
|
|
34113
34141
|
var _a;
|
|
34114
34142
|
var group = document.createElementNS(ns, 'g');
|
|
34115
34143
|
group.setAttribute('class', 'markup-arrow');
|
|
34116
|
-
|
|
34117
|
-
|
|
34144
|
+
group.setAttribute('cursor', 'inherit');
|
|
34145
|
+
group.setAttribute('pointer-events', 'painted');
|
|
34146
|
+
// Endpoint coordinates
|
|
34147
|
+
var x1 = 0,
|
|
34148
|
+
y1 = 0,
|
|
34149
|
+
x2 = 1,
|
|
34150
|
+
y2 = 0;
|
|
34118
34151
|
if (((_a = element.shape) === null || _a === void 0 ? void 0 : _a.points) && element.shape.points.length >= 4) {
|
|
34119
|
-
|
|
34120
|
-
|
|
34121
|
-
|
|
34122
|
-
|
|
34123
|
-
} else {
|
|
34124
|
-
|
|
34125
|
-
|
|
34126
|
-
|
|
34127
|
-
|
|
34128
|
-
|
|
34129
|
-
|
|
34130
|
-
|
|
34131
|
-
|
|
34132
|
-
|
|
34133
|
-
|
|
34134
|
-
|
|
34135
|
-
|
|
34152
|
+
x1 = element.shape.points[0];
|
|
34153
|
+
y1 = element.shape.points[1];
|
|
34154
|
+
x2 = element.shape.points[2];
|
|
34155
|
+
y2 = element.shape.points[3];
|
|
34156
|
+
} else if (element.size) {
|
|
34157
|
+
x2 = element.size[0];
|
|
34158
|
+
y2 = element.size[1];
|
|
34159
|
+
}
|
|
34160
|
+
var sw = element.style.sw || 0.025;
|
|
34161
|
+
var cx = (x1 + x2) / 2;
|
|
34162
|
+
var cy = (y1 + y2) / 2;
|
|
34163
|
+
var dx = x2 - x1;
|
|
34164
|
+
var dy = y2 - y1;
|
|
34165
|
+
var totalLength = Math.sqrt(dx * dx + dy * dy);
|
|
34166
|
+
var angleDeg = Math.atan2(dy, dx) * (180 / Math.PI);
|
|
34167
|
+
var hl = totalLength / 2;
|
|
34168
|
+
var hh = sw / 2;
|
|
34169
|
+
var ahh = 1.5 * sw;
|
|
34170
|
+
var al = 3 * sw;
|
|
34171
|
+
var ni = 0.3 * sw;
|
|
34172
|
+
// Shaft length must be positive; guard against arrows shorter than the arrowhead
|
|
34173
|
+
var shaftLen = Math.max(0, 2 * hl - al);
|
|
34174
|
+
// Arrow path: horizontal, pointing right (+x), centered at origin.
|
|
34175
|
+
// Apply transform="translate(cx,cy) rotate(angleDeg)" to position and orient.
|
|
34176
|
+
var d = ["M ".concat(-hl, " ").concat(-hh), "l ".concat(shaftLen, " 0"), "l ".concat(-ni, " ").concat(-(ahh - hh)), "l ".concat(al + ni, " ").concat(ahh), "l ".concat(-(al + ni), " ").concat(ahh), "l ".concat(ni, " ").concat(-(ahh - hh)), "l ".concat(-shaftLen, " 0"), 'z'].join(' ');
|
|
34177
|
+
var transform = "translate(".concat(cx, ", ").concat(cy, ") rotate(").concat(angleDeg, ")");
|
|
34178
|
+
var strokeColor = element.style.sc || 'rgba(0,0,0,1)';
|
|
34179
|
+
// Main arrow path (filled + stroked like native Forge Viewer arrow)
|
|
34180
|
+
var markupPath = document.createElementNS(ns, 'path');
|
|
34181
|
+
markupPath.setAttribute('id', 'markup');
|
|
34182
|
+
markupPath.setAttribute('d', d);
|
|
34183
|
+
markupPath.setAttribute('stroke-width', String(sw));
|
|
34184
|
+
markupPath.setAttribute('stroke', strokeColor);
|
|
34185
|
+
markupPath.setAttribute('fill', strokeColor);
|
|
34186
|
+
markupPath.setAttribute('transform', transform);
|
|
34187
|
+
group.appendChild(markupPath);
|
|
34188
|
+
// Transparent hit area with larger stroke-width for easier selection
|
|
34189
|
+
var hitPath = document.createElementNS(ns, 'path');
|
|
34190
|
+
hitPath.setAttribute('id', 'hitarea');
|
|
34191
|
+
hitPath.setAttribute('d', d);
|
|
34192
|
+
hitPath.setAttribute('fill', 'transparent');
|
|
34193
|
+
hitPath.setAttribute('stroke', 'transparent');
|
|
34194
|
+
hitPath.setAttribute('stroke-width', String(sw * 6.86));
|
|
34195
|
+
hitPath.setAttribute('transform', transform);
|
|
34196
|
+
group.appendChild(hitPath);
|
|
34136
34197
|
return group;
|
|
34137
34198
|
}
|
|
34138
34199
|
/**
|
|
@@ -34307,23 +34368,37 @@ function createCalloutElement(element, ns) {
|
|
|
34307
34368
|
return group;
|
|
34308
34369
|
}
|
|
34309
34370
|
/**
|
|
34310
|
-
* Create stamp/image SVG element
|
|
34311
|
-
*
|
|
34371
|
+
* Create stamp/image SVG element for collaborative rendering (User B).
|
|
34372
|
+
*
|
|
34373
|
+
* imageData is raw base64 (data URL) — no counter-transform needed here.
|
|
34374
|
+
* Forge's markup canvas is Y-up, so a plain <image> would appear upside-down.
|
|
34375
|
+
* We wrap it in a <g> and apply scale(1,-1) on the image to flip it into
|
|
34376
|
+
* correct screen orientation, matching what MarkupStamp renders locally.
|
|
34377
|
+
*
|
|
34378
|
+
* Position is CENTER, so offset the image by -w/2, -h/2.
|
|
34312
34379
|
* @private
|
|
34313
34380
|
*/
|
|
34314
34381
|
function createStampElement(element, ns) {
|
|
34315
34382
|
var _a;
|
|
34383
|
+
var group = document.createElementNS(ns, 'g');
|
|
34384
|
+
group.setAttribute('class', 'markup-stamp');
|
|
34385
|
+
var w = element.size[0];
|
|
34386
|
+
var h = element.size[1];
|
|
34316
34387
|
var image = document.createElementNS(ns, 'image');
|
|
34317
|
-
image.setAttribute('
|
|
34318
|
-
|
|
34319
|
-
image.setAttribute('
|
|
34320
|
-
image.setAttribute('
|
|
34321
|
-
image
|
|
34322
|
-
|
|
34388
|
+
image.setAttribute('x', String(-w / 2));
|
|
34389
|
+
image.setAttribute('y', String(-h / 2));
|
|
34390
|
+
image.setAttribute('width', String(w));
|
|
34391
|
+
image.setAttribute('height', String(h));
|
|
34392
|
+
// scale(1,-1) flips the image content vertically in-place (the image is centered at
|
|
34393
|
+
// the origin so scale(1,-1) keeps the bounding box in the same position while reversing
|
|
34394
|
+
// the pixel rows). This is needed because SVG <image> pixels are Y-down but Forge's
|
|
34395
|
+
// markup canvas is Y-up — without the flip the image appears upside-down.
|
|
34396
|
+
image.setAttribute('transform', "scale(1,-1)");
|
|
34323
34397
|
if ((_a = element.shape) === null || _a === void 0 ? void 0 : _a.imageData) {
|
|
34324
34398
|
image.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', element.shape.imageData);
|
|
34325
34399
|
}
|
|
34326
|
-
|
|
34400
|
+
group.appendChild(image);
|
|
34401
|
+
return group;
|
|
34327
34402
|
}
|
|
34328
34403
|
// ========== Helper Functions ==========
|
|
34329
34404
|
/**
|
|
@@ -34410,36 +34485,6 @@ function generateCloudPath(width, height, arcCount) {
|
|
|
34410
34485
|
d += ' Z';
|
|
34411
34486
|
return d;
|
|
34412
34487
|
}
|
|
34413
|
-
/**
|
|
34414
|
-
* Ensure arrowhead marker exists in SVG defs
|
|
34415
|
-
* @private
|
|
34416
|
-
*/
|
|
34417
|
-
var arrowMarkerCreated = false;
|
|
34418
|
-
function ensureArrowMarker(ns) {
|
|
34419
|
-
if (arrowMarkerCreated) return;
|
|
34420
|
-
var svg = document.querySelector('svg.markups-svg');
|
|
34421
|
-
if (!svg) return;
|
|
34422
|
-
var defs = svg.querySelector('defs');
|
|
34423
|
-
if (!defs) {
|
|
34424
|
-
defs = document.createElementNS(ns, 'defs');
|
|
34425
|
-
svg.insertBefore(defs, svg.firstChild);
|
|
34426
|
-
}
|
|
34427
|
-
if (!defs.querySelector('#arrowhead')) {
|
|
34428
|
-
var marker = document.createElementNS(ns, 'marker');
|
|
34429
|
-
marker.setAttribute('id', 'arrowhead');
|
|
34430
|
-
marker.setAttribute('markerWidth', '10');
|
|
34431
|
-
marker.setAttribute('markerHeight', '7');
|
|
34432
|
-
marker.setAttribute('refX', '9');
|
|
34433
|
-
marker.setAttribute('refY', '3.5');
|
|
34434
|
-
marker.setAttribute('orient', 'auto');
|
|
34435
|
-
var polygon = document.createElementNS(ns, 'polygon');
|
|
34436
|
-
polygon.setAttribute('points', '0 0, 10 3.5, 0 7');
|
|
34437
|
-
polygon.setAttribute('fill', 'inherit');
|
|
34438
|
-
marker.appendChild(polygon);
|
|
34439
|
-
defs.appendChild(marker);
|
|
34440
|
-
arrowMarkerCreated = true;
|
|
34441
|
-
}
|
|
34442
|
-
}
|
|
34443
34488
|
|
|
34444
34489
|
/**
|
|
34445
34490
|
* SVG Parser Utilities
|
|
@@ -36837,6 +36882,12 @@ var EditModeManager = /*#__PURE__*/function () {
|
|
|
36837
36882
|
this.onEditModeChange = null;
|
|
36838
36883
|
this.onClearCurrentTool = null;
|
|
36839
36884
|
this.onExtensionReloaded = null;
|
|
36885
|
+
// Tracks explicit user intent to be in edit mode.
|
|
36886
|
+
// Immune to markupsCore.editMode being temporarily null during changeEditMode() transitions.
|
|
36887
|
+
this.userIntendedEditMode = false;
|
|
36888
|
+
// Set to true by refreshExtensionReferences() when MarkupsCore was fully reloaded.
|
|
36889
|
+
// Consumed in enterEditMode() to restore savedMarkupsSvg into the fresh edit canvas.
|
|
36890
|
+
this.extensionWasReloaded = false;
|
|
36840
36891
|
// Track if page changed since last markup mode
|
|
36841
36892
|
// Used to force extension reload when entering markup mode after page change
|
|
36842
36893
|
this.pageChangedSinceLastMarkup = false;
|
|
@@ -36936,7 +36987,14 @@ var EditModeManager = /*#__PURE__*/function () {
|
|
|
36936
36987
|
value: function handleEditModeChanged(event) {
|
|
36937
36988
|
var _a;
|
|
36938
36989
|
var wasInEditMode = this.editMode;
|
|
36939
|
-
//
|
|
36990
|
+
// CRITICAL FIX: When switching tools, markupsCore.changeEditMode() fires
|
|
36991
|
+
// EVENT_EDITMODE_CHANGED with active:false while markupsCore.editMode is temporarily null.
|
|
36992
|
+
// Using userIntendedEditMode (set explicitly by enterEditMode/leaveEditMode) instead of
|
|
36993
|
+
// markupsCore.editMode avoids the race condition where the guard fails during transitions.
|
|
36994
|
+
if (event.active === false && this.userIntendedEditMode) {
|
|
36995
|
+
console.log('[EditModeManager] Ignoring editMode=false: user intentionally in edit mode (tool-switch transition)');
|
|
36996
|
+
return;
|
|
36997
|
+
}
|
|
36940
36998
|
var isActive = event.active === true || event.active !== false && !!((_a = this.context.markupsCore) === null || _a === void 0 ? void 0 : _a.editMode);
|
|
36941
36999
|
this.editMode = isActive;
|
|
36942
37000
|
console.log('[EditModeManager] handleEditModeChanged:', {
|
|
@@ -36965,10 +37023,16 @@ var EditModeManager = /*#__PURE__*/function () {
|
|
|
36965
37023
|
key: "enterEditMode",
|
|
36966
37024
|
value: function enterEditMode() {
|
|
36967
37025
|
return __awaiter(this, void 0, void 0, /*#__PURE__*/_regenerator().m(function _callee2() {
|
|
36968
|
-
var _t;
|
|
37026
|
+
var savedSvg, layerId, editLayerId, _yield$import$catch, patchForgeMarkupStampRestore, loaded, _t, _t2;
|
|
36969
37027
|
return _regenerator().w(function (_context2) {
|
|
36970
37028
|
while (1) switch (_context2.p = _context2.n) {
|
|
36971
37029
|
case 0:
|
|
37030
|
+
// Mark explicit intent BEFORE any async work so the guard in handleEditModeChanged
|
|
37031
|
+
// can filter out spurious active:false events fired during enterEditMode() itself.
|
|
37032
|
+
this.userIntendedEditMode = true;
|
|
37033
|
+
// CRITICAL: Re-fetch MarkupsCore extension reference before entering edit mode
|
|
37034
|
+
// After page change, the extension might have been reset and we need fresh reference
|
|
37035
|
+
// This is async because extension may need to be reloaded via loadExtension()
|
|
36972
37036
|
_context2.n = 1;
|
|
36973
37037
|
return this.refreshExtensionReferences();
|
|
36974
37038
|
case 1:
|
|
@@ -36983,15 +37047,65 @@ var EditModeManager = /*#__PURE__*/function () {
|
|
|
36983
37047
|
_context2.p = 3;
|
|
36984
37048
|
// Unload existing markups from view-only layer before entering edit mode
|
|
36985
37049
|
this.markupOpsManager.unloadMarkupsBeforeEditMode();
|
|
36986
|
-
//
|
|
37050
|
+
// CRITICAL: Pre-load saved markups into a named layer BEFORE calling
|
|
37051
|
+
// enterEditMode(). Forge's loadMarkups() explicitly rejects calls while
|
|
37052
|
+
// duringEditMode===true, so loading must happen in view mode. By passing
|
|
37053
|
+
// the same layerId to enterEditMode(layerId) the pre-loaded markups become
|
|
37054
|
+
// interactive in the edit canvas.
|
|
37055
|
+
//
|
|
37056
|
+
// Additionally, apply the Forge MarkupStamp patch so that when Forge's
|
|
37057
|
+
// createMarkupFromSVG creates a MarkupStamp from the loaded SVG it can
|
|
37058
|
+
// fall back to style['text-data'] (which we populate in setMetadata()) when
|
|
37059
|
+
// scriptSvgData is a DOM element that DOMParser cannot parse.
|
|
37060
|
+
savedSvg = this.markupOpsManager.getSavedMarkupsSvg();
|
|
37061
|
+
layerId = this.markupOpsManager.getLayerId();
|
|
37062
|
+
if (!(savedSvg && savedSvg.trim().length > 0)) {
|
|
37063
|
+
_context2.n = 7;
|
|
37064
|
+
break;
|
|
37065
|
+
}
|
|
37066
|
+
_context2.p = 4;
|
|
37067
|
+
_context2.n = 5;
|
|
37068
|
+
return Promise.resolve().then(function () { return StampMarkup; })["catch"](function () {
|
|
37069
|
+
return {
|
|
37070
|
+
patchForgeMarkupStampRestore: null
|
|
37071
|
+
};
|
|
37072
|
+
});
|
|
37073
|
+
case 5:
|
|
37074
|
+
_yield$import$catch = _context2.v;
|
|
37075
|
+
patchForgeMarkupStampRestore = _yield$import$catch.patchForgeMarkupStampRestore;
|
|
37076
|
+
patchForgeMarkupStampRestore === null || patchForgeMarkupStampRestore === void 0 ? void 0 : patchForgeMarkupStampRestore();
|
|
37077
|
+
// Ensure view mode is active (loadMarkups requires duringViewMode===true)
|
|
37078
|
+
if (!this.context.markupsCore.duringViewMode) {
|
|
37079
|
+
try {
|
|
37080
|
+
this.context.markupsCore.show();
|
|
37081
|
+
} catch (_e) {
|
|
37082
|
+
/* ignore — enterEditMode() will call show() internally */
|
|
37083
|
+
}
|
|
37084
|
+
}
|
|
37085
|
+
loaded = this.context.markupsCore.loadMarkups(savedSvg, layerId);
|
|
37086
|
+
if (loaded) {
|
|
37087
|
+
editLayerId = layerId;
|
|
37088
|
+
console.log('[EditModeManager] Pre-loaded saved markups into layer:', layerId);
|
|
37089
|
+
} else {
|
|
37090
|
+
console.warn('[EditModeManager] loadMarkups returned false — will enter clean edit mode');
|
|
37091
|
+
}
|
|
37092
|
+
_context2.n = 7;
|
|
37093
|
+
break;
|
|
37094
|
+
case 6:
|
|
37095
|
+
_context2.p = 6;
|
|
37096
|
+
_t = _context2.v;
|
|
37097
|
+
console.warn('[EditModeManager] Could not pre-load markups before edit mode:', _t);
|
|
37098
|
+
case 7:
|
|
37099
|
+
// Enter edit mode — with layerId when we pre-loaded (restores markups),
|
|
37100
|
+
// or without to start a clean empty canvas.
|
|
36987
37101
|
console.log('[EditModeManager] Calling markupsCore.enterEditMode()...');
|
|
36988
|
-
_context2.n =
|
|
36989
|
-
return this.context.markupsCore.enterEditMode();
|
|
36990
|
-
case
|
|
37102
|
+
_context2.n = 8;
|
|
37103
|
+
return this.context.markupsCore.enterEditMode(editLayerId);
|
|
37104
|
+
case 8:
|
|
36991
37105
|
console.log('[EditModeManager] markupsCore.enterEditMode() completed, svg:', !!this.context.markupsCore.svg);
|
|
36992
37106
|
// Verify that svg layer was created (can fail after page change)
|
|
36993
37107
|
if (this.context.markupsCore.svg) {
|
|
36994
|
-
_context2.n =
|
|
37108
|
+
_context2.n = 11;
|
|
36995
37109
|
break;
|
|
36996
37110
|
}
|
|
36997
37111
|
console.warn('[EditModeManager] svg layer is null after enterEditMode, retrying with delay...');
|
|
@@ -37002,29 +37116,32 @@ var EditModeManager = /*#__PURE__*/function () {
|
|
|
37002
37116
|
console.warn('[EditModeManager] Error leaving edit mode for retry:', e);
|
|
37003
37117
|
}
|
|
37004
37118
|
// Wait a bit for viewer to stabilize after page change
|
|
37005
|
-
_context2.n =
|
|
37119
|
+
_context2.n = 9;
|
|
37006
37120
|
return new Promise(function (resolve) {
|
|
37007
37121
|
return setTimeout(resolve, 100);
|
|
37008
37122
|
});
|
|
37009
|
-
case
|
|
37010
|
-
// Re-enter edit mode
|
|
37123
|
+
case 9:
|
|
37124
|
+
// Re-enter edit mode (use layerId again if we pre-loaded — the layer
|
|
37125
|
+
// survives leaveEditMode() since it only removes the edit canvas node)
|
|
37011
37126
|
console.log('[EditModeManager] Retrying enterEditMode after delay...');
|
|
37012
|
-
_context2.n =
|
|
37013
|
-
return this.context.markupsCore.enterEditMode();
|
|
37014
|
-
case
|
|
37127
|
+
_context2.n = 10;
|
|
37128
|
+
return this.context.markupsCore.enterEditMode(editLayerId);
|
|
37129
|
+
case 10:
|
|
37015
37130
|
console.log('[EditModeManager] Retry completed, svg:', !!this.context.markupsCore.svg);
|
|
37016
37131
|
if (this.context.markupsCore.svg) {
|
|
37017
|
-
_context2.n =
|
|
37132
|
+
_context2.n = 11;
|
|
37018
37133
|
break;
|
|
37019
37134
|
}
|
|
37020
37135
|
console.error('[EditModeManager] Failed to create svg layer after retry');
|
|
37021
37136
|
this.editMode = false;
|
|
37137
|
+
this.userIntendedEditMode = false;
|
|
37022
37138
|
return _context2.a(2);
|
|
37023
|
-
case
|
|
37139
|
+
case 11:
|
|
37024
37140
|
// Set editMode flag explicitly to true
|
|
37025
37141
|
this.editMode = true;
|
|
37026
37142
|
console.log('[EditModeManager] editMode flag set to true explicitly');
|
|
37027
37143
|
console.log('[EditModeManager] svg layer exists:', !!this.context.markupsCore.svg);
|
|
37144
|
+
this.extensionWasReloaded = false;
|
|
37028
37145
|
// Notify presence manager of edit mode state
|
|
37029
37146
|
if (this.onEditModeChange) {
|
|
37030
37147
|
this.onEditModeChange(true);
|
|
@@ -37033,17 +37150,18 @@ var EditModeManager = /*#__PURE__*/function () {
|
|
|
37033
37150
|
this.toolbarVisManager.hideDefaultToolbar();
|
|
37034
37151
|
this.eventBus.emit('drawing:editModeEntered');
|
|
37035
37152
|
console.log('[EditModeManager] Entered edit mode');
|
|
37036
|
-
_context2.n =
|
|
37153
|
+
_context2.n = 13;
|
|
37037
37154
|
break;
|
|
37038
|
-
case
|
|
37039
|
-
_context2.p =
|
|
37040
|
-
|
|
37041
|
-
console.error('[EditModeManager] Failed to enter edit mode:',
|
|
37155
|
+
case 12:
|
|
37156
|
+
_context2.p = 12;
|
|
37157
|
+
_t2 = _context2.v;
|
|
37158
|
+
console.error('[EditModeManager] Failed to enter edit mode:', _t2);
|
|
37042
37159
|
this.editMode = false;
|
|
37043
|
-
|
|
37160
|
+
this.userIntendedEditMode = false;
|
|
37161
|
+
case 13:
|
|
37044
37162
|
return _context2.a(2);
|
|
37045
37163
|
}
|
|
37046
|
-
}, _callee2, this, [[3,
|
|
37164
|
+
}, _callee2, this, [[4, 6], [3, 12]]);
|
|
37047
37165
|
}));
|
|
37048
37166
|
}
|
|
37049
37167
|
/**
|
|
@@ -37058,7 +37176,7 @@ var EditModeManager = /*#__PURE__*/function () {
|
|
|
37058
37176
|
key: "refreshExtensionReferences",
|
|
37059
37177
|
value: function refreshExtensionReferences() {
|
|
37060
37178
|
return __awaiter(this, void 0, void 0, /*#__PURE__*/_regenerator().m(function _callee3() {
|
|
37061
|
-
var viewer, extensionWasReloaded, markupsCore, markupsGui,
|
|
37179
|
+
var viewer, extensionWasReloaded, markupsCore, markupsGui, _t3, _t4, _t5, _t6, _t7;
|
|
37062
37180
|
return _regenerator().w(function (_context3) {
|
|
37063
37181
|
while (1) switch (_context3.p = _context3.n) {
|
|
37064
37182
|
case 0:
|
|
@@ -37089,8 +37207,8 @@ var EditModeManager = /*#__PURE__*/function () {
|
|
|
37089
37207
|
break;
|
|
37090
37208
|
case 4:
|
|
37091
37209
|
_context3.p = 4;
|
|
37092
|
-
|
|
37093
|
-
console.warn('[EditModeManager] Failed to unload stale MarkupsCore:',
|
|
37210
|
+
_t3 = _context3.v;
|
|
37211
|
+
console.warn('[EditModeManager] Failed to unload stale MarkupsCore:', _t3);
|
|
37094
37212
|
case 5:
|
|
37095
37213
|
if (markupsCore) {
|
|
37096
37214
|
_context3.n = 9;
|
|
@@ -37109,8 +37227,8 @@ var EditModeManager = /*#__PURE__*/function () {
|
|
|
37109
37227
|
break;
|
|
37110
37228
|
case 8:
|
|
37111
37229
|
_context3.p = 8;
|
|
37112
|
-
|
|
37113
|
-
console.error('[EditModeManager] Failed to reload MarkupsCore extension:',
|
|
37230
|
+
_t4 = _context3.v;
|
|
37231
|
+
console.error('[EditModeManager] Failed to reload MarkupsCore extension:', _t4);
|
|
37114
37232
|
case 9:
|
|
37115
37233
|
if (markupsCore) {
|
|
37116
37234
|
this.context.markupsCore = markupsCore;
|
|
@@ -37133,8 +37251,8 @@ var EditModeManager = /*#__PURE__*/function () {
|
|
|
37133
37251
|
break;
|
|
37134
37252
|
case 12:
|
|
37135
37253
|
_context3.p = 12;
|
|
37136
|
-
|
|
37137
|
-
console.warn('[EditModeManager] Failed to unload stale MarkupsGui:',
|
|
37254
|
+
_t5 = _context3.v;
|
|
37255
|
+
console.warn('[EditModeManager] Failed to unload stale MarkupsGui:', _t5);
|
|
37138
37256
|
case 13:
|
|
37139
37257
|
if (markupsGui) {
|
|
37140
37258
|
_context3.n = 17;
|
|
@@ -37152,8 +37270,8 @@ var EditModeManager = /*#__PURE__*/function () {
|
|
|
37152
37270
|
break;
|
|
37153
37271
|
case 16:
|
|
37154
37272
|
_context3.p = 16;
|
|
37155
|
-
|
|
37156
|
-
console.error('[EditModeManager] Failed to reload MarkupsGui extension:',
|
|
37273
|
+
_t6 = _context3.v;
|
|
37274
|
+
console.error('[EditModeManager] Failed to reload MarkupsGui extension:', _t6);
|
|
37157
37275
|
case 17:
|
|
37158
37276
|
if (markupsGui) {
|
|
37159
37277
|
this.context.markupsGui = markupsGui;
|
|
@@ -37177,16 +37295,20 @@ var EditModeManager = /*#__PURE__*/function () {
|
|
|
37177
37295
|
case 18:
|
|
37178
37296
|
// Notify listeners that extension was reloaded
|
|
37179
37297
|
// This allows ToolManager to reinitialize its ToolFactory with the new MarkupsCore
|
|
37180
|
-
if (extensionWasReloaded
|
|
37181
|
-
|
|
37182
|
-
this.
|
|
37298
|
+
if (extensionWasReloaded) {
|
|
37299
|
+
// Persist flag so enterEditMode() can reload savedMarkupsSvg into the fresh canvas
|
|
37300
|
+
this.extensionWasReloaded = true;
|
|
37301
|
+
if (this.onExtensionReloaded) {
|
|
37302
|
+
console.log('[EditModeManager] Notifying listeners of extension reload');
|
|
37303
|
+
this.onExtensionReloaded();
|
|
37304
|
+
}
|
|
37183
37305
|
}
|
|
37184
37306
|
_context3.n = 20;
|
|
37185
37307
|
break;
|
|
37186
37308
|
case 19:
|
|
37187
37309
|
_context3.p = 19;
|
|
37188
|
-
|
|
37189
|
-
console.error('[EditModeManager] Failed to refresh extension references:',
|
|
37310
|
+
_t7 = _context3.v;
|
|
37311
|
+
console.error('[EditModeManager] Failed to refresh extension references:', _t7);
|
|
37190
37312
|
case 20:
|
|
37191
37313
|
return _context3.a(2);
|
|
37192
37314
|
}
|
|
@@ -37200,19 +37322,24 @@ var EditModeManager = /*#__PURE__*/function () {
|
|
|
37200
37322
|
key: "leaveEditMode",
|
|
37201
37323
|
value: function leaveEditMode() {
|
|
37202
37324
|
var _this3 = this;
|
|
37325
|
+
this.userIntendedEditMode = false;
|
|
37203
37326
|
if (!this.context.markupsCore) {
|
|
37204
37327
|
console.warn('[EditModeManager] Cannot leave edit mode: MarkupsCore not available');
|
|
37205
37328
|
return;
|
|
37206
37329
|
}
|
|
37207
37330
|
try {
|
|
37208
|
-
// Save markups
|
|
37209
|
-
this.markupOpsManager.
|
|
37331
|
+
// Step 1: Save current edit-mode markups while still in edit mode
|
|
37332
|
+
this.markupOpsManager.saveMarkupsOnLeave(function () {
|
|
37210
37333
|
var _a;
|
|
37211
37334
|
return ((_a = _this3.context.markupsCore) === null || _a === void 0 ? void 0 : _a.generateData()) || '';
|
|
37212
37335
|
});
|
|
37213
|
-
// Leave edit mode (
|
|
37336
|
+
// Step 2: Leave edit mode (Forge clears its edit canvas)
|
|
37214
37337
|
this.context.markupsCore.leaveEditMode();
|
|
37215
37338
|
this.editMode = false;
|
|
37339
|
+
// Step 3: Load saved markups into view-only layer AFTER leaving edit mode.
|
|
37340
|
+
// CRITICAL: doing this BEFORE leaveEditMode() caused Forge to clear the
|
|
37341
|
+
// loaded layer during the leaveEditMode() call, making markups disappear.
|
|
37342
|
+
this.markupOpsManager.reloadMarkupsToViewLayer();
|
|
37216
37343
|
// Notify presence manager of edit mode state
|
|
37217
37344
|
if (this.onEditModeChange) {
|
|
37218
37345
|
this.onEditModeChange(false);
|
|
@@ -37445,6 +37572,22 @@ var MarkupOperationsManager = /*#__PURE__*/function () {
|
|
|
37445
37572
|
console.error('[MarkupOperationsManager] Failed to redo:', error);
|
|
37446
37573
|
}
|
|
37447
37574
|
}
|
|
37575
|
+
/**
|
|
37576
|
+
* Load savedMarkupsSvg into the view-only layer so markups are visible
|
|
37577
|
+
* when NOT in edit mode. Must be called AFTER markupsCore.leaveEditMode().
|
|
37578
|
+
*/
|
|
37579
|
+
}, {
|
|
37580
|
+
key: "reloadMarkupsToViewLayer",
|
|
37581
|
+
value: function reloadMarkupsToViewLayer() {
|
|
37582
|
+
if (!this.context.markupsCore) return;
|
|
37583
|
+
if (!this.savedMarkupsSvg || this.savedMarkupsSvg.trim().length === 0) return;
|
|
37584
|
+
try {
|
|
37585
|
+
this.context.markupsCore.loadMarkups(this.savedMarkupsSvg, this.layerId);
|
|
37586
|
+
console.log('[MarkupOperationsManager] Markups reloaded to view layer after leaveEditMode');
|
|
37587
|
+
} catch (error) {
|
|
37588
|
+
console.warn('[MarkupOperationsManager] Failed to reload markups to view layer:', error);
|
|
37589
|
+
}
|
|
37590
|
+
}
|
|
37448
37591
|
/**
|
|
37449
37592
|
* Unload markups from layer before entering edit mode
|
|
37450
37593
|
*/
|
|
@@ -37462,29 +37605,24 @@ var MarkupOperationsManager = /*#__PURE__*/function () {
|
|
|
37462
37605
|
}
|
|
37463
37606
|
}
|
|
37464
37607
|
/**
|
|
37465
|
-
* Save
|
|
37608
|
+
* Save markup SVG from edit mode into savedMarkupsSvg.
|
|
37609
|
+
* Does NOT call loadMarkups — that must happen AFTER markupsCore.leaveEditMode().
|
|
37610
|
+
* See reloadMarkupsToViewLayer().
|
|
37466
37611
|
*
|
|
37467
|
-
* @param generateData - Function
|
|
37612
|
+
* @param generateData - Function that returns SVG from current edit mode state
|
|
37468
37613
|
*/
|
|
37469
37614
|
}, {
|
|
37470
|
-
key: "
|
|
37471
|
-
value: function
|
|
37615
|
+
key: "saveMarkupsOnLeave",
|
|
37616
|
+
value: function saveMarkupsOnLeave(generateData) {
|
|
37472
37617
|
if (!this.context.markupsCore) return;
|
|
37473
|
-
// Check if markupsCore is in a valid state (svg layer exists)
|
|
37474
|
-
// This can be null if page changed or extension was reset
|
|
37475
37618
|
if (!this.context.markupsCore.svg) {
|
|
37476
37619
|
console.warn('[MarkupOperationsManager] MarkupsCore.svg is null, skipping save');
|
|
37477
37620
|
return;
|
|
37478
37621
|
}
|
|
37479
37622
|
try {
|
|
37480
|
-
// Save markups before leaving edit mode
|
|
37481
37623
|
var svgString = generateData();
|
|
37482
37624
|
this.savedMarkupsSvg = svgString || '';
|
|
37483
|
-
|
|
37484
|
-
if (this.savedMarkupsSvg && this.savedMarkupsSvg.trim().length > 0) {
|
|
37485
|
-
this.context.markupsCore.loadMarkups(this.savedMarkupsSvg, this.layerId);
|
|
37486
|
-
console.log('[MarkupOperationsManager] Markups saved and reloaded to preserve them');
|
|
37487
|
-
}
|
|
37625
|
+
console.log('[MarkupOperationsManager] Markups saved on leave:', this.savedMarkupsSvg.length, 'chars');
|
|
37488
37626
|
} catch (error) {
|
|
37489
37627
|
console.warn('[MarkupOperationsManager] Error saving markups on leave:', error);
|
|
37490
37628
|
}
|
|
@@ -45561,6 +45699,8 @@ function createMarkupStampClass() {
|
|
|
45561
45699
|
_classCallCheck(this, MarkupStamp);
|
|
45562
45700
|
_this = _callSuper(this, MarkupStamp, [id, editor, ['stroke-width', 'stroke-color', 'stroke-opacity', 'fill-color', 'fill-opacity']]);
|
|
45563
45701
|
_this.type = 'stamp';
|
|
45702
|
+
/** Raw base64 image data (data URL) for collaborative serialization */
|
|
45703
|
+
_this.imageData = '';
|
|
45564
45704
|
_this.type = 'stamp';
|
|
45565
45705
|
_this.customSVG = customSVG;
|
|
45566
45706
|
_this.addMarkupMetadata = avemcu.addMarkupMetadata.bind(_this);
|
|
@@ -45571,8 +45711,12 @@ function createMarkupStampClass() {
|
|
|
45571
45711
|
_this$getDimensions2 = _slicedToArray(_this$getDimensions, 2),
|
|
45572
45712
|
width = _this$getDimensions2[0],
|
|
45573
45713
|
height = _this$getDimensions2[1];
|
|
45574
|
-
|
|
45575
|
-
|
|
45714
|
+
// Extract raw base64 image data for collaborative serialization.
|
|
45715
|
+
// MarkupsCore serializers read markup.imageData to pass via compact JSON
|
|
45716
|
+
// to remote users (User B). Storing raw base64 (not the SVG wrapper)
|
|
45717
|
+
// means createStampElement can render it directly without any transform issues.
|
|
45718
|
+
var imgEl = customSVG.querySelector('image');
|
|
45719
|
+
_this.imageData = (imgEl === null || imgEl === void 0 ? void 0 : imgEl.getAttribute('href')) || (imgEl === null || imgEl === void 0 ? void 0 : imgEl.getAttributeNS('http://www.w3.org/1999/xlink', 'href')) || '';
|
|
45576
45720
|
// Copy SVG content
|
|
45577
45721
|
_this.group.innerHTML = customSVG.innerHTML;
|
|
45578
45722
|
// Create hit area for selection
|
|
@@ -45663,6 +45807,16 @@ function createMarkupStampClass() {
|
|
|
45663
45807
|
metadata.position = [this.position.x, this.position.y].join(' ');
|
|
45664
45808
|
metadata.size = [this.size.x, this.size.y].join(' ');
|
|
45665
45809
|
metadata.rotation = String(this.rotation);
|
|
45810
|
+
// Store image SVG as text-data so Forge's createMarkupFromSVG can restore
|
|
45811
|
+
// the stamp image when loadMarkups() is called (e.g. on re-entry to edit mode).
|
|
45812
|
+
// Forge's MarkupStamp.loadSvgData() reads style['text-data'] as fallback.
|
|
45813
|
+
if (this.imageData) {
|
|
45814
|
+
var _this$getDimensions3 = this.getDimensions(this.customSVG),
|
|
45815
|
+
_this$getDimensions4 = _slicedToArray(_this$getDimensions3, 2),
|
|
45816
|
+
w = _this$getDimensions4[0],
|
|
45817
|
+
h = _this$getDimensions4[1];
|
|
45818
|
+
metadata['text-data'] = "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 ".concat(w, " ").concat(h, "\" width=\"").concat(w, "\" height=\"").concat(h, "\"><image width=\"").concat(w, "\" height=\"").concat(h, "\" href=\"").concat(this.imageData, "\"/></svg>");
|
|
45819
|
+
}
|
|
45666
45820
|
return this.addMarkupMetadata(this.shape, metadata);
|
|
45667
45821
|
}
|
|
45668
45822
|
}]);
|
|
@@ -45970,11 +46124,66 @@ function parseSVGString(svgString) {
|
|
|
45970
46124
|
}
|
|
45971
46125
|
/**
|
|
45972
46126
|
* Create SVG element with embedded image (base64)
|
|
45973
|
-
* This format is compatible with MarkupsCore
|
|
46127
|
+
* This format is compatible with MarkupsCore.
|
|
46128
|
+
*
|
|
46129
|
+
* NOTE: Do NOT apply a Y-flip transform to the <image> here.
|
|
46130
|
+
* MarkupStamp.group already applies scale(1/W, -1/H) which handles the Y-axis
|
|
46131
|
+
* flip for the Forge Y-up coordinate system. Adding a pre-flip would double-flip
|
|
46132
|
+
* the image causing it to appear upside-down for User A.
|
|
46133
|
+
* The collaborative overlay (User B) applies its own scale(1,-1) separately
|
|
46134
|
+
* via generateVisualElement() in MarkupConverterService.
|
|
45974
46135
|
*/
|
|
45975
46136
|
function createImageSVG(base64Data, width, height) {
|
|
45976
46137
|
return "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"".concat(width, "\" height=\"").concat(height, "\" viewBox=\"0 0 ").concat(width, " ").concat(height, "\">\n <image width=\"").concat(width, "\" height=\"").concat(height, "\" href=\"").concat(base64Data, "\"/>\n</svg>");
|
|
45977
46138
|
}
|
|
46139
|
+
/**
|
|
46140
|
+
* Patch Forge's built-in MarkupStamp.prototype.loadSvgData so that when
|
|
46141
|
+
* createMarkupFromSVG passes the full child DOM element as svgData (which
|
|
46142
|
+
* cannot be parsed by DOMParser), the method falls back to style['text-data']
|
|
46143
|
+
* instead. Our setMetadata() stores the image SVG there so Forge can
|
|
46144
|
+
* properly restore stamp images when loadMarkups() → enterEditMode() is used.
|
|
46145
|
+
*
|
|
46146
|
+
* Safe to call multiple times — guarded by a _patched flag.
|
|
46147
|
+
*/
|
|
46148
|
+
function patchForgeMarkupStampRestore() {
|
|
46149
|
+
var _a, _b, _c;
|
|
46150
|
+
var avemc = getMarkupsCore();
|
|
46151
|
+
if (!avemc) return;
|
|
46152
|
+
// The class may be exposed directly on the Core namespace
|
|
46153
|
+
var ForgeMarkupStamp = avemc.MarkupStamp || ((_a = avemc.Classes) === null || _a === void 0 ? void 0 : _a.MarkupStamp) || ((_b = avemc.Markups) === null || _b === void 0 ? void 0 : _b.MarkupStamp);
|
|
46154
|
+
if (!ForgeMarkupStamp || typeof ((_c = ForgeMarkupStamp.prototype) === null || _c === void 0 ? void 0 : _c.loadSvgData) !== 'function') return;
|
|
46155
|
+
if (ForgeMarkupStamp.prototype.loadSvgData._patched) return;
|
|
46156
|
+
var originalLoadSvgData = ForgeMarkupStamp.prototype.loadSvgData;
|
|
46157
|
+
ForgeMarkupStamp.prototype.loadSvgData = function patchedLoadSvgData() {
|
|
46158
|
+
var _a;
|
|
46159
|
+
// When scriptSvgData is a DOM element (not a string), DOMParser cannot parse
|
|
46160
|
+
// it — fall back to style['text-data'] which contains the real image SVG.
|
|
46161
|
+
if (this.scriptSvgData && typeof this.scriptSvgData !== 'string') {
|
|
46162
|
+
var textData = (_a = this.style) === null || _a === void 0 ? void 0 : _a['text-data'];
|
|
46163
|
+
if (textData && typeof textData === 'string') {
|
|
46164
|
+
var saved = this.scriptSvgData;
|
|
46165
|
+
this.scriptSvgData = null; // force the fallback branch
|
|
46166
|
+
originalLoadSvgData.call(this);
|
|
46167
|
+
this.scriptSvgData = saved; // restore so other code (e.g. undo) still works
|
|
46168
|
+
return;
|
|
46169
|
+
}
|
|
46170
|
+
}
|
|
46171
|
+
originalLoadSvgData.call(this);
|
|
46172
|
+
};
|
|
46173
|
+
ForgeMarkupStamp.prototype.loadSvgData._patched = true;
|
|
46174
|
+
}
|
|
46175
|
+
|
|
46176
|
+
var StampMarkup = /*#__PURE__*/Object.freeze({
|
|
46177
|
+
__proto__: null,
|
|
46178
|
+
createImageSVG: createImageSVG,
|
|
46179
|
+
createMarkupStampClass: createMarkupStampClass,
|
|
46180
|
+
getEditModeStampClass: getEditModeStampClass,
|
|
46181
|
+
getStampCreateActionClass: getStampCreateActionClass,
|
|
46182
|
+
getStampDeleteActionClass: getStampDeleteActionClass,
|
|
46183
|
+
getStampUpdateActionClass: getStampUpdateActionClass,
|
|
46184
|
+
parseSVGString: parseSVGString,
|
|
46185
|
+
patchForgeMarkupStampRestore: patchForgeMarkupStampRestore
|
|
46186
|
+
});
|
|
45978
46187
|
|
|
45979
46188
|
/**
|
|
45980
46189
|
* Image tool for inserting images as markups
|
|
@@ -47341,7 +47550,6 @@ var DrawingManager = /*#__PURE__*/function () {
|
|
|
47341
47550
|
var _this = this;
|
|
47342
47551
|
var config = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
|
47343
47552
|
_classCallCheck(this, DrawingManager);
|
|
47344
|
-
this.eventBus = eventBus;
|
|
47345
47553
|
// Initialize context
|
|
47346
47554
|
this.context = {
|
|
47347
47555
|
viewer: viewer,
|
|
@@ -47420,7 +47628,10 @@ var DrawingManager = /*#__PURE__*/function () {
|
|
|
47420
47628
|
}, {
|
|
47421
47629
|
key: "setupEventListeners",
|
|
47422
47630
|
value: function setupEventListeners() {
|
|
47423
|
-
|
|
47631
|
+
// NOTE: 'drawing:toggle' is handled exclusively by ViewerForgePDF (React layer)
|
|
47632
|
+
// which orchestrates: enterEditMode() → setShowMarkupToolbar(true).
|
|
47633
|
+
// Subscribing here caused double-call to enterEditMode(), resetting Forge Viewer
|
|
47634
|
+
// to its default Arrow tool on every markup mode entry.
|
|
47424
47635
|
if (this.context.markupsCore) {
|
|
47425
47636
|
this.context.markupsCore.addEventListener('EVENT_EDITMODE_CHANGED', this.editModeManager.handleEditModeChanged.bind(this.editModeManager));
|
|
47426
47637
|
this.context.markupsCore.addEventListener('EVENT_MARKUP_SELECTED', this.propertyManager.handleMarkupSelected.bind(this.propertyManager));
|
|
@@ -48043,7 +48254,6 @@ var DrawingManager = /*#__PURE__*/function () {
|
|
|
48043
48254
|
this.collaborativeManager.destroy();
|
|
48044
48255
|
this.presenceManager.destroy();
|
|
48045
48256
|
// Remove event listeners
|
|
48046
|
-
this.eventBus.off('drawing:toggle', this.editModeManager.handleToggle.bind(this.editModeManager));
|
|
48047
48257
|
if (this.context.markupsCore) {
|
|
48048
48258
|
this.context.markupsCore.removeEventListener('EVENT_EDITMODE_CHANGED', this.editModeManager.handleEditModeChanged.bind(this.editModeManager));
|
|
48049
48259
|
this.context.markupsCore.removeEventListener('EVENT_MARKUP_SELECTED', this.propertyManager.handleMarkupSelected.bind(this.propertyManager));
|
|
@@ -48089,7 +48299,7 @@ function styleInject(css, ref) {
|
|
|
48089
48299
|
var css_248z$3 = "/**\n * MarkupToolbar Styles\n *\n * @file markup-toolbar.css\n * @description Excalidraw-inspired toolbar styles with clean, minimal design\n */\n\n/* ========================================\n Hide Default Forge Viewer Markup Toolbar\n ======================================== */\n\n/* Hide all vertical toolbars when custom markup toolbar is active */\nbody:has(.markup-toolbar) .lmv-markup-gui-toolbar,\nbody:has(.markup-toolbar) .adsk-toolbar-vertical,\nbody:has(.markup-toolbar) .markup-mode-toolbar,\nbody:has(.markup-toolbar) .adsk-control-group[id*='markup'],\nbody:has(.markup-toolbar) .adsk-toolbar[id*='markup'],\n.adsk-viewing-viewer:has(.markup-toolbar) .adsk-toolbar-vertical,\n.lmv-markup-gui-toolbar {\n display: none !important;\n visibility: hidden !important;\n opacity: 0 !important;\n pointer-events: none !important;\n}\n\n/* ========================================\n Toolbar Container\n ======================================== */\n\n.markup-toolbar {\n position: fixed;\n left: 50%;\n transform: translateX(-50%);\n background: rgba(34, 34, 34, 0.94);\n border: 1px solid rgba(255, 255, 255, 0.12);\n border-radius: 8px;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);\n padding: 8px 12px;\n display: flex;\n gap: 12px;\n align-items: center;\n z-index: 10000;\n transition: all 200ms ease;\n font-family:\n -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu',\n 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif;\n user-select: none;\n}\n\n.markup-toolbar-top {\n top: 60px;\n}\n\n.markup-toolbar-bottom {\n bottom: 80px;\n}\n\n/* ========================================\n Toolbar Sections\n ======================================== */\n\n.toolbar-section {\n display: flex;\n gap: 4px;\n align-items: center;\n padding: 0 8px;\n border-right: 1px solid var(--toolbar-border, #e0e0e0);\n}\n\n.toolbar-section:last-child {\n border-right: none;\n}\n\n.toolbar-section:first-child {\n padding-left: 0;\n}\n\n.toolbar-section.close {\n padding-right: 0;\n}\n\n/* ========================================\n Toolbar Divider (Excalidraw style)\n ======================================== */\n\n.toolbar-divider {\n width: 1px;\n height: 24px;\n background: rgba(255, 255, 255, 0.24);\n margin: 0 4px;\n}\n\n/* ========================================\n Tool Buttons\n ======================================== */\n\n.tool-button {\n width: 36px;\n height: 36px;\n border: none;\n background: transparent;\n border-radius: 4px;\n cursor: pointer;\n transition: background 150ms ease;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 18px;\n color: #ced4da;\n padding: 0;\n outline: none;\n}\n\n.tool-button svg {\n color: #ced4da;\n fill: currentColor;\n stroke: currentColor;\n}\n\n.tool-button:hover {\n background: rgba(255, 255, 255, 0.08);\n}\n\n.tool-button:active {\n background: rgba(255, 255, 255, 0.12);\n}\n\n.tool-button.active {\n background: #5b8def;\n color: white;\n}\n\n.tool-button.active svg {\n color: white;\n fill: white;\n stroke: white;\n}\n\n.tool-button .tool-icon {\n font-size: 20px;\n line-height: 1;\n}\n\n/* Antd Icon sizing */\n.tool-button .anticon {\n font-size: 16px;\n}\n\n/* ========================================\n Style Controls\n ======================================== */\n\n.toolbar-section.styles {\n gap: 6px;\n}\n\n.style-button {\n height: 32px;\n display: flex;\n align-items: center;\n gap: 4px;\n font-size: 12px;\n}\n\n/* Color picker custom styling */\n.ant-color-picker-trigger {\n height: 32px;\n border-radius: 4px;\n border: 1px solid var(--toolbar-border, #e0e0e0);\n cursor: pointer;\n transition: all 150ms ease;\n}\n\n.ant-color-picker-trigger:hover {\n border-color: var(--toolbar-accent, #1890ff);\n}\n\n/* ========================================\n Action Buttons\n ======================================== */\n\n.toolbar-section.actions {\n gap: 4px;\n}\n\n.action-button {\n height: 32px;\n width: 32px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 4px;\n transition: all 150ms ease;\n}\n\n.action-button:hover {\n background: var(--tool-hover-bg, #f5f5f5);\n}\n\n.action-button.ant-btn-dangerous {\n color: #ff4d4f;\n}\n\n.action-button.ant-btn-dangerous:hover {\n color: #ff7875;\n background: #fff1f0;\n}\n\n/* ========================================\n Close Button\n ======================================== */\n\n.close-button {\n height: 32px;\n width: 32px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 4px;\n transition: all 150ms ease;\n color: var(--tool-text-color, #333333);\n}\n\n.close-button:hover {\n background: var(--tool-hover-bg, #f5f5f5);\n color: #ff4d4f;\n}\n\n/* ========================================\n Popover Customization\n ======================================== */\n\n.ant-popover {\n z-index: 1001;\n}\n\n.ant-popover-inner {\n border-radius: 6px;\n box-shadow: 0 3px 12px rgba(0, 0, 0, 0.15);\n}\n\n.ant-popover-title {\n font-weight: 600;\n font-size: 13px;\n border-bottom: 1px solid var(--toolbar-border, #e0e0e0);\n}\n\n/* ========================================\n Slider Customization\n ======================================== */\n\n.ant-slider {\n margin: 8px 0;\n}\n\n.ant-slider-mark-text {\n font-size: 11px;\n}\n\n/* ========================================\n Dark Theme\n ======================================== */\n\n.theme-dark {\n --toolbar-bg: #2c2c2c;\n --toolbar-border: #404040;\n --toolbar-accent: #4096ff;\n --tool-text-color: #e0e0e0;\n --tool-hover-bg: #3c3c3c;\n --tool-active-bg-temp: #4c4c4c;\n --tool-active-bg: #1890ff;\n}\n\n.theme-dark .tool-button {\n color: var(--tool-text-color);\n}\n\n.theme-dark .tool-button.active {\n color: white;\n}\n\n.theme-dark .close-button {\n color: var(--tool-text-color);\n}\n\n.theme-dark .close-button:hover {\n background: var(--tool-hover-bg);\n color: #ff7875;\n}\n\n.theme-dark .ant-color-picker-trigger {\n border-color: var(--toolbar-border);\n background: var(--toolbar-bg);\n}\n\n.theme-dark .ant-color-picker-trigger:hover {\n border-color: var(--toolbar-accent);\n}\n\n.theme-dark .action-button {\n color: var(--tool-text-color);\n}\n\n.theme-dark .action-button:hover {\n background: var(--tool-hover-bg);\n}\n\n.theme-dark .action-button.ant-btn-dangerous {\n color: #ff7875;\n}\n\n.theme-dark .action-button.ant-btn-dangerous:hover {\n background: #3c2424;\n}\n\n/* ========================================\n Responsive Design\n ======================================== */\n\n@media (max-width: 768px) {\n .markup-toolbar {\n flex-wrap: wrap;\n max-width: 90vw;\n padding: 6px 8px;\n gap: 8px;\n }\n\n .toolbar-section {\n padding: 0 4px;\n }\n\n .tool-button {\n width: 32px;\n height: 32px;\n font-size: 16px;\n }\n\n .style-button,\n .action-button,\n .close-button {\n height: 28px;\n width: 28px;\n }\n}\n\n@media (max-width: 480px) {\n .markup-toolbar {\n bottom: 8px;\n top: auto !important;\n max-width: 95vw;\n }\n\n .toolbar-section {\n gap: 2px;\n padding: 0 2px;\n }\n\n .tool-button {\n width: 28px;\n height: 28px;\n font-size: 14px;\n }\n\n .tool-button .anticon {\n font-size: 14px;\n }\n\n .style-button,\n .action-button,\n .close-button {\n height: 24px;\n width: 24px;\n }\n\n /* Hide text labels on mobile */\n .style-button span:not(.anticon) {\n display: none;\n }\n}\n\n/* ========================================\n Animations\n ======================================== */\n\n@keyframes toolbar-fade-in {\n from {\n opacity: 0;\n transform: translateX(-50%) translateY(-10px);\n }\n to {\n opacity: 1;\n transform: translateX(-50%) translateY(0);\n }\n}\n\n.markup-toolbar {\n animation: toolbar-fade-in 200ms ease-out;\n}\n\n/* ========================================\n Print Mode (Hide toolbar when printing)\n ======================================== */\n\n@media print {\n .markup-toolbar {\n display: none !important;\n }\n}\n\n/* ========================================\n Accessibility\n ======================================== */\n\n.tool-button:focus-visible,\n.action-button:focus-visible,\n.close-button:focus-visible {\n outline: 2px solid var(--toolbar-accent, #1890ff);\n outline-offset: 2px;\n}\n\n/* High contrast mode support */\n@media (prefers-contrast: high) {\n .markup-toolbar {\n border-width: 2px;\n }\n\n .tool-button,\n .action-button,\n .close-button {\n border: 1px solid transparent;\n }\n\n .tool-button:focus-visible,\n .action-button:focus-visible,\n .close-button:focus-visible {\n border-color: currentColor;\n }\n}\n\n/* Reduce motion for accessibility */\n@media (prefers-reduced-motion: reduce) {\n .markup-toolbar,\n .tool-button,\n .action-button,\n .close-button,\n .ant-color-picker-trigger {\n transition: none;\n }\n\n .markup-toolbar {\n animation: none;\n }\n}\n";
|
|
48090
48300
|
styleInject(css_248z$3);
|
|
48091
48301
|
|
|
48092
|
-
var css_248z$2 = "/**\n * Property Panel Styles - Excalidraw 100% Match\n *\n * @file property-panel.css\n * @description Exact match of Excalidraw's property panel (Island + App-menu__left)\n */\n\n/* ========================================\n CSS Variables (Excalidraw Exact)\n ======================================== */\n\n.property-panel {\n /* Sizing */\n --default-button-size: 2rem;\n --default-icon-size: 1rem;\n --border-radius-lg: 0.5rem;\n --border-radius-md: 0.375rem;\n --space-factor: 0.25rem;\n --padding: 2;\n\n /* Colors - Dark Theme */\n --island-bg-color: rgba(34, 34, 34, 0.94);\n --button-bg: rgba(255, 255, 255, 0.1);\n --button-hover-bg: rgba(255, 255, 255, 0.15);\n --button-active-bg: rgba(255, 255, 255, 0.2);\n --button-active-border: #6965db;\n --button-border: rgba(255, 255, 255, 0.1);\n --button-gray-1: rgba(255, 255, 255, 0.08);\n --button-gray-2: rgba(255, 255, 255, 0.12);\n --button-gray-3: rgba(255, 255, 255, 0.16);\n --default-border-color: rgba(255, 255, 255, 0.15);\n --text-primary-color: #e0e0e0;\n --icon-fill-color: #e0e0e0;\n --color-primary: #6965db;\n --color-primary-darkest: #8b87ff;\n --color-surface-primary-container: rgba(101, 97, 219, 0.3);\n --color-on-primary-container: #ffffff;\n\n /* Slider */\n --slider-thumb-size: 16px;\n --color-slider-track: rgba(255, 255, 255, 0.2);\n --color-slider-thumb: #e0e0e0;\n\n /* Shadow */\n --shadow-island:\n 0px 2px 8px rgba(0, 0, 0, 0.3), 0px 4px 16px rgba(0, 0, 0, 0.2);\n\n /* UI Font */\n --ui-font:\n -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu',\n 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif;\n}\n\n/* ========================================\n Island Container (Excalidraw Structure)\n ======================================== */\n\n.property-panel.Island {\n box-sizing: border-box;\n background-color: var(--island-bg-color);\n box-shadow: var(--shadow-island);\n border-radius: var(--border-radius-lg);\n padding: calc(var(--padding) * var(--space-factor)); /* 0.5rem */\n position: fixed;\n top: 80px;\n left: 16px;\n z-index: 9998;\n animation: fadeInSlide 200ms ease;\n overflow: visible; /* Allow popups to overflow */\n max-height: calc(100vh - 100px);\n font-family: var(--ui-font);\n}\n\n/* ========================================\n App Menu Left (Excalidraw Structure)\n ======================================== */\n\n.property-panel.App-menu__left {\n overflow-y: auto; /* Scrollable content */\n overflow-x: visible; /* Allow horizontal overflow for popups */\n padding: 0.5rem; /* Compact padding */\n width: 14rem; /* 224px - wider to fit 5 colors + gaps + active color */\n max-height: calc(100vh - 100px);\n box-sizing: border-box;\n\n /* Dark theme button overrides */\n --button-border: rgba(255, 255, 255, 0.1);\n --button-bg: rgba(255, 255, 255, 0.1);\n}\n\n.App-menu__left .buttonList {\n padding: 0.25rem 0;\n}\n\n/* ========================================\n Selected Shape Actions (Excalidraw Structure)\n ======================================== */\n\n.selected-shape-actions {\n display: flex;\n flex-direction: column;\n row-gap: 0.5rem; /* 8px - compact spacing */\n}\n\n@keyframes fadeInSlide {\n from {\n opacity: 0;\n transform: translateY(-8px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n.property-panel-right {\n left: auto;\n right: 16px;\n}\n\n/* ========================================\n Scrollbar Styling\n ======================================== */\n\n.property-panel.App-menu__left::-webkit-scrollbar {\n width: 4px;\n}\n\n.property-panel.App-menu__left::-webkit-scrollbar-track {\n background: transparent;\n}\n\n.property-panel.App-menu__left::-webkit-scrollbar-thumb {\n background: var(--default-border-color);\n border-radius: 2px;\n}\n\n/* ========================================\n Typography & Fieldset (Excalidraw Exact)\n ======================================== */\n\n.selected-shape-actions fieldset {\n margin: 0; /* NO margin-bottom! Parent row-gap handles spacing */\n padding: 0;\n border: none;\n}\n\n.selected-shape-actions h3,\n.selected-shape-actions legend,\n.selected-shape-actions .control-label {\n margin: 0;\n margin-bottom: 0.25rem; /* 4px, NOT 8px! */\n font-size: 0.75rem; /* 12px */\n color: var(--text-primary-color);\n font-weight: 400; /* NOT 500! */\n display: block;\n line-height: 1;\n}\n\n.selected-shape-actions legend {\n padding: 0;\n}\n\n/* ========================================\n Button List (Excalidraw outlineButtonIconStyles)\n ======================================== */\n\n.selected-shape-actions .buttonList {\n flex-wrap: wrap;\n display: flex;\n column-gap: 0.5rem; /* 8px */\n row-gap: 0.5rem; /* 8px */\n}\n\n.buttonList label,\n.buttonList button,\n.zIndexButton {\n /* outlineButtonStyles base + icon override */\n display: flex;\n justify-content: center;\n align-items: center;\n padding: 0; /* NOT 0.625rem! outlineButtonIconStyles override */\n width: var(--default-button-size); /* 2rem */\n height: var(--default-button-size);\n box-sizing: border-box;\n border-width: 1px;\n border-style: solid;\n border-color: var(--button-border); /* transparent */\n border-radius: var(--border-radius-lg); /* 0.5rem = 8px */\n cursor: pointer;\n background-color: var(--button-bg); /* #f6f6f9 */\n color: var(--icon-fill-color);\n font-family: var(--ui-font);\n transition: all 150ms ease;\n margin: 0;\n position: relative;\n}\n\n.buttonList label:hover,\n.buttonList button:not(.ToolIcon):hover,\n.zIndexButton:hover {\n background-color: var(--button-hover-bg); /* #f1f0ff */\n border-color: var(--default-border-color); /* #f1f0ff */\n}\n\n.buttonList label:active,\n.buttonList button:not(.ToolIcon):active,\n.zIndexButton:active {\n background-color: var(--button-active-bg); /* #f1f0ff */\n border-color: var(--button-active-border); /* #4440bf */\n}\n\n.buttonList label.active,\n.buttonList button:not(.ToolIcon).active {\n background-color: var(--color-surface-primary-container);\n border-color: var(--color-primary);\n box-shadow: 0 0 0 2px var(--color-primary);\n color: var(--color-on-primary-container);\n}\n\n.buttonList label.active svg,\n.buttonList button:not(.ToolIcon).active svg {\n color: var(--color-on-primary-container);\n}\n\n/* ToolIcon buttons in buttonList - hover state targets inner icon */\n.buttonList button.ToolIcon:hover .ToolIcon__icon {\n background-color: var(--button-hover-bg);\n border-color: var(--default-border-color);\n}\n\n/* ToolIcon buttons in buttonList - active/pressed state */\n.buttonList button.ToolIcon:active .ToolIcon__icon {\n background-color: var(--button-active-bg);\n border-color: var(--button-active-border);\n}\n\n/* ToolIcon buttons in buttonList - selected state */\n.buttonList button.ToolIcon.active .ToolIcon__icon {\n background-color: var(--color-surface-primary-container);\n border-color: var(--color-primary);\n box-shadow: 0 0 0 2px var(--color-primary);\n color: var(--color-on-primary-container);\n}\n\n.buttonList button.ToolIcon.active .ToolIcon__icon svg {\n color: var(--color-on-primary-container);\n}\n\n/* Danger variant in buttonList */\n.buttonList button.ToolIcon.danger .ToolIcon__icon {\n color: #ff6b6b;\n}\n\n.buttonList button.ToolIcon.danger:hover .ToolIcon__icon {\n background-color: rgba(255, 107, 107, 0.15);\n border-color: #ff6b6b;\n}\n\n/* Hide radio inputs */\n.buttonList input[type='radio'],\n.buttonList input[type='checkbox'] {\n opacity: 0;\n position: absolute;\n pointer-events: none;\n}\n\n/* Focus state */\n.buttonList label:focus-within {\n outline: transparent;\n box-shadow: 0 0 0 2px var(--color-primary); /* Excalidraw focus */\n}\n\n/* SVG icons inside buttons */\n.buttonList svg {\n position: relative;\n width: var(--default-icon-size); /* 1rem */\n height: var(--default-icon-size);\n stroke: currentColor;\n fill: none;\n}\n\n/* ========================================\n Color Picker (Excalidraw Exact)\n ======================================== */\n\n.color-picker-container {\n display: flex;\n gap: 0.5rem; /* 8px gap between sections */\n padding: 0.25rem 0px;\n align-items: center;\n}\n\n.color-picker__top-picks {\n display: flex;\n gap: 0.5rem; /* 8px gap between color buttons */\n align-items: center;\n flex: 1; /* Take remaining space */\n}\n\n.color-picker__button {\n --radius: 4px;\n --size: 1.375rem; /* 22px for top picks, NOT 2rem! */\n\n padding: 0;\n margin: 0;\n width: var(--size);\n height: var(--size);\n border: 0; /* NO border! */\n border-radius: var(--radius);\n background-color: var(--swatch-color);\n cursor: pointer;\n position: relative;\n transition: transform 150ms ease;\n filter: var(--theme-filter, none);\n}\n\n.color-picker__button:hover:not(.active):not(.active-color) {\n transform: scale(1.075); /* Exact Excalidraw */\n}\n\n.color-picker__button.active .color-picker__button-outline {\n position: absolute;\n --offset: -1px;\n top: var(--offset);\n left: var(--offset);\n right: var(--offset);\n bottom: var(--offset);\n box-shadow: 0 0 0 1px var(--color-primary-darkest); /* #4a47b1, NOT border! */\n z-index: 1;\n border-radius: var(--radius);\n filter: var(--theme-filter, none);\n}\n\n.color-picker__button-outline {\n /* Empty outline by default */\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n/* Hotkey label on color buttons (Excalidraw exact) */\n.color-picker__button__hotkey-label {\n position: absolute;\n right: 5px;\n bottom: 3px;\n filter: none;\n font-size: 11px;\n font-weight: 500;\n pointer-events: none; /* Don't interfere with button clicks */\n user-select: none;\n line-height: 1;\n}\n\n/* Color divider */\n.color-divider {\n width: 1px;\n height: 1rem;\n background-color: var(--default-border-color); /* #f1f0ff */\n margin: 0; /* Grid handles spacing */\n}\n\n/* Active color button (larger) */\n.color-picker__button.active-color {\n width: 1.625rem; /* 26px */\n height: 1.625rem;\n border-radius: calc(var(--radius) + 1px); /* 5px */\n position: relative; /* For popup positioning */\n}\n\n/* Color Picker Popup Container (Excalidraw style) */\n.color-picker-popup-wrapper {\n position: relative;\n}\n\n.color-picker-popup {\n /* Position set via inline style (Portal with dynamic fixed position) */\n z-index: 10000; /* High z-index to appear above everything */\n background: var(--island-bg-color);\n box-shadow: var(--shadow-island);\n border-radius: var(--border-radius-lg);\n padding: 0.5rem;\n pointer-events: all; /* Ensure popup is clickable */\n}\n\n/* Island Wrapper (Color Picker Popup - Light theme for readability) */\n.Island {\n /* Define CSS variables for popup (since it's portaled to body) */\n --padding: 0;\n --space-factor: 0.25rem;\n --border-radius-lg: 0.5rem;\n --island-bg-color: rgba(34, 34, 34, 0.96);\n --shadow-island:\n 0px 2px 8px rgba(0, 0, 0, 0.3), 0px 4px 16px rgba(0, 0, 0, 0.2);\n --text-primary-color: #e0e0e0;\n --default-border-color: rgba(255, 255, 255, 0.15);\n --color-primary: #6965db;\n --color-primary-darkest: #8b87ff;\n --ui-font:\n -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu',\n 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif;\n\n box-sizing: border-box;\n background-color: var(--island-bg-color);\n box-shadow: var(--shadow-island);\n border-radius: var(--border-radius-lg);\n padding: calc(var(--padding) * var(--space-factor));\n position: relative;\n transition: box-shadow 0.5s ease-in-out;\n font-family: var(--ui-font);\n}\n\n/* Arrow SVG container - Excalidraw exact positioning */\n.color-picker-popup-arrow {\n position: absolute;\n left: 0px;\n transform-origin: 0px 0px;\n transform: translateY(50%) rotate(90deg) translateX(-50%);\n /* top is set dynamically via inline style */\n pointer-events: none;\n}\n\n.color-picker-popup-arrow svg {\n display: block;\n fill: rgba(34, 34, 34, 0.96);\n filter: drop-shadow(rgba(0, 0, 0, 0.2) 0px 3px 2px);\n}\n\n/* Legacy triangle - kept for backwards compatibility */\n.color-picker-popup-triangle {\n width: 0;\n height: 0;\n border-style: solid;\n border-width: 9px 10px 9px 0;\n border-color: transparent var(--island-bg-color) transparent transparent;\n position: absolute;\n left: -10px;\n top: 25px;\n filter: drop-shadow(-1px 0 1px rgba(0, 0, 0, 0.1));\n}\n\n.color-picker__button.active-color .color-picker__button-outline {\n position: absolute;\n --offset: -1px;\n top: var(--offset);\n left: var(--offset);\n right: var(--offset);\n bottom: var(--offset);\n box-shadow: 0 0 0 1px var(--color-primary-darkest);\n border-radius: calc(var(--radius) + 1px);\n filter: var(--theme-filter, none);\n}\n\n/* ========================================\n Color Picker Popup Content (Excalidraw Exact)\n ======================================== */\n\n.color-picker-content {\n display: flex;\n flex-direction: column;\n gap: 0.75rem; /* 12px between sections */\n outline: none;\n}\n\n.color-picker-content.properties-content {\n padding: 0.5rem; /* 8px padding inside popup */\n}\n\n/* Ensure all sections inside popup are visible */\n.color-picker-content > div {\n display: block;\n}\n\n.color-picker__heading {\n padding: 0 0.5rem;\n font-size: 0.75rem; /* 12px */\n text-align: left;\n color: var(--text-primary-color);\n margin-bottom: 0.5rem; /* 8px */\n font-weight: 400;\n}\n\n.color-picker-content--default {\n padding: 0.5rem; /* 8px */\n display: grid;\n grid-template-columns: repeat(5, 1.875rem); /* 5 columns, 30px each */\n grid-gap: 0.25rem; /* 4px gap */\n border-radius: 4px;\n}\n\n.color-picker-content--default:focus {\n outline: none;\n box-shadow: 0 0 0 2px var(--color-primary);\n}\n\n/* Shades section styling */\n.color-picker-content--default.shades {\n margin-top: 0;\n}\n\n/* Large buttons in popup (30px vs 22px in top picks) */\n.color-picker__button--large {\n --size: 1.875rem; /* 30px */\n width: var(--size) !important;\n height: var(--size) !important;\n}\n\n.color-picker__button.has-outline {\n box-shadow: inset 0 0 0 1px #d9d9d9;\n}\n\n/* No focus visible button (for shades placeholder) */\n.color-picker__button--no-focus-visible {\n border: 0;\n}\n\n.color-picker__button--no-focus-visible::after {\n display: none;\n}\n\n.color-picker__button--no-focus-visible:focus-visible {\n outline: none !important;\n}\n\n/* Transparent button (checkerboard pattern) */\n.color-picker__button.is-transparent {\n background-color: transparent !important;\n background-image:\n linear-gradient(45deg, #808080 25%, transparent 25%),\n linear-gradient(-45deg, #808080 25%, transparent 25%),\n linear-gradient(45deg, transparent 75%, #808080 75%),\n linear-gradient(-45deg, transparent 75%, #808080 75%);\n background-size: 8px 8px;\n background-position:\n 0 0,\n 0 4px,\n 4px -4px,\n -4px 0px;\n}\n\n.color-picker__button.is-transparent.has-outline {\n box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.3);\n}\n\n/* Hex input field (Excalidraw exact) */\n.color-picker__input-label {\n display: grid;\n grid-template-columns: auto 1fr auto auto;\n gap: 8px;\n align-items: center;\n border: 1px solid var(--default-border-color);\n border-radius: 8px;\n padding: 0 12px;\n margin: 8px;\n box-sizing: border-box;\n}\n\n.color-picker__input-label:focus-within {\n box-shadow: 0 0 0 1px var(--color-primary-darkest);\n border-radius: var(--border-radius-lg);\n}\n\n.color-picker__input-hash {\n padding: 0 0.25rem;\n color: var(--text-primary-color);\n}\n\n.color-picker-input {\n box-sizing: border-box;\n width: 100%;\n margin: 0;\n font-size: 0.875rem; /* 14px */\n font-family: inherit;\n background-color: transparent;\n color: var(--text-primary-color);\n border: 0;\n outline: none;\n height: var(--default-button-size); /* 2rem = 32px */\n letter-spacing: 0.4px;\n padding: 0.5rem 0.25rem;\n}\n\n.color-picker-input:focus-visible {\n box-shadow: none;\n}\n\n/* Hex input divider */\n.color-picker__input-divider {\n width: 1px;\n height: 1.25rem; /* 20px */\n background-color: var(--default-border-color);\n margin: 0;\n}\n\n/* Eye dropper trigger (Excalidraw exact) */\n.excalidraw-eye-dropper-trigger {\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--text-primary-color);\n transition: color 150ms ease;\n width: 1rem; /* 16px - fixed width */\n height: 1rem; /* 16px - fixed height */\n flex-shrink: 0; /* Don't shrink */\n}\n\n.excalidraw-eye-dropper-trigger:hover {\n color: var(--color-primary-darkest);\n}\n\n.excalidraw-eye-dropper-trigger svg {\n width: 1rem; /* 16px - Excalidraw exact */\n height: 1rem;\n}\n\n/* ========================================\n Range Slider (Excalidraw Exact)\n ======================================== */\n\n.range-wrapper {\n position: relative;\n padding-top: 8px;\n padding-bottom: 20px;\n overflow: visible;\n}\n\n.range-input {\n width: 100%;\n height: 6px;\n -webkit-appearance: none;\n background: var(--color-slider-track);\n border-radius: 3px;\n outline: none;\n cursor: pointer;\n}\n\n.range-input::-webkit-slider-thumb {\n -webkit-appearance: none;\n appearance: none;\n width: var(--slider-thumb-size); /* 16px */\n height: var(--slider-thumb-size);\n background: var(--color-primary);\n border-radius: 50%;\n cursor: pointer;\n border: 2px solid #fff;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);\n transition: transform 0.1s ease;\n}\n\n.range-input::-webkit-slider-thumb:hover {\n transform: scale(1.1);\n}\n\n.range-input::-webkit-slider-thumb:active {\n transform: scale(1.15);\n}\n\n.range-input::-moz-range-thumb {\n width: var(--slider-thumb-size);\n height: var(--slider-thumb-size);\n background: var(--color-primary);\n border-radius: 50%;\n cursor: pointer;\n border: 2px solid #fff;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);\n}\n\n.range-input::-moz-range-track {\n background: transparent;\n border: none;\n}\n\n.range-input:focus {\n outline: none;\n}\n\n.range-input:focus::-webkit-slider-thumb {\n box-shadow:\n 0 0 0 3px rgba(105, 101, 219, 0.3),\n 0 1px 3px rgba(0, 0, 0, 0.3);\n}\n\n/* Value bubble - always visible, follows thumb */\n.value-bubble {\n position: absolute;\n bottom: 0;\n transform: translateX(-50%);\n font-size: 12px;\n font-weight: 500;\n color: var(--color-primary);\n pointer-events: none;\n transition: left 0.05s ease-out;\n}\n\n.zero-label {\n position: absolute;\n bottom: 0;\n left: 0;\n font-size: 11px;\n color: var(--text-primary-color);\n opacity: 0.6;\n transition: opacity 0.15s ease;\n}\n\n.max-label {\n position: absolute;\n bottom: 0;\n right: 0;\n font-size: 11px;\n color: var(--text-primary-color);\n opacity: 0.6;\n transition: opacity 0.15s ease;\n}\n\n/* Hide min/max labels when value is close */\n.zero-label.hidden,\n.max-label.hidden {\n opacity: 0;\n}\n\n/* Ant Design Slider override */\n.slider-control .ant-slider {\n margin: 8px 0;\n}\n\n.slider-control .ant-slider-rail {\n background: var(--panel-border, #e5e5e5);\n}\n\n.slider-control .ant-slider-track {\n background: var(--panel-accent, #6965db);\n}\n\n.slider-control .ant-slider-handle::after {\n box-shadow: 0 0 0 2px var(--panel-accent, #6965db);\n}\n\n/* ========================================\n Select Dropdown (Excalidraw Style)\n ======================================== */\n\n.iconSelectList {\n display: flex;\n gap: 0.5rem;\n}\n\n.iconSelectList.buttonList {\n flex-wrap: wrap;\n column-gap: 0.5rem;\n row-gap: 0.5rem;\n}\n\n.iconSelectList button,\n.iconSelectList label {\n width: auto;\n min-width: 2rem;\n height: 2rem;\n padding: 0 0.25rem;\n border: 1px solid var(--panel-border, #e5e5e5);\n border-radius: 4px;\n background-color: var(--panel-bg, #ffffff);\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: all 150ms ease;\n}\n\n.iconSelectList button:hover,\n.iconSelectList label:hover {\n background-color: var(--panel-hover-bg, #f5f5f5);\n border-color: var(--panel-accent, #6965db);\n}\n\n.iconSelectList button svg,\n.iconSelectList label svg {\n stroke: currentColor;\n fill: none;\n}\n\n/* Ant Design Select override */\n.select-control .ant-select-selector {\n border-radius: 4px;\n border: 1px solid var(--panel-border, #e5e5e5);\n background: var(--panel-bg, #ffffff);\n font-size: 0.75rem;\n height: 2rem;\n}\n\n/* ========================================\n Layer Actions (Now handled by buttonList)\n ======================================== */\n/* .zIndexButton styles are now covered by .buttonList button styles above */\n\n/* ========================================\n ToolIcon Component (Excalidraw Exact)\n ======================================== */\n\n.ToolIcon {\n border-radius: var(--border-radius-lg);\n display: inline-flex;\n align-items: center;\n position: relative;\n cursor: pointer;\n -webkit-tap-highlight-color: transparent;\n user-select: none;\n}\n\n.ToolIcon_type_button {\n padding: 0;\n border: none;\n margin: 0;\n font-size: inherit;\n background-color: initial; /* transparent */\n}\n\n.ToolIcon_type_button:focus-visible {\n box-shadow: 0 0 0 2px var(--color-primary);\n}\n\n.ToolIcon_type_button:active {\n background-color: transparent; /* Button itself stays transparent */\n}\n\n.ToolIcon_type_button.ToolIcon--selected {\n background-color: transparent;\n}\n\n.ToolIcon__icon {\n box-sizing: border-box;\n width: var(--default-button-size); /* 2rem */\n height: var(--default-button-size);\n color: var(--icon-fill-color);\n display: flex;\n justify-content: center;\n align-items: center;\n border-radius: var(--border-radius-lg); /* 0.5rem */\n border-width: 1px;\n border-style: solid;\n border-color: var(--button-border); /* transparent */\n background-color: var(--button-bg); /* #f6f6f9 */\n transition: all 150ms ease;\n}\n\n.ToolIcon__icon:hover {\n background-color: var(--button-hover-bg); /* #f1f0ff */\n border-color: var(--default-border-color); /* #f1f0ff */\n}\n\n.ToolIcon__icon:active {\n background-color: var(--button-active-bg); /* #f1f0ff */\n border-color: var(--button-active-border); /* #4440bf */\n}\n\n.ToolIcon__icon[aria-disabled='true'] {\n background: initial;\n border: none;\n}\n\n.ToolIcon__icon[aria-disabled='true'] svg {\n color: var(--color-disabled, #c0c0c0);\n}\n\n.ToolIcon__icon svg {\n position: relative;\n width: var(--default-icon-size); /* 1rem */\n height: var(--default-icon-size);\n color: var(--icon-fill-color);\n}\n\n.ToolIcon_size_small .ToolIcon__icon {\n width: 2rem;\n height: 2rem;\n font-size: 0.8em;\n}\n\n.ToolIcon_size_medium .ToolIcon__icon {\n width: 2rem;\n height: 2rem;\n}\n\n/* Selected state for ToolIcon (matching buttonList .active) */\n.ToolIcon.active .ToolIcon__icon,\n.ToolIcon--selected .ToolIcon__icon {\n background-color: var(--color-surface-primary-container);\n border-color: var(--color-primary);\n box-shadow: 0 0 0 2px var(--color-primary);\n color: var(--color-on-primary-container);\n}\n\n.ToolIcon.active .ToolIcon__icon svg,\n.ToolIcon--selected .ToolIcon__icon svg {\n color: var(--color-on-primary-container);\n}\n\n/* Danger variant for delete actions */\n.ToolIcon.danger .ToolIcon__icon {\n color: #ff6b6b;\n}\n\n.ToolIcon.danger .ToolIcon__icon:hover {\n background-color: rgba(255, 107, 107, 0.15);\n border-color: #ff6b6b;\n}\n\n/* Danger variant active state (keep danger styling even when active) */\n.ToolIcon.danger.active .ToolIcon__icon,\n.ToolIcon.danger.ToolIcon--selected .ToolIcon__icon {\n background-color: rgba(255, 107, 107, 0.25);\n border-color: #ff6b6b;\n box-shadow: 0 0 0 2px #ff6b6b;\n color: #ff6b6b;\n}\n\n/* ========================================\n Action Icon Buttons (Legacy - to be removed)\n ======================================== */\n\n.action-icon-button {\n width: 2rem;\n height: 2rem;\n padding: 0;\n border: 1px solid var(--panel-border, #e5e5e5);\n border-radius: 4px;\n background-color: var(--panel-bg, #ffffff);\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: all 150ms ease;\n font-size: 1rem;\n color: var(--panel-text, #1e1e1e);\n}\n\n.action-icon-button:hover {\n background-color: var(--panel-hover-bg, #f5f5f5);\n border-color: var(--panel-accent, #6965db);\n}\n\n.action-icon-button:active {\n transform: scale(0.95);\n}\n\n.action-icon-button.danger {\n color: #ff6b6b;\n}\n\n.action-icon-button.danger:hover {\n background-color: rgba(255, 107, 107, 0.15);\n border-color: #ff6b6b;\n}\n\n/* ========================================\n Divider\n ======================================== */\n\n.property-divider {\n height: 1px;\n background: var(--panel-border, #e5e5e5);\n margin: 12px 0;\n}\n\n/* ========================================\n Property Sections\n ======================================== */\n\n.property-section {\n margin-bottom: 12px;\n}\n\n.property-section:last-child {\n margin-bottom: 0;\n}\n\n.property-control {\n margin-bottom: 12px;\n}\n\n.property-control:last-child {\n margin-bottom: 0;\n}\n\n/* ========================================\n Dark Theme (Excalidraw Exact)\n ======================================== */\n\n.theme-dark .property-panel {\n /* Dark theme colors */\n --island-bg-color: #121212;\n --button-bg: #363541;\n --button-hover-bg: #363541;\n --button-active-bg: #363541;\n --button-gray-1: #363636;\n --button-gray-2: #272727;\n --button-gray-3: #222;\n --default-border-color: #3a3a3a;\n --text-primary-color: #e0e0e0;\n --icon-fill-color: #e0e0e0;\n --color-slider-track: #3a3a3a;\n --color-slider-thumb: #b8b8b8;\n --button-border: transparent;\n}\n\n.theme-dark .property-panel.App-menu__left {\n --button-bg: var(--color-surface-high, #2a2a3a);\n}\n\n.theme-dark .property-panel.Island {\n box-shadow: 0 4px 16px rgba(0, 0, 0, 0.4);\n}\n\n/* ========================================\n Responsive\n ======================================== */\n\n@media (max-width: 768px) {\n .property-panel {\n width: 180px;\n top: 70px;\n left: 8px;\n }\n\n .property-panel-right {\n right: 8px;\n }\n}\n\n/* ========================================\n Utility Classes\n ======================================== */\n\n.property-panel-hidden {\n display: none;\n}\n\n.property-panel-compact {\n width: 160px;\n}\n\n.text-muted {\n color: var(--panel-text-secondary, #6b6b6b);\n font-size: 0.7rem;\n}\n\n.text-small {\n font-size: 0.7rem;\n}\n\n/* ========================================\n Inline Select (for button groups)\n ======================================== */\n\n.buttonList .inline-select {\n width: var(--default-button-size);\n height: var(--default-button-size);\n padding: 0;\n border: 1px solid var(--button-border);\n border-radius: var(--border-radius-lg);\n font-size: 0.65rem;\n text-align: center;\n text-align-last: center;\n background-color: var(--button-bg);\n color: var(--text-primary-color);\n cursor: pointer;\n flex-shrink: 0;\n appearance: none;\n -webkit-appearance: none;\n -moz-appearance: none;\n transition: all 150ms ease;\n}\n\n.buttonList .inline-select:hover {\n background-color: var(--button-hover-bg);\n border-color: var(--default-border-color);\n}\n\n.buttonList .inline-select:focus {\n outline: none;\n box-shadow: 0 0 0 2px var(--color-primary);\n}\n\n.buttonList .inline-select.active {\n background-color: var(--color-surface-primary-container);\n border-color: var(--color-primary);\n box-shadow: 0 0 0 2px var(--color-primary);\n color: var(--color-on-primary-container);\n}\n\n.buttonList .inline-select option {\n background-color: var(--island-bg-color);\n color: var(--text-primary-color);\n}\n\n/* ========================================\n Control Label (for Opacity slider)\n ======================================== */\n\n.control-label {\n display: block;\n font-size: 0.75rem;\n font-weight: 500;\n color: var(--text-primary-color, #e0e0e0);\n margin-bottom: 4px;\n}\n";
|
|
48302
|
+
var css_248z$2 = "/**\n * Property Panel Styles - Excalidraw 100% Match\n *\n * @file property-panel.css\n * @description Exact match of Excalidraw's property panel (Island + App-menu__left)\n */\n\n/* ========================================\n CSS Variables (Excalidraw Exact)\n ======================================== */\n\n.property-panel {\n /* Sizing */\n --default-button-size: 2rem;\n --default-icon-size: 1rem;\n --border-radius-lg: 0.5rem;\n --border-radius-md: 0.375rem;\n --space-factor: 0.25rem;\n --padding: 2;\n\n /* Colors - Dark Theme */\n --island-bg-color: rgba(34, 34, 34, 0.94);\n --button-bg: rgba(255, 255, 255, 0.1);\n --button-hover-bg: rgba(255, 255, 255, 0.15);\n --button-active-bg: rgba(255, 255, 255, 0.2);\n --button-active-border: #6965db;\n --button-border: rgba(255, 255, 255, 0.1);\n --button-gray-1: rgba(255, 255, 255, 0.08);\n --button-gray-2: rgba(255, 255, 255, 0.12);\n --button-gray-3: rgba(255, 255, 255, 0.16);\n --default-border-color: rgba(255, 255, 255, 0.15);\n --text-primary-color: #e0e0e0;\n --icon-fill-color: #e0e0e0;\n --color-primary: #6965db;\n --color-primary-darkest: #8b87ff;\n --color-surface-primary-container: rgba(101, 97, 219, 0.3);\n --color-on-primary-container: #ffffff;\n\n /* Slider */\n --slider-thumb-size: 16px;\n --color-slider-track: rgba(255, 255, 255, 0.2);\n --color-slider-thumb: #e0e0e0;\n\n /* Shadow */\n --shadow-island:\n 0px 2px 8px rgba(0, 0, 0, 0.3), 0px 4px 16px rgba(0, 0, 0, 0.2);\n\n /* UI Font */\n --ui-font:\n -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu',\n 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif;\n}\n\n/* ========================================\n Island Container (Excalidraw Structure)\n ======================================== */\n\n.property-panel.Island {\n box-sizing: border-box;\n background-color: var(--island-bg-color);\n box-shadow: var(--shadow-island);\n border-radius: var(--border-radius-lg);\n padding: calc(var(--padding) * var(--space-factor)); /* 0.5rem */\n position: fixed;\n top: 180px;\n left: 16px;\n z-index: 9998;\n animation: fadeInSlide 200ms ease;\n overflow: visible; /* Allow popups to overflow */\n max-height: calc(100vh - 200px);\n font-family: var(--ui-font);\n}\n\n/* ========================================\n App Menu Left (Excalidraw Structure)\n ======================================== */\n\n.property-panel.App-menu__left {\n overflow-y: auto; /* Scrollable content */\n overflow-x: visible; /* Allow horizontal overflow for popups */\n padding: 0.5rem; /* Compact padding */\n width: 14rem; /* 224px - wider to fit 5 colors + gaps + active color */\n max-height: calc(100vh - 100px);\n box-sizing: border-box;\n\n /* Dark theme button overrides */\n --button-border: rgba(255, 255, 255, 0.1);\n --button-bg: rgba(255, 255, 255, 0.1);\n}\n\n.App-menu__left .buttonList {\n padding: 0.25rem 0;\n}\n\n/* ========================================\n Selected Shape Actions (Excalidraw Structure)\n ======================================== */\n\n.selected-shape-actions {\n display: flex;\n flex-direction: column;\n row-gap: 0.5rem; /* 8px - compact spacing */\n}\n\n@keyframes fadeInSlide {\n from {\n opacity: 0;\n transform: translateY(-8px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n.property-panel-right {\n left: auto;\n right: 16px;\n}\n\n/* ========================================\n Scrollbar Styling\n ======================================== */\n\n.property-panel.App-menu__left::-webkit-scrollbar {\n width: 4px;\n}\n\n.property-panel.App-menu__left::-webkit-scrollbar-track {\n background: transparent;\n}\n\n.property-panel.App-menu__left::-webkit-scrollbar-thumb {\n background: var(--default-border-color);\n border-radius: 2px;\n}\n\n/* ========================================\n Typography & Fieldset (Excalidraw Exact)\n ======================================== */\n\n.selected-shape-actions fieldset {\n margin: 0; /* NO margin-bottom! Parent row-gap handles spacing */\n padding: 0;\n border: none;\n}\n\n.selected-shape-actions h3,\n.selected-shape-actions legend,\n.selected-shape-actions .control-label {\n margin: 0;\n margin-bottom: 0.25rem; /* 4px, NOT 8px! */\n font-size: 0.75rem; /* 12px */\n color: var(--text-primary-color);\n font-weight: 400; /* NOT 500! */\n display: block;\n line-height: 1;\n}\n\n.selected-shape-actions legend {\n padding: 0;\n}\n\n/* ========================================\n Button List (Excalidraw outlineButtonIconStyles)\n ======================================== */\n\n.selected-shape-actions .buttonList {\n flex-wrap: wrap;\n display: flex;\n column-gap: 0.5rem; /* 8px */\n row-gap: 0.5rem; /* 8px */\n}\n\n.buttonList label,\n.buttonList button,\n.zIndexButton {\n /* outlineButtonStyles base + icon override */\n display: flex;\n justify-content: center;\n align-items: center;\n padding: 0; /* NOT 0.625rem! outlineButtonIconStyles override */\n width: var(--default-button-size); /* 2rem */\n height: var(--default-button-size);\n box-sizing: border-box;\n border-width: 1px;\n border-style: solid;\n border-color: var(--button-border); /* transparent */\n border-radius: var(--border-radius-lg); /* 0.5rem = 8px */\n cursor: pointer;\n background-color: var(--button-bg); /* #f6f6f9 */\n color: var(--icon-fill-color);\n font-family: var(--ui-font);\n transition: all 150ms ease;\n margin: 0;\n position: relative;\n}\n\n.buttonList label:hover,\n.buttonList button:not(.ToolIcon):hover,\n.zIndexButton:hover {\n background-color: var(--button-hover-bg); /* #f1f0ff */\n border-color: var(--default-border-color); /* #f1f0ff */\n}\n\n.buttonList label:active,\n.buttonList button:not(.ToolIcon):active,\n.zIndexButton:active {\n background-color: var(--button-active-bg); /* #f1f0ff */\n border-color: var(--button-active-border); /* #4440bf */\n}\n\n.buttonList label.active,\n.buttonList button:not(.ToolIcon).active {\n background-color: var(--color-surface-primary-container);\n border-color: var(--color-primary);\n box-shadow: 0 0 0 2px var(--color-primary);\n color: var(--color-on-primary-container);\n}\n\n.buttonList label.active svg,\n.buttonList button:not(.ToolIcon).active svg {\n color: var(--color-on-primary-container);\n}\n\n/* ToolIcon buttons in buttonList - make outer button transparent so inner .ToolIcon__icon handles all visuals */\n.buttonList button.ToolIcon {\n background-color: transparent;\n border-color: transparent;\n box-shadow: none;\n padding: 0;\n}\n\n/* ToolIcon buttons in buttonList - hover state targets inner icon */\n.buttonList button.ToolIcon:hover .ToolIcon__icon {\n background-color: var(--button-hover-bg);\n border-color: var(--default-border-color);\n}\n\n/* ToolIcon buttons in buttonList - active/pressed state */\n.buttonList button.ToolIcon:active .ToolIcon__icon {\n background-color: var(--button-active-bg);\n border-color: var(--button-active-border);\n}\n\n/* ToolIcon buttons in buttonList - selected state */\n.buttonList button.ToolIcon.active .ToolIcon__icon {\n background-color: var(--color-surface-primary-container);\n border-color: var(--color-primary);\n box-shadow: 0 0 0 2px var(--color-primary);\n color: var(--color-on-primary-container);\n}\n\n.buttonList button.ToolIcon.active .ToolIcon__icon svg {\n color: var(--color-on-primary-container);\n}\n\n/* Danger variant in buttonList */\n.buttonList button.ToolIcon.danger .ToolIcon__icon {\n color: #ff6b6b;\n}\n\n.buttonList button.ToolIcon.danger:hover .ToolIcon__icon {\n background-color: rgba(255, 107, 107, 0.15);\n border-color: #ff6b6b;\n}\n\n/* Hide radio inputs */\n.buttonList input[type='radio'],\n.buttonList input[type='checkbox'] {\n opacity: 0;\n position: absolute;\n pointer-events: none;\n}\n\n/* Focus state */\n.buttonList label:focus-within {\n outline: transparent;\n box-shadow: 0 0 0 2px var(--color-primary); /* Excalidraw focus */\n}\n\n/* SVG icons inside buttons */\n.buttonList svg {\n position: relative;\n width: var(--default-icon-size); /* 1rem */\n height: var(--default-icon-size);\n stroke: currentColor;\n fill: none;\n}\n\n/* ========================================\n Color Picker (Excalidraw Exact)\n ======================================== */\n\n.color-picker-container {\n display: flex;\n gap: 0.5rem; /* 8px gap between sections */\n padding: 0.25rem 0px;\n align-items: center;\n}\n\n.color-picker__top-picks {\n display: flex;\n gap: 0.5rem; /* 8px gap between color buttons */\n align-items: center;\n flex: 1; /* Take remaining space */\n}\n\n.color-picker__button {\n --radius: 4px;\n --size: 1.375rem; /* 22px for top picks, NOT 2rem! */\n\n padding: 0;\n margin: 0;\n width: var(--size);\n height: var(--size);\n border: 0; /* NO border! */\n border-radius: var(--radius);\n background-color: var(--swatch-color);\n cursor: pointer;\n position: relative;\n transition: transform 150ms ease;\n filter: var(--theme-filter, none);\n}\n\n.color-picker__button:hover:not(.active):not(.active-color) {\n transform: scale(1.075); /* Exact Excalidraw */\n}\n\n.color-picker__button.active .color-picker__button-outline {\n position: absolute;\n --offset: -1px;\n top: var(--offset);\n left: var(--offset);\n right: var(--offset);\n bottom: var(--offset);\n box-shadow: 0 0 0 1px var(--color-primary-darkest); /* #4a47b1, NOT border! */\n z-index: 1;\n border-radius: var(--radius);\n filter: var(--theme-filter, none);\n}\n\n.color-picker__button-outline {\n /* Empty outline by default */\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n/* Hotkey label on color buttons (Excalidraw exact) */\n.color-picker__button__hotkey-label {\n position: absolute;\n right: 5px;\n bottom: 3px;\n filter: none;\n font-size: 11px;\n font-weight: 500;\n pointer-events: none; /* Don't interfere with button clicks */\n user-select: none;\n line-height: 1;\n}\n\n/* Color divider */\n.color-divider {\n width: 1px;\n height: 1rem;\n background-color: var(--default-border-color); /* #f1f0ff */\n margin: 0; /* Grid handles spacing */\n}\n\n/* Active color button (larger) */\n.color-picker__button.active-color {\n width: 1.625rem; /* 26px */\n height: 1.625rem;\n border-radius: calc(var(--radius) + 1px); /* 5px */\n position: relative; /* For popup positioning */\n}\n\n/* Color Picker Popup Container (Excalidraw style) */\n.color-picker-popup-wrapper {\n position: relative;\n}\n\n.color-picker-popup {\n /* Position set via inline style (Portal with dynamic fixed position) */\n z-index: 10000; /* High z-index to appear above everything */\n background: var(--island-bg-color);\n box-shadow: var(--shadow-island);\n border-radius: var(--border-radius-lg);\n padding: 0.5rem;\n pointer-events: all; /* Ensure popup is clickable */\n}\n\n/* Island Wrapper (Color Picker Popup - Light theme for readability) */\n.Island {\n /* Define CSS variables for popup (since it's portaled to body) */\n --padding: 0;\n --space-factor: 0.25rem;\n --border-radius-lg: 0.5rem;\n --island-bg-color: rgba(34, 34, 34, 0.96);\n --shadow-island:\n 0px 2px 8px rgba(0, 0, 0, 0.3), 0px 4px 16px rgba(0, 0, 0, 0.2);\n --text-primary-color: #e0e0e0;\n --default-border-color: rgba(255, 255, 255, 0.15);\n --color-primary: #6965db;\n --color-primary-darkest: #8b87ff;\n --ui-font:\n -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu',\n 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif;\n\n box-sizing: border-box;\n background-color: var(--island-bg-color);\n box-shadow: var(--shadow-island);\n border-radius: var(--border-radius-lg);\n padding: calc(var(--padding) * var(--space-factor));\n position: relative;\n transition: box-shadow 0.5s ease-in-out;\n font-family: var(--ui-font);\n}\n\n/* Arrow SVG container - Excalidraw exact positioning */\n.color-picker-popup-arrow {\n position: absolute;\n left: 0px;\n transform-origin: 0px 0px;\n transform: translateY(50%) rotate(90deg) translateX(-50%);\n /* top is set dynamically via inline style */\n pointer-events: none;\n}\n\n.color-picker-popup-arrow svg {\n display: block;\n fill: rgba(34, 34, 34, 0.96);\n filter: drop-shadow(rgba(0, 0, 0, 0.2) 0px 3px 2px);\n}\n\n/* Legacy triangle - kept for backwards compatibility */\n.color-picker-popup-triangle {\n width: 0;\n height: 0;\n border-style: solid;\n border-width: 9px 10px 9px 0;\n border-color: transparent var(--island-bg-color) transparent transparent;\n position: absolute;\n left: -10px;\n top: 25px;\n filter: drop-shadow(-1px 0 1px rgba(0, 0, 0, 0.1));\n}\n\n.color-picker__button.active-color .color-picker__button-outline {\n position: absolute;\n --offset: -1px;\n top: var(--offset);\n left: var(--offset);\n right: var(--offset);\n bottom: var(--offset);\n box-shadow: 0 0 0 1px var(--color-primary-darkest);\n border-radius: calc(var(--radius) + 1px);\n filter: var(--theme-filter, none);\n}\n\n/* ========================================\n Color Picker Popup Content (Excalidraw Exact)\n ======================================== */\n\n.color-picker-content {\n display: flex;\n flex-direction: column;\n gap: 0.75rem; /* 12px between sections */\n outline: none;\n}\n\n.color-picker-content.properties-content {\n padding: 0.5rem; /* 8px padding inside popup */\n}\n\n/* Ensure all sections inside popup are visible */\n.color-picker-content > div {\n display: block;\n}\n\n.color-picker__heading {\n padding: 0 0.5rem;\n font-size: 0.75rem; /* 12px */\n text-align: left;\n color: var(--text-primary-color);\n margin-bottom: 0.5rem; /* 8px */\n font-weight: 400;\n}\n\n.color-picker-content--default {\n padding: 0.5rem; /* 8px */\n display: grid;\n grid-template-columns: repeat(5, 1.875rem); /* 5 columns, 30px each */\n grid-gap: 0.25rem; /* 4px gap */\n border-radius: 4px;\n}\n\n.color-picker-content--default:focus {\n outline: none;\n box-shadow: 0 0 0 2px var(--color-primary);\n}\n\n/* Shades section styling */\n.color-picker-content--default.shades {\n margin-top: 0;\n}\n\n/* Large buttons in popup (30px vs 22px in top picks) */\n.color-picker__button--large {\n --size: 1.875rem; /* 30px */\n width: var(--size) !important;\n height: var(--size) !important;\n}\n\n.color-picker__button.has-outline {\n box-shadow: inset 0 0 0 1px #d9d9d9;\n}\n\n/* No focus visible button (for shades placeholder) */\n.color-picker__button--no-focus-visible {\n border: 0;\n}\n\n.color-picker__button--no-focus-visible::after {\n display: none;\n}\n\n.color-picker__button--no-focus-visible:focus-visible {\n outline: none !important;\n}\n\n/* Transparent button (checkerboard pattern) */\n.color-picker__button.is-transparent {\n background-color: transparent !important;\n background-image:\n linear-gradient(45deg, #808080 25%, transparent 25%),\n linear-gradient(-45deg, #808080 25%, transparent 25%),\n linear-gradient(45deg, transparent 75%, #808080 75%),\n linear-gradient(-45deg, transparent 75%, #808080 75%);\n background-size: 8px 8px;\n background-position:\n 0 0,\n 0 4px,\n 4px -4px,\n -4px 0px;\n}\n\n.color-picker__button.is-transparent.has-outline {\n box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.3);\n}\n\n/* Hex input field (Excalidraw exact) */\n.color-picker__input-label {\n display: grid;\n grid-template-columns: auto 1fr auto auto;\n gap: 8px;\n align-items: center;\n border: 1px solid var(--default-border-color);\n border-radius: 8px;\n padding: 0 12px;\n margin: 8px;\n box-sizing: border-box;\n}\n\n.color-picker__input-label:focus-within {\n box-shadow: 0 0 0 1px var(--color-primary-darkest);\n border-radius: var(--border-radius-lg);\n}\n\n.color-picker__input-hash {\n padding: 0 0.25rem;\n color: var(--text-primary-color);\n}\n\n.color-picker-input {\n box-sizing: border-box;\n width: 100%;\n margin: 0;\n font-size: 0.875rem; /* 14px */\n font-family: inherit;\n background-color: transparent;\n color: var(--text-primary-color);\n border: 0;\n outline: none;\n height: var(--default-button-size); /* 2rem = 32px */\n letter-spacing: 0.4px;\n padding: 0.5rem 0.25rem;\n}\n\n.color-picker-input:focus-visible {\n box-shadow: none;\n}\n\n/* Hex input divider */\n.color-picker__input-divider {\n width: 1px;\n height: 1.25rem; /* 20px */\n background-color: var(--default-border-color);\n margin: 0;\n}\n\n/* Eye dropper trigger (Excalidraw exact) */\n.excalidraw-eye-dropper-trigger {\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--text-primary-color);\n transition: color 150ms ease;\n width: 1rem; /* 16px - fixed width */\n height: 1rem; /* 16px - fixed height */\n flex-shrink: 0; /* Don't shrink */\n}\n\n.excalidraw-eye-dropper-trigger:hover {\n color: var(--color-primary-darkest);\n}\n\n.excalidraw-eye-dropper-trigger svg {\n width: 1rem; /* 16px - Excalidraw exact */\n height: 1rem;\n}\n\n/* ========================================\n Range Slider (Excalidraw Exact)\n ======================================== */\n\n.range-wrapper {\n position: relative;\n padding-top: 8px;\n padding-bottom: 20px;\n overflow: visible;\n}\n\n.range-input {\n width: 100%;\n height: 6px;\n -webkit-appearance: none;\n background: var(--color-slider-track);\n border-radius: 3px;\n outline: none;\n cursor: pointer;\n}\n\n.range-input::-webkit-slider-thumb {\n -webkit-appearance: none;\n appearance: none;\n width: var(--slider-thumb-size); /* 16px */\n height: var(--slider-thumb-size);\n background: var(--color-primary);\n border-radius: 50%;\n cursor: pointer;\n border: 2px solid #fff;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);\n transition: transform 0.1s ease;\n}\n\n.range-input::-webkit-slider-thumb:hover {\n transform: scale(1.1);\n}\n\n.range-input::-webkit-slider-thumb:active {\n transform: scale(1.15);\n}\n\n.range-input::-moz-range-thumb {\n width: var(--slider-thumb-size);\n height: var(--slider-thumb-size);\n background: var(--color-primary);\n border-radius: 50%;\n cursor: pointer;\n border: 2px solid #fff;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);\n}\n\n.range-input::-moz-range-track {\n background: transparent;\n border: none;\n}\n\n.range-input:focus {\n outline: none;\n}\n\n.range-input:focus::-webkit-slider-thumb {\n box-shadow:\n 0 0 0 3px rgba(105, 101, 219, 0.3),\n 0 1px 3px rgba(0, 0, 0, 0.3);\n}\n\n/* Value bubble - always visible, follows thumb */\n.value-bubble {\n position: absolute;\n bottom: 0;\n transform: translateX(-50%);\n font-size: 12px;\n font-weight: 500;\n color: var(--color-primary);\n pointer-events: none;\n transition: left 0.05s ease-out;\n}\n\n.zero-label {\n position: absolute;\n bottom: 0;\n left: 0;\n font-size: 11px;\n color: var(--text-primary-color);\n opacity: 0.6;\n transition: opacity 0.15s ease;\n}\n\n.max-label {\n position: absolute;\n bottom: 0;\n right: 0;\n font-size: 11px;\n color: var(--text-primary-color);\n opacity: 0.6;\n transition: opacity 0.15s ease;\n}\n\n/* Hide min/max labels when value is close */\n.zero-label.hidden,\n.max-label.hidden {\n opacity: 0;\n}\n\n/* Ant Design Slider override */\n.slider-control .ant-slider {\n margin: 8px 0;\n}\n\n.slider-control .ant-slider-rail {\n background: var(--panel-border, #e5e5e5);\n}\n\n.slider-control .ant-slider-track {\n background: var(--panel-accent, #6965db);\n}\n\n.slider-control .ant-slider-handle::after {\n box-shadow: 0 0 0 2px var(--panel-accent, #6965db);\n}\n\n/* ========================================\n Select Dropdown (Excalidraw Style)\n ======================================== */\n\n.iconSelectList {\n display: flex;\n gap: 0.5rem;\n}\n\n.iconSelectList.buttonList {\n flex-wrap: wrap;\n column-gap: 0.5rem;\n row-gap: 0.5rem;\n}\n\n.iconSelectList button,\n.iconSelectList label {\n width: auto;\n min-width: 2rem;\n height: 2rem;\n padding: 0 0.25rem;\n border: 1px solid var(--panel-border, #e5e5e5);\n border-radius: 4px;\n background-color: var(--panel-bg, #ffffff);\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: all 150ms ease;\n}\n\n.iconSelectList button:hover,\n.iconSelectList label:hover {\n background-color: var(--panel-hover-bg, #f5f5f5);\n border-color: var(--panel-accent, #6965db);\n}\n\n.iconSelectList button svg,\n.iconSelectList label svg {\n stroke: currentColor;\n fill: none;\n}\n\n/* Ant Design Select override */\n.select-control .ant-select-selector {\n border-radius: 4px;\n border: 1px solid var(--panel-border, #e5e5e5);\n background: var(--panel-bg, #ffffff);\n font-size: 0.75rem;\n height: 2rem;\n}\n\n/* ========================================\n Layer Actions (Now handled by buttonList)\n ======================================== */\n/* .zIndexButton styles are now covered by .buttonList button styles above */\n\n/* ========================================\n ToolIcon Component (Excalidraw Exact)\n ======================================== */\n\n.ToolIcon {\n border-radius: var(--border-radius-lg);\n display: inline-flex;\n align-items: center;\n position: relative;\n cursor: pointer;\n -webkit-tap-highlight-color: transparent;\n user-select: none;\n}\n\n.ToolIcon_type_button {\n padding: 0;\n border: none;\n margin: 0;\n font-size: inherit;\n background-color: initial; /* transparent */\n}\n\n.ToolIcon_type_button:focus-visible {\n box-shadow: 0 0 0 2px var(--color-primary);\n}\n\n.ToolIcon_type_button:active {\n background-color: transparent; /* Button itself stays transparent */\n}\n\n.ToolIcon_type_button.ToolIcon--selected {\n background-color: transparent;\n}\n\n.ToolIcon__icon {\n box-sizing: border-box;\n width: var(--default-button-size); /* 2rem */\n height: var(--default-button-size);\n color: var(--icon-fill-color);\n display: flex;\n justify-content: center;\n align-items: center;\n border-radius: var(--border-radius-lg); /* 0.5rem */\n border-width: 1px;\n border-style: solid;\n border-color: var(--button-border); /* transparent */\n background-color: var(--button-bg); /* #f6f6f9 */\n transition: all 150ms ease;\n}\n\n.ToolIcon__icon:hover {\n background-color: var(--button-hover-bg); /* #f1f0ff */\n border-color: var(--default-border-color); /* #f1f0ff */\n}\n\n.ToolIcon__icon:active {\n background-color: var(--button-active-bg); /* #f1f0ff */\n border-color: var(--button-active-border); /* #4440bf */\n}\n\n.ToolIcon__icon[aria-disabled='true'] {\n background: initial;\n border: none;\n}\n\n.ToolIcon__icon[aria-disabled='true'] svg {\n color: var(--color-disabled, #c0c0c0);\n}\n\n.ToolIcon__icon svg {\n position: relative;\n width: var(--default-icon-size); /* 1rem */\n height: var(--default-icon-size);\n color: var(--icon-fill-color);\n}\n\n.ToolIcon_size_small .ToolIcon__icon {\n width: 2rem;\n height: 2rem;\n font-size: 0.8em;\n}\n\n.ToolIcon_size_medium .ToolIcon__icon {\n width: 2rem;\n height: 2rem;\n}\n\n/* Selected state for ToolIcon (matching buttonList .active) */\n.ToolIcon.active .ToolIcon__icon,\n.ToolIcon--selected .ToolIcon__icon {\n background-color: var(--color-surface-primary-container);\n border-color: var(--color-primary);\n box-shadow: 0 0 0 2px var(--color-primary);\n color: var(--color-on-primary-container);\n}\n\n.ToolIcon.active .ToolIcon__icon svg,\n.ToolIcon--selected .ToolIcon__icon svg {\n color: var(--color-on-primary-container);\n}\n\n/* Danger variant for delete actions */\n.ToolIcon.danger .ToolIcon__icon {\n color: #ff6b6b;\n}\n\n.ToolIcon.danger .ToolIcon__icon:hover {\n background-color: rgba(255, 107, 107, 0.15);\n border-color: #ff6b6b;\n}\n\n/* Danger variant active state (keep danger styling even when active) */\n.ToolIcon.danger.active .ToolIcon__icon,\n.ToolIcon.danger.ToolIcon--selected .ToolIcon__icon {\n background-color: rgba(255, 107, 107, 0.25);\n border-color: #ff6b6b;\n box-shadow: 0 0 0 2px #ff6b6b;\n color: #ff6b6b;\n}\n\n/* ========================================\n Action Icon Buttons (Legacy - to be removed)\n ======================================== */\n\n.action-icon-button {\n width: 2rem;\n height: 2rem;\n padding: 0;\n border: 1px solid var(--panel-border, #e5e5e5);\n border-radius: 4px;\n background-color: var(--panel-bg, #ffffff);\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: all 150ms ease;\n font-size: 1rem;\n color: var(--panel-text, #1e1e1e);\n}\n\n.action-icon-button:hover {\n background-color: var(--panel-hover-bg, #f5f5f5);\n border-color: var(--panel-accent, #6965db);\n}\n\n.action-icon-button:active {\n transform: scale(0.95);\n}\n\n.action-icon-button.danger {\n color: #ff6b6b;\n}\n\n.action-icon-button.danger:hover {\n background-color: rgba(255, 107, 107, 0.15);\n border-color: #ff6b6b;\n}\n\n/* ========================================\n Divider\n ======================================== */\n\n.property-divider {\n height: 1px;\n background: var(--panel-border, #e5e5e5);\n margin: 12px 0;\n}\n\n/* ========================================\n Property Sections\n ======================================== */\n\n.property-section {\n margin-bottom: 12px;\n}\n\n.property-section:last-child {\n margin-bottom: 0;\n}\n\n.property-control {\n margin-bottom: 12px;\n}\n\n.property-control:last-child {\n margin-bottom: 0;\n}\n\n/* ========================================\n Dark Theme (Excalidraw Exact)\n ======================================== */\n\n.theme-dark .property-panel {\n /* Dark theme colors */\n --island-bg-color: #121212;\n --button-bg: #363541;\n --button-hover-bg: #363541;\n --button-active-bg: #363541;\n --button-gray-1: #363636;\n --button-gray-2: #272727;\n --button-gray-3: #222;\n --default-border-color: #3a3a3a;\n --text-primary-color: #e0e0e0;\n --icon-fill-color: #e0e0e0;\n --color-slider-track: #3a3a3a;\n --color-slider-thumb: #b8b8b8;\n --button-border: transparent;\n}\n\n.theme-dark .property-panel.App-menu__left {\n --button-bg: var(--color-surface-high, #2a2a3a);\n}\n\n.theme-dark .property-panel.Island {\n box-shadow: 0 4px 16px rgba(0, 0, 0, 0.4);\n}\n\n/* ========================================\n Responsive\n ======================================== */\n\n@media (max-width: 768px) {\n .property-panel {\n width: 180px;\n top: 70px;\n left: 8px;\n }\n\n .property-panel-right {\n right: 8px;\n }\n}\n\n/* ========================================\n Utility Classes\n ======================================== */\n\n.property-panel-hidden {\n display: none;\n}\n\n.property-panel-compact {\n width: 160px;\n}\n\n.text-muted {\n color: var(--panel-text-secondary, #6b6b6b);\n font-size: 0.7rem;\n}\n\n.text-small {\n font-size: 0.7rem;\n}\n\n/* ========================================\n Inline Select (for button groups)\n ======================================== */\n\n.buttonList .inline-select {\n width: var(--default-button-size);\n height: var(--default-button-size);\n padding: 0;\n border: 1px solid var(--button-border);\n border-radius: var(--border-radius-lg);\n font-size: 0.65rem;\n text-align: center;\n text-align-last: center;\n background-color: var(--button-bg);\n color: var(--text-primary-color);\n cursor: pointer;\n flex-shrink: 0;\n appearance: none;\n -webkit-appearance: none;\n -moz-appearance: none;\n transition: all 150ms ease;\n}\n\n.buttonList .inline-select:hover {\n background-color: var(--button-hover-bg);\n border-color: var(--default-border-color);\n}\n\n.buttonList .inline-select:focus {\n outline: none;\n box-shadow: 0 0 0 2px var(--color-primary);\n}\n\n.buttonList .inline-select.active {\n background-color: var(--color-surface-primary-container);\n border-color: var(--color-primary);\n box-shadow: 0 0 0 2px var(--color-primary);\n color: var(--color-on-primary-container);\n}\n\n.buttonList .inline-select option {\n background-color: var(--island-bg-color);\n color: var(--text-primary-color);\n}\n\n/* ========================================\n Control Label (for Opacity slider)\n ======================================== */\n\n.control-label {\n display: block;\n font-size: 0.75rem;\n font-weight: 500;\n color: var(--text-primary-color, #e0e0e0);\n margin-bottom: 4px;\n}\n";
|
|
48093
48303
|
styleInject(css_248z$2);
|
|
48094
48304
|
|
|
48095
48305
|
var css_248z$1 = "#navTools,\n#modelTools,\n#settingsTools,\n#measureTools {\n display: none !important;\n visibility: hidden !important;\n}\n#guiviewer3d-toolbar {\n display: flex !important;\n align-items: center !important;\n justify-content: center !important;\n gap: 20px;\n position: fixed !important;\n bottom: 10px !important;\n left: 50% !important;\n transform: translateX(-50%) !important;\n width: auto !important;\n border-radius: 4px !important;\n padding: 8px 12px !important;\n}\n#custom-tool-group {\n display: flex !important;\n margin: 0 !important;\n padding: 0 !important;\n}\n#custom-pagination-group {\n display: flex;\n position: relative !important;\n margin: 0 !important;\n padding: 0 !important;\n transform: none !important;\n left: auto !important;\n}\n\n/* Export Combo Dropdown Styles */\n.export-combo-dropdown {\n position: absolute;\n bottom: 100%;\n left: 50%;\n transform: translateX(-50%);\n background: #2d2d2d;\n border-radius: 4px;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);\n min-width: 180px;\n padding: 4px 0;\n margin-bottom: 8px;\n z-index: 1000;\n}\n\n.export-combo-dropdown::after {\n content: '';\n position: absolute;\n bottom: -6px;\n left: 50%;\n transform: translateX(-50%);\n border-left: 6px solid transparent;\n border-right: 6px solid transparent;\n border-top: 6px solid #2d2d2d;\n}\n\n.export-combo-option {\n display: flex;\n align-items: center;\n padding: 8px 12px;\n cursor: pointer;\n transition: background-color 0.15s ease;\n color: #fff;\n font-size: 13px;\n white-space: nowrap;\n}\n\n.export-combo-option:hover {\n background-color: #3d3d3d;\n}\n\n.export-combo-option:active {\n background-color: #4d4d4d;\n}\n\n.export-combo-icon {\n margin-right: 8px;\n font-size: 16px;\n opacity: 0.8;\n}\n\n.export-combo-label {\n flex: 1;\n}\n\n/* Active state for combo button */\n.custom-export-combo-btn.active {\n background-color: #3d3d3d !important;\n}\n";
|
|
@@ -48352,21 +48562,26 @@ var MarkupToolbar = function MarkupToolbar(_ref) {
|
|
|
48352
48562
|
setActiveTool = _useState2[1];
|
|
48353
48563
|
// Refs
|
|
48354
48564
|
var toolbarRef = React.useRef(null);
|
|
48355
|
-
|
|
48356
|
-
//
|
|
48357
|
-
//
|
|
48565
|
+
// Activate Pen tool immediately on mount.
|
|
48566
|
+
// Edit mode is guaranteed active — ViewerForgePDF awaits enterEditMode() before
|
|
48567
|
+
// setting showMarkupToolbar=true, so no delay needed.
|
|
48358
48568
|
React.useEffect(function () {
|
|
48359
|
-
|
|
48360
|
-
|
|
48361
|
-
|
|
48362
|
-
|
|
48363
|
-
|
|
48364
|
-
|
|
48365
|
-
|
|
48569
|
+
drawingManager.setActiveTool(MARKUP_TOOLS.PEN);
|
|
48570
|
+
console.log('[MarkupToolbar] Activated Pen tool on mount');
|
|
48571
|
+
}, [drawingManager]);
|
|
48572
|
+
// Sync activeTool React state from Forge Viewer events.
|
|
48573
|
+
// Keeps the toolbar highlight correct if the active tool changes externally.
|
|
48574
|
+
React.useEffect(function () {
|
|
48575
|
+
var eventBus = EventBus.getInstance();
|
|
48576
|
+
var handleToolChanged = function handleToolChanged(_ref2) {
|
|
48577
|
+
var tool = _ref2.tool;
|
|
48578
|
+
setActiveTool(tool);
|
|
48579
|
+
};
|
|
48580
|
+
eventBus.on('drawing:toolChanged', handleToolChanged);
|
|
48366
48581
|
return function () {
|
|
48367
|
-
|
|
48582
|
+
eventBus.off('drawing:toolChanged', handleToolChanged);
|
|
48368
48583
|
};
|
|
48369
|
-
}, [
|
|
48584
|
+
}, []);
|
|
48370
48585
|
/**
|
|
48371
48586
|
* Handle tool selection
|
|
48372
48587
|
* Note: Edit mode is already managed by ViewerForgePDF, no need to check/enter here
|
|
@@ -48796,7 +49011,7 @@ var SliderControl = function SliderControl(_ref2) {
|
|
|
48796
49011
|
}, displayValue), /*#__PURE__*/React.createElement("div", {
|
|
48797
49012
|
className: 'zero-label'
|
|
48798
49013
|
}, "0"), /*#__PURE__*/React.createElement("div", {
|
|
48799
|
-
className: "max-label ".concat(displayValue
|
|
49014
|
+
className: "max-label ".concat(displayValue === max ? 'hidden' : '')
|
|
48800
49015
|
}, "100")));
|
|
48801
49016
|
};
|
|
48802
49017
|
/**
|
|
@@ -49213,7 +49428,9 @@ var ViewerForgePDF = function ViewerForgePDF(_ref) {
|
|
|
49213
49428
|
_ref$enableCustomMark = _ref.enableCustomMarkups,
|
|
49214
49429
|
enableCustomMarkups = _ref$enableCustomMark === void 0 ? false : _ref$enableCustomMark,
|
|
49215
49430
|
_ref$markupConfig = _ref.markupConfig,
|
|
49216
|
-
markupConfig = _ref$markupConfig === void 0 ? {} : _ref$markupConfig
|
|
49431
|
+
markupConfig = _ref$markupConfig === void 0 ? {} : _ref$markupConfig,
|
|
49432
|
+
_ref$toolbarOptions = _ref.toolbarOptions,
|
|
49433
|
+
toolbarOptions = _ref$toolbarOptions === void 0 ? {} : _ref$toolbarOptions;
|
|
49217
49434
|
// State for drawing functionality
|
|
49218
49435
|
var _useState = React.useState(null),
|
|
49219
49436
|
_useState2 = _slicedToArray(_useState, 2),
|