@vertexvis/viewer-toolkit-react 0.0.2-canary.2 → 0.0.2-canary.3

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.
@@ -3,29 +3,29 @@
3
3
  var jsxRuntime = require('react/jsx-runtime');
4
4
  var uiReact = require('@vertexvis/ui-react');
5
5
  var classNames = require('classnames');
6
- var React = require('react');
7
- var utils = require('@vertexvis/utils');
8
6
  var recoil = require('recoil');
9
- var geometry = require('@vertexvis/geometry');
10
7
  var Pino = require('pino');
8
+ var geometry = require('@vertexvis/geometry');
9
+ var utils = require('@vertexvis/utils');
10
+ var React = require('react');
11
11
  var viewerReact = require('@vertexvis/viewer-react');
12
12
  var loader = require('@vertexvis/viewer/loader');
13
13
 
14
14
  function _interopNamespaceDefault(e) {
15
- var n = Object.create(null);
16
- if (e) {
17
- Object.keys(e).forEach(function (k) {
18
- if (k !== 'default') {
19
- var d = Object.getOwnPropertyDescriptor(e, k);
20
- Object.defineProperty(n, k, d.get ? d : {
21
- enumerable: true,
22
- get: function () { return e[k]; }
23
- });
24
- }
15
+ var n = Object.create(null);
16
+ if (e) {
17
+ Object.keys(e).forEach(function (k) {
18
+ if (k !== 'default') {
19
+ var d = Object.getOwnPropertyDescriptor(e, k);
20
+ Object.defineProperty(n, k, d.get ? d : {
21
+ enumerable: true,
22
+ get: function () { return e[k]; }
25
23
  });
26
- }
27
- n.default = e;
28
- return Object.freeze(n);
24
+ }
25
+ });
26
+ }
27
+ n.default = e;
28
+ return Object.freeze(n);
29
29
  }
30
30
 
31
31
  var React__namespace = /*#__PURE__*/_interopNamespaceDefault(React);
@@ -64,539 +64,240 @@ const VertexResizableContent = ({ displayShadow, heading, id, initialScale, posi
64
64
  }), children: children })] }) }));
65
65
  };
66
66
 
67
- // DEPRECATED - avoid if possible
68
- const useRecoilReducer = ({ reducer, atom, }) => {
69
- const state = recoil.useRecoilValue(atom);
70
- const dispatch = useRecoilReducerDispatch({
71
- reducer,
72
- atom,
73
- });
74
- return [state, dispatch];
75
- };
76
- // DEPRECATED - avoid if possible
77
- const useRecoilReducerDispatch = ({ reducer, atom, }) => {
78
- const dispatch = recoil.useRecoilCallback(({ set }) => async (action) => {
79
- set(atom, (previousValue) => reducer(previousValue, action));
80
- }, []);
81
- return dispatch;
82
- };
67
+ function contextMenuItemIsRow(item) {
68
+ var _a;
69
+ return item != null && ((_a = item === null || item === void 0 ? void 0 : item.node) === null || _a === void 0 ? void 0 : _a.id) != null;
70
+ }
71
+ const contextMenuActive = recoil.atom({
72
+ key: 'contextMenuActive',
73
+ default: undefined,
74
+ });
75
+ const contextMenuPosition = recoil.atom({
76
+ key: 'contextMenuPosition',
77
+ default: undefined,
78
+ });
79
+ const contextMenuTarget = recoil.atom({
80
+ key: 'contextMenuTarget',
81
+ default: undefined,
82
+ });
83
+ const contextMenuItem = recoil.atom({
84
+ key: 'contextMenuItem',
85
+ default: undefined,
86
+ });
87
+ const contextMenuActions = recoil.atom({
88
+ key: 'contextMenuActions',
89
+ default: [],
90
+ });
91
+ const contextMenuActivePosition = recoil.selector({
92
+ key: 'contextMenuActivePosition',
93
+ get: ({ get }) => get(contextMenuActive) != null ? get(contextMenuPosition) : undefined,
94
+ });
83
95
 
84
- const isInputElement = (target) => {
85
- const isAutoResizeTextarea = target instanceof HTMLElement &&
86
- target.tagName === 'VERTEX-AUTO-RESIZE-TEXTAREA';
87
- const isTextField = target instanceof HTMLElement && target.tagName === 'VERTEX-TEXTFIELD';
88
- const isContentEditable = target instanceof HTMLElement && target.contentEditable === 'true';
89
- const isSceneTreeSearch = target instanceof HTMLElement &&
90
- target.tagName === 'VERTEX-SCENE-TREE-SEARCH';
91
- const isInput = target instanceof HTMLInputElement || target instanceof HTMLTextAreaElement;
92
- const isVertexViewerPinTool = target instanceof HTMLElement &&
93
- target.tagName === 'VERTEX-VIEWER-PIN-TOOL';
94
- const isVertexViewerTransformWidget = target instanceof HTMLElement &&
95
- target.tagName === 'VERTEX-VIEWER-TRANSFORM-WIDGET';
96
- return (isAutoResizeTextarea ||
97
- isTextField ||
98
- isContentEditable ||
99
- isSceneTreeSearch ||
100
- isInput ||
101
- isVertexViewerPinTool ||
102
- isVertexViewerTransformWidget);
96
+ /******************************************************************************
97
+ Copyright (c) Microsoft Corporation.
98
+
99
+ Permission to use, copy, modify, and/or distribute this software for any
100
+ purpose with or without fee is hereby granted.
101
+
102
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
103
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
104
+ AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
105
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
106
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
107
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
108
+ PERFORMANCE OF THIS SOFTWARE.
109
+ ***************************************************************************** */
110
+ /* global Reflect, Promise, SuppressedError, Symbol, Iterator */
111
+
112
+
113
+ function __rest(s, e) {
114
+ var t = {};
115
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
116
+ t[p] = s[p];
117
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
118
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
119
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
120
+ t[p[i]] = s[p[i]];
121
+ }
122
+ return t;
123
+ }
124
+
125
+ typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
126
+ var e = new Error(message);
127
+ return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
103
128
  };
104
129
 
105
- const keyBindings = recoil.atom({
106
- key: 'keyBindings',
107
- default: {
108
- applyBindings: [],
109
- bindings: {},
110
- pressed: {},
130
+ // Create a new logger instance
131
+ const pinoLogger = Pino({
132
+ formatters: {
133
+ level(level) {
134
+ return { level };
135
+ },
111
136
  },
112
137
  });
113
- function reducer(state, action) {
114
- var _a, _b, _c, _d;
115
- switch (action.type) {
116
- case 'push-key-binding':
117
- const toAdd = (_a = state.bindings[action.binding.keyBind]) === null || _a === void 0 ? void 0 : _a.find((b) => b.id === action.binding.id);
118
- return toAdd != null
119
- ? state
120
- : Object.assign(Object.assign({}, state), { bindings: Object.assign(Object.assign({}, state.bindings), { [action.binding.keyBind]: [
121
- ...((_b = state.bindings[action.binding.keyBind]) !== null && _b !== void 0 ? _b : []),
122
- action.binding,
123
- ] }) });
124
- case 'remove-key-binding':
125
- const toRemove = (_c = state.bindings[action.binding.keyBind]) === null || _c === void 0 ? void 0 : _c.find((b) => b.id === action.binding.id);
126
- return toRemove == null
127
- ? state
128
- : Object.assign(Object.assign({}, state), { bindings: Object.assign(Object.assign({}, state.bindings), { [action.binding.keyBind]: ((_d = state.bindings[action.binding.keyBind]) !== null && _d !== void 0 ? _d : []).filter((b) => b.id !== action.binding.id) }) });
129
- case 'add-apply-key-binding':
130
- return Object.assign(Object.assign({}, state), { applyBindings: [...state.applyBindings, action.binding] });
131
- case 'remove-apply-key-binding':
132
- return Object.assign(Object.assign({}, state), { applyBindings: state.applyBindings.filter((binding) => binding.id !== action.id) });
133
- case 'set-key-pressed':
134
- return Object.assign(Object.assign({}, state), { applyBindings: state.applyBindings.map((binding) => (Object.assign(Object.assign({}, binding), { active: binding.keyBind != null &&
135
- allPressed(binding.keyBind, state.pressed) }))), pressed: Object.assign(Object.assign({}, state.pressed), { [action.key]: action.pressed }), lastPressed: action.pressed ? action.key : undefined });
136
- }
137
- }
138
- const useKeyBindingState = () => {
139
- return useRecoilReducer({
140
- reducer,
141
- atom: keyBindings,
142
- });
138
+ const logger = {
139
+ error: (message, error) => {
140
+ if (error != null) {
141
+ pinoLogger.error(error, message);
142
+ }
143
+ else {
144
+ pinoLogger.error(message);
145
+ }
146
+ },
147
+ info: (message, obj) => {
148
+ if (obj != null) {
149
+ pinoLogger.info(obj, message);
150
+ }
151
+ else {
152
+ pinoLogger.info(message);
153
+ }
154
+ },
155
+ warn: (message, err) => {
156
+ if (err != null) {
157
+ pinoLogger.warn(err, message);
158
+ }
159
+ else {
160
+ pinoLogger.warn(message);
161
+ }
162
+ },
163
+ debug: (message, obj) => {
164
+ if (obj != null) {
165
+ pinoLogger.debug(obj, message);
166
+ }
167
+ else {
168
+ pinoLogger.debug(message);
169
+ }
170
+ },
143
171
  };
144
- function pressedValue(keyBind, pressed) {
145
- return keyBind.includes('!')
146
- ? !pressed[keyBind.replace('!', '')] &&
147
- !pressed[keyBind.replace('!', '').toLowerCase()]
148
- : pressed[keyBind] || pressed[keyBind.toLowerCase()];
149
- }
150
- function isPressed(keyBind, pressed) {
151
- const keys = keyBind.split('||');
152
- return keys.length > 1
153
- ? keys.some((key) => pressedValue(key, pressed))
154
- : pressedValue(keys[0], pressed);
155
- }
156
- function allPressed(keyBind, pressed) {
157
- const keys = keyBind.split('+');
158
- return keys.every((key) => isPressed(key, pressed));
159
- }
160
- function matchingSingleFnBindings(applyBindings, pressed, lastPressed) {
161
- return applyBindings
162
- .filter((binding) => !binding.repeat)
163
- .filter((binding) => {
164
- var _a;
165
- return binding.keyBind != null &&
166
- lastPressed != null &&
167
- ((_a = binding.keyBind) === null || _a === void 0 ? void 0 : _a.includes(lastPressed)) &&
168
- allPressed(binding.keyBind, pressed);
169
- })
170
- .map((binding) => binding.fn);
171
- }
172
- function matchingOffBindings(applyBindings, pressed, lastPressed) {
173
- return applyBindings
174
- .filter((binding) => binding.off &&
175
- binding.active &&
176
- binding.keyBind != null &&
177
- lastPressed == null &&
178
- !allPressed(binding.keyBind, pressed))
179
- .map((binding) => binding.off);
172
+ /* eslint-enable @typescript-eslint/no-explicit-any */
173
+
174
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
175
+ class DefaultRecoilDeps {
180
176
  }
181
177
  /**
182
- * Depends on `useKeyBindings`.
183
- *
184
- * Adds a global key binding. Any key binding
185
- * added this way will listen to global state for pressed
186
- * keys, and executed whenever the key state matches the
187
- * provided `keyBind`.
178
+ * Returns a Recoil callback that can be used for action hooks.
188
179
  *
189
- * @param binding - The `ApplyKeyBinding` to add.
190
- */
191
- const useApplyKeyBinding = (binding) => {
192
- const [state, dispatch] = useKeyBindingState();
193
- React.useEffect(() => {
194
- const id = utils.UUID.create();
195
- dispatch({
196
- type: 'add-apply-key-binding',
197
- binding: Object.assign(Object.assign({}, binding), { id, active: binding.keyBind != null && allPressed(binding.keyBind, state.pressed) }),
198
- });
199
- return () => {
200
- dispatch({
201
- type: 'remove-apply-key-binding',
202
- id,
203
- });
204
- };
205
- }, [binding.fn, binding.off, binding.keyBind, binding.repeat]);
206
- };
207
- /**
208
- * Depends on `useKeyBindings`.
180
+ * This uses `useRecoilCallback` but the deps implementation differs from
181
+ * Recoil. If no deps are provided, then it will always return the same function
182
+ * vs returning a new function.
209
183
  *
210
- * Adds a stack-based key binding. Any key binding
211
- * added this way will be added to an existing (or new)
212
- * stack for the specified `keyBind`.
184
+ * If you want to use the original Recoil callback behavior, pass
185
+ * `DefaultRecoilCallbackDepsBehavior`.
213
186
  *
214
- * Provided `binding`s will be added and cancelled based
215
- * on the specified `addPredicate` and `cancelPredicate`
216
- * respectively. These predicates are evaluated any time
217
- * that the `deps` array changes.
218
- *
219
- * @param binding - The `StackKeyBinding` to add.
220
- * @param deps (optional) - The React dependency list.
187
+ * @param fn The callback.
188
+ * @param deps The deps to memoize over. Defaults to `[]`.
189
+ * @returns A callback function
190
+ * @see https://recoiljs.org/docs/api-reference/core/useRecoilCallback
221
191
  */
222
- const useStackKeyBinding = (binding, deps = []) => {
223
- const [, dispatch] = useKeyBindingState();
224
- React.useEffect(() => {
225
- const addPredicatePassing = binding.addPredicate == null || binding.addPredicate();
226
- const cancelPredicatePassing = binding.cancelPredicate != null && binding.cancelPredicate();
227
- if (addPredicatePassing) {
228
- dispatch({
229
- type: 'push-key-binding',
230
- binding,
231
- });
232
- }
233
- if (cancelPredicatePassing) {
234
- dispatch({
235
- type: 'remove-key-binding',
236
- binding,
237
- });
238
- }
239
- }, deps);
240
- };
192
+ function useActionCallback(fn, deps = []) {
193
+ const d = deps instanceof DefaultRecoilDeps ? undefined : deps;
194
+ // eslint-disable-next-line react-hooks/exhaustive-deps
195
+ return recoil.useRecoilCallback((cbInterface) => fn(Object.assign(Object.assign({}, cbInterface), { snapshot: Object.defineProperties(cbInterface.snapshot, {
196
+ getPromiseRequired: {
197
+ configurable: true,
198
+ value: createGetPromiseRequiredWrapper(cbInterface.snapshot),
199
+ },
200
+ tryGetPromise: {
201
+ configurable: true,
202
+ value: createTryGetPromiseWrapper(cbInterface.snapshot),
203
+ },
204
+ }) })), d);
205
+ }
241
206
  /**
242
- * Enables key binding usage.
207
+ * Returns a callback that can be used with `useActionCallback` or `useRecoilCallback`,
208
+ * and automatically handles retention of the `snapshot` object for use with asynchronous
209
+ * selectors.
243
210
  *
244
- * This hook must appear in the tree for `useStackKeyBinding`
245
- * or `useApplyKeyBinding` to work.
211
+ * This function expects a callback that would ordinarily be passed to `useActionCallback`
212
+ * or `useRecoilCallback`, but that returns an asynchronous action where the `snapshot` is
213
+ * used.
214
+ *
215
+ * @example
216
+ *
217
+ * const asyncSelector = selector({
218
+ * key: 'asyncSelector',
219
+ * get: async ({ get }) => {
220
+ * return await fetch('/api/item');
221
+ * }
222
+ * })
223
+ *
224
+ * useActionCallback(
225
+ * retainSnapshot(
226
+ * ({ snapshot }) => async () => {
227
+ * const asyncValue = await snapshot.getPromise(asyncSelector);
228
+ * }
229
+ * )
230
+ * )
231
+ *
232
+ * @param fn The callback.
233
+ * @returns The callback wrapped with a retain/release of the underlying snapshot.
246
234
  */
247
- const useKeyBindings = ({ keydownRepeatInterval = 25, keydownIgnorePredicate = isInputElement, } = {}) => {
248
- const [state, dispatch] = useKeyBindingState();
249
- const applyStackKeyBindings = React.useCallback((key) => {
250
- Object.keys(state.bindings)
251
- .filter((k) => k.includes(key) && allPressed(k, Object.assign(Object.assign({}, state.pressed), { [key]: true })))
252
- .forEach((k) => {
253
- const bindings = state.bindings[k];
254
- const poppedBinding = bindings.length > 0 ? bindings[bindings.length - 1] : undefined;
255
- if (poppedBinding != null) {
256
- poppedBinding.fn();
257
- dispatch({
258
- type: 'remove-key-binding',
259
- binding: poppedBinding,
260
- });
235
+ function retainSnapshot(fn) {
236
+ return (_a) => {
237
+ var { snapshot } = _a, cb = __rest(_a, ["snapshot"]);
238
+ return async (...args) => {
239
+ const release = snapshot.retain();
240
+ try {
241
+ const returnValue = await fn(Object.assign(Object.assign({}, cb), { snapshot }))(...args);
242
+ return returnValue;
261
243
  }
262
- });
263
- }, [state]);
264
- React.useEffect(() => {
265
- const handleKeyDown = (event) => {
266
- if (!event.repeat && !keydownIgnorePredicate(event.target)) {
267
- dispatch({
268
- type: 'set-key-pressed',
269
- key: event.key,
270
- pressed: true,
271
- });
272
- applyStackKeyBindings(event.key);
273
- // If the key is associated with a keybinding, then prevent default behavior
274
- const currentPressed = Object.assign(Object.assign({}, state.pressed), { [event.key]: true });
275
- const activeMatchesSingleFnBindings = matchingSingleFnBindings(state.applyBindings, currentPressed, event.key);
276
- const activeMatchesOffBindings = matchingOffBindings(state.applyBindings, currentPressed, event.key);
277
- if (activeMatchesSingleFnBindings.length > 0 ||
278
- activeMatchesOffBindings.length > 0) {
279
- event.preventDefault();
280
- }
244
+ finally {
245
+ release();
281
246
  }
282
247
  };
283
- const handleKeyUp = (event) => {
284
- dispatch({
285
- type: 'set-key-pressed',
286
- key: event.key,
287
- pressed: false,
288
- });
289
- };
290
- window.addEventListener('keydown', handleKeyDown);
291
- window.addEventListener('keyup', handleKeyUp);
292
- return () => {
293
- window.removeEventListener('keydown', handleKeyDown);
294
- window.removeEventListener('keyup', handleKeyUp);
295
- };
296
- }, [applyStackKeyBindings, state.applyBindings, state.pressed]);
297
- React.useEffect(() => {
298
- const activeMatchesSingleFnBindings = matchingSingleFnBindings(state.applyBindings, state.pressed, state.lastPressed);
299
- const activeMatchesOffBindings = matchingOffBindings(state.applyBindings, state.pressed, state.lastPressed);
300
- activeMatchesSingleFnBindings.forEach((fn) => fn());
301
- activeMatchesOffBindings.forEach((fn) => fn());
302
- }, [state.pressed, state.lastPressed]);
303
- React.useEffect(() => {
304
- const matchingRepeatBindings = state.applyBindings
305
- .filter((binding) => binding.repeat &&
306
- binding.keyBind != null &&
307
- allPressed(binding.keyBind, state.pressed))
308
- .map((binding) => binding.fn);
309
- if (matchingRepeatBindings.length > 0) {
310
- const interval = setInterval(() => {
311
- matchingRepeatBindings.forEach((fn) => fn());
312
- }, keydownRepeatInterval);
313
- return () => {
314
- clearInterval(interval);
315
- };
248
+ };
249
+ }
250
+ function createGetPromiseRequiredWrapper(snapshot) {
251
+ return async (recoilValue, error) => {
252
+ const value = await snapshot.getPromise(recoilValue);
253
+ if (value == null) {
254
+ throw (error !== null && error !== void 0 ? error : new Error(`No value present for required value ${recoilValue.key}`));
316
255
  }
317
- else {
318
- return () => {
319
- return undefined;
256
+ return value;
257
+ };
258
+ }
259
+ function createTryGetPromiseWrapper(snapshot) {
260
+ return async (value) => {
261
+ try {
262
+ return { value: await snapshot.getPromise(value) };
263
+ }
264
+ catch (e) {
265
+ logger.debug(`Error encountered retrieving Recoil value. [key={${value.key}}]`, e);
266
+ return {
267
+ error: e,
320
268
  };
321
269
  }
322
- }, [state.applyBindings, state.lastPressed]);
323
- };
324
-
325
- function useLongPress({ target, callback, delay = 500, onMovement, }) {
326
- const [longPressTimeout, setLongPressTimeout] = React__namespace.useState();
327
- const [touchStartPosition, setTouchStartPosition] = React__namespace.useState();
328
- React__namespace.useEffect(() => {
329
- const handleTouchStart = (e) => {
330
- const event = e;
331
- if (event.touches != null && event.touches.length === 1) {
332
- if (longPressTimeout != null) {
333
- clearTimeout(longPressTimeout);
334
- }
335
- setTouchStartPosition(geometry.Point.create(event.touches[0].clientX, event.touches[0].clientY));
336
- setLongPressTimeout(setTimeout(() => callback === null || callback === void 0 ? void 0 : callback(event), delay));
337
- }
338
- };
339
- const handleTouchMove = (e) => {
340
- const event = e;
341
- if (event.touches != null &&
342
- event.touches.length > 0 &&
343
- longPressTimeout != null &&
344
- touchStartPosition != null &&
345
- geometry.Point.distance(touchStartPosition, geometry.Point.create(event.touches[0].clientX, event.touches[0].clientY)) >= 2) {
346
- clearTimeout(longPressTimeout);
347
- onMovement === null || onMovement === void 0 ? void 0 : onMovement();
348
- }
349
- };
350
- const handleTouchEnd = () => {
351
- if (longPressTimeout != null) {
352
- clearTimeout(longPressTimeout);
353
- }
354
- };
355
- target === null || target === void 0 ? void 0 : target.addEventListener('touchstart', handleTouchStart);
356
- target === null || target === void 0 ? void 0 : target.addEventListener('touchmove', handleTouchMove);
357
- target === null || target === void 0 ? void 0 : target.addEventListener('touchend', handleTouchEnd);
358
- return () => {
359
- target === null || target === void 0 ? void 0 : target.removeEventListener('touchstart', handleTouchStart);
360
- target === null || target === void 0 ? void 0 : target.removeEventListener('touchmove', handleTouchMove);
361
- target === null || target === void 0 ? void 0 : target.removeEventListener('touchend', handleTouchEnd);
362
- };
363
- }, [target, longPressTimeout, touchStartPosition]);
270
+ };
364
271
  }
365
272
 
366
- function contextMenuItemIsRow(item) {
367
- var _a;
368
- return item != null && ((_a = item === null || item === void 0 ? void 0 : item.node) === null || _a === void 0 ? void 0 : _a.id) != null;
369
- }
370
- const contextMenuActive = recoil.atom({
371
- key: 'contextMenuActive',
273
+ const viewerElement = recoil.atom({
274
+ key: 'viewerToolkitViewerElement',
372
275
  default: undefined,
276
+ dangerouslyAllowMutability: true,
373
277
  });
374
- const contextMenuPosition = recoil.atom({
375
- key: 'contextMenuPosition',
376
- default: undefined,
278
+ const viewerInitialSceneReady = recoil.atom({
279
+ key: 'viewerInitialSceneReady',
280
+ default: false,
377
281
  });
378
- const contextMenuTarget = recoil.atom({
379
- key: 'contextMenuTarget',
380
- default: undefined,
282
+ const viewerBaseInteractionHandlerProvider = recoil.atom({
283
+ key: 'viewerBaseInteractionHandlerProvider',
284
+ default: Promise.resolve(undefined),
285
+ dangerouslyAllowMutability: true,
381
286
  });
382
- const contextMenuItem = recoil.atom({
383
- key: 'contextMenuItem',
384
- default: undefined,
287
+ const viewerPrimaryInteractionType = recoil.atom({
288
+ key: 'viewerPrimaryInteractionType',
289
+ default: 'rotate',
385
290
  });
386
- const contextMenuActions = recoil.atom({
387
- key: 'contextMenuActions',
388
- default: [],
291
+
292
+ const viewerSceneProvider = recoil.selector({
293
+ key: 'viewerScene',
294
+ get: ({ get }) => async () => { var _a; return (_a = get(viewerElement)) === null || _a === void 0 ? void 0 : _a.scene(); },
295
+ dangerouslyAllowMutability: true,
389
296
  });
390
- const contextMenuActivePosition = recoil.selector({
391
- key: 'contextMenuActivePosition',
392
- get: ({ get }) => get(contextMenuActive) != null ? get(contextMenuPosition) : undefined,
393
- });
394
-
395
- /******************************************************************************
396
- Copyright (c) Microsoft Corporation.
397
-
398
- Permission to use, copy, modify, and/or distribute this software for any
399
- purpose with or without fee is hereby granted.
400
-
401
- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
402
- REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
403
- AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
404
- INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
405
- LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
406
- OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
407
- PERFORMANCE OF THIS SOFTWARE.
408
- ***************************************************************************** */
409
- /* global Reflect, Promise, SuppressedError, Symbol, Iterator */
410
-
411
-
412
- function __rest(s, e) {
413
- var t = {};
414
- for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
415
- t[p] = s[p];
416
- if (s != null && typeof Object.getOwnPropertySymbols === "function")
417
- for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
418
- if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
419
- t[p[i]] = s[p[i]];
420
- }
421
- return t;
422
- }
423
-
424
- typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
425
- var e = new Error(message);
426
- return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
427
- };
428
-
429
- // Create a new logger instance
430
- const pinoLogger = Pino({
431
- formatters: {
432
- level(level) {
433
- return { level };
434
- },
435
- },
436
- });
437
- const logger = {
438
- error: (message, error) => {
439
- if (error != null) {
440
- pinoLogger.error(error, message);
441
- }
442
- else {
443
- pinoLogger.error(message);
444
- }
445
- },
446
- info: (message, obj) => {
447
- if (obj != null) {
448
- pinoLogger.info(obj, message);
449
- }
450
- else {
451
- pinoLogger.info(message);
452
- }
453
- },
454
- warn: (message, err) => {
455
- if (err != null) {
456
- pinoLogger.warn(err, message);
457
- }
458
- else {
459
- pinoLogger.warn(message);
460
- }
461
- },
462
- debug: (message, obj) => {
463
- if (obj != null) {
464
- pinoLogger.debug(obj, message);
465
- }
466
- else {
467
- pinoLogger.debug(message);
468
- }
469
- },
470
- };
471
- /* eslint-enable @typescript-eslint/no-explicit-any */
472
-
473
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
474
- class DefaultRecoilDeps {
475
- }
476
- /**
477
- * Returns a Recoil callback that can be used for action hooks.
478
- *
479
- * This uses `useRecoilCallback` but the deps implementation differs from
480
- * Recoil. If no deps are provided, then it will always return the same function
481
- * vs returning a new function.
482
- *
483
- * If you want to use the original Recoil callback behavior, pass
484
- * `DefaultRecoilCallbackDepsBehavior`.
485
- *
486
- * @param fn The callback.
487
- * @param deps The deps to memoize over. Defaults to `[]`.
488
- * @returns A callback function
489
- * @see https://recoiljs.org/docs/api-reference/core/useRecoilCallback
490
- */
491
- function useActionCallback(fn, deps = []) {
492
- const d = deps instanceof DefaultRecoilDeps ? undefined : deps;
493
- // eslint-disable-next-line react-hooks/exhaustive-deps
494
- return recoil.useRecoilCallback((cbInterface) => fn(Object.assign(Object.assign({}, cbInterface), { snapshot: Object.defineProperties(cbInterface.snapshot, {
495
- getPromiseRequired: {
496
- configurable: true,
497
- value: createGetPromiseRequiredWrapper(cbInterface.snapshot),
498
- },
499
- tryGetPromise: {
500
- configurable: true,
501
- value: createTryGetPromiseWrapper(cbInterface.snapshot),
502
- },
503
- }) })), d);
504
- }
505
- /**
506
- * Returns a callback that can be used with `useActionCallback` or `useRecoilCallback`,
507
- * and automatically handles retention of the `snapshot` object for use with asynchronous
508
- * selectors.
509
- *
510
- * This function expects a callback that would ordinarily be passed to `useActionCallback`
511
- * or `useRecoilCallback`, but that returns an asynchronous action where the `snapshot` is
512
- * used.
513
- *
514
- * @example
515
- *
516
- * const asyncSelector = selector({
517
- * key: 'asyncSelector',
518
- * get: async ({ get }) => {
519
- * return await fetch('/api/item');
520
- * }
521
- * })
522
- *
523
- * useActionCallback(
524
- * retainSnapshot(
525
- * ({ snapshot }) => async () => {
526
- * const asyncValue = await snapshot.getPromise(asyncSelector);
527
- * }
528
- * )
529
- * )
530
- *
531
- * @param fn The callback.
532
- * @returns The callback wrapped with a retain/release of the underlying snapshot.
533
- */
534
- function retainSnapshot(fn) {
535
- return (_a) => {
536
- var { snapshot } = _a, cb = __rest(_a, ["snapshot"]);
537
- return async (...args) => {
538
- const release = snapshot.retain();
539
- try {
540
- const returnValue = await fn(Object.assign(Object.assign({}, cb), { snapshot }))(...args);
541
- return returnValue;
542
- }
543
- finally {
544
- release();
545
- }
546
- };
547
- };
548
- }
549
- function createGetPromiseRequiredWrapper(snapshot) {
550
- return async (recoilValue, error) => {
551
- const value = await snapshot.getPromise(recoilValue);
552
- if (value == null) {
553
- throw (error !== null && error !== void 0 ? error : new Error(`No value present for required value ${recoilValue.key}`));
554
- }
555
- return value;
556
- };
557
- }
558
- function createTryGetPromiseWrapper(snapshot) {
559
- return async (value) => {
560
- try {
561
- return { value: await snapshot.getPromise(value) };
562
- }
563
- catch (e) {
564
- logger.debug(`Error encountered retrieving Recoil value. [key={${value.key}}]`, e);
565
- return {
566
- error: e,
567
- };
568
- }
569
- };
570
- }
571
-
572
- const viewerElement = recoil.atom({
573
- key: 'viewerToolkitViewerElement',
574
- default: undefined,
575
- dangerouslyAllowMutability: true,
576
- });
577
- const viewerInitialSceneReady = recoil.atom({
578
- key: 'viewerInitialSceneReady',
579
- default: false,
580
- });
581
- const viewerBaseInteractionHandlerProvider = recoil.atom({
582
- key: 'viewerBaseInteractionHandlerProvider',
583
- default: Promise.resolve(undefined),
584
- dangerouslyAllowMutability: true,
585
- });
586
- const viewerPrimaryInteractionType = recoil.atom({
587
- key: 'viewerPrimaryInteractionType',
588
- default: 'rotate',
589
- });
590
-
591
- const viewerSceneProvider = recoil.selector({
592
- key: 'viewerScene',
593
- get: ({ get }) => async () => { var _a; return (_a = get(viewerElement)) === null || _a === void 0 ? void 0 : _a.scene(); },
594
- dangerouslyAllowMutability: true,
595
- });
596
- const viewerFrameScene = recoil.atom({
597
- key: 'viewerFrameScene',
598
- default: undefined,
599
- dangerouslyAllowMutability: true,
297
+ const viewerFrameScene = recoil.atom({
298
+ key: 'viewerFrameScene',
299
+ default: undefined,
300
+ dangerouslyAllowMutability: true,
600
301
  });
601
302
  const viewerSceneVisibleBoundingBox = recoil.selector({
602
303
  key: 'viewerSceneVisibleBoundingBox',
@@ -1189,27 +890,27 @@ function useCrossSectioningActions() {
1189
890
  }
1190
891
 
1191
892
  var index$3 = /*#__PURE__*/Object.freeze({
1192
- __proto__: null,
1193
- DEFAULT_ALIGN_TO_PLANE_ANIMATION_DURATION_MS: DEFAULT_ALIGN_TO_PLANE_ANIMATION_DURATION_MS,
1194
- DEFAULT_SLIDER_RANGE: DEFAULT_SLIDER_RANGE,
1195
- crossSectioningActiveAxis: crossSectioningActiveAxis,
1196
- crossSectioningAdditionalToolsOpen: crossSectioningAdditionalToolsOpen,
1197
- crossSectioningAlignment: crossSectioningAlignment,
1198
- crossSectioningAlignmentToolsOpen: crossSectioningAlignmentToolsOpen,
1199
- crossSectioningAvailableAxes: crossSectioningAvailableAxes,
1200
- crossSectioningAxisToolsOpen: crossSectioningAxisToolsOpen,
1201
- crossSectioningBorderWidth: crossSectioningBorderWidth,
1202
- crossSectioningEnabled: crossSectioningEnabled,
1203
- crossSectioningHighlightColor: crossSectioningHighlightColor,
1204
- crossSectioningInteractionHandler: crossSectioningInteractionHandler,
1205
- crossSectioningIsInteractive: crossSectioningIsInteractive,
1206
- crossSectioningOffsetScalar: crossSectioningOffsetScalar,
1207
- crossSectioningPlaneDisplayOffset: crossSectioningPlaneDisplayOffset,
1208
- crossSectioningPlanes: crossSectioningPlanes,
1209
- crossSectioningSliderRange: crossSectioningSliderRange,
1210
- crossSectioningTargetBoundingBox: crossSectioningTargetBoundingBox,
1211
- useCrossSectioning: useCrossSectioning,
1212
- useCrossSectioningActions: useCrossSectioningActions
893
+ __proto__: null,
894
+ DEFAULT_ALIGN_TO_PLANE_ANIMATION_DURATION_MS: DEFAULT_ALIGN_TO_PLANE_ANIMATION_DURATION_MS,
895
+ DEFAULT_SLIDER_RANGE: DEFAULT_SLIDER_RANGE,
896
+ crossSectioningActiveAxis: crossSectioningActiveAxis,
897
+ crossSectioningAdditionalToolsOpen: crossSectioningAdditionalToolsOpen,
898
+ crossSectioningAlignment: crossSectioningAlignment,
899
+ crossSectioningAlignmentToolsOpen: crossSectioningAlignmentToolsOpen,
900
+ crossSectioningAvailableAxes: crossSectioningAvailableAxes,
901
+ crossSectioningAxisToolsOpen: crossSectioningAxisToolsOpen,
902
+ crossSectioningBorderWidth: crossSectioningBorderWidth,
903
+ crossSectioningEnabled: crossSectioningEnabled,
904
+ crossSectioningHighlightColor: crossSectioningHighlightColor,
905
+ crossSectioningInteractionHandler: crossSectioningInteractionHandler,
906
+ crossSectioningIsInteractive: crossSectioningIsInteractive,
907
+ crossSectioningOffsetScalar: crossSectioningOffsetScalar,
908
+ crossSectioningPlaneDisplayOffset: crossSectioningPlaneDisplayOffset,
909
+ crossSectioningPlanes: crossSectioningPlanes,
910
+ crossSectioningSliderRange: crossSectioningSliderRange,
911
+ crossSectioningTargetBoundingBox: crossSectioningTargetBoundingBox,
912
+ useCrossSectioning: useCrossSectioning,
913
+ useCrossSectioningActions: useCrossSectioningActions
1213
914
  });
1214
915
 
1215
916
  const useHitActions = () => {
@@ -1259,108 +960,407 @@ const useHitActions = () => {
1259
960
  updateTransformWidgetPosition();
1260
961
  }
1261
962
  }
1262
- setContextMenuItem();
1263
- crossSectioningActions.sectionCurrentHit();
1264
- setCurrentHitResult();
1265
- })),
1266
- longPress: useActionCallback(retainSnapshot(({ snapshot, set, reset }) => async (event) => {
1267
- reset(hitResultsTapDetails);
1268
- set(hitResultsLongPressDetails, event.detail);
1269
- await snapshot.tryGetPromise(hitResult);
1270
- setContextMenuItem();
1271
- setCurrentHitResult();
1272
- })),
1273
- };
1274
- };
1275
-
1276
- const hitState = recoil.selector({
1277
- key: 'viewerToolkitHitState',
1278
- get: ({ get }) => {
1279
- const tapDetails = get(hitResultsTapDetails);
1280
- const longPressDetails = get(hitResultsLongPressDetails);
1281
- const previous = get(previousHitResult);
1282
- const current = get(currentHitResult);
1283
- const state = {
1284
- tapDetails,
1285
- longPressDetails,
1286
- previousHitResult: previous,
1287
- currentHitResult: current,
963
+ setContextMenuItem();
964
+ crossSectioningActions.sectionCurrentHit();
965
+ setCurrentHitResult();
966
+ })),
967
+ longPress: useActionCallback(retainSnapshot(({ snapshot, set, reset }) => async (event) => {
968
+ reset(hitResultsTapDetails);
969
+ set(hitResultsLongPressDetails, event.detail);
970
+ await snapshot.tryGetPromise(hitResult);
971
+ setContextMenuItem();
972
+ setCurrentHitResult();
973
+ })),
974
+ };
975
+ };
976
+
977
+ const hitState = recoil.selector({
978
+ key: 'viewerToolkitHitState',
979
+ get: ({ get }) => {
980
+ const tapDetails = get(hitResultsTapDetails);
981
+ const longPressDetails = get(hitResultsLongPressDetails);
982
+ const previous = get(previousHitResult);
983
+ const current = get(currentHitResult);
984
+ const state = {
985
+ tapDetails,
986
+ longPressDetails,
987
+ previousHitResult: previous,
988
+ currentHitResult: current,
989
+ };
990
+ return state;
991
+ },
992
+ });
993
+
994
+ var index$2 = /*#__PURE__*/Object.freeze({
995
+ __proto__: null,
996
+ currentHitResult: currentHitResult,
997
+ hitResult: hitResult,
998
+ hitResultsLongPressDetails: hitResultsLongPressDetails,
999
+ hitResultsSkipNextTap: hitResultsSkipNextTap,
1000
+ hitResultsTapDetails: hitResultsTapDetails,
1001
+ hitState: hitState,
1002
+ previousHitResult: previousHitResult,
1003
+ useHitActions: useHitActions
1004
+ });
1005
+
1006
+ function useContextMenuActions() {
1007
+ return {
1008
+ pointerDown: useActionCallback(({ set }) => async (event, pointOverride) => {
1009
+ var _a, _b;
1010
+ if (event.button === 2) {
1011
+ const xCoordinate = (_a = pointOverride === null || pointOverride === void 0 ? void 0 : pointOverride.x) !== null && _a !== void 0 ? _a : event.clientX;
1012
+ const yCoordinate = (_b = pointOverride === null || pointOverride === void 0 ? void 0 : pointOverride.y) !== null && _b !== void 0 ? _b : event === null || event === void 0 ? void 0 : event.clientY;
1013
+ set(contextMenuPosition, geometry.Point.create(xCoordinate, yCoordinate));
1014
+ set(contextMenuTarget, event.target);
1015
+ }
1016
+ }),
1017
+ pointerUp: useActionCallback(({ snapshot, set }) => async (event, type, predicate, onOpen, pointOverride) => {
1018
+ var _a, _b;
1019
+ const downPosition = await snapshot.getPromise(contextMenuPosition);
1020
+ const active = await snapshot.getPromise(contextMenuActive);
1021
+ if (downPosition != null && active == null) {
1022
+ const xCoordinate = (_a = pointOverride === null || pointOverride === void 0 ? void 0 : pointOverride.x) !== null && _a !== void 0 ? _a : event.clientX;
1023
+ const yCoordinate = (_b = pointOverride === null || pointOverride === void 0 ? void 0 : pointOverride.y) !== null && _b !== void 0 ? _b : event === null || event === void 0 ? void 0 : event.clientY;
1024
+ const point = geometry.Point.create(xCoordinate, yCoordinate);
1025
+ const pointDistance = downPosition != null ? geometry.Point.distance(downPosition, point) : 0;
1026
+ const predicateResult = predicate == null || predicate(event);
1027
+ if (pointDistance < 2 && predicateResult) {
1028
+ onOpen === null || onOpen === void 0 ? void 0 : onOpen(event, downPosition !== null && downPosition !== void 0 ? downPosition : point);
1029
+ set(contextMenuActive, type);
1030
+ }
1031
+ }
1032
+ }),
1033
+ contextMenu: useActionCallback(() => (event, predicate) => {
1034
+ if (predicate == null || predicate(event)) {
1035
+ event.preventDefault();
1036
+ }
1037
+ }),
1038
+ longPress: useActionCallback(({ set }) => (event, type, predicate, onOpen) => {
1039
+ if (predicate == null || predicate(event)) {
1040
+ const point = geometry.Point.create(event.touches[0].clientX, event.touches[0].clientY);
1041
+ set(contextMenuPosition, point);
1042
+ set(contextMenuTarget, event.target);
1043
+ set(contextMenuActive, type);
1044
+ onOpen === null || onOpen === void 0 ? void 0 : onOpen(event, point);
1045
+ }
1046
+ }),
1047
+ clearActiveContextMenu: useActionCallback(({ reset, set }) => (dismissedFromWindowPointerEvent) => {
1048
+ set(hitResultsSkipNextTap, !!dismissedFromWindowPointerEvent);
1049
+ reset(contextMenuActive);
1050
+ reset(contextMenuActions);
1051
+ reset(contextMenuPosition);
1052
+ }),
1053
+ clearDismissedState: useActionCallback(({ reset }) => () => reset(hitResultsSkipNextTap)),
1054
+ };
1055
+ }
1056
+
1057
+ function targetWithinMenu(event) {
1058
+ return (event.target instanceof Element && isChildOf('vertex-menu', event.target));
1059
+ }
1060
+ function targetShouldSkipNextHit(event) {
1061
+ return (event.target instanceof Element && isChildOf('vertex-viewer', event.target));
1062
+ }
1063
+ function isChildOf(elementType, target) {
1064
+ return target.closest(elementType) != null;
1065
+ }
1066
+
1067
+ const isInputElement = (target) => {
1068
+ const isAutoResizeTextarea = target instanceof HTMLElement &&
1069
+ target.tagName === 'VERTEX-AUTO-RESIZE-TEXTAREA';
1070
+ const isTextField = target instanceof HTMLElement && target.tagName === 'VERTEX-TEXTFIELD';
1071
+ const isContentEditable = target instanceof HTMLElement && target.contentEditable === 'true';
1072
+ const isSceneTreeSearch = target instanceof HTMLElement &&
1073
+ target.tagName === 'VERTEX-SCENE-TREE-SEARCH';
1074
+ const isInput = target instanceof HTMLInputElement || target instanceof HTMLTextAreaElement;
1075
+ const isVertexViewerPinTool = target instanceof HTMLElement &&
1076
+ target.tagName === 'VERTEX-VIEWER-PIN-TOOL';
1077
+ const isVertexViewerTransformWidget = target instanceof HTMLElement &&
1078
+ target.tagName === 'VERTEX-VIEWER-TRANSFORM-WIDGET';
1079
+ return (isAutoResizeTextarea ||
1080
+ isTextField ||
1081
+ isContentEditable ||
1082
+ isSceneTreeSearch ||
1083
+ isInput ||
1084
+ isVertexViewerPinTool ||
1085
+ isVertexViewerTransformWidget);
1086
+ };
1087
+
1088
+ // DEPRECATED - avoid if possible
1089
+ const useRecoilReducer = ({ reducer, atom, }) => {
1090
+ const state = recoil.useRecoilValue(atom);
1091
+ const dispatch = useRecoilReducerDispatch({
1092
+ reducer,
1093
+ atom,
1094
+ });
1095
+ return [state, dispatch];
1096
+ };
1097
+ // DEPRECATED - avoid if possible
1098
+ const useRecoilReducerDispatch = ({ reducer, atom, }) => {
1099
+ const dispatch = recoil.useRecoilCallback(({ set }) => async (action) => {
1100
+ set(atom, (previousValue) => reducer(previousValue, action));
1101
+ }, []);
1102
+ return dispatch;
1103
+ };
1104
+
1105
+ const keyBindings = recoil.atom({
1106
+ key: 'keyBindings',
1107
+ default: {
1108
+ applyBindings: [],
1109
+ bindings: {},
1110
+ pressed: {},
1111
+ },
1112
+ });
1113
+ function reducer(state, action) {
1114
+ var _a, _b, _c, _d;
1115
+ switch (action.type) {
1116
+ case 'push-key-binding':
1117
+ const toAdd = (_a = state.bindings[action.binding.keyBind]) === null || _a === void 0 ? void 0 : _a.find((b) => b.id === action.binding.id);
1118
+ return toAdd != null
1119
+ ? state
1120
+ : Object.assign(Object.assign({}, state), { bindings: Object.assign(Object.assign({}, state.bindings), { [action.binding.keyBind]: [
1121
+ ...((_b = state.bindings[action.binding.keyBind]) !== null && _b !== void 0 ? _b : []),
1122
+ action.binding,
1123
+ ] }) });
1124
+ case 'remove-key-binding':
1125
+ const toRemove = (_c = state.bindings[action.binding.keyBind]) === null || _c === void 0 ? void 0 : _c.find((b) => b.id === action.binding.id);
1126
+ return toRemove == null
1127
+ ? state
1128
+ : Object.assign(Object.assign({}, state), { bindings: Object.assign(Object.assign({}, state.bindings), { [action.binding.keyBind]: ((_d = state.bindings[action.binding.keyBind]) !== null && _d !== void 0 ? _d : []).filter((b) => b.id !== action.binding.id) }) });
1129
+ case 'add-apply-key-binding':
1130
+ return Object.assign(Object.assign({}, state), { applyBindings: [...state.applyBindings, action.binding] });
1131
+ case 'remove-apply-key-binding':
1132
+ return Object.assign(Object.assign({}, state), { applyBindings: state.applyBindings.filter((binding) => binding.id !== action.id) });
1133
+ case 'set-key-pressed':
1134
+ return Object.assign(Object.assign({}, state), { applyBindings: state.applyBindings.map((binding) => (Object.assign(Object.assign({}, binding), { active: binding.keyBind != null &&
1135
+ allPressed(binding.keyBind, state.pressed) }))), pressed: Object.assign(Object.assign({}, state.pressed), { [action.key]: action.pressed }), lastPressed: action.pressed ? action.key : undefined });
1136
+ }
1137
+ }
1138
+ const useKeyBindingState = () => {
1139
+ return useRecoilReducer({
1140
+ reducer,
1141
+ atom: keyBindings,
1142
+ });
1143
+ };
1144
+ function pressedValue(keyBind, pressed) {
1145
+ return keyBind.includes('!')
1146
+ ? !pressed[keyBind.replace('!', '')] &&
1147
+ !pressed[keyBind.replace('!', '').toLowerCase()]
1148
+ : pressed[keyBind] || pressed[keyBind.toLowerCase()];
1149
+ }
1150
+ function isPressed(keyBind, pressed) {
1151
+ const keys = keyBind.split('||');
1152
+ return keys.length > 1
1153
+ ? keys.some((key) => pressedValue(key, pressed))
1154
+ : pressedValue(keys[0], pressed);
1155
+ }
1156
+ function allPressed(keyBind, pressed) {
1157
+ const keys = keyBind.split('+');
1158
+ return keys.every((key) => isPressed(key, pressed));
1159
+ }
1160
+ function matchingSingleFnBindings(applyBindings, pressed, lastPressed) {
1161
+ return applyBindings
1162
+ .filter((binding) => !binding.repeat)
1163
+ .filter((binding) => {
1164
+ var _a;
1165
+ return binding.keyBind != null &&
1166
+ lastPressed != null &&
1167
+ ((_a = binding.keyBind) === null || _a === void 0 ? void 0 : _a.includes(lastPressed)) &&
1168
+ allPressed(binding.keyBind, pressed);
1169
+ })
1170
+ .map((binding) => binding.fn);
1171
+ }
1172
+ function matchingOffBindings(applyBindings, pressed, lastPressed) {
1173
+ return applyBindings
1174
+ .filter((binding) => binding.off &&
1175
+ binding.active &&
1176
+ binding.keyBind != null &&
1177
+ lastPressed == null &&
1178
+ !allPressed(binding.keyBind, pressed))
1179
+ .map((binding) => binding.off);
1180
+ }
1181
+ /**
1182
+ * Depends on `useKeyBindings`.
1183
+ *
1184
+ * Adds a global key binding. Any key binding
1185
+ * added this way will listen to global state for pressed
1186
+ * keys, and executed whenever the key state matches the
1187
+ * provided `keyBind`.
1188
+ *
1189
+ * @param binding - The `ApplyKeyBinding` to add.
1190
+ */
1191
+ const useApplyKeyBinding = (binding) => {
1192
+ const [state, dispatch] = useKeyBindingState();
1193
+ React.useEffect(() => {
1194
+ const id = utils.UUID.create();
1195
+ dispatch({
1196
+ type: 'add-apply-key-binding',
1197
+ binding: Object.assign(Object.assign({}, binding), { id, active: binding.keyBind != null && allPressed(binding.keyBind, state.pressed) }),
1198
+ });
1199
+ return () => {
1200
+ dispatch({
1201
+ type: 'remove-apply-key-binding',
1202
+ id,
1203
+ });
1204
+ };
1205
+ }, [binding.fn, binding.off, binding.keyBind, binding.repeat]);
1206
+ };
1207
+ /**
1208
+ * Depends on `useKeyBindings`.
1209
+ *
1210
+ * Adds a stack-based key binding. Any key binding
1211
+ * added this way will be added to an existing (or new)
1212
+ * stack for the specified `keyBind`.
1213
+ *
1214
+ * Provided `binding`s will be added and cancelled based
1215
+ * on the specified `addPredicate` and `cancelPredicate`
1216
+ * respectively. These predicates are evaluated any time
1217
+ * that the `deps` array changes.
1218
+ *
1219
+ * @param binding - The `StackKeyBinding` to add.
1220
+ * @param deps (optional) - The React dependency list.
1221
+ */
1222
+ const useStackKeyBinding = (binding, deps = []) => {
1223
+ const [, dispatch] = useKeyBindingState();
1224
+ React.useEffect(() => {
1225
+ const addPredicatePassing = binding.addPredicate == null || binding.addPredicate();
1226
+ const cancelPredicatePassing = binding.cancelPredicate != null && binding.cancelPredicate();
1227
+ if (addPredicatePassing) {
1228
+ dispatch({
1229
+ type: 'push-key-binding',
1230
+ binding,
1231
+ });
1232
+ }
1233
+ if (cancelPredicatePassing) {
1234
+ dispatch({
1235
+ type: 'remove-key-binding',
1236
+ binding,
1237
+ });
1238
+ }
1239
+ }, deps);
1240
+ };
1241
+ /**
1242
+ * Enables key binding usage.
1243
+ *
1244
+ * This hook must appear in the tree for `useStackKeyBinding`
1245
+ * or `useApplyKeyBinding` to work.
1246
+ */
1247
+ const useKeyBindings = ({ keydownRepeatInterval = 25, keydownIgnorePredicate = isInputElement, } = {}) => {
1248
+ const [state, dispatch] = useKeyBindingState();
1249
+ const applyStackKeyBindings = React.useCallback((key) => {
1250
+ Object.keys(state.bindings)
1251
+ .filter((k) => k.includes(key) && allPressed(k, Object.assign(Object.assign({}, state.pressed), { [key]: true })))
1252
+ .forEach((k) => {
1253
+ const bindings = state.bindings[k];
1254
+ const poppedBinding = bindings.length > 0 ? bindings[bindings.length - 1] : undefined;
1255
+ if (poppedBinding != null) {
1256
+ poppedBinding.fn();
1257
+ dispatch({
1258
+ type: 'remove-key-binding',
1259
+ binding: poppedBinding,
1260
+ });
1261
+ }
1262
+ });
1263
+ }, [state]);
1264
+ React.useEffect(() => {
1265
+ const handleKeyDown = (event) => {
1266
+ if (!event.repeat && !keydownIgnorePredicate(event.target)) {
1267
+ dispatch({
1268
+ type: 'set-key-pressed',
1269
+ key: event.key,
1270
+ pressed: true,
1271
+ });
1272
+ applyStackKeyBindings(event.key);
1273
+ // If the key is associated with a keybinding, then prevent default behavior
1274
+ const currentPressed = Object.assign(Object.assign({}, state.pressed), { [event.key]: true });
1275
+ const activeMatchesSingleFnBindings = matchingSingleFnBindings(state.applyBindings, currentPressed, event.key);
1276
+ const activeMatchesOffBindings = matchingOffBindings(state.applyBindings, currentPressed, event.key);
1277
+ if (activeMatchesSingleFnBindings.length > 0 ||
1278
+ activeMatchesOffBindings.length > 0) {
1279
+ event.preventDefault();
1280
+ }
1281
+ }
1288
1282
  };
1289
- return state;
1290
- },
1291
- });
1292
-
1293
- var index$2 = /*#__PURE__*/Object.freeze({
1294
- __proto__: null,
1295
- currentHitResult: currentHitResult,
1296
- hitResult: hitResult,
1297
- hitResultsLongPressDetails: hitResultsLongPressDetails,
1298
- hitResultsSkipNextTap: hitResultsSkipNextTap,
1299
- hitResultsTapDetails: hitResultsTapDetails,
1300
- hitState: hitState,
1301
- previousHitResult: previousHitResult,
1302
- useHitActions: useHitActions
1303
- });
1283
+ const handleKeyUp = (event) => {
1284
+ dispatch({
1285
+ type: 'set-key-pressed',
1286
+ key: event.key,
1287
+ pressed: false,
1288
+ });
1289
+ };
1290
+ window.addEventListener('keydown', handleKeyDown);
1291
+ window.addEventListener('keyup', handleKeyUp);
1292
+ return () => {
1293
+ window.removeEventListener('keydown', handleKeyDown);
1294
+ window.removeEventListener('keyup', handleKeyUp);
1295
+ };
1296
+ }, [applyStackKeyBindings, state.applyBindings, state.pressed]);
1297
+ React.useEffect(() => {
1298
+ const activeMatchesSingleFnBindings = matchingSingleFnBindings(state.applyBindings, state.pressed, state.lastPressed);
1299
+ const activeMatchesOffBindings = matchingOffBindings(state.applyBindings, state.pressed, state.lastPressed);
1300
+ activeMatchesSingleFnBindings.forEach((fn) => fn());
1301
+ activeMatchesOffBindings.forEach((fn) => fn());
1302
+ }, [state.pressed, state.lastPressed]);
1303
+ React.useEffect(() => {
1304
+ const matchingRepeatBindings = state.applyBindings
1305
+ .filter((binding) => binding.repeat &&
1306
+ binding.keyBind != null &&
1307
+ allPressed(binding.keyBind, state.pressed))
1308
+ .map((binding) => binding.fn);
1309
+ if (matchingRepeatBindings.length > 0) {
1310
+ const interval = setInterval(() => {
1311
+ matchingRepeatBindings.forEach((fn) => fn());
1312
+ }, keydownRepeatInterval);
1313
+ return () => {
1314
+ clearInterval(interval);
1315
+ };
1316
+ }
1317
+ else {
1318
+ return () => {
1319
+ return undefined;
1320
+ };
1321
+ }
1322
+ }, [state.applyBindings, state.lastPressed]);
1323
+ };
1304
1324
 
1305
- function useContextMenuActions() {
1306
- return {
1307
- pointerDown: useActionCallback(({ set }) => async (event, pointOverride) => {
1308
- var _a, _b;
1309
- if (event.button === 2) {
1310
- const xCoordinate = (_a = pointOverride === null || pointOverride === void 0 ? void 0 : pointOverride.x) !== null && _a !== void 0 ? _a : event.clientX;
1311
- const yCoordinate = (_b = pointOverride === null || pointOverride === void 0 ? void 0 : pointOverride.y) !== null && _b !== void 0 ? _b : event === null || event === void 0 ? void 0 : event.clientY;
1312
- set(contextMenuPosition, geometry.Point.create(xCoordinate, yCoordinate));
1313
- set(contextMenuTarget, event.target);
1314
- }
1315
- }),
1316
- pointerUp: useActionCallback(({ snapshot, set }) => async (event, type, predicate, onOpen, pointOverride) => {
1317
- var _a, _b;
1318
- const downPosition = await snapshot.getPromise(contextMenuPosition);
1319
- const active = await snapshot.getPromise(contextMenuActive);
1320
- if (downPosition != null && active == null) {
1321
- const xCoordinate = (_a = pointOverride === null || pointOverride === void 0 ? void 0 : pointOverride.x) !== null && _a !== void 0 ? _a : event.clientX;
1322
- const yCoordinate = (_b = pointOverride === null || pointOverride === void 0 ? void 0 : pointOverride.y) !== null && _b !== void 0 ? _b : event === null || event === void 0 ? void 0 : event.clientY;
1323
- const point = geometry.Point.create(xCoordinate, yCoordinate);
1324
- const pointDistance = downPosition != null ? geometry.Point.distance(downPosition, point) : 0;
1325
- const predicateResult = predicate == null || predicate(event);
1326
- if (pointDistance < 2 && predicateResult) {
1327
- onOpen === null || onOpen === void 0 ? void 0 : onOpen(event, downPosition !== null && downPosition !== void 0 ? downPosition : point);
1328
- set(contextMenuActive, type);
1325
+ function useLongPress({ target, callback, delay = 500, onMovement, }) {
1326
+ const [longPressTimeout, setLongPressTimeout] = React__namespace.useState();
1327
+ const [touchStartPosition, setTouchStartPosition] = React__namespace.useState();
1328
+ React__namespace.useEffect(() => {
1329
+ const handleTouchStart = (e) => {
1330
+ const event = e;
1331
+ if (event.touches != null && event.touches.length === 1) {
1332
+ if (longPressTimeout != null) {
1333
+ clearTimeout(longPressTimeout);
1329
1334
  }
1335
+ setTouchStartPosition(geometry.Point.create(event.touches[0].clientX, event.touches[0].clientY));
1336
+ setLongPressTimeout(setTimeout(() => callback === null || callback === void 0 ? void 0 : callback(event), delay));
1330
1337
  }
1331
- }),
1332
- contextMenu: useActionCallback(() => (event, predicate) => {
1333
- if (predicate == null || predicate(event)) {
1334
- event.preventDefault();
1338
+ };
1339
+ const handleTouchMove = (e) => {
1340
+ const event = e;
1341
+ if (event.touches != null &&
1342
+ event.touches.length > 0 &&
1343
+ longPressTimeout != null &&
1344
+ touchStartPosition != null &&
1345
+ geometry.Point.distance(touchStartPosition, geometry.Point.create(event.touches[0].clientX, event.touches[0].clientY)) >= 2) {
1346
+ clearTimeout(longPressTimeout);
1347
+ onMovement === null || onMovement === void 0 ? void 0 : onMovement();
1335
1348
  }
1336
- }),
1337
- longPress: useActionCallback(({ set }) => (event, type, predicate, onOpen) => {
1338
- if (predicate == null || predicate(event)) {
1339
- const point = geometry.Point.create(event.touches[0].clientX, event.touches[0].clientY);
1340
- set(contextMenuPosition, point);
1341
- set(contextMenuTarget, event.target);
1342
- set(contextMenuActive, type);
1343
- onOpen === null || onOpen === void 0 ? void 0 : onOpen(event, point);
1349
+ };
1350
+ const handleTouchEnd = () => {
1351
+ if (longPressTimeout != null) {
1352
+ clearTimeout(longPressTimeout);
1344
1353
  }
1345
- }),
1346
- clearActiveContextMenu: useActionCallback(({ reset, set }) => (dismissedFromWindowPointerEvent) => {
1347
- set(hitResultsSkipNextTap, !!dismissedFromWindowPointerEvent);
1348
- reset(contextMenuActive);
1349
- reset(contextMenuActions);
1350
- reset(contextMenuPosition);
1351
- }),
1352
- clearDismissedState: useActionCallback(({ reset }) => () => reset(hitResultsSkipNextTap)),
1353
- };
1354
- }
1355
-
1356
- function targetWithinMenu(event) {
1357
- return (event.target instanceof Element && isChildOf('vertex-menu', event.target));
1358
- }
1359
- function targetShouldSkipNextHit(event) {
1360
- return (event.target instanceof Element && isChildOf('vertex-viewer', event.target));
1361
- }
1362
- function isChildOf(elementType, target) {
1363
- return target.closest(elementType) != null;
1354
+ };
1355
+ target === null || target === void 0 ? void 0 : target.addEventListener('touchstart', handleTouchStart);
1356
+ target === null || target === void 0 ? void 0 : target.addEventListener('touchmove', handleTouchMove);
1357
+ target === null || target === void 0 ? void 0 : target.addEventListener('touchend', handleTouchEnd);
1358
+ return () => {
1359
+ target === null || target === void 0 ? void 0 : target.removeEventListener('touchstart', handleTouchStart);
1360
+ target === null || target === void 0 ? void 0 : target.removeEventListener('touchmove', handleTouchMove);
1361
+ target === null || target === void 0 ? void 0 : target.removeEventListener('touchend', handleTouchEnd);
1362
+ };
1363
+ }, [target, longPressTimeout, touchStartPosition]);
1364
1364
  }
1365
1365
 
1366
1366
  const VertexContextMenu = ({ targetElement, menuType, disableBackdrop, openPredicate, onOpen, onClose, children, }) => {
@@ -1412,7 +1412,9 @@ const VertexContextMenu = ({ targetElement, menuType, disableBackdrop, openPredi
1412
1412
  var _a, _b;
1413
1413
  const pointerEvent = event;
1414
1414
  const targetElement = target;
1415
- const boundingBox = targetElement != null ? targetElement.getBoundingClientRect() : undefined;
1415
+ const boundingBox = targetElement != null
1416
+ ? targetElement.getBoundingClientRect()
1417
+ : undefined;
1416
1418
  const xCoordinate = pointerEvent.clientX - ((_a = boundingBox === null || boundingBox === void 0 ? void 0 : boundingBox.x) !== null && _a !== void 0 ? _a : 0);
1417
1419
  const yCoordinate = pointerEvent.clientY - ((_b = boundingBox === null || boundingBox === void 0 ? void 0 : boundingBox.y) !== null && _b !== void 0 ? _b : 0);
1418
1420
  contextMenuActions.pointerDown(pointerEvent, geometry.Point.create(xCoordinate, yCoordinate));
@@ -1421,7 +1423,9 @@ const VertexContextMenu = ({ targetElement, menuType, disableBackdrop, openPredi
1421
1423
  var _a, _b;
1422
1424
  const pointerEvent = event;
1423
1425
  const targetElement = target;
1424
- const boundingBox = targetElement != null ? targetElement.getBoundingClientRect() : undefined;
1426
+ const boundingBox = targetElement != null
1427
+ ? targetElement.getBoundingClientRect()
1428
+ : undefined;
1425
1429
  const xCoordinate = pointerEvent.clientX - ((_a = boundingBox === null || boundingBox === void 0 ? void 0 : boundingBox.x) !== null && _a !== void 0 ? _a : 0);
1426
1430
  const yCoordinate = pointerEvent.clientY - ((_b = boundingBox === null || boundingBox === void 0 ? void 0 : boundingBox.y) !== null && _b !== void 0 ? _b : 0);
1427
1431
  contextMenuActions.pointerUp(event, menuType, openPredicate, onOpen, geometry.Point.create(xCoordinate, yCoordinate));
@@ -1681,18 +1685,18 @@ const selectionState = recoil.selector({
1681
1685
  });
1682
1686
 
1683
1687
  var index$1 = /*#__PURE__*/Object.freeze({
1684
- __proto__: null,
1685
- selectionHighestSelectedAncestor: selectionHighestSelectedAncestor,
1686
- selectionLastSelectWasMultiSelect: selectionLastSelectWasMultiSelect,
1687
- selectionLastSelected: selectionLastSelected,
1688
- selectionLastSelectionFromViewer: selectionLastSelectionFromViewer,
1689
- selectionPreviousVisibleSummary: selectionPreviousVisibleSummary,
1690
- selectionSelectedItemIds: selectionSelectedItemIds,
1691
- selectionSelectedItems: selectionSelectedItems,
1692
- selectionState: selectionState,
1693
- selectionVisibleCount: selectionVisibleCount,
1694
- selectionVisibleSummary: selectionVisibleSummary,
1695
- useSelectionActions: useSelectionActions
1688
+ __proto__: null,
1689
+ selectionHighestSelectedAncestor: selectionHighestSelectedAncestor,
1690
+ selectionLastSelectWasMultiSelect: selectionLastSelectWasMultiSelect,
1691
+ selectionLastSelected: selectionLastSelected,
1692
+ selectionLastSelectionFromViewer: selectionLastSelectionFromViewer,
1693
+ selectionPreviousVisibleSummary: selectionPreviousVisibleSummary,
1694
+ selectionSelectedItemIds: selectionSelectedItemIds,
1695
+ selectionSelectedItems: selectionSelectedItems,
1696
+ selectionState: selectionState,
1697
+ selectionVisibleCount: selectionVisibleCount,
1698
+ selectionVisibleSummary: selectionVisibleSummary,
1699
+ useSelectionActions: useSelectionActions
1696
1700
  });
1697
1701
 
1698
1702
  const VertexFitSelectedMenuItem = () => {
@@ -1712,16 +1716,14 @@ const VertexFlyToMenuItem = () => {
1712
1716
  return (jsxRuntime.jsxs(uiReact.VertexMenuItem, { "data-testid": "fly-to-part-menu-option", onClick: () => {
1713
1717
  var _a;
1714
1718
  const isRow = contextMenuItemIsRow(currentItem);
1715
- const itemId = isRow
1716
- ? (_a = currentItem === null || currentItem === void 0 ? void 0 : currentItem.node.id) === null || _a === void 0 ? void 0 : _a.hex
1717
- : currentItem === null || currentItem === void 0 ? void 0 : currentItem.id;
1719
+ const itemId = isRow ? (_a = currentItem === null || currentItem === void 0 ? void 0 : currentItem.node.id) === null || _a === void 0 ? void 0 : _a.hex : currentItem === null || currentItem === void 0 ? void 0 : currentItem.id;
1718
1720
  if (itemId != null) {
1719
1721
  cameraActions.flyToById(itemId);
1720
1722
  }
1721
1723
  }, disabled: currentItem == null, children: [jsxRuntime.jsx(uiReact.VertexIcon, { slot: "icon", name: "paper-airplane", size: "sm" }), jsxRuntime.jsx("div", { className: "pl-2", children: "Fly To" })] }));
1722
1724
  };
1723
1725
 
1724
- function useSceneItemsOperations({ viewerElement }) {
1726
+ function useSceneItemsOperations({ viewerElement, }) {
1725
1727
  const sceneItemsOperation = React.useCallback(async (f, ids) => {
1726
1728
  const scene = await (viewerElement === null || viewerElement === void 0 ? void 0 : viewerElement.scene());
1727
1729
  if (ids == null) {
@@ -1767,7 +1769,9 @@ function useSceneItemsOperations({ viewerElement }) {
1767
1769
 
1768
1770
  const VertexHideAllMenuItem = () => {
1769
1771
  const viewerHTMLElement = recoil.useRecoilValue(viewerElement);
1770
- const sceneItemOperations = useSceneItemsOperations({ viewerElement: viewerHTMLElement !== null && viewerHTMLElement !== void 0 ? viewerHTMLElement : null });
1772
+ const sceneItemOperations = useSceneItemsOperations({
1773
+ viewerElement: viewerHTMLElement !== null && viewerHTMLElement !== void 0 ? viewerHTMLElement : null,
1774
+ });
1771
1775
  return (jsxRuntime.jsxs(uiReact.VertexMenuItem, { "data-testid": "hide-all-menu-option", onClick: () => {
1772
1776
  sceneItemOperations.sceneItemsOperation((builder) => builder.hide());
1773
1777
  }, children: [jsxRuntime.jsx(uiReact.VertexIcon, { slot: "icon", name: "visibility-hidden", size: "sm" }), jsxRuntime.jsx("div", { className: "pl-2", children: "Hide All Parts" })] }));
@@ -1776,13 +1780,13 @@ const VertexHideAllMenuItem = () => {
1776
1780
  const VertexHidePartMenuItem = () => {
1777
1781
  const viewerHTMLElement = recoil.useRecoilValue(viewerElement);
1778
1782
  const currentItem = recoil.useRecoilValue(contextMenuItem);
1779
- const sceneItemOperations = useSceneItemsOperations({ viewerElement: viewerHTMLElement !== null && viewerHTMLElement !== void 0 ? viewerHTMLElement : null });
1783
+ const sceneItemOperations = useSceneItemsOperations({
1784
+ viewerElement: viewerHTMLElement !== null && viewerHTMLElement !== void 0 ? viewerHTMLElement : null,
1785
+ });
1780
1786
  return (jsxRuntime.jsxs(uiReact.VertexMenuItem, { "data-testid": "hide-menu-option", onClick: () => {
1781
1787
  var _a;
1782
1788
  const isRow = contextMenuItemIsRow(currentItem);
1783
- const itemId = isRow
1784
- ? (_a = currentItem === null || currentItem === void 0 ? void 0 : currentItem.node.id) === null || _a === void 0 ? void 0 : _a.hex
1785
- : currentItem.id;
1789
+ const itemId = isRow ? (_a = currentItem === null || currentItem === void 0 ? void 0 : currentItem.node.id) === null || _a === void 0 ? void 0 : _a.hex : currentItem.id;
1786
1790
  if (itemId != null) {
1787
1791
  sceneItemOperations.sceneItemsOperation((builder) => builder.hide(), [itemId]);
1788
1792
  }
@@ -1792,13 +1796,17 @@ const VertexHidePartMenuItem = () => {
1792
1796
  const VertexHideSelectedMenuItem = () => {
1793
1797
  const viewerHTMLElement = recoil.useRecoilValue(viewerElement);
1794
1798
  const selectedItems = recoil.useRecoilValue(selectionSelectedItemIds);
1795
- const sceneItemOperations = useSceneItemsOperations({ viewerElement: viewerHTMLElement !== null && viewerHTMLElement !== void 0 ? viewerHTMLElement : null });
1799
+ const sceneItemOperations = useSceneItemsOperations({
1800
+ viewerElement: viewerHTMLElement !== null && viewerHTMLElement !== void 0 ? viewerHTMLElement : null,
1801
+ });
1796
1802
  return (jsxRuntime.jsxs(uiReact.VertexMenuItem, { "data-testid": "hide-selected-menu-option", onClick: () => sceneItemOperations.hideSelected(), disabled: selectedItems.length === 0, children: [jsxRuntime.jsx(uiReact.VertexIcon, { slot: "icon", name: "visibility-hidden", size: "sm" }), jsxRuntime.jsx("div", { className: "pl-2", children: "Hide Selected" })] }));
1797
1803
  };
1798
1804
 
1799
1805
  const VertexShowAllMenuItem = () => {
1800
1806
  const viewerHTMLElement = recoil.useRecoilValue(viewerElement);
1801
- const sceneItemOperations = useSceneItemsOperations({ viewerElement: viewerHTMLElement !== null && viewerHTMLElement !== void 0 ? viewerHTMLElement : null });
1807
+ const sceneItemOperations = useSceneItemsOperations({
1808
+ viewerElement: viewerHTMLElement !== null && viewerHTMLElement !== void 0 ? viewerHTMLElement : null,
1809
+ });
1802
1810
  return (jsxRuntime.jsxs(uiReact.VertexMenuItem, { "data-testid": "show-all-menu-option", onClick: () => {
1803
1811
  sceneItemOperations.sceneItemsOperation((builder) => builder.show());
1804
1812
  }, children: [jsxRuntime.jsx(uiReact.VertexIcon, { slot: "icon", name: "visibility-visible", size: "sm" }), jsxRuntime.jsx("div", { className: "pl-2", children: "Show All Parts" })] }));
@@ -1807,13 +1815,13 @@ const VertexShowAllMenuItem = () => {
1807
1815
  const VertexShowOnlyMenuItem = () => {
1808
1816
  const viewerHTMLElement = recoil.useRecoilValue(viewerElement);
1809
1817
  const currentItem = recoil.useRecoilValue(contextMenuItem);
1810
- const sceneItemOperations = useSceneItemsOperations({ viewerElement: viewerHTMLElement !== null && viewerHTMLElement !== void 0 ? viewerHTMLElement : null });
1818
+ const sceneItemOperations = useSceneItemsOperations({
1819
+ viewerElement: viewerHTMLElement !== null && viewerHTMLElement !== void 0 ? viewerHTMLElement : null,
1820
+ });
1811
1821
  return (jsxRuntime.jsxs(uiReact.VertexMenuItem, { "data-testid": "show-only-menu-option", onClick: () => {
1812
1822
  var _a;
1813
1823
  const isRow = contextMenuItemIsRow(currentItem);
1814
- const itemId = isRow
1815
- ? (_a = currentItem === null || currentItem === void 0 ? void 0 : currentItem.node.id) === null || _a === void 0 ? void 0 : _a.hex
1816
- : currentItem === null || currentItem === void 0 ? void 0 : currentItem.id;
1824
+ const itemId = isRow ? (_a = currentItem === null || currentItem === void 0 ? void 0 : currentItem.node.id) === null || _a === void 0 ? void 0 : _a.hex : currentItem === null || currentItem === void 0 ? void 0 : currentItem.id;
1817
1825
  if (itemId != null) {
1818
1826
  sceneItemOperations.showOnlyItem(itemId);
1819
1827
  }
@@ -1823,7 +1831,9 @@ const VertexShowOnlyMenuItem = () => {
1823
1831
  const VertexShowOnlySelectedMenuItem = () => {
1824
1832
  const viewerHTMLElement = recoil.useRecoilValue(viewerElement);
1825
1833
  const selectedItems = recoil.useRecoilValue(selectionSelectedItemIds);
1826
- const sceneItemOperations = useSceneItemsOperations({ viewerElement: viewerHTMLElement !== null && viewerHTMLElement !== void 0 ? viewerHTMLElement : null });
1834
+ const sceneItemOperations = useSceneItemsOperations({
1835
+ viewerElement: viewerHTMLElement !== null && viewerHTMLElement !== void 0 ? viewerHTMLElement : null,
1836
+ });
1827
1837
  return (jsxRuntime.jsxs(uiReact.VertexMenuItem, { "data-testid": "show-only-selected-menu-option", onClick: () => sceneItemOperations.showOnlySelected(), disabled: selectedItems.length === 0, children: [jsxRuntime.jsx(uiReact.VertexIcon, { slot: "icon", name: "visibility-visible", size: "sm" }), jsxRuntime.jsx("div", { className: "pl-2", children: "Show Only Selected" })] }));
1828
1838
  };
1829
1839
 
@@ -1908,16 +1918,14 @@ const DefaultSceneTreeContextMenu = () => {
1908
1918
  return (jsxRuntime.jsxs("div", { className: "w-56", children: [jsxRuntime.jsx(VertexHideSelectedMenuItem, {}), jsxRuntime.jsx(VertexHideAllMenuItem, {}), jsxRuntime.jsx(VertexShowOnlyMenuItem, {}), jsxRuntime.jsx(VertexShowOnlySelectedMenuItem, {}), jsxRuntime.jsx(VertexShowAllMenuItem, {}), jsxRuntime.jsx(uiReact.VertexMenuDivider, { className: "md:contents hidden short:hidden" }), jsxRuntime.jsx(VertexFitSelectedMenuItem, {}), jsxRuntime.jsx(VertexFlyToMenuItem, {})] }));
1909
1919
  };
1910
1920
 
1911
- const VertexSceneTreeContextMenu = ({ children }) => {
1921
+ const VertexSceneTreeContextMenu = ({ children, }) => {
1912
1922
  const sceneTreeActions = useSceneTreeActions();
1913
1923
  const sceneTreeHTMLElement = recoil.useRecoilValue(sceneTreeElement);
1914
1924
  const hasDefinedChildren = children != null && children !== false;
1915
1925
  return (jsxRuntime.jsx(VertexContextMenu, { menuType: "scene-tree", targetElement: sceneTreeHTMLElement, onOpen: async (event, _pt) => {
1916
1926
  const pointerEvent = event;
1917
1927
  await sceneTreeActions.setContextMenuItem(pointerEvent.clientY);
1918
- }, disableBackdrop: true, children: hasDefinedChildren
1919
- ? (children)
1920
- : (jsxRuntime.jsx(DefaultSceneTreeContextMenu, {})) }));
1928
+ }, disableBackdrop: true, children: hasDefinedChildren ? children : jsxRuntime.jsx(DefaultSceneTreeContextMenu, {}) }));
1921
1929
  };
1922
1930
 
1923
1931
  const DefaultViewerContextMenu = () => {
@@ -1927,9 +1935,7 @@ const DefaultViewerContextMenu = () => {
1927
1935
  const VertexViewerContextMenu = ({ children }) => {
1928
1936
  const viewerHTMLElement = recoil.useRecoilValue(viewerElement);
1929
1937
  const hasDefinedChildren = children != null && children !== false;
1930
- return (jsxRuntime.jsx(VertexContextMenu, { menuType: "viewer", targetElement: viewerHTMLElement, disableBackdrop: true, children: hasDefinedChildren
1931
- ? (children)
1932
- : (jsxRuntime.jsx(DefaultViewerContextMenu, {})) }));
1938
+ return (jsxRuntime.jsx(VertexContextMenu, { menuType: "viewer", targetElement: viewerHTMLElement, disableBackdrop: true, children: hasDefinedChildren ? children : jsxRuntime.jsx(DefaultViewerContextMenu, {}) }));
1933
1939
  };
1934
1940
 
1935
1941
  const sdkConfig = recoil.atom({
@@ -1979,6 +1985,24 @@ function styleFromFontFace(fontFace) {
1979
1985
  }
1980
1986
  }
1981
1987
 
1988
+ const VertexSceneTreeCollapseAll = () => {
1989
+ const sceneTreeHTMLElement = recoil.useRecoilValue(sceneTreeElement);
1990
+ return (jsxRuntime.jsx(uiReact.VertexTooltip, { className: "w-auto", content: "Collapse All", placement: "top", children: jsxRuntime.jsx(uiReact.VertexIcon, { size: "sm", className: "h-6 w-6 hover:bg-neutral-300 rounded cursor-pointer", "data-testid": "collapse-all-icon", name: "collapse-all", onClick: () => {
1991
+ sceneTreeHTMLElement === null || sceneTreeHTMLElement === void 0 ? void 0 : sceneTreeHTMLElement.collapseAll();
1992
+ } }) }));
1993
+ };
1994
+
1995
+ const VertexSceneTreeExpandAll = () => {
1996
+ const sceneTreeHTMLElement = recoil.useRecoilValue(sceneTreeElement);
1997
+ return (jsxRuntime.jsx(uiReact.VertexTooltip, { className: "w-auto", content: "Expand All", placement: "top", children: jsxRuntime.jsx(uiReact.VertexIcon, { size: "sm", "data-testid": "expand-all-icon", className: "h-6 w-6 hover:bg-neutral-300 rounded cursor-pointer", name: "expand-all", onClick: () => {
1998
+ sceneTreeHTMLElement === null || sceneTreeHTMLElement === void 0 ? void 0 : sceneTreeHTMLElement.expandAll();
1999
+ } }) }));
2000
+ };
2001
+
2002
+ function VertexSceneTreeToolbar() {
2003
+ return (jsxRuntime.jsx(viewerReact.VertexSceneTreeToolbar, { className: "h-10 border-b border-neutral-300 box-border", children: jsxRuntime.jsxs("div", { className: "flex flex-shrink-0 w-full text-neutral-700 items-center gap mx-2", children: [jsxRuntime.jsx(VertexSceneTreeExpandAll, {}), jsxRuntime.jsx(VertexSceneTreeCollapseAll, {})] }) }));
2004
+ }
2005
+
1982
2006
  const DEFAULT_NAME_COLUMN = {
1983
2007
  binding: '{{row.node.name}}',
1984
2008
  label: 'Name',
@@ -2057,24 +2081,6 @@ const VertexSceneTreeTableLayout = (sdkProps) => {
2057
2081
  }) })));
2058
2082
  };
2059
2083
 
2060
- const VertexSceneTreeExpandAll = () => {
2061
- const sceneTreeHTMLElement = recoil.useRecoilValue(sceneTreeElement);
2062
- return (jsxRuntime.jsx(uiReact.VertexTooltip, { className: "w-auto", content: "Expand All", placement: "top", children: jsxRuntime.jsx(uiReact.VertexIcon, { size: "sm", "data-testid": "expand-all-icon", className: "h-6 w-6 hover:bg-neutral-300 rounded cursor-pointer", name: "expand-all", onClick: () => {
2063
- sceneTreeHTMLElement === null || sceneTreeHTMLElement === void 0 ? void 0 : sceneTreeHTMLElement.expandAll();
2064
- } }) }));
2065
- };
2066
-
2067
- const VertexSceneTreeCollapseAll = () => {
2068
- const sceneTreeHTMLElement = recoil.useRecoilValue(sceneTreeElement);
2069
- return (jsxRuntime.jsx(uiReact.VertexTooltip, { className: "w-auto", content: "Collapse All", placement: "top", children: jsxRuntime.jsx(uiReact.VertexIcon, { size: "sm", className: "h-6 w-6 hover:bg-neutral-300 rounded cursor-pointer", "data-testid": "collapse-all-icon", name: "collapse-all", onClick: () => {
2070
- sceneTreeHTMLElement === null || sceneTreeHTMLElement === void 0 ? void 0 : sceneTreeHTMLElement.collapseAll();
2071
- } }) }));
2072
- };
2073
-
2074
- function VertexSceneTreeToolbar() {
2075
- return (jsxRuntime.jsx(viewerReact.VertexSceneTreeToolbar, { className: "h-10 border-b border-neutral-300 box-border", children: jsxRuntime.jsxs("div", { className: "flex flex-shrink-0 w-full text-neutral-700 items-center gap mx-2", children: [jsxRuntime.jsx(VertexSceneTreeExpandAll, {}), jsxRuntime.jsx(VertexSceneTreeCollapseAll, {})] }) }));
2076
- }
2077
-
2078
2084
  const VertexSceneTree = (_a) => {
2079
2085
  var { id, font, backgroundColors, children, style, onPointerDown, onClick, onToggleSelection, onToggleExpansion, onToggleVisibility, className, rowData } = _a, sdkProps = __rest(_a, ["id", "font", "backgroundColors", "children", "style", "onPointerDown", "onClick", "onToggleSelection", "onToggleExpansion", "onToggleVisibility", "className", "rowData"]);
2080
2086
  const config = recoil.useRecoilValue(sdkConfig);
@@ -2571,8 +2577,8 @@ const VertexViewerToolkitRootConfig = ({ config, children, }) => {
2571
2577
  };
2572
2578
 
2573
2579
  var index = /*#__PURE__*/Object.freeze({
2574
- __proto__: null,
2575
- get AssemblyFontFace () { return AssemblyFontFace; }
2580
+ __proto__: null,
2581
+ get AssemblyFontFace () { return AssemblyFontFace; }
2576
2582
  });
2577
2583
 
2578
2584
  exports.CrossSection = index$3;