@volter/editor-threejs 0.5.212 → 0.5.214
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-node/serving.mjs +4 -20
- package/package.json +3 -5
- package/serving/animation-live-module.ts +4 -20
- package/src/animation/live-mixers.ts +1 -9
- package/src/kit/animation/three-clips-subject.ts +10 -50
- package/src/kit/authoring/component-instance-root.ts +2 -3
- package/src/kit/components/Object3DDocumentToolbar.tsx +1 -2
- package/src/kit/components/Object3DDocumentViewport.tsx +2 -4
- package/src/kit/components/StageHost.tsx +78 -208
- package/src/kit/components/ViewportViewMenu.tsx +1 -1
- package/src/kit/components/asset-viewers/EntityModelDocument.tsx +2 -4
- package/src/kit/components/asset-viewers/EnvironmentAssetDocument.tsx +4 -6
- package/src/kit/components/asset-viewers/LiveModuleDocument.tsx +7 -31
- package/src/kit/components/asset-viewers/LutAssetDocument.tsx +4 -6
- package/src/kit/components/asset-viewers/ModelAssetDocument.tsx +4 -8
- package/src/kit/components/asset-viewers/Object3DPreview.tsx +3 -19
- package/src/kit/components/asset-viewers/QuarksAssetDocument.tsx +4 -8
- package/src/kit/components/asset-viewers/ShaderAssetDocument.tsx +37 -55
- package/src/kit/components/object3d-contribution-surfaces.tsx +4 -2
- package/src/kit/components/stage-transform-tools.tsx +1 -2
- package/src/kit/editor-shell-store.ts +2 -26
- package/src/kit/editor-viewport.ts +11 -1
- package/src/kit/three-integration.ts +0 -2
- package/src/viewport-api.ts +4 -16
- package/src/viewport-door.ts +2 -38
- package/src/kit/components/world-root-binding.ts +0 -59
- package/src/kit/play-camera-flight.ts +0 -291
- package/src/kit/scene-document-viewport.ts +0 -51
- package/src/kit/viewport-surface-status.tsx +0 -44
|
@@ -1,291 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* THE PLAY ENTRY CAMERA FLIGHT — the Three integration's half of Play's immersive entry
|
|
3
|
-
* (`@volter/sdk/play-camera-flight`). The kit's transition owns the phases and the
|
|
4
|
-
* chrome; this owns the camera: the editor viewport flies along a Catmull-Rom spline from its
|
|
5
|
-
* preview pose to the AUTHORED game camera's pose, retargets to the game's live camera once it
|
|
6
|
-
* boots so the cross-fade is pixel-continuous, and restores the preview pose when Play ends. The
|
|
7
|
-
* flight reads the authored viewport's rig through the viewport door and rides its frame hook, so
|
|
8
|
-
* flight pacing rides the editor's own frame clock.
|
|
9
|
-
*/
|
|
10
|
-
import { registerPlayCameraFlight, type LiveCameraLookup } from '@volter/sdk/play-camera-flight';
|
|
11
|
-
import { onViewportFrame, viewportRig } from '../viewport-door';
|
|
12
|
-
import * as THREE from 'three';
|
|
13
|
-
import { threeStoreForHost } from './three-state';
|
|
14
|
-
|
|
15
|
-
/** Flight time scales mildly with distance so short hops feel snappy and
|
|
16
|
-
* cross-scene flights stay graceful, clamped to a tight band. */
|
|
17
|
-
export function flightDurationMs(distance: number): number {
|
|
18
|
-
return Math.min(1600, Math.max(800, 900 + distance * 25));
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export function easeInOutCubic(t: number): number {
|
|
22
|
-
return t < 0.5 ? 4 * t * t * t : 1 - (-2 * t + 2) ** 3 / 2;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Control points for the camera flight spline: start, two interior points
|
|
27
|
-
* forming a gentle arc, end. The arc lifts along world-up and bows slightly
|
|
28
|
-
* sideways, both proportional to (but clamped against) the travel distance —
|
|
29
|
-
* a short hop barely arcs, a long flight gets a visible swoop, and a
|
|
30
|
-
* degenerate zero-length flight returns a straight (stationary) curve.
|
|
31
|
-
*/
|
|
32
|
-
export function computeFlightControlPoints(
|
|
33
|
-
start: THREE.Vector3,
|
|
34
|
-
end: THREE.Vector3,
|
|
35
|
-
up: THREE.Vector3 = new THREE.Vector3(0, 1, 0),
|
|
36
|
-
): THREE.Vector3[] {
|
|
37
|
-
const travel = new THREE.Vector3().subVectors(end, start);
|
|
38
|
-
const distance = travel.length();
|
|
39
|
-
if (distance < 1e-6) {
|
|
40
|
-
return [start.clone(), start.clone(), end.clone(), end.clone()];
|
|
41
|
-
}
|
|
42
|
-
const lift = Math.min(distance * 0.18, 6);
|
|
43
|
-
// Side bias perpendicular to travel and up — gives the arc a slight bank
|
|
44
|
-
// instead of a purely vertical hump. Falls back to zero when travel is
|
|
45
|
-
// parallel to up (straight vertical flights just lift).
|
|
46
|
-
const side = new THREE.Vector3().crossVectors(travel, up);
|
|
47
|
-
if (side.lengthSq() > 1e-9) side.normalize().multiplyScalar(Math.min(distance * 0.08, 2.5));
|
|
48
|
-
else side.set(0, 0, 0);
|
|
49
|
-
const liftVec = up.clone().normalize().multiplyScalar(lift);
|
|
50
|
-
const p1 = start.clone().addScaledVector(travel, 0.3).add(liftVec).add(side);
|
|
51
|
-
const p2 = end
|
|
52
|
-
.clone()
|
|
53
|
-
.addScaledVector(travel, -0.3)
|
|
54
|
-
.addScaledVector(liftVec, 0.6)
|
|
55
|
-
.addScaledVector(side, 0.5);
|
|
56
|
-
return [start.clone(), p1, p2, end.clone()];
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/** The narrow store surface `resolveAuthoredCameraTarget` reads. */
|
|
60
|
-
export interface PlayCameraSourceStore {
|
|
61
|
-
readonly objectMap: ReadonlyMap<string, THREE.Object3D>;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
export interface AuthoredCameraTarget {
|
|
65
|
-
entityId: string;
|
|
66
|
-
position: [number, number, number];
|
|
67
|
-
quaternion: [number, number, number, number];
|
|
68
|
-
fov: number;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
/** Editor-only overlays (helpers, gizmos) live on layer 31 — never flight targets. */
|
|
72
|
-
const EDITOR_ONLY_LAYER_MASK = 1 << 31;
|
|
73
|
-
|
|
74
|
-
function isEditorOnlyOrGizmo(obj: THREE.Object3D): boolean {
|
|
75
|
-
return (obj.layers.mask & EDITOR_ONLY_LAYER_MASK) !== 0 || /gizmo/i.test(obj.name);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
/** Depth-first search for the first real camera in a subtree, skipping
|
|
79
|
-
* editor-only/gizmo branches wholesale. */
|
|
80
|
-
function findCameraInSubtree(obj: THREE.Object3D): THREE.Camera | null {
|
|
81
|
-
if (isEditorOnlyOrGizmo(obj)) return null;
|
|
82
|
-
if ((obj as Partial<THREE.Camera>).isCamera) return obj as THREE.Camera;
|
|
83
|
-
for (const child of obj.children) {
|
|
84
|
-
const found = findCameraInSubtree(child);
|
|
85
|
-
if (found) return found;
|
|
86
|
-
}
|
|
87
|
-
return null;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
function targetFromObject(
|
|
91
|
-
entityId: string,
|
|
92
|
-
obj: THREE.Object3D,
|
|
93
|
-
fov: number,
|
|
94
|
-
): AuthoredCameraTarget {
|
|
95
|
-
const position = new THREE.Vector3();
|
|
96
|
-
const quaternion = new THREE.Quaternion();
|
|
97
|
-
obj.getWorldPosition(position);
|
|
98
|
-
obj.getWorldQuaternion(quaternion);
|
|
99
|
-
return {
|
|
100
|
-
entityId,
|
|
101
|
-
position: position.toArray() as [number, number, number],
|
|
102
|
-
quaternion: quaternion.toArray() as [number, number, number, number],
|
|
103
|
-
fov,
|
|
104
|
-
};
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
/**
|
|
108
|
-
* Find the authored camera in the current editor scene outside editor-only and gizmo branches, and
|
|
109
|
-
* return its live world transform. Return null when the mapped object graph contains no camera.
|
|
110
|
-
*/
|
|
111
|
-
export function resolveAuthoredCameraTarget(
|
|
112
|
-
store: PlayCameraSourceStore,
|
|
113
|
-
): AuthoredCameraTarget | null {
|
|
114
|
-
for (const [id, obj] of store.objectMap) {
|
|
115
|
-
const camera = findCameraInSubtree(obj);
|
|
116
|
-
if (!camera) continue;
|
|
117
|
-
const perspective = camera as Partial<THREE.PerspectiveCamera>;
|
|
118
|
-
return targetFromObject(id, camera, perspective.isPerspectiveCamera ? perspective.fov! : 60);
|
|
119
|
-
}
|
|
120
|
-
return null;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
interface FlightRuntime {
|
|
124
|
-
startPos: THREE.Vector3;
|
|
125
|
-
startQuat: THREE.Quaternion;
|
|
126
|
-
startFov: number;
|
|
127
|
-
endPos: THREE.Vector3;
|
|
128
|
-
endQuat: THREE.Quaternion;
|
|
129
|
-
endFov: number;
|
|
130
|
-
curve: THREE.CatmullRomCurve3;
|
|
131
|
-
startedAt: number;
|
|
132
|
-
durationMs: number;
|
|
133
|
-
landed: boolean;
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
function rebuildCurve(flight: FlightRuntime): void {
|
|
137
|
-
flight.curve = new THREE.CatmullRomCurve3(
|
|
138
|
-
computeFlightControlPoints(flight.startPos, flight.endPos),
|
|
139
|
-
);
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
interface ActiveFlight {
|
|
143
|
-
readonly runtime: FlightRuntime;
|
|
144
|
-
readonly snapshot: { position: THREE.Vector3; target: THREE.Vector3; up: THREE.Vector3; fov: number };
|
|
145
|
-
readonly onLanded: () => void;
|
|
146
|
-
/** Live camera, registered at live-ready — the flight retargets to it
|
|
147
|
-
* each frame so the hand-off converges on whatever the project actually does
|
|
148
|
-
* with its camera during boot (follow rigs, SceneCamera components…). */
|
|
149
|
-
getLiveCamera: LiveCameraLookup | null;
|
|
150
|
-
/** Driving the camera: from `begin` until the game is on screen (`settle`) or Play ends. */
|
|
151
|
-
driving: boolean;
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
let _flight: ActiveFlight | null = null;
|
|
155
|
-
|
|
156
|
-
function begin(onLanded: () => void): boolean {
|
|
157
|
-
const viewport = viewportRig();
|
|
158
|
-
const objects = threeStoreForHost()?.objectMap;
|
|
159
|
-
const target = objects ? resolveAuthoredCameraTarget({ objectMap: objects }) : null;
|
|
160
|
-
if (!target || !viewport) return false;
|
|
161
|
-
const startPos = viewport.camera.position.clone();
|
|
162
|
-
const endPos = new THREE.Vector3().fromArray(target.position);
|
|
163
|
-
_flight = {
|
|
164
|
-
runtime: {
|
|
165
|
-
startPos,
|
|
166
|
-
startQuat: viewport.camera.quaternion.clone(),
|
|
167
|
-
startFov: viewport.camera.fov,
|
|
168
|
-
endPos,
|
|
169
|
-
endQuat: new THREE.Quaternion().fromArray(target.quaternion),
|
|
170
|
-
endFov: target.fov,
|
|
171
|
-
curve: new THREE.CatmullRomCurve3(computeFlightControlPoints(startPos, endPos)),
|
|
172
|
-
startedAt: performance.now(),
|
|
173
|
-
durationMs: flightDurationMs(startPos.distanceTo(endPos)),
|
|
174
|
-
landed: false,
|
|
175
|
-
},
|
|
176
|
-
snapshot: {
|
|
177
|
-
position: viewport.camera.position.clone(),
|
|
178
|
-
target: viewport.orbit.target.clone(),
|
|
179
|
-
up: viewport.camera.up.clone(),
|
|
180
|
-
fov: viewport.camera.fov,
|
|
181
|
-
},
|
|
182
|
-
onLanded,
|
|
183
|
-
getLiveCamera: null,
|
|
184
|
-
driving: true,
|
|
185
|
-
};
|
|
186
|
-
viewport.orbit.enabled = false;
|
|
187
|
-
return true;
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
/** After the flight, leave OrbitControls in a sane state at the landed pose
|
|
191
|
-
* so the viewport still orbits correctly during play. */
|
|
192
|
-
function settle(): void {
|
|
193
|
-
const viewport = viewportRig();
|
|
194
|
-
const active = _flight;
|
|
195
|
-
if (!active) return;
|
|
196
|
-
active.driving = false;
|
|
197
|
-
if (!viewport) return;
|
|
198
|
-
const camera = viewport.camera;
|
|
199
|
-
const forward = new THREE.Vector3(0, 0, -1).applyQuaternion(camera.quaternion);
|
|
200
|
-
const distance = Math.max(1, active.snapshot.position.distanceTo(active.snapshot.target));
|
|
201
|
-
viewport.orbit.target.copy(camera.position).addScaledVector(forward, distance);
|
|
202
|
-
// The orbit re-aims with the camera's up: the landed pose's own, so its roll stands.
|
|
203
|
-
camera.up.set(0, 1, 0).applyQuaternion(camera.quaternion);
|
|
204
|
-
viewport.orbit.enabled = true;
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
/** Restore the pre-play camera pose. */
|
|
208
|
-
function end(): void {
|
|
209
|
-
const active = _flight;
|
|
210
|
-
if (!active) return;
|
|
211
|
-
_flight = null;
|
|
212
|
-
const viewport = viewportRig();
|
|
213
|
-
if (!viewport) return;
|
|
214
|
-
const snap = active.snapshot;
|
|
215
|
-
viewport.camera.position.copy(snap.position);
|
|
216
|
-
viewport.orbit.target.copy(snap.target);
|
|
217
|
-
viewport.camera.up.copy(snap.up);
|
|
218
|
-
viewport.camera.lookAt(snap.target);
|
|
219
|
-
if (viewport.camera.fov !== snap.fov) {
|
|
220
|
-
viewport.camera.fov = snap.fov;
|
|
221
|
-
viewport.camera.updateProjectionMatrix();
|
|
222
|
-
}
|
|
223
|
-
viewport.orbit.enabled = true;
|
|
224
|
-
viewport.orbit.update();
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
const _liveCamPos = new THREE.Vector3();
|
|
228
|
-
const _liveCamQuat = new THREE.Quaternion();
|
|
229
|
-
|
|
230
|
-
/**
|
|
231
|
-
* Per-frame flight driver — called from the world root's stage's RAF loop right after
|
|
232
|
-
* `viewport.update(dt)` so the flight has final say over the camera pose.
|
|
233
|
-
*/
|
|
234
|
-
onViewportFrame(playTransitionFrame);
|
|
235
|
-
|
|
236
|
-
function playTransitionFrame(): void {
|
|
237
|
-
const active = _flight;
|
|
238
|
-
const viewport = viewportRig();
|
|
239
|
-
if (!active || !viewport || !active.driving) return;
|
|
240
|
-
const flight = active.runtime;
|
|
241
|
-
|
|
242
|
-
// Retarget to the live game camera once it exists (`track`).
|
|
243
|
-
// The kit hands the lane's lookup over unread; only an `Object3D` is a camera to converge on.
|
|
244
|
-
const found = active.getLiveCamera?.() ?? null;
|
|
245
|
-
const liveCamera = (found as Partial<THREE.Object3D> | null)?.isObject3D ? (found as THREE.Object3D) : null;
|
|
246
|
-
if (liveCamera) {
|
|
247
|
-
liveCamera.getWorldPosition(_liveCamPos);
|
|
248
|
-
liveCamera.getWorldQuaternion(_liveCamQuat);
|
|
249
|
-
if (_liveCamPos.distanceToSquared(flight.endPos) > 1e-8) {
|
|
250
|
-
flight.endPos.copy(_liveCamPos);
|
|
251
|
-
rebuildCurve(flight);
|
|
252
|
-
}
|
|
253
|
-
flight.endQuat.copy(_liveCamQuat);
|
|
254
|
-
const liveFov = (liveCamera as THREE.PerspectiveCamera).fov;
|
|
255
|
-
if (typeof liveFov === 'number') flight.endFov = liveFov;
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
const camera = viewport.camera;
|
|
259
|
-
if (flight.landed) {
|
|
260
|
-
// Holding/cross-fading: pin to the (possibly live-tracked) end pose.
|
|
261
|
-
camera.position.copy(flight.endPos);
|
|
262
|
-
camera.quaternion.copy(flight.endQuat);
|
|
263
|
-
if (camera.fov !== flight.endFov) {
|
|
264
|
-
camera.fov = flight.endFov;
|
|
265
|
-
camera.updateProjectionMatrix();
|
|
266
|
-
}
|
|
267
|
-
return;
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
const t = Math.min(1, (performance.now() - flight.startedAt) / flight.durationMs);
|
|
271
|
-
const eased = easeInOutCubic(t);
|
|
272
|
-
camera.position.copy(flight.curve.getPoint(eased));
|
|
273
|
-
camera.quaternion.slerpQuaternions(flight.startQuat, flight.endQuat, eased);
|
|
274
|
-
camera.fov = flight.startFov + (flight.endFov - flight.startFov) * eased;
|
|
275
|
-
camera.updateProjectionMatrix();
|
|
276
|
-
if (t >= 1) {
|
|
277
|
-
flight.landed = true;
|
|
278
|
-
active.onLanded();
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
export function registerThreePlayCameraFlight(): () => void {
|
|
283
|
-
return registerPlayCameraFlight({
|
|
284
|
-
begin,
|
|
285
|
-
track: (liveCamera) => {
|
|
286
|
-
if (_flight) _flight.getLiveCamera = liveCamera;
|
|
287
|
-
},
|
|
288
|
-
settle,
|
|
289
|
-
end,
|
|
290
|
-
});
|
|
291
|
-
}
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* THE SCENE'S VIEWPORT (`@volter/sdk/document-viewports`): the world
|
|
3
|
-
* stage draws the Scene through the session store's own camera, shading and
|
|
4
|
-
* grid, and frames the shell's selection. It keeps no selection of its own, so a
|
|
5
|
-
* view's selection is the shell's.
|
|
6
|
-
*/
|
|
7
|
-
import type { DocumentViewport } from '@volter/sdk/document-viewports';
|
|
8
|
-
import type { EditorShellStore } from './editor-shell-store';
|
|
9
|
-
import { viewGridVisible } from '@volter/sdk/viewport-presentation';
|
|
10
|
-
|
|
11
|
-
type ShadingMode = Parameters<EditorShellStore['setShadingMode']>[0];
|
|
12
|
-
|
|
13
|
-
const SCENE_MODES = new Set<string>(['solid', 'clay', 'unlit', 'wireframe', 'normals', 'overdraw']);
|
|
14
|
-
|
|
15
|
-
export function sceneDocumentViewport(store: EditorShellStore, documentId: string): DocumentViewport {
|
|
16
|
-
return {
|
|
17
|
-
read: () => {
|
|
18
|
-
const pose = store.cameraPose;
|
|
19
|
-
if (!pose) return null;
|
|
20
|
-
const { position, target } = pose;
|
|
21
|
-
return {
|
|
22
|
-
camera: {
|
|
23
|
-
position: { x: position.x, y: position.y, z: position.z },
|
|
24
|
-
target: { x: target.x, y: target.y, z: target.z },
|
|
25
|
-
...(pose.fov ? { fov: pose.fov } : {}),
|
|
26
|
-
},
|
|
27
|
-
diagnostic: store.shadingMode,
|
|
28
|
-
grid: viewGridVisible(documentId),
|
|
29
|
-
};
|
|
30
|
-
},
|
|
31
|
-
setDiagnostic: (diagnostic) => {
|
|
32
|
-
if (!SCENE_MODES.has(diagnostic)) return false;
|
|
33
|
-
store.setShadingMode(diagnostic as ShadingMode);
|
|
34
|
-
return true;
|
|
35
|
-
},
|
|
36
|
-
setCamera: (camera) => {
|
|
37
|
-
if (typeof camera !== 'string') {
|
|
38
|
-
store.shell.setCameraPose(camera.position, camera.target, camera.fov);
|
|
39
|
-
return true;
|
|
40
|
-
}
|
|
41
|
-
if (camera === 'isometric') return false;
|
|
42
|
-
store.shell.setViewPreset(camera);
|
|
43
|
-
return true;
|
|
44
|
-
},
|
|
45
|
-
frame: (target) => {
|
|
46
|
-
if (target === 'document') return false;
|
|
47
|
-
store.shell.focusOnSelection();
|
|
48
|
-
return true;
|
|
49
|
-
},
|
|
50
|
-
};
|
|
51
|
-
}
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The 3D board's empty-viewport vocabulary, reused by every other design
|
|
3
|
-
* surface that would otherwise sit blank while it builds. Scene's root-aware
|
|
4
|
-
* loading/failure/empty states live in `SurfaceStateOverlay`; this compact
|
|
5
|
-
* label remains for object/board construction whose subject is already known.
|
|
6
|
-
*
|
|
7
|
-
* Idle / building / ready is viewport STATE, not a new overlay channel —
|
|
8
|
-
* the board already owns this shape (`ThreeBoardDocument`: idle "Open this
|
|
9
|
-
* tab…", building "Settling N stories…"). Scene's first design
|
|
10
|
-
* mount and `Object3DDocumentViewport`'s first construct are the same wait
|
|
11
|
-
* with different subjects. Copy names the subject being prepared; it does not
|
|
12
|
-
* claim a narrower phase (such as physics settling) while indexing, mounting,
|
|
13
|
-
* bounds/layout, or renderer setup is actually in flight.
|
|
14
|
-
*/
|
|
15
|
-
|
|
16
|
-
import { themeVars } from '@volter/sdk/widgets';
|
|
17
|
-
import type { ReactNode } from 'react';
|
|
18
|
-
|
|
19
|
-
/** Fixed construct tail after the board scene exists — viewport-bind, not settle. */
|
|
20
|
-
export const OBJECT3D_SURFACE_BUILDING = 'Preparing the viewport…';
|
|
21
|
-
|
|
22
|
-
export function ViewportSurfaceStatus({
|
|
23
|
-
testId,
|
|
24
|
-
children,
|
|
25
|
-
}: {
|
|
26
|
-
readonly testId: string;
|
|
27
|
-
readonly children: ReactNode;
|
|
28
|
-
}) {
|
|
29
|
-
return (
|
|
30
|
-
<div
|
|
31
|
-
data-testid={testId}
|
|
32
|
-
style={{
|
|
33
|
-
position: 'absolute',
|
|
34
|
-
inset: 0,
|
|
35
|
-
padding: 16,
|
|
36
|
-
fontSize: 12,
|
|
37
|
-
color: themeVars.content.muted,
|
|
38
|
-
pointerEvents: 'none',
|
|
39
|
-
}}
|
|
40
|
-
>
|
|
41
|
-
{children}
|
|
42
|
-
</div>
|
|
43
|
-
);
|
|
44
|
-
}
|