@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.esm.js
CHANGED
|
@@ -2550,6 +2550,14 @@ var MarkupConverterService = /*#__PURE__*/function () {
|
|
|
2550
2550
|
if (shape === null || shape === void 0 ? void 0 : shape.text) {
|
|
2551
2551
|
attrs += " text=\"".concat(this.escapeXml(shape.text), "\"");
|
|
2552
2552
|
}
|
|
2553
|
+
// Add text-data for stamp/image types.
|
|
2554
|
+
// Forge's MarkupStamp.loadSvgData() reads style['text-data'] as the image SVG source.
|
|
2555
|
+
// Without this, Forge creates a blank (invisible) stamp when loadMarkups() + enterEditMode()
|
|
2556
|
+
// is used to restore stamps into the edit canvas (used by reloadEditCanvasWithMergedMarkups).
|
|
2557
|
+
if (forgeType === 'stamp' && (shape === null || shape === void 0 ? void 0 : shape.imageData)) {
|
|
2558
|
+
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>");
|
|
2559
|
+
attrs += " text-data=\"".concat(this.escapeXml(svgData), "\"");
|
|
2560
|
+
}
|
|
2553
2561
|
// Add font attributes.
|
|
2554
2562
|
// CRITICAL: The <metadata><markup_element font-size="..."/> is parsed by Forge's
|
|
2555
2563
|
// loadMarkups() as a COORDINATE-SPACE value (model units), NOT SVG pixel units.
|
|
@@ -2775,7 +2783,12 @@ var MarkupConverterService = /*#__PURE__*/function () {
|
|
|
2775
2783
|
var _h3 = size[1];
|
|
2776
2784
|
var x = -_w2 / 2;
|
|
2777
2785
|
var y = -_h3 / 2;
|
|
2778
|
-
|
|
2786
|
+
// Forge's markup SVG canvas uses a Y-up coordinate system.
|
|
2787
|
+
// Raster <image> pixels are always Y-down (screen space), so they appear
|
|
2788
|
+
// upside-down without a counter-flip. Append scale(1,-1) to flip the image
|
|
2789
|
+
// content back to the correct screen orientation for User B's overlay.
|
|
2790
|
+
// The hitarea rect does not need a flip — it is transparent and just tracks hits.
|
|
2791
|
+
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, "\"/>");
|
|
2779
2792
|
}
|
|
2780
2793
|
if (imgData === '__pending__') {
|
|
2781
2794
|
// Render a placeholder rectangle while image chunks are still arriving
|
|
@@ -34104,33 +34117,81 @@ function updateShapeAttributes(svgElement, element) {
|
|
|
34104
34117
|
}
|
|
34105
34118
|
// ========== Shape Creation Functions ==========
|
|
34106
34119
|
/**
|
|
34107
|
-
* Create arrow SVG element
|
|
34120
|
+
* Create arrow SVG element matching Forge Viewer's native arrow format.
|
|
34121
|
+
*
|
|
34122
|
+
* Forge Viewer renders arrows as a single filled <path> (shaft + arrowhead merged)
|
|
34123
|
+
* centered at the midpoint of the two endpoints and rotated to the correct angle.
|
|
34124
|
+
* This matches the native SVG:
|
|
34125
|
+
* <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"
|
|
34126
|
+
* transform="translate(cx, cy) rotate(angleDeg)" stroke-width="sw" fill="strokeColor" stroke="strokeColor"/>
|
|
34127
|
+
*
|
|
34128
|
+
* Geometry constants (in Forge coordinate units):
|
|
34129
|
+
* sw = stroke-width
|
|
34130
|
+
* hl = totalLength / 2 (half the arrow length, placed symmetrically)
|
|
34131
|
+
* hh = sw / 2 (shaft half-height)
|
|
34132
|
+
* ahh = 1.5 * sw (arrowhead half-height)
|
|
34133
|
+
* al = 3 * sw (arrowhead length along x-axis)
|
|
34134
|
+
* ni = 0.3 * sw (neck inset — small notch where shaft meets arrowhead)
|
|
34135
|
+
*
|
|
34108
34136
|
* @private
|
|
34109
34137
|
*/
|
|
34110
34138
|
function createArrowElement(element, ns) {
|
|
34111
34139
|
var _a;
|
|
34112
34140
|
var group = document.createElementNS(ns, 'g');
|
|
34113
34141
|
group.setAttribute('class', 'markup-arrow');
|
|
34114
|
-
|
|
34115
|
-
|
|
34142
|
+
group.setAttribute('cursor', 'inherit');
|
|
34143
|
+
group.setAttribute('pointer-events', 'painted');
|
|
34144
|
+
// Endpoint coordinates
|
|
34145
|
+
var x1 = 0,
|
|
34146
|
+
y1 = 0,
|
|
34147
|
+
x2 = 1,
|
|
34148
|
+
y2 = 0;
|
|
34116
34149
|
if (((_a = element.shape) === null || _a === void 0 ? void 0 : _a.points) && element.shape.points.length >= 4) {
|
|
34117
|
-
|
|
34118
|
-
|
|
34119
|
-
|
|
34120
|
-
|
|
34121
|
-
} else {
|
|
34122
|
-
|
|
34123
|
-
|
|
34124
|
-
|
|
34125
|
-
|
|
34126
|
-
|
|
34127
|
-
|
|
34128
|
-
|
|
34129
|
-
|
|
34130
|
-
|
|
34131
|
-
|
|
34132
|
-
|
|
34133
|
-
|
|
34150
|
+
x1 = element.shape.points[0];
|
|
34151
|
+
y1 = element.shape.points[1];
|
|
34152
|
+
x2 = element.shape.points[2];
|
|
34153
|
+
y2 = element.shape.points[3];
|
|
34154
|
+
} else if (element.size) {
|
|
34155
|
+
x2 = element.size[0];
|
|
34156
|
+
y2 = element.size[1];
|
|
34157
|
+
}
|
|
34158
|
+
var sw = element.style.sw || 0.025;
|
|
34159
|
+
var cx = (x1 + x2) / 2;
|
|
34160
|
+
var cy = (y1 + y2) / 2;
|
|
34161
|
+
var dx = x2 - x1;
|
|
34162
|
+
var dy = y2 - y1;
|
|
34163
|
+
var totalLength = Math.sqrt(dx * dx + dy * dy);
|
|
34164
|
+
var angleDeg = Math.atan2(dy, dx) * (180 / Math.PI);
|
|
34165
|
+
var hl = totalLength / 2;
|
|
34166
|
+
var hh = sw / 2;
|
|
34167
|
+
var ahh = 1.5 * sw;
|
|
34168
|
+
var al = 3 * sw;
|
|
34169
|
+
var ni = 0.3 * sw;
|
|
34170
|
+
// Shaft length must be positive; guard against arrows shorter than the arrowhead
|
|
34171
|
+
var shaftLen = Math.max(0, 2 * hl - al);
|
|
34172
|
+
// Arrow path: horizontal, pointing right (+x), centered at origin.
|
|
34173
|
+
// Apply transform="translate(cx,cy) rotate(angleDeg)" to position and orient.
|
|
34174
|
+
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(' ');
|
|
34175
|
+
var transform = "translate(".concat(cx, ", ").concat(cy, ") rotate(").concat(angleDeg, ")");
|
|
34176
|
+
var strokeColor = element.style.sc || 'rgba(0,0,0,1)';
|
|
34177
|
+
// Main arrow path (filled + stroked like native Forge Viewer arrow)
|
|
34178
|
+
var markupPath = document.createElementNS(ns, 'path');
|
|
34179
|
+
markupPath.setAttribute('id', 'markup');
|
|
34180
|
+
markupPath.setAttribute('d', d);
|
|
34181
|
+
markupPath.setAttribute('stroke-width', String(sw));
|
|
34182
|
+
markupPath.setAttribute('stroke', strokeColor);
|
|
34183
|
+
markupPath.setAttribute('fill', strokeColor);
|
|
34184
|
+
markupPath.setAttribute('transform', transform);
|
|
34185
|
+
group.appendChild(markupPath);
|
|
34186
|
+
// Transparent hit area with larger stroke-width for easier selection
|
|
34187
|
+
var hitPath = document.createElementNS(ns, 'path');
|
|
34188
|
+
hitPath.setAttribute('id', 'hitarea');
|
|
34189
|
+
hitPath.setAttribute('d', d);
|
|
34190
|
+
hitPath.setAttribute('fill', 'transparent');
|
|
34191
|
+
hitPath.setAttribute('stroke', 'transparent');
|
|
34192
|
+
hitPath.setAttribute('stroke-width', String(sw * 6.86));
|
|
34193
|
+
hitPath.setAttribute('transform', transform);
|
|
34194
|
+
group.appendChild(hitPath);
|
|
34134
34195
|
return group;
|
|
34135
34196
|
}
|
|
34136
34197
|
/**
|
|
@@ -34305,23 +34366,37 @@ function createCalloutElement(element, ns) {
|
|
|
34305
34366
|
return group;
|
|
34306
34367
|
}
|
|
34307
34368
|
/**
|
|
34308
|
-
* Create stamp/image SVG element
|
|
34309
|
-
*
|
|
34369
|
+
* Create stamp/image SVG element for collaborative rendering (User B).
|
|
34370
|
+
*
|
|
34371
|
+
* imageData is raw base64 (data URL) — no counter-transform needed here.
|
|
34372
|
+
* Forge's markup canvas is Y-up, so a plain <image> would appear upside-down.
|
|
34373
|
+
* We wrap it in a <g> and apply scale(1,-1) on the image to flip it into
|
|
34374
|
+
* correct screen orientation, matching what MarkupStamp renders locally.
|
|
34375
|
+
*
|
|
34376
|
+
* Position is CENTER, so offset the image by -w/2, -h/2.
|
|
34310
34377
|
* @private
|
|
34311
34378
|
*/
|
|
34312
34379
|
function createStampElement(element, ns) {
|
|
34313
34380
|
var _a;
|
|
34381
|
+
var group = document.createElementNS(ns, 'g');
|
|
34382
|
+
group.setAttribute('class', 'markup-stamp');
|
|
34383
|
+
var w = element.size[0];
|
|
34384
|
+
var h = element.size[1];
|
|
34314
34385
|
var image = document.createElementNS(ns, 'image');
|
|
34315
|
-
image.setAttribute('
|
|
34316
|
-
|
|
34317
|
-
image.setAttribute('
|
|
34318
|
-
image.setAttribute('
|
|
34319
|
-
image
|
|
34320
|
-
|
|
34386
|
+
image.setAttribute('x', String(-w / 2));
|
|
34387
|
+
image.setAttribute('y', String(-h / 2));
|
|
34388
|
+
image.setAttribute('width', String(w));
|
|
34389
|
+
image.setAttribute('height', String(h));
|
|
34390
|
+
// scale(1,-1) flips the image content vertically in-place (the image is centered at
|
|
34391
|
+
// the origin so scale(1,-1) keeps the bounding box in the same position while reversing
|
|
34392
|
+
// the pixel rows). This is needed because SVG <image> pixels are Y-down but Forge's
|
|
34393
|
+
// markup canvas is Y-up — without the flip the image appears upside-down.
|
|
34394
|
+
image.setAttribute('transform', "scale(1,-1)");
|
|
34321
34395
|
if ((_a = element.shape) === null || _a === void 0 ? void 0 : _a.imageData) {
|
|
34322
34396
|
image.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', element.shape.imageData);
|
|
34323
34397
|
}
|
|
34324
|
-
|
|
34398
|
+
group.appendChild(image);
|
|
34399
|
+
return group;
|
|
34325
34400
|
}
|
|
34326
34401
|
// ========== Helper Functions ==========
|
|
34327
34402
|
/**
|
|
@@ -34408,36 +34483,6 @@ function generateCloudPath(width, height, arcCount) {
|
|
|
34408
34483
|
d += ' Z';
|
|
34409
34484
|
return d;
|
|
34410
34485
|
}
|
|
34411
|
-
/**
|
|
34412
|
-
* Ensure arrowhead marker exists in SVG defs
|
|
34413
|
-
* @private
|
|
34414
|
-
*/
|
|
34415
|
-
var arrowMarkerCreated = false;
|
|
34416
|
-
function ensureArrowMarker(ns) {
|
|
34417
|
-
if (arrowMarkerCreated) return;
|
|
34418
|
-
var svg = document.querySelector('svg.markups-svg');
|
|
34419
|
-
if (!svg) return;
|
|
34420
|
-
var defs = svg.querySelector('defs');
|
|
34421
|
-
if (!defs) {
|
|
34422
|
-
defs = document.createElementNS(ns, 'defs');
|
|
34423
|
-
svg.insertBefore(defs, svg.firstChild);
|
|
34424
|
-
}
|
|
34425
|
-
if (!defs.querySelector('#arrowhead')) {
|
|
34426
|
-
var marker = document.createElementNS(ns, 'marker');
|
|
34427
|
-
marker.setAttribute('id', 'arrowhead');
|
|
34428
|
-
marker.setAttribute('markerWidth', '10');
|
|
34429
|
-
marker.setAttribute('markerHeight', '7');
|
|
34430
|
-
marker.setAttribute('refX', '9');
|
|
34431
|
-
marker.setAttribute('refY', '3.5');
|
|
34432
|
-
marker.setAttribute('orient', 'auto');
|
|
34433
|
-
var polygon = document.createElementNS(ns, 'polygon');
|
|
34434
|
-
polygon.setAttribute('points', '0 0, 10 3.5, 0 7');
|
|
34435
|
-
polygon.setAttribute('fill', 'inherit');
|
|
34436
|
-
marker.appendChild(polygon);
|
|
34437
|
-
defs.appendChild(marker);
|
|
34438
|
-
arrowMarkerCreated = true;
|
|
34439
|
-
}
|
|
34440
|
-
}
|
|
34441
34486
|
|
|
34442
34487
|
/**
|
|
34443
34488
|
* SVG Parser Utilities
|
|
@@ -36835,6 +36880,12 @@ var EditModeManager = /*#__PURE__*/function () {
|
|
|
36835
36880
|
this.onEditModeChange = null;
|
|
36836
36881
|
this.onClearCurrentTool = null;
|
|
36837
36882
|
this.onExtensionReloaded = null;
|
|
36883
|
+
// Tracks explicit user intent to be in edit mode.
|
|
36884
|
+
// Immune to markupsCore.editMode being temporarily null during changeEditMode() transitions.
|
|
36885
|
+
this.userIntendedEditMode = false;
|
|
36886
|
+
// Set to true by refreshExtensionReferences() when MarkupsCore was fully reloaded.
|
|
36887
|
+
// Consumed in enterEditMode() to restore savedMarkupsSvg into the fresh edit canvas.
|
|
36888
|
+
this.extensionWasReloaded = false;
|
|
36838
36889
|
// Track if page changed since last markup mode
|
|
36839
36890
|
// Used to force extension reload when entering markup mode after page change
|
|
36840
36891
|
this.pageChangedSinceLastMarkup = false;
|
|
@@ -36934,7 +36985,14 @@ var EditModeManager = /*#__PURE__*/function () {
|
|
|
36934
36985
|
value: function handleEditModeChanged(event) {
|
|
36935
36986
|
var _a;
|
|
36936
36987
|
var wasInEditMode = this.editMode;
|
|
36937
|
-
//
|
|
36988
|
+
// CRITICAL FIX: When switching tools, markupsCore.changeEditMode() fires
|
|
36989
|
+
// EVENT_EDITMODE_CHANGED with active:false while markupsCore.editMode is temporarily null.
|
|
36990
|
+
// Using userIntendedEditMode (set explicitly by enterEditMode/leaveEditMode) instead of
|
|
36991
|
+
// markupsCore.editMode avoids the race condition where the guard fails during transitions.
|
|
36992
|
+
if (event.active === false && this.userIntendedEditMode) {
|
|
36993
|
+
console.log('[EditModeManager] Ignoring editMode=false: user intentionally in edit mode (tool-switch transition)');
|
|
36994
|
+
return;
|
|
36995
|
+
}
|
|
36938
36996
|
var isActive = event.active === true || event.active !== false && !!((_a = this.context.markupsCore) === null || _a === void 0 ? void 0 : _a.editMode);
|
|
36939
36997
|
this.editMode = isActive;
|
|
36940
36998
|
console.log('[EditModeManager] handleEditModeChanged:', {
|
|
@@ -36963,10 +37021,16 @@ var EditModeManager = /*#__PURE__*/function () {
|
|
|
36963
37021
|
key: "enterEditMode",
|
|
36964
37022
|
value: function enterEditMode() {
|
|
36965
37023
|
return __awaiter(this, void 0, void 0, /*#__PURE__*/_regenerator().m(function _callee2() {
|
|
36966
|
-
var _t;
|
|
37024
|
+
var savedSvg, layerId, editLayerId, _yield$import$catch, patchForgeMarkupStampRestore, loaded, _t, _t2;
|
|
36967
37025
|
return _regenerator().w(function (_context2) {
|
|
36968
37026
|
while (1) switch (_context2.p = _context2.n) {
|
|
36969
37027
|
case 0:
|
|
37028
|
+
// Mark explicit intent BEFORE any async work so the guard in handleEditModeChanged
|
|
37029
|
+
// can filter out spurious active:false events fired during enterEditMode() itself.
|
|
37030
|
+
this.userIntendedEditMode = true;
|
|
37031
|
+
// CRITICAL: Re-fetch MarkupsCore extension reference before entering edit mode
|
|
37032
|
+
// After page change, the extension might have been reset and we need fresh reference
|
|
37033
|
+
// This is async because extension may need to be reloaded via loadExtension()
|
|
36970
37034
|
_context2.n = 1;
|
|
36971
37035
|
return this.refreshExtensionReferences();
|
|
36972
37036
|
case 1:
|
|
@@ -36981,15 +37045,65 @@ var EditModeManager = /*#__PURE__*/function () {
|
|
|
36981
37045
|
_context2.p = 3;
|
|
36982
37046
|
// Unload existing markups from view-only layer before entering edit mode
|
|
36983
37047
|
this.markupOpsManager.unloadMarkupsBeforeEditMode();
|
|
36984
|
-
//
|
|
37048
|
+
// CRITICAL: Pre-load saved markups into a named layer BEFORE calling
|
|
37049
|
+
// enterEditMode(). Forge's loadMarkups() explicitly rejects calls while
|
|
37050
|
+
// duringEditMode===true, so loading must happen in view mode. By passing
|
|
37051
|
+
// the same layerId to enterEditMode(layerId) the pre-loaded markups become
|
|
37052
|
+
// interactive in the edit canvas.
|
|
37053
|
+
//
|
|
37054
|
+
// Additionally, apply the Forge MarkupStamp patch so that when Forge's
|
|
37055
|
+
// createMarkupFromSVG creates a MarkupStamp from the loaded SVG it can
|
|
37056
|
+
// fall back to style['text-data'] (which we populate in setMetadata()) when
|
|
37057
|
+
// scriptSvgData is a DOM element that DOMParser cannot parse.
|
|
37058
|
+
savedSvg = this.markupOpsManager.getSavedMarkupsSvg();
|
|
37059
|
+
layerId = this.markupOpsManager.getLayerId();
|
|
37060
|
+
if (!(savedSvg && savedSvg.trim().length > 0)) {
|
|
37061
|
+
_context2.n = 7;
|
|
37062
|
+
break;
|
|
37063
|
+
}
|
|
37064
|
+
_context2.p = 4;
|
|
37065
|
+
_context2.n = 5;
|
|
37066
|
+
return Promise.resolve().then(function () { return StampMarkup; })["catch"](function () {
|
|
37067
|
+
return {
|
|
37068
|
+
patchForgeMarkupStampRestore: null
|
|
37069
|
+
};
|
|
37070
|
+
});
|
|
37071
|
+
case 5:
|
|
37072
|
+
_yield$import$catch = _context2.v;
|
|
37073
|
+
patchForgeMarkupStampRestore = _yield$import$catch.patchForgeMarkupStampRestore;
|
|
37074
|
+
patchForgeMarkupStampRestore === null || patchForgeMarkupStampRestore === void 0 ? void 0 : patchForgeMarkupStampRestore();
|
|
37075
|
+
// Ensure view mode is active (loadMarkups requires duringViewMode===true)
|
|
37076
|
+
if (!this.context.markupsCore.duringViewMode) {
|
|
37077
|
+
try {
|
|
37078
|
+
this.context.markupsCore.show();
|
|
37079
|
+
} catch (_e) {
|
|
37080
|
+
/* ignore — enterEditMode() will call show() internally */
|
|
37081
|
+
}
|
|
37082
|
+
}
|
|
37083
|
+
loaded = this.context.markupsCore.loadMarkups(savedSvg, layerId);
|
|
37084
|
+
if (loaded) {
|
|
37085
|
+
editLayerId = layerId;
|
|
37086
|
+
console.log('[EditModeManager] Pre-loaded saved markups into layer:', layerId);
|
|
37087
|
+
} else {
|
|
37088
|
+
console.warn('[EditModeManager] loadMarkups returned false — will enter clean edit mode');
|
|
37089
|
+
}
|
|
37090
|
+
_context2.n = 7;
|
|
37091
|
+
break;
|
|
37092
|
+
case 6:
|
|
37093
|
+
_context2.p = 6;
|
|
37094
|
+
_t = _context2.v;
|
|
37095
|
+
console.warn('[EditModeManager] Could not pre-load markups before edit mode:', _t);
|
|
37096
|
+
case 7:
|
|
37097
|
+
// Enter edit mode — with layerId when we pre-loaded (restores markups),
|
|
37098
|
+
// or without to start a clean empty canvas.
|
|
36985
37099
|
console.log('[EditModeManager] Calling markupsCore.enterEditMode()...');
|
|
36986
|
-
_context2.n =
|
|
36987
|
-
return this.context.markupsCore.enterEditMode();
|
|
36988
|
-
case
|
|
37100
|
+
_context2.n = 8;
|
|
37101
|
+
return this.context.markupsCore.enterEditMode(editLayerId);
|
|
37102
|
+
case 8:
|
|
36989
37103
|
console.log('[EditModeManager] markupsCore.enterEditMode() completed, svg:', !!this.context.markupsCore.svg);
|
|
36990
37104
|
// Verify that svg layer was created (can fail after page change)
|
|
36991
37105
|
if (this.context.markupsCore.svg) {
|
|
36992
|
-
_context2.n =
|
|
37106
|
+
_context2.n = 11;
|
|
36993
37107
|
break;
|
|
36994
37108
|
}
|
|
36995
37109
|
console.warn('[EditModeManager] svg layer is null after enterEditMode, retrying with delay...');
|
|
@@ -37000,29 +37114,32 @@ var EditModeManager = /*#__PURE__*/function () {
|
|
|
37000
37114
|
console.warn('[EditModeManager] Error leaving edit mode for retry:', e);
|
|
37001
37115
|
}
|
|
37002
37116
|
// Wait a bit for viewer to stabilize after page change
|
|
37003
|
-
_context2.n =
|
|
37117
|
+
_context2.n = 9;
|
|
37004
37118
|
return new Promise(function (resolve) {
|
|
37005
37119
|
return setTimeout(resolve, 100);
|
|
37006
37120
|
});
|
|
37007
|
-
case
|
|
37008
|
-
// Re-enter edit mode
|
|
37121
|
+
case 9:
|
|
37122
|
+
// Re-enter edit mode (use layerId again if we pre-loaded — the layer
|
|
37123
|
+
// survives leaveEditMode() since it only removes the edit canvas node)
|
|
37009
37124
|
console.log('[EditModeManager] Retrying enterEditMode after delay...');
|
|
37010
|
-
_context2.n =
|
|
37011
|
-
return this.context.markupsCore.enterEditMode();
|
|
37012
|
-
case
|
|
37125
|
+
_context2.n = 10;
|
|
37126
|
+
return this.context.markupsCore.enterEditMode(editLayerId);
|
|
37127
|
+
case 10:
|
|
37013
37128
|
console.log('[EditModeManager] Retry completed, svg:', !!this.context.markupsCore.svg);
|
|
37014
37129
|
if (this.context.markupsCore.svg) {
|
|
37015
|
-
_context2.n =
|
|
37130
|
+
_context2.n = 11;
|
|
37016
37131
|
break;
|
|
37017
37132
|
}
|
|
37018
37133
|
console.error('[EditModeManager] Failed to create svg layer after retry');
|
|
37019
37134
|
this.editMode = false;
|
|
37135
|
+
this.userIntendedEditMode = false;
|
|
37020
37136
|
return _context2.a(2);
|
|
37021
|
-
case
|
|
37137
|
+
case 11:
|
|
37022
37138
|
// Set editMode flag explicitly to true
|
|
37023
37139
|
this.editMode = true;
|
|
37024
37140
|
console.log('[EditModeManager] editMode flag set to true explicitly');
|
|
37025
37141
|
console.log('[EditModeManager] svg layer exists:', !!this.context.markupsCore.svg);
|
|
37142
|
+
this.extensionWasReloaded = false;
|
|
37026
37143
|
// Notify presence manager of edit mode state
|
|
37027
37144
|
if (this.onEditModeChange) {
|
|
37028
37145
|
this.onEditModeChange(true);
|
|
@@ -37031,17 +37148,18 @@ var EditModeManager = /*#__PURE__*/function () {
|
|
|
37031
37148
|
this.toolbarVisManager.hideDefaultToolbar();
|
|
37032
37149
|
this.eventBus.emit('drawing:editModeEntered');
|
|
37033
37150
|
console.log('[EditModeManager] Entered edit mode');
|
|
37034
|
-
_context2.n =
|
|
37151
|
+
_context2.n = 13;
|
|
37035
37152
|
break;
|
|
37036
|
-
case
|
|
37037
|
-
_context2.p =
|
|
37038
|
-
|
|
37039
|
-
console.error('[EditModeManager] Failed to enter edit mode:',
|
|
37153
|
+
case 12:
|
|
37154
|
+
_context2.p = 12;
|
|
37155
|
+
_t2 = _context2.v;
|
|
37156
|
+
console.error('[EditModeManager] Failed to enter edit mode:', _t2);
|
|
37040
37157
|
this.editMode = false;
|
|
37041
|
-
|
|
37158
|
+
this.userIntendedEditMode = false;
|
|
37159
|
+
case 13:
|
|
37042
37160
|
return _context2.a(2);
|
|
37043
37161
|
}
|
|
37044
|
-
}, _callee2, this, [[3,
|
|
37162
|
+
}, _callee2, this, [[4, 6], [3, 12]]);
|
|
37045
37163
|
}));
|
|
37046
37164
|
}
|
|
37047
37165
|
/**
|
|
@@ -37056,7 +37174,7 @@ var EditModeManager = /*#__PURE__*/function () {
|
|
|
37056
37174
|
key: "refreshExtensionReferences",
|
|
37057
37175
|
value: function refreshExtensionReferences() {
|
|
37058
37176
|
return __awaiter(this, void 0, void 0, /*#__PURE__*/_regenerator().m(function _callee3() {
|
|
37059
|
-
var viewer, extensionWasReloaded, markupsCore, markupsGui,
|
|
37177
|
+
var viewer, extensionWasReloaded, markupsCore, markupsGui, _t3, _t4, _t5, _t6, _t7;
|
|
37060
37178
|
return _regenerator().w(function (_context3) {
|
|
37061
37179
|
while (1) switch (_context3.p = _context3.n) {
|
|
37062
37180
|
case 0:
|
|
@@ -37087,8 +37205,8 @@ var EditModeManager = /*#__PURE__*/function () {
|
|
|
37087
37205
|
break;
|
|
37088
37206
|
case 4:
|
|
37089
37207
|
_context3.p = 4;
|
|
37090
|
-
|
|
37091
|
-
console.warn('[EditModeManager] Failed to unload stale MarkupsCore:',
|
|
37208
|
+
_t3 = _context3.v;
|
|
37209
|
+
console.warn('[EditModeManager] Failed to unload stale MarkupsCore:', _t3);
|
|
37092
37210
|
case 5:
|
|
37093
37211
|
if (markupsCore) {
|
|
37094
37212
|
_context3.n = 9;
|
|
@@ -37107,8 +37225,8 @@ var EditModeManager = /*#__PURE__*/function () {
|
|
|
37107
37225
|
break;
|
|
37108
37226
|
case 8:
|
|
37109
37227
|
_context3.p = 8;
|
|
37110
|
-
|
|
37111
|
-
console.error('[EditModeManager] Failed to reload MarkupsCore extension:',
|
|
37228
|
+
_t4 = _context3.v;
|
|
37229
|
+
console.error('[EditModeManager] Failed to reload MarkupsCore extension:', _t4);
|
|
37112
37230
|
case 9:
|
|
37113
37231
|
if (markupsCore) {
|
|
37114
37232
|
this.context.markupsCore = markupsCore;
|
|
@@ -37131,8 +37249,8 @@ var EditModeManager = /*#__PURE__*/function () {
|
|
|
37131
37249
|
break;
|
|
37132
37250
|
case 12:
|
|
37133
37251
|
_context3.p = 12;
|
|
37134
|
-
|
|
37135
|
-
console.warn('[EditModeManager] Failed to unload stale MarkupsGui:',
|
|
37252
|
+
_t5 = _context3.v;
|
|
37253
|
+
console.warn('[EditModeManager] Failed to unload stale MarkupsGui:', _t5);
|
|
37136
37254
|
case 13:
|
|
37137
37255
|
if (markupsGui) {
|
|
37138
37256
|
_context3.n = 17;
|
|
@@ -37150,8 +37268,8 @@ var EditModeManager = /*#__PURE__*/function () {
|
|
|
37150
37268
|
break;
|
|
37151
37269
|
case 16:
|
|
37152
37270
|
_context3.p = 16;
|
|
37153
|
-
|
|
37154
|
-
console.error('[EditModeManager] Failed to reload MarkupsGui extension:',
|
|
37271
|
+
_t6 = _context3.v;
|
|
37272
|
+
console.error('[EditModeManager] Failed to reload MarkupsGui extension:', _t6);
|
|
37155
37273
|
case 17:
|
|
37156
37274
|
if (markupsGui) {
|
|
37157
37275
|
this.context.markupsGui = markupsGui;
|
|
@@ -37175,16 +37293,20 @@ var EditModeManager = /*#__PURE__*/function () {
|
|
|
37175
37293
|
case 18:
|
|
37176
37294
|
// Notify listeners that extension was reloaded
|
|
37177
37295
|
// This allows ToolManager to reinitialize its ToolFactory with the new MarkupsCore
|
|
37178
|
-
if (extensionWasReloaded
|
|
37179
|
-
|
|
37180
|
-
this.
|
|
37296
|
+
if (extensionWasReloaded) {
|
|
37297
|
+
// Persist flag so enterEditMode() can reload savedMarkupsSvg into the fresh canvas
|
|
37298
|
+
this.extensionWasReloaded = true;
|
|
37299
|
+
if (this.onExtensionReloaded) {
|
|
37300
|
+
console.log('[EditModeManager] Notifying listeners of extension reload');
|
|
37301
|
+
this.onExtensionReloaded();
|
|
37302
|
+
}
|
|
37181
37303
|
}
|
|
37182
37304
|
_context3.n = 20;
|
|
37183
37305
|
break;
|
|
37184
37306
|
case 19:
|
|
37185
37307
|
_context3.p = 19;
|
|
37186
|
-
|
|
37187
|
-
console.error('[EditModeManager] Failed to refresh extension references:',
|
|
37308
|
+
_t7 = _context3.v;
|
|
37309
|
+
console.error('[EditModeManager] Failed to refresh extension references:', _t7);
|
|
37188
37310
|
case 20:
|
|
37189
37311
|
return _context3.a(2);
|
|
37190
37312
|
}
|
|
@@ -37198,19 +37320,24 @@ var EditModeManager = /*#__PURE__*/function () {
|
|
|
37198
37320
|
key: "leaveEditMode",
|
|
37199
37321
|
value: function leaveEditMode() {
|
|
37200
37322
|
var _this3 = this;
|
|
37323
|
+
this.userIntendedEditMode = false;
|
|
37201
37324
|
if (!this.context.markupsCore) {
|
|
37202
37325
|
console.warn('[EditModeManager] Cannot leave edit mode: MarkupsCore not available');
|
|
37203
37326
|
return;
|
|
37204
37327
|
}
|
|
37205
37328
|
try {
|
|
37206
|
-
// Save markups
|
|
37207
|
-
this.markupOpsManager.
|
|
37329
|
+
// Step 1: Save current edit-mode markups while still in edit mode
|
|
37330
|
+
this.markupOpsManager.saveMarkupsOnLeave(function () {
|
|
37208
37331
|
var _a;
|
|
37209
37332
|
return ((_a = _this3.context.markupsCore) === null || _a === void 0 ? void 0 : _a.generateData()) || '';
|
|
37210
37333
|
});
|
|
37211
|
-
// Leave edit mode (
|
|
37334
|
+
// Step 2: Leave edit mode (Forge clears its edit canvas)
|
|
37212
37335
|
this.context.markupsCore.leaveEditMode();
|
|
37213
37336
|
this.editMode = false;
|
|
37337
|
+
// Step 3: Load saved markups into view-only layer AFTER leaving edit mode.
|
|
37338
|
+
// CRITICAL: doing this BEFORE leaveEditMode() caused Forge to clear the
|
|
37339
|
+
// loaded layer during the leaveEditMode() call, making markups disappear.
|
|
37340
|
+
this.markupOpsManager.reloadMarkupsToViewLayer();
|
|
37214
37341
|
// Notify presence manager of edit mode state
|
|
37215
37342
|
if (this.onEditModeChange) {
|
|
37216
37343
|
this.onEditModeChange(false);
|
|
@@ -37443,6 +37570,22 @@ var MarkupOperationsManager = /*#__PURE__*/function () {
|
|
|
37443
37570
|
console.error('[MarkupOperationsManager] Failed to redo:', error);
|
|
37444
37571
|
}
|
|
37445
37572
|
}
|
|
37573
|
+
/**
|
|
37574
|
+
* Load savedMarkupsSvg into the view-only layer so markups are visible
|
|
37575
|
+
* when NOT in edit mode. Must be called AFTER markupsCore.leaveEditMode().
|
|
37576
|
+
*/
|
|
37577
|
+
}, {
|
|
37578
|
+
key: "reloadMarkupsToViewLayer",
|
|
37579
|
+
value: function reloadMarkupsToViewLayer() {
|
|
37580
|
+
if (!this.context.markupsCore) return;
|
|
37581
|
+
if (!this.savedMarkupsSvg || this.savedMarkupsSvg.trim().length === 0) return;
|
|
37582
|
+
try {
|
|
37583
|
+
this.context.markupsCore.loadMarkups(this.savedMarkupsSvg, this.layerId);
|
|
37584
|
+
console.log('[MarkupOperationsManager] Markups reloaded to view layer after leaveEditMode');
|
|
37585
|
+
} catch (error) {
|
|
37586
|
+
console.warn('[MarkupOperationsManager] Failed to reload markups to view layer:', error);
|
|
37587
|
+
}
|
|
37588
|
+
}
|
|
37446
37589
|
/**
|
|
37447
37590
|
* Unload markups from layer before entering edit mode
|
|
37448
37591
|
*/
|
|
@@ -37460,29 +37603,24 @@ var MarkupOperationsManager = /*#__PURE__*/function () {
|
|
|
37460
37603
|
}
|
|
37461
37604
|
}
|
|
37462
37605
|
/**
|
|
37463
|
-
* Save
|
|
37606
|
+
* Save markup SVG from edit mode into savedMarkupsSvg.
|
|
37607
|
+
* Does NOT call loadMarkups — that must happen AFTER markupsCore.leaveEditMode().
|
|
37608
|
+
* See reloadMarkupsToViewLayer().
|
|
37464
37609
|
*
|
|
37465
|
-
* @param generateData - Function
|
|
37610
|
+
* @param generateData - Function that returns SVG from current edit mode state
|
|
37466
37611
|
*/
|
|
37467
37612
|
}, {
|
|
37468
|
-
key: "
|
|
37469
|
-
value: function
|
|
37613
|
+
key: "saveMarkupsOnLeave",
|
|
37614
|
+
value: function saveMarkupsOnLeave(generateData) {
|
|
37470
37615
|
if (!this.context.markupsCore) return;
|
|
37471
|
-
// Check if markupsCore is in a valid state (svg layer exists)
|
|
37472
|
-
// This can be null if page changed or extension was reset
|
|
37473
37616
|
if (!this.context.markupsCore.svg) {
|
|
37474
37617
|
console.warn('[MarkupOperationsManager] MarkupsCore.svg is null, skipping save');
|
|
37475
37618
|
return;
|
|
37476
37619
|
}
|
|
37477
37620
|
try {
|
|
37478
|
-
// Save markups before leaving edit mode
|
|
37479
37621
|
var svgString = generateData();
|
|
37480
37622
|
this.savedMarkupsSvg = svgString || '';
|
|
37481
|
-
|
|
37482
|
-
if (this.savedMarkupsSvg && this.savedMarkupsSvg.trim().length > 0) {
|
|
37483
|
-
this.context.markupsCore.loadMarkups(this.savedMarkupsSvg, this.layerId);
|
|
37484
|
-
console.log('[MarkupOperationsManager] Markups saved and reloaded to preserve them');
|
|
37485
|
-
}
|
|
37623
|
+
console.log('[MarkupOperationsManager] Markups saved on leave:', this.savedMarkupsSvg.length, 'chars');
|
|
37486
37624
|
} catch (error) {
|
|
37487
37625
|
console.warn('[MarkupOperationsManager] Error saving markups on leave:', error);
|
|
37488
37626
|
}
|
|
@@ -45559,6 +45697,8 @@ function createMarkupStampClass() {
|
|
|
45559
45697
|
_classCallCheck(this, MarkupStamp);
|
|
45560
45698
|
_this = _callSuper(this, MarkupStamp, [id, editor, ['stroke-width', 'stroke-color', 'stroke-opacity', 'fill-color', 'fill-opacity']]);
|
|
45561
45699
|
_this.type = 'stamp';
|
|
45700
|
+
/** Raw base64 image data (data URL) for collaborative serialization */
|
|
45701
|
+
_this.imageData = '';
|
|
45562
45702
|
_this.type = 'stamp';
|
|
45563
45703
|
_this.customSVG = customSVG;
|
|
45564
45704
|
_this.addMarkupMetadata = avemcu.addMarkupMetadata.bind(_this);
|
|
@@ -45569,8 +45709,12 @@ function createMarkupStampClass() {
|
|
|
45569
45709
|
_this$getDimensions2 = _slicedToArray(_this$getDimensions, 2),
|
|
45570
45710
|
width = _this$getDimensions2[0],
|
|
45571
45711
|
height = _this$getDimensions2[1];
|
|
45572
|
-
|
|
45573
|
-
|
|
45712
|
+
// Extract raw base64 image data for collaborative serialization.
|
|
45713
|
+
// MarkupsCore serializers read markup.imageData to pass via compact JSON
|
|
45714
|
+
// to remote users (User B). Storing raw base64 (not the SVG wrapper)
|
|
45715
|
+
// means createStampElement can render it directly without any transform issues.
|
|
45716
|
+
var imgEl = customSVG.querySelector('image');
|
|
45717
|
+
_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')) || '';
|
|
45574
45718
|
// Copy SVG content
|
|
45575
45719
|
_this.group.innerHTML = customSVG.innerHTML;
|
|
45576
45720
|
// Create hit area for selection
|
|
@@ -45661,6 +45805,16 @@ function createMarkupStampClass() {
|
|
|
45661
45805
|
metadata.position = [this.position.x, this.position.y].join(' ');
|
|
45662
45806
|
metadata.size = [this.size.x, this.size.y].join(' ');
|
|
45663
45807
|
metadata.rotation = String(this.rotation);
|
|
45808
|
+
// Store image SVG as text-data so Forge's createMarkupFromSVG can restore
|
|
45809
|
+
// the stamp image when loadMarkups() is called (e.g. on re-entry to edit mode).
|
|
45810
|
+
// Forge's MarkupStamp.loadSvgData() reads style['text-data'] as fallback.
|
|
45811
|
+
if (this.imageData) {
|
|
45812
|
+
var _this$getDimensions3 = this.getDimensions(this.customSVG),
|
|
45813
|
+
_this$getDimensions4 = _slicedToArray(_this$getDimensions3, 2),
|
|
45814
|
+
w = _this$getDimensions4[0],
|
|
45815
|
+
h = _this$getDimensions4[1];
|
|
45816
|
+
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>");
|
|
45817
|
+
}
|
|
45664
45818
|
return this.addMarkupMetadata(this.shape, metadata);
|
|
45665
45819
|
}
|
|
45666
45820
|
}]);
|
|
@@ -45968,11 +46122,66 @@ function parseSVGString(svgString) {
|
|
|
45968
46122
|
}
|
|
45969
46123
|
/**
|
|
45970
46124
|
* Create SVG element with embedded image (base64)
|
|
45971
|
-
* This format is compatible with MarkupsCore
|
|
46125
|
+
* This format is compatible with MarkupsCore.
|
|
46126
|
+
*
|
|
46127
|
+
* NOTE: Do NOT apply a Y-flip transform to the <image> here.
|
|
46128
|
+
* MarkupStamp.group already applies scale(1/W, -1/H) which handles the Y-axis
|
|
46129
|
+
* flip for the Forge Y-up coordinate system. Adding a pre-flip would double-flip
|
|
46130
|
+
* the image causing it to appear upside-down for User A.
|
|
46131
|
+
* The collaborative overlay (User B) applies its own scale(1,-1) separately
|
|
46132
|
+
* via generateVisualElement() in MarkupConverterService.
|
|
45972
46133
|
*/
|
|
45973
46134
|
function createImageSVG(base64Data, width, height) {
|
|
45974
46135
|
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>");
|
|
45975
46136
|
}
|
|
46137
|
+
/**
|
|
46138
|
+
* Patch Forge's built-in MarkupStamp.prototype.loadSvgData so that when
|
|
46139
|
+
* createMarkupFromSVG passes the full child DOM element as svgData (which
|
|
46140
|
+
* cannot be parsed by DOMParser), the method falls back to style['text-data']
|
|
46141
|
+
* instead. Our setMetadata() stores the image SVG there so Forge can
|
|
46142
|
+
* properly restore stamp images when loadMarkups() → enterEditMode() is used.
|
|
46143
|
+
*
|
|
46144
|
+
* Safe to call multiple times — guarded by a _patched flag.
|
|
46145
|
+
*/
|
|
46146
|
+
function patchForgeMarkupStampRestore() {
|
|
46147
|
+
var _a, _b, _c;
|
|
46148
|
+
var avemc = getMarkupsCore();
|
|
46149
|
+
if (!avemc) return;
|
|
46150
|
+
// The class may be exposed directly on the Core namespace
|
|
46151
|
+
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);
|
|
46152
|
+
if (!ForgeMarkupStamp || typeof ((_c = ForgeMarkupStamp.prototype) === null || _c === void 0 ? void 0 : _c.loadSvgData) !== 'function') return;
|
|
46153
|
+
if (ForgeMarkupStamp.prototype.loadSvgData._patched) return;
|
|
46154
|
+
var originalLoadSvgData = ForgeMarkupStamp.prototype.loadSvgData;
|
|
46155
|
+
ForgeMarkupStamp.prototype.loadSvgData = function patchedLoadSvgData() {
|
|
46156
|
+
var _a;
|
|
46157
|
+
// When scriptSvgData is a DOM element (not a string), DOMParser cannot parse
|
|
46158
|
+
// it — fall back to style['text-data'] which contains the real image SVG.
|
|
46159
|
+
if (this.scriptSvgData && typeof this.scriptSvgData !== 'string') {
|
|
46160
|
+
var textData = (_a = this.style) === null || _a === void 0 ? void 0 : _a['text-data'];
|
|
46161
|
+
if (textData && typeof textData === 'string') {
|
|
46162
|
+
var saved = this.scriptSvgData;
|
|
46163
|
+
this.scriptSvgData = null; // force the fallback branch
|
|
46164
|
+
originalLoadSvgData.call(this);
|
|
46165
|
+
this.scriptSvgData = saved; // restore so other code (e.g. undo) still works
|
|
46166
|
+
return;
|
|
46167
|
+
}
|
|
46168
|
+
}
|
|
46169
|
+
originalLoadSvgData.call(this);
|
|
46170
|
+
};
|
|
46171
|
+
ForgeMarkupStamp.prototype.loadSvgData._patched = true;
|
|
46172
|
+
}
|
|
46173
|
+
|
|
46174
|
+
var StampMarkup = /*#__PURE__*/Object.freeze({
|
|
46175
|
+
__proto__: null,
|
|
46176
|
+
createImageSVG: createImageSVG,
|
|
46177
|
+
createMarkupStampClass: createMarkupStampClass,
|
|
46178
|
+
getEditModeStampClass: getEditModeStampClass,
|
|
46179
|
+
getStampCreateActionClass: getStampCreateActionClass,
|
|
46180
|
+
getStampDeleteActionClass: getStampDeleteActionClass,
|
|
46181
|
+
getStampUpdateActionClass: getStampUpdateActionClass,
|
|
46182
|
+
parseSVGString: parseSVGString,
|
|
46183
|
+
patchForgeMarkupStampRestore: patchForgeMarkupStampRestore
|
|
46184
|
+
});
|
|
45976
46185
|
|
|
45977
46186
|
/**
|
|
45978
46187
|
* Image tool for inserting images as markups
|
|
@@ -47339,7 +47548,6 @@ var DrawingManager = /*#__PURE__*/function () {
|
|
|
47339
47548
|
var _this = this;
|
|
47340
47549
|
var config = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
|
47341
47550
|
_classCallCheck(this, DrawingManager);
|
|
47342
|
-
this.eventBus = eventBus;
|
|
47343
47551
|
// Initialize context
|
|
47344
47552
|
this.context = {
|
|
47345
47553
|
viewer: viewer,
|
|
@@ -47418,7 +47626,10 @@ var DrawingManager = /*#__PURE__*/function () {
|
|
|
47418
47626
|
}, {
|
|
47419
47627
|
key: "setupEventListeners",
|
|
47420
47628
|
value: function setupEventListeners() {
|
|
47421
|
-
|
|
47629
|
+
// NOTE: 'drawing:toggle' is handled exclusively by ViewerForgePDF (React layer)
|
|
47630
|
+
// which orchestrates: enterEditMode() → setShowMarkupToolbar(true).
|
|
47631
|
+
// Subscribing here caused double-call to enterEditMode(), resetting Forge Viewer
|
|
47632
|
+
// to its default Arrow tool on every markup mode entry.
|
|
47422
47633
|
if (this.context.markupsCore) {
|
|
47423
47634
|
this.context.markupsCore.addEventListener('EVENT_EDITMODE_CHANGED', this.editModeManager.handleEditModeChanged.bind(this.editModeManager));
|
|
47424
47635
|
this.context.markupsCore.addEventListener('EVENT_MARKUP_SELECTED', this.propertyManager.handleMarkupSelected.bind(this.propertyManager));
|
|
@@ -48041,7 +48252,6 @@ var DrawingManager = /*#__PURE__*/function () {
|
|
|
48041
48252
|
this.collaborativeManager.destroy();
|
|
48042
48253
|
this.presenceManager.destroy();
|
|
48043
48254
|
// Remove event listeners
|
|
48044
|
-
this.eventBus.off('drawing:toggle', this.editModeManager.handleToggle.bind(this.editModeManager));
|
|
48045
48255
|
if (this.context.markupsCore) {
|
|
48046
48256
|
this.context.markupsCore.removeEventListener('EVENT_EDITMODE_CHANGED', this.editModeManager.handleEditModeChanged.bind(this.editModeManager));
|
|
48047
48257
|
this.context.markupsCore.removeEventListener('EVENT_MARKUP_SELECTED', this.propertyManager.handleMarkupSelected.bind(this.propertyManager));
|
|
@@ -48087,7 +48297,7 @@ function styleInject(css, ref) {
|
|
|
48087
48297
|
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";
|
|
48088
48298
|
styleInject(css_248z$3);
|
|
48089
48299
|
|
|
48090
|
-
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";
|
|
48300
|
+
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";
|
|
48091
48301
|
styleInject(css_248z$2);
|
|
48092
48302
|
|
|
48093
48303
|
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";
|
|
@@ -48350,21 +48560,26 @@ var MarkupToolbar = function MarkupToolbar(_ref) {
|
|
|
48350
48560
|
setActiveTool = _useState2[1];
|
|
48351
48561
|
// Refs
|
|
48352
48562
|
var toolbarRef = useRef(null);
|
|
48353
|
-
|
|
48354
|
-
//
|
|
48355
|
-
//
|
|
48563
|
+
// Activate Pen tool immediately on mount.
|
|
48564
|
+
// Edit mode is guaranteed active — ViewerForgePDF awaits enterEditMode() before
|
|
48565
|
+
// setting showMarkupToolbar=true, so no delay needed.
|
|
48356
48566
|
useEffect(function () {
|
|
48357
|
-
|
|
48358
|
-
|
|
48359
|
-
|
|
48360
|
-
|
|
48361
|
-
|
|
48362
|
-
|
|
48363
|
-
|
|
48567
|
+
drawingManager.setActiveTool(MARKUP_TOOLS.PEN);
|
|
48568
|
+
console.log('[MarkupToolbar] Activated Pen tool on mount');
|
|
48569
|
+
}, [drawingManager]);
|
|
48570
|
+
// Sync activeTool React state from Forge Viewer events.
|
|
48571
|
+
// Keeps the toolbar highlight correct if the active tool changes externally.
|
|
48572
|
+
useEffect(function () {
|
|
48573
|
+
var eventBus = EventBus.getInstance();
|
|
48574
|
+
var handleToolChanged = function handleToolChanged(_ref2) {
|
|
48575
|
+
var tool = _ref2.tool;
|
|
48576
|
+
setActiveTool(tool);
|
|
48577
|
+
};
|
|
48578
|
+
eventBus.on('drawing:toolChanged', handleToolChanged);
|
|
48364
48579
|
return function () {
|
|
48365
|
-
|
|
48580
|
+
eventBus.off('drawing:toolChanged', handleToolChanged);
|
|
48366
48581
|
};
|
|
48367
|
-
}, [
|
|
48582
|
+
}, []);
|
|
48368
48583
|
/**
|
|
48369
48584
|
* Handle tool selection
|
|
48370
48585
|
* Note: Edit mode is already managed by ViewerForgePDF, no need to check/enter here
|
|
@@ -48794,7 +49009,7 @@ var SliderControl = function SliderControl(_ref2) {
|
|
|
48794
49009
|
}, displayValue), /*#__PURE__*/React.createElement("div", {
|
|
48795
49010
|
className: 'zero-label'
|
|
48796
49011
|
}, "0"), /*#__PURE__*/React.createElement("div", {
|
|
48797
|
-
className: "max-label ".concat(displayValue
|
|
49012
|
+
className: "max-label ".concat(displayValue === max ? 'hidden' : '')
|
|
48798
49013
|
}, "100")));
|
|
48799
49014
|
};
|
|
48800
49015
|
/**
|
|
@@ -49211,7 +49426,9 @@ var ViewerForgePDF = function ViewerForgePDF(_ref) {
|
|
|
49211
49426
|
_ref$enableCustomMark = _ref.enableCustomMarkups,
|
|
49212
49427
|
enableCustomMarkups = _ref$enableCustomMark === void 0 ? false : _ref$enableCustomMark,
|
|
49213
49428
|
_ref$markupConfig = _ref.markupConfig,
|
|
49214
|
-
markupConfig = _ref$markupConfig === void 0 ? {} : _ref$markupConfig
|
|
49429
|
+
markupConfig = _ref$markupConfig === void 0 ? {} : _ref$markupConfig,
|
|
49430
|
+
_ref$toolbarOptions = _ref.toolbarOptions,
|
|
49431
|
+
toolbarOptions = _ref$toolbarOptions === void 0 ? {} : _ref$toolbarOptions;
|
|
49215
49432
|
// State for drawing functionality
|
|
49216
49433
|
var _useState = useState(null),
|
|
49217
49434
|
_useState2 = _slicedToArray(_useState, 2),
|