@vertexvis/viewer-toolkit-react 0.0.2-canary.1 → 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.
@@ -1,557 +1,292 @@
1
1
  'use strict';
2
2
 
3
3
  var jsxRuntime = require('react/jsx-runtime');
4
- var React = require('react');
5
4
  var uiReact = require('@vertexvis/ui-react');
6
- var utils = require('@vertexvis/utils');
5
+ var classNames = require('classnames');
7
6
  var recoil = require('recoil');
8
- var geometry = require('@vertexvis/geometry');
9
7
  var Pino = require('pino');
8
+ var geometry = require('@vertexvis/geometry');
9
+ var utils = require('@vertexvis/utils');
10
+ var React = require('react');
10
11
  var viewerReact = require('@vertexvis/viewer-react');
11
- var classNames = require('classnames');
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
- }
25
- });
26
- }
27
- n.default = e;
28
- return Object.freeze(n);
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
+ }
25
+ });
26
+ }
27
+ n.default = e;
28
+ return Object.freeze(n);
29
29
  }
30
30
 
31
31
  var React__namespace = /*#__PURE__*/_interopNamespaceDefault(React);
32
32
 
33
- // DEPRECATED - avoid if possible
34
- const useRecoilReducer = ({ reducer, atom, }) => {
35
- const state = recoil.useRecoilValue(atom);
36
- const dispatch = useRecoilReducerDispatch({
37
- reducer,
38
- atom,
39
- });
40
- return [state, dispatch];
41
- };
42
- // DEPRECATED - avoid if possible
43
- const useRecoilReducerDispatch = ({ reducer, atom, }) => {
44
- const dispatch = recoil.useRecoilCallback(({ set }) => async (action) => {
45
- set(atom, (previousValue) => reducer(previousValue, action));
46
- }, []);
47
- return dispatch;
33
+ const DEFAULT_VERTICAL_SCALE = 1;
34
+ const VertexResizableContent = ({ displayShadow, heading, id, initialScale, position = 'left', children, onResize, }) => {
35
+ const isHorizontallyPositioned = position === 'left' || position === 'right';
36
+ const isVerticallyPositioned = position === 'top';
37
+ function getHorizontalResizeDirection() {
38
+ switch (position) {
39
+ case 'left':
40
+ return 'right';
41
+ case 'right':
42
+ return 'left';
43
+ default:
44
+ return 'none';
45
+ }
46
+ }
47
+ function getVerticalResizeDirection() {
48
+ return position === 'top' ? 'top' : 'none';
49
+ }
50
+ const initialVerticalScale = initialScale != null ? initialScale : DEFAULT_VERTICAL_SCALE;
51
+ return (jsxRuntime.jsx(uiReact.VertexResizable, { id: id, "data-testid": `resizable-content-position-${position}`, className: classNames('pointer-events-auto z-popover md:z-overlay bg-white bg-opacity-95 flex-grow-0 flex-shrink-0', {
52
+ ['border-r min-w-75 max-w-half']: position === 'left',
53
+ ['sidebar-shadow-right']: position === 'left' && displayShadow,
54
+ ['border-l right-0 relative']: position === 'right',
55
+ ['sidebar-shadow-left']: position === 'right' && displayShadow,
56
+ ['border-t bottom-0 fixed']: position === 'top',
57
+ ['min-h-12 sheet']: isVerticallyPositioned,
58
+ }), style: {
59
+ // This corrects an issue on mobile where `100vh` reflects the space
60
+ // under the address bar and bottom toolbar in CSS.
61
+ maxHeight: position === 'top' ? window.innerHeight : undefined,
62
+ }, initialHorizontalScale: isHorizontallyPositioned ? initialScale : undefined, initialVerticalScale: isVerticallyPositioned ? initialVerticalScale : undefined, horizontalDirection: getHorizontalResizeDirection(), verticalDirection: getVerticalResizeDirection(), position: position === 'right' || position === 'top' ? 'absolute' : 'relative', onResizeEnd: () => onResize === null || onResize === void 0 ? void 0 : onResize(), children: jsxRuntime.jsxs("div", { className: "flex flex-col h-full w-full", children: [jsxRuntime.jsx("div", { className: "flex justify-center w-full", children: jsxRuntime.jsx("div", { className: "block md:hidden w-20 h-0.5 mt-0.5 bg-neutral-600 rounded" }) }), heading, jsxRuntime.jsx("div", { className: classNames('w-full flex flex-col h-0 flex-grow', {
63
+ ['right-0']: position === 'right',
64
+ }), children: children })] }) }));
48
65
  };
49
66
 
50
- const isInputElement = (target) => {
51
- const isAutoResizeTextarea = target instanceof HTMLElement &&
52
- target.tagName === 'VERTEX-AUTO-RESIZE-TEXTAREA';
53
- const isTextField = target instanceof HTMLElement && target.tagName === 'VERTEX-TEXTFIELD';
54
- const isContentEditable = target instanceof HTMLElement && target.contentEditable === 'true';
55
- const isSceneTreeSearch = target instanceof HTMLElement &&
56
- target.tagName === 'VERTEX-SCENE-TREE-SEARCH';
57
- const isInput = target instanceof HTMLInputElement || target instanceof HTMLTextAreaElement;
58
- const isVertexViewerPinTool = target instanceof HTMLElement &&
59
- target.tagName === 'VERTEX-VIEWER-PIN-TOOL';
60
- const isVertexViewerTransformWidget = target instanceof HTMLElement &&
61
- target.tagName === 'VERTEX-VIEWER-TRANSFORM-WIDGET';
62
- return (isAutoResizeTextarea ||
63
- isTextField ||
64
- isContentEditable ||
65
- isSceneTreeSearch ||
66
- isInput ||
67
- isVertexViewerPinTool ||
68
- isVertexViewerTransformWidget);
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
+ });
95
+
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;
69
128
  };
70
129
 
71
- const keyBindings = recoil.atom({
72
- key: 'keyBindings',
73
- default: {
74
- applyBindings: [],
75
- bindings: {},
76
- pressed: {},
130
+ // Create a new logger instance
131
+ const pinoLogger = Pino({
132
+ formatters: {
133
+ level(level) {
134
+ return { level };
135
+ },
77
136
  },
78
137
  });
79
- function reducer(state, action) {
80
- var _a, _b, _c, _d;
81
- switch (action.type) {
82
- case 'push-key-binding':
83
- const toAdd = (_a = state.bindings[action.binding.keyBind]) === null || _a === void 0 ? void 0 : _a.find((b) => b.id === action.binding.id);
84
- return toAdd != null
85
- ? state
86
- : Object.assign(Object.assign({}, state), { bindings: Object.assign(Object.assign({}, state.bindings), { [action.binding.keyBind]: [
87
- ...((_b = state.bindings[action.binding.keyBind]) !== null && _b !== void 0 ? _b : []),
88
- action.binding,
89
- ] }) });
90
- case 'remove-key-binding':
91
- const toRemove = (_c = state.bindings[action.binding.keyBind]) === null || _c === void 0 ? void 0 : _c.find((b) => b.id === action.binding.id);
92
- return toRemove == null
93
- ? state
94
- : 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) }) });
95
- case 'add-apply-key-binding':
96
- return Object.assign(Object.assign({}, state), { applyBindings: [...state.applyBindings, action.binding] });
97
- case 'remove-apply-key-binding':
98
- return Object.assign(Object.assign({}, state), { applyBindings: state.applyBindings.filter((binding) => binding.id !== action.id) });
99
- case 'set-key-pressed':
100
- return Object.assign(Object.assign({}, state), { applyBindings: state.applyBindings.map((binding) => (Object.assign(Object.assign({}, binding), { active: binding.keyBind != null &&
101
- allPressed(binding.keyBind, state.pressed) }))), pressed: Object.assign(Object.assign({}, state.pressed), { [action.key]: action.pressed }), lastPressed: action.pressed ? action.key : undefined });
102
- }
103
- }
104
- const useKeyBindingState = () => {
105
- return useRecoilReducer({
106
- reducer,
107
- atom: keyBindings,
108
- });
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
+ },
109
171
  };
110
- function pressedValue(keyBind, pressed) {
111
- return keyBind.includes('!')
112
- ? !pressed[keyBind.replace('!', '')] &&
113
- !pressed[keyBind.replace('!', '').toLowerCase()]
114
- : pressed[keyBind] || pressed[keyBind.toLowerCase()];
115
- }
116
- function isPressed(keyBind, pressed) {
117
- const keys = keyBind.split('||');
118
- return keys.length > 1
119
- ? keys.some((key) => pressedValue(key, pressed))
120
- : pressedValue(keys[0], pressed);
121
- }
122
- function allPressed(keyBind, pressed) {
123
- const keys = keyBind.split('+');
124
- return keys.every((key) => isPressed(key, pressed));
125
- }
126
- function matchingSingleFnBindings(applyBindings, pressed, lastPressed) {
127
- return applyBindings
128
- .filter((binding) => !binding.repeat)
129
- .filter((binding) => {
130
- var _a;
131
- return binding.keyBind != null &&
132
- lastPressed != null &&
133
- ((_a = binding.keyBind) === null || _a === void 0 ? void 0 : _a.includes(lastPressed)) &&
134
- allPressed(binding.keyBind, pressed);
135
- })
136
- .map((binding) => binding.fn);
137
- }
138
- function matchingOffBindings(applyBindings, pressed, lastPressed) {
139
- return applyBindings
140
- .filter((binding) => binding.off &&
141
- binding.active &&
142
- binding.keyBind != null &&
143
- lastPressed == null &&
144
- !allPressed(binding.keyBind, pressed))
145
- .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 {
146
176
  }
147
177
  /**
148
- * Depends on `useKeyBindings`.
178
+ * Returns a Recoil callback that can be used for action hooks.
149
179
  *
150
- * Adds a global key binding. Any key binding
151
- * added this way will listen to global state for pressed
152
- * keys, and executed whenever the key state matches the
153
- * provided `keyBind`.
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.
154
183
  *
155
- * @param binding - The `ApplyKeyBinding` to add.
156
- */
157
- const useApplyKeyBinding = (binding) => {
158
- const [state, dispatch] = useKeyBindingState();
159
- React.useEffect(() => {
160
- const id = utils.UUID.create();
161
- dispatch({
162
- type: 'add-apply-key-binding',
163
- binding: Object.assign(Object.assign({}, binding), { id, active: binding.keyBind != null && allPressed(binding.keyBind, state.pressed) }),
164
- });
165
- return () => {
166
- dispatch({
167
- type: 'remove-apply-key-binding',
168
- id,
169
- });
170
- };
171
- }, [binding.fn, binding.off, binding.keyBind, binding.repeat]);
172
- };
173
- /**
174
- * Depends on `useKeyBindings`.
184
+ * If you want to use the original Recoil callback behavior, pass
185
+ * `DefaultRecoilCallbackDepsBehavior`.
175
186
  *
176
- * Adds a stack-based key binding. Any key binding
177
- * added this way will be added to an existing (or new)
178
- * stack for the specified `keyBind`.
179
- *
180
- * Provided `binding`s will be added and cancelled based
181
- * on the specified `addPredicate` and `cancelPredicate`
182
- * respectively. These predicates are evaluated any time
183
- * that the `deps` array changes.
184
- *
185
- * @param binding - The `StackKeyBinding` to add.
186
- * @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
187
191
  */
188
- const useStackKeyBinding = (binding, deps = []) => {
189
- const [, dispatch] = useKeyBindingState();
190
- React.useEffect(() => {
191
- const addPredicatePassing = binding.addPredicate == null || binding.addPredicate();
192
- const cancelPredicatePassing = binding.cancelPredicate != null && binding.cancelPredicate();
193
- if (addPredicatePassing) {
194
- dispatch({
195
- type: 'push-key-binding',
196
- binding,
197
- });
198
- }
199
- if (cancelPredicatePassing) {
200
- dispatch({
201
- type: 'remove-key-binding',
202
- binding,
203
- });
204
- }
205
- }, deps);
206
- };
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
+ }
207
206
  /**
208
- * 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.
209
210
  *
210
- * This hook must appear in the tree for `useStackKeyBinding`
211
- * 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.
212
234
  */
213
- const useKeyBindings = ({ keydownRepeatInterval = 25, keydownIgnorePredicate = isInputElement, } = {}) => {
214
- const [state, dispatch] = useKeyBindingState();
215
- const applyStackKeyBindings = React.useCallback((key) => {
216
- Object.keys(state.bindings)
217
- .filter((k) => k.includes(key) && allPressed(k, Object.assign(Object.assign({}, state.pressed), { [key]: true })))
218
- .forEach((k) => {
219
- const bindings = state.bindings[k];
220
- const poppedBinding = bindings.length > 0 ? bindings[bindings.length - 1] : undefined;
221
- if (poppedBinding != null) {
222
- poppedBinding.fn();
223
- dispatch({
224
- type: 'remove-key-binding',
225
- binding: poppedBinding,
226
- });
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;
227
243
  }
228
- });
229
- }, [state]);
230
- React.useEffect(() => {
231
- const handleKeyDown = (event) => {
232
- if (!event.repeat && !keydownIgnorePredicate(event.target)) {
233
- dispatch({
234
- type: 'set-key-pressed',
235
- key: event.key,
236
- pressed: true,
237
- });
238
- applyStackKeyBindings(event.key);
239
- // If the key is associated with a keybinding, then prevent default behavior
240
- const currentPressed = Object.assign(Object.assign({}, state.pressed), { [event.key]: true });
241
- const activeMatchesSingleFnBindings = matchingSingleFnBindings(state.applyBindings, currentPressed, event.key);
242
- const activeMatchesOffBindings = matchingOffBindings(state.applyBindings, currentPressed, event.key);
243
- if (activeMatchesSingleFnBindings.length > 0 ||
244
- activeMatchesOffBindings.length > 0) {
245
- event.preventDefault();
246
- }
244
+ finally {
245
+ release();
247
246
  }
248
247
  };
249
- const handleKeyUp = (event) => {
250
- dispatch({
251
- type: 'set-key-pressed',
252
- key: event.key,
253
- pressed: false,
254
- });
255
- };
256
- window.addEventListener('keydown', handleKeyDown);
257
- window.addEventListener('keyup', handleKeyUp);
258
- return () => {
259
- window.removeEventListener('keydown', handleKeyDown);
260
- window.removeEventListener('keyup', handleKeyUp);
261
- };
262
- }, [applyStackKeyBindings, state.applyBindings, state.pressed]);
263
- React.useEffect(() => {
264
- const activeMatchesSingleFnBindings = matchingSingleFnBindings(state.applyBindings, state.pressed, state.lastPressed);
265
- const activeMatchesOffBindings = matchingOffBindings(state.applyBindings, state.pressed, state.lastPressed);
266
- activeMatchesSingleFnBindings.forEach((fn) => fn());
267
- activeMatchesOffBindings.forEach((fn) => fn());
268
- }, [state.pressed, state.lastPressed]);
269
- React.useEffect(() => {
270
- const matchingRepeatBindings = state.applyBindings
271
- .filter((binding) => binding.repeat &&
272
- binding.keyBind != null &&
273
- allPressed(binding.keyBind, state.pressed))
274
- .map((binding) => binding.fn);
275
- if (matchingRepeatBindings.length > 0) {
276
- const interval = setInterval(() => {
277
- matchingRepeatBindings.forEach((fn) => fn());
278
- }, keydownRepeatInterval);
279
- return () => {
280
- clearInterval(interval);
281
- };
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}`));
282
255
  }
283
- else {
284
- return () => {
285
- 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,
286
268
  };
287
269
  }
288
- }, [state.applyBindings, state.lastPressed]);
289
- };
290
-
291
- function useLongPress({ target, callback, delay = 500, onMovement, }) {
292
- const [longPressTimeout, setLongPressTimeout] = React__namespace.useState();
293
- const [touchStartPosition, setTouchStartPosition] = React__namespace.useState();
294
- React__namespace.useEffect(() => {
295
- const handleTouchStart = (e) => {
296
- const event = e;
297
- if (event.touches != null && event.touches.length === 1) {
298
- if (longPressTimeout != null) {
299
- clearTimeout(longPressTimeout);
300
- }
301
- setTouchStartPosition(geometry.Point.create(event.touches[0].clientX, event.touches[0].clientY));
302
- setLongPressTimeout(setTimeout(() => callback === null || callback === void 0 ? void 0 : callback(event), delay));
303
- }
304
- };
305
- const handleTouchMove = (e) => {
306
- const event = e;
307
- if (event.touches != null &&
308
- event.touches.length > 0 &&
309
- longPressTimeout != null &&
310
- touchStartPosition != null &&
311
- geometry.Point.distance(touchStartPosition, geometry.Point.create(event.touches[0].clientX, event.touches[0].clientY)) >= 2) {
312
- clearTimeout(longPressTimeout);
313
- onMovement === null || onMovement === void 0 ? void 0 : onMovement();
314
- }
315
- };
316
- const handleTouchEnd = () => {
317
- if (longPressTimeout != null) {
318
- clearTimeout(longPressTimeout);
319
- }
320
- };
321
- target === null || target === void 0 ? void 0 : target.addEventListener('touchstart', handleTouchStart);
322
- target === null || target === void 0 ? void 0 : target.addEventListener('touchmove', handleTouchMove);
323
- target === null || target === void 0 ? void 0 : target.addEventListener('touchend', handleTouchEnd);
324
- return () => {
325
- target === null || target === void 0 ? void 0 : target.removeEventListener('touchstart', handleTouchStart);
326
- target === null || target === void 0 ? void 0 : target.removeEventListener('touchmove', handleTouchMove);
327
- target === null || target === void 0 ? void 0 : target.removeEventListener('touchend', handleTouchEnd);
328
- };
329
- }, [target, longPressTimeout, touchStartPosition]);
270
+ };
330
271
  }
331
272
 
332
- function contextMenuItemIsRow(item) {
333
- var _a;
334
- return item != null && ((_a = item === null || item === void 0 ? void 0 : item.node) === null || _a === void 0 ? void 0 : _a.id) != null;
335
- }
336
- const contextMenuActive = recoil.atom({
337
- key: 'contextMenuActive',
338
- default: undefined,
339
- });
340
- const contextMenuPosition = recoil.atom({
341
- key: 'contextMenuPosition',
342
- default: undefined,
343
- });
344
- const contextMenuTarget = recoil.atom({
345
- key: 'contextMenuTarget',
273
+ const viewerElement = recoil.atom({
274
+ key: 'viewerToolkitViewerElement',
346
275
  default: undefined,
276
+ dangerouslyAllowMutability: true,
347
277
  });
348
- const contextMenuItem = recoil.atom({
349
- key: 'contextMenuItem',
350
- default: undefined,
278
+ const viewerInitialSceneReady = recoil.atom({
279
+ key: 'viewerInitialSceneReady',
280
+ default: false,
351
281
  });
352
- const contextMenuActions = recoil.atom({
353
- key: 'contextMenuActions',
354
- default: [],
282
+ const viewerBaseInteractionHandlerProvider = recoil.atom({
283
+ key: 'viewerBaseInteractionHandlerProvider',
284
+ default: Promise.resolve(undefined),
285
+ dangerouslyAllowMutability: true,
355
286
  });
356
- const contextMenuActivePosition = recoil.selector({
357
- key: 'contextMenuActivePosition',
358
- get: ({ get }) => get(contextMenuActive) != null ? get(contextMenuPosition) : undefined,
359
- });
360
-
361
- /******************************************************************************
362
- Copyright (c) Microsoft Corporation.
363
-
364
- Permission to use, copy, modify, and/or distribute this software for any
365
- purpose with or without fee is hereby granted.
366
-
367
- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
368
- REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
369
- AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
370
- INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
371
- LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
372
- OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
373
- PERFORMANCE OF THIS SOFTWARE.
374
- ***************************************************************************** */
375
- /* global Reflect, Promise, SuppressedError, Symbol, Iterator */
376
-
377
-
378
- function __rest(s, e) {
379
- var t = {};
380
- for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
381
- t[p] = s[p];
382
- if (s != null && typeof Object.getOwnPropertySymbols === "function")
383
- for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
384
- if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
385
- t[p[i]] = s[p[i]];
386
- }
387
- return t;
388
- }
389
-
390
- typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
391
- var e = new Error(message);
392
- return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
393
- };
394
-
395
- // Create a new logger instance
396
- const pinoLogger = Pino({
397
- formatters: {
398
- level(level) {
399
- return { level };
400
- },
401
- },
402
- });
403
- const logger = {
404
- error: (message, error) => {
405
- if (error != null) {
406
- pinoLogger.error(error, message);
407
- }
408
- else {
409
- pinoLogger.error(message);
410
- }
411
- },
412
- info: (message, obj) => {
413
- if (obj != null) {
414
- pinoLogger.info(obj, message);
415
- }
416
- else {
417
- pinoLogger.info(message);
418
- }
419
- },
420
- warn: (message, err) => {
421
- if (err != null) {
422
- pinoLogger.warn(err, message);
423
- }
424
- else {
425
- pinoLogger.warn(message);
426
- }
427
- },
428
- debug: (message, obj) => {
429
- if (obj != null) {
430
- pinoLogger.debug(obj, message);
431
- }
432
- else {
433
- pinoLogger.debug(message);
434
- }
435
- },
436
- };
437
- /* eslint-enable @typescript-eslint/no-explicit-any */
438
-
439
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
440
- class DefaultRecoilDeps {
441
- }
442
- /**
443
- * Returns a Recoil callback that can be used for action hooks.
444
- *
445
- * This uses `useRecoilCallback` but the deps implementation differs from
446
- * Recoil. If no deps are provided, then it will always return the same function
447
- * vs returning a new function.
448
- *
449
- * If you want to use the original Recoil callback behavior, pass
450
- * `DefaultRecoilCallbackDepsBehavior`.
451
- *
452
- * @param fn The callback.
453
- * @param deps The deps to memoize over. Defaults to `[]`.
454
- * @returns A callback function
455
- * @see https://recoiljs.org/docs/api-reference/core/useRecoilCallback
456
- */
457
- function useActionCallback(fn, deps = []) {
458
- const d = deps instanceof DefaultRecoilDeps ? undefined : deps;
459
- // eslint-disable-next-line react-hooks/exhaustive-deps
460
- return recoil.useRecoilCallback((cbInterface) => fn(Object.assign(Object.assign({}, cbInterface), { snapshot: Object.defineProperties(cbInterface.snapshot, {
461
- getPromiseRequired: {
462
- configurable: true,
463
- value: createGetPromiseRequiredWrapper(cbInterface.snapshot),
464
- },
465
- tryGetPromise: {
466
- configurable: true,
467
- value: createTryGetPromiseWrapper(cbInterface.snapshot),
468
- },
469
- }) })), d);
470
- }
471
- /**
472
- * Returns a callback that can be used with `useActionCallback` or `useRecoilCallback`,
473
- * and automatically handles retention of the `snapshot` object for use with asynchronous
474
- * selectors.
475
- *
476
- * This function expects a callback that would ordinarily be passed to `useActionCallback`
477
- * or `useRecoilCallback`, but that returns an asynchronous action where the `snapshot` is
478
- * used.
479
- *
480
- * @example
481
- *
482
- * const asyncSelector = selector({
483
- * key: 'asyncSelector',
484
- * get: async ({ get }) => {
485
- * return await fetch('/api/item');
486
- * }
487
- * })
488
- *
489
- * useActionCallback(
490
- * retainSnapshot(
491
- * ({ snapshot }) => async () => {
492
- * const asyncValue = await snapshot.getPromise(asyncSelector);
493
- * }
494
- * )
495
- * )
496
- *
497
- * @param fn The callback.
498
- * @returns The callback wrapped with a retain/release of the underlying snapshot.
499
- */
500
- function retainSnapshot(fn) {
501
- return (_a) => {
502
- var { snapshot } = _a, cb = __rest(_a, ["snapshot"]);
503
- return async (...args) => {
504
- const release = snapshot.retain();
505
- try {
506
- const returnValue = await fn(Object.assign(Object.assign({}, cb), { snapshot }))(...args);
507
- return returnValue;
508
- }
509
- finally {
510
- release();
511
- }
512
- };
513
- };
514
- }
515
- function createGetPromiseRequiredWrapper(snapshot) {
516
- return async (recoilValue, error) => {
517
- const value = await snapshot.getPromise(recoilValue);
518
- if (value == null) {
519
- throw (error !== null && error !== void 0 ? error : new Error(`No value present for required value ${recoilValue.key}`));
520
- }
521
- return value;
522
- };
523
- }
524
- function createTryGetPromiseWrapper(snapshot) {
525
- return async (value) => {
526
- try {
527
- return { value: await snapshot.getPromise(value) };
528
- }
529
- catch (e) {
530
- logger.debug(`Error encountered retrieving Recoil value. [key={${value.key}}]`, e);
531
- return {
532
- error: e,
533
- };
534
- }
535
- };
536
- }
537
-
538
- const viewerElement = recoil.atom({
539
- key: 'viewerToolkitViewerElement',
540
- default: undefined,
541
- dangerouslyAllowMutability: true,
542
- });
543
- const viewerInitialSceneReady = recoil.atom({
544
- key: 'viewerInitialSceneReady',
545
- default: false,
546
- });
547
- const viewerBaseInteractionHandlerProvider = recoil.atom({
548
- key: 'viewerBaseInteractionHandlerProvider',
549
- default: Promise.resolve(undefined),
550
- dangerouslyAllowMutability: true,
551
- });
552
- const viewerPrimaryInteractionType = recoil.atom({
553
- key: 'viewerPrimaryInteractionType',
554
- default: 'rotate',
287
+ const viewerPrimaryInteractionType = recoil.atom({
288
+ key: 'viewerPrimaryInteractionType',
289
+ default: 'rotate',
555
290
  });
556
291
 
557
292
  const viewerSceneProvider = recoil.selector({
@@ -1155,27 +890,27 @@ function useCrossSectioningActions() {
1155
890
  }
1156
891
 
1157
892
  var index$3 = /*#__PURE__*/Object.freeze({
1158
- __proto__: null,
1159
- DEFAULT_ALIGN_TO_PLANE_ANIMATION_DURATION_MS: DEFAULT_ALIGN_TO_PLANE_ANIMATION_DURATION_MS,
1160
- DEFAULT_SLIDER_RANGE: DEFAULT_SLIDER_RANGE,
1161
- crossSectioningActiveAxis: crossSectioningActiveAxis,
1162
- crossSectioningAdditionalToolsOpen: crossSectioningAdditionalToolsOpen,
1163
- crossSectioningAlignment: crossSectioningAlignment,
1164
- crossSectioningAlignmentToolsOpen: crossSectioningAlignmentToolsOpen,
1165
- crossSectioningAvailableAxes: crossSectioningAvailableAxes,
1166
- crossSectioningAxisToolsOpen: crossSectioningAxisToolsOpen,
1167
- crossSectioningBorderWidth: crossSectioningBorderWidth,
1168
- crossSectioningEnabled: crossSectioningEnabled,
1169
- crossSectioningHighlightColor: crossSectioningHighlightColor,
1170
- crossSectioningInteractionHandler: crossSectioningInteractionHandler,
1171
- crossSectioningIsInteractive: crossSectioningIsInteractive,
1172
- crossSectioningOffsetScalar: crossSectioningOffsetScalar,
1173
- crossSectioningPlaneDisplayOffset: crossSectioningPlaneDisplayOffset,
1174
- crossSectioningPlanes: crossSectioningPlanes,
1175
- crossSectioningSliderRange: crossSectioningSliderRange,
1176
- crossSectioningTargetBoundingBox: crossSectioningTargetBoundingBox,
1177
- useCrossSectioning: useCrossSectioning,
1178
- 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
1179
914
  });
1180
915
 
1181
916
  const useHitActions = () => {
@@ -1225,108 +960,407 @@ const useHitActions = () => {
1225
960
  updateTransformWidgetPosition();
1226
961
  }
1227
962
  }
1228
- setContextMenuItem();
1229
- crossSectioningActions.sectionCurrentHit();
1230
- setCurrentHitResult();
1231
- })),
1232
- longPress: useActionCallback(retainSnapshot(({ snapshot, set, reset }) => async (event) => {
1233
- reset(hitResultsTapDetails);
1234
- set(hitResultsLongPressDetails, event.detail);
1235
- await snapshot.tryGetPromise(hitResult);
1236
- setContextMenuItem();
1237
- setCurrentHitResult();
1238
- })),
1239
- };
1240
- };
1241
-
1242
- const hitState = recoil.selector({
1243
- key: 'viewerToolkitHitState',
1244
- get: ({ get }) => {
1245
- const tapDetails = get(hitResultsTapDetails);
1246
- const longPressDetails = get(hitResultsLongPressDetails);
1247
- const previous = get(previousHitResult);
1248
- const current = get(currentHitResult);
1249
- const state = {
1250
- tapDetails,
1251
- longPressDetails,
1252
- previousHitResult: previous,
1253
- 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
+ }
1254
1282
  };
1255
- return state;
1256
- },
1257
- });
1258
-
1259
- var index$2 = /*#__PURE__*/Object.freeze({
1260
- __proto__: null,
1261
- currentHitResult: currentHitResult,
1262
- hitResult: hitResult,
1263
- hitResultsLongPressDetails: hitResultsLongPressDetails,
1264
- hitResultsSkipNextTap: hitResultsSkipNextTap,
1265
- hitResultsTapDetails: hitResultsTapDetails,
1266
- hitState: hitState,
1267
- previousHitResult: previousHitResult,
1268
- useHitActions: useHitActions
1269
- });
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
+ };
1270
1324
 
1271
- function useContextMenuActions() {
1272
- return {
1273
- pointerDown: useActionCallback(({ set }) => async (event, pointOverride) => {
1274
- var _a, _b;
1275
- if (event.button === 2) {
1276
- const xCoordinate = (_a = pointOverride === null || pointOverride === void 0 ? void 0 : pointOverride.x) !== null && _a !== void 0 ? _a : event.clientX;
1277
- 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;
1278
- set(contextMenuPosition, geometry.Point.create(xCoordinate, yCoordinate));
1279
- set(contextMenuTarget, event.target);
1280
- }
1281
- }),
1282
- pointerUp: useActionCallback(({ snapshot, set }) => async (event, type, predicate, onOpen, pointOverride) => {
1283
- var _a, _b;
1284
- const downPosition = await snapshot.getPromise(contextMenuPosition);
1285
- const active = await snapshot.getPromise(contextMenuActive);
1286
- if (downPosition != null && active == null) {
1287
- const xCoordinate = (_a = pointOverride === null || pointOverride === void 0 ? void 0 : pointOverride.x) !== null && _a !== void 0 ? _a : event.clientX;
1288
- 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;
1289
- const point = geometry.Point.create(xCoordinate, yCoordinate);
1290
- const pointDistance = downPosition != null ? geometry.Point.distance(downPosition, point) : 0;
1291
- const predicateResult = predicate == null || predicate(event);
1292
- if (pointDistance < 2 && predicateResult) {
1293
- onOpen === null || onOpen === void 0 ? void 0 : onOpen(event, downPosition !== null && downPosition !== void 0 ? downPosition : point);
1294
- 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);
1295
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));
1296
1337
  }
1297
- }),
1298
- contextMenu: useActionCallback(() => (event, predicate) => {
1299
- if (predicate == null || predicate(event)) {
1300
- 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();
1301
1348
  }
1302
- }),
1303
- longPress: useActionCallback(({ set }) => (event, type, predicate, onOpen) => {
1304
- if (predicate == null || predicate(event)) {
1305
- const point = geometry.Point.create(event.touches[0].clientX, event.touches[0].clientY);
1306
- set(contextMenuPosition, point);
1307
- set(contextMenuTarget, event.target);
1308
- set(contextMenuActive, type);
1309
- onOpen === null || onOpen === void 0 ? void 0 : onOpen(event, point);
1349
+ };
1350
+ const handleTouchEnd = () => {
1351
+ if (longPressTimeout != null) {
1352
+ clearTimeout(longPressTimeout);
1310
1353
  }
1311
- }),
1312
- clearActiveContextMenu: useActionCallback(({ reset, set }) => (dismissedFromWindowPointerEvent) => {
1313
- set(hitResultsSkipNextTap, !!dismissedFromWindowPointerEvent);
1314
- reset(contextMenuActive);
1315
- reset(contextMenuActions);
1316
- reset(contextMenuPosition);
1317
- }),
1318
- clearDismissedState: useActionCallback(({ reset }) => () => reset(hitResultsSkipNextTap)),
1319
- };
1320
- }
1321
-
1322
- function targetWithinMenu(event) {
1323
- return (event.target instanceof Element && isChildOf('vertex-menu', event.target));
1324
- }
1325
- function targetShouldSkipNextHit(event) {
1326
- return (event.target instanceof Element && isChildOf('vertex-viewer', event.target));
1327
- }
1328
- function isChildOf(elementType, target) {
1329
- 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]);
1330
1364
  }
1331
1365
 
1332
1366
  const VertexContextMenu = ({ targetElement, menuType, disableBackdrop, openPredicate, onOpen, onClose, children, }) => {
@@ -1378,7 +1412,9 @@ const VertexContextMenu = ({ targetElement, menuType, disableBackdrop, openPredi
1378
1412
  var _a, _b;
1379
1413
  const pointerEvent = event;
1380
1414
  const targetElement = target;
1381
- const boundingBox = targetElement != null ? targetElement.getBoundingClientRect() : undefined;
1415
+ const boundingBox = targetElement != null
1416
+ ? targetElement.getBoundingClientRect()
1417
+ : undefined;
1382
1418
  const xCoordinate = pointerEvent.clientX - ((_a = boundingBox === null || boundingBox === void 0 ? void 0 : boundingBox.x) !== null && _a !== void 0 ? _a : 0);
1383
1419
  const yCoordinate = pointerEvent.clientY - ((_b = boundingBox === null || boundingBox === void 0 ? void 0 : boundingBox.y) !== null && _b !== void 0 ? _b : 0);
1384
1420
  contextMenuActions.pointerDown(pointerEvent, geometry.Point.create(xCoordinate, yCoordinate));
@@ -1387,7 +1423,9 @@ const VertexContextMenu = ({ targetElement, menuType, disableBackdrop, openPredi
1387
1423
  var _a, _b;
1388
1424
  const pointerEvent = event;
1389
1425
  const targetElement = target;
1390
- const boundingBox = targetElement != null ? targetElement.getBoundingClientRect() : undefined;
1426
+ const boundingBox = targetElement != null
1427
+ ? targetElement.getBoundingClientRect()
1428
+ : undefined;
1391
1429
  const xCoordinate = pointerEvent.clientX - ((_a = boundingBox === null || boundingBox === void 0 ? void 0 : boundingBox.x) !== null && _a !== void 0 ? _a : 0);
1392
1430
  const yCoordinate = pointerEvent.clientY - ((_b = boundingBox === null || boundingBox === void 0 ? void 0 : boundingBox.y) !== null && _b !== void 0 ? _b : 0);
1393
1431
  contextMenuActions.pointerUp(event, menuType, openPredicate, onOpen, geometry.Point.create(xCoordinate, yCoordinate));
@@ -1647,18 +1685,18 @@ const selectionState = recoil.selector({
1647
1685
  });
1648
1686
 
1649
1687
  var index$1 = /*#__PURE__*/Object.freeze({
1650
- __proto__: null,
1651
- selectionHighestSelectedAncestor: selectionHighestSelectedAncestor,
1652
- selectionLastSelectWasMultiSelect: selectionLastSelectWasMultiSelect,
1653
- selectionLastSelected: selectionLastSelected,
1654
- selectionLastSelectionFromViewer: selectionLastSelectionFromViewer,
1655
- selectionPreviousVisibleSummary: selectionPreviousVisibleSummary,
1656
- selectionSelectedItemIds: selectionSelectedItemIds,
1657
- selectionSelectedItems: selectionSelectedItems,
1658
- selectionState: selectionState,
1659
- selectionVisibleCount: selectionVisibleCount,
1660
- selectionVisibleSummary: selectionVisibleSummary,
1661
- 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
1662
1700
  });
1663
1701
 
1664
1702
  const VertexFitSelectedMenuItem = () => {
@@ -1678,16 +1716,14 @@ const VertexFlyToMenuItem = () => {
1678
1716
  return (jsxRuntime.jsxs(uiReact.VertexMenuItem, { "data-testid": "fly-to-part-menu-option", onClick: () => {
1679
1717
  var _a;
1680
1718
  const isRow = contextMenuItemIsRow(currentItem);
1681
- const itemId = isRow
1682
- ? (_a = currentItem === null || currentItem === void 0 ? void 0 : currentItem.node.id) === null || _a === void 0 ? void 0 : _a.hex
1683
- : 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;
1684
1720
  if (itemId != null) {
1685
1721
  cameraActions.flyToById(itemId);
1686
1722
  }
1687
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" })] }));
1688
1724
  };
1689
1725
 
1690
- function useSceneItemsOperations({ viewerElement }) {
1726
+ function useSceneItemsOperations({ viewerElement, }) {
1691
1727
  const sceneItemsOperation = React.useCallback(async (f, ids) => {
1692
1728
  const scene = await (viewerElement === null || viewerElement === void 0 ? void 0 : viewerElement.scene());
1693
1729
  if (ids == null) {
@@ -1733,7 +1769,9 @@ function useSceneItemsOperations({ viewerElement }) {
1733
1769
 
1734
1770
  const VertexHideAllMenuItem = () => {
1735
1771
  const viewerHTMLElement = recoil.useRecoilValue(viewerElement);
1736
- 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
+ });
1737
1775
  return (jsxRuntime.jsxs(uiReact.VertexMenuItem, { "data-testid": "hide-all-menu-option", onClick: () => {
1738
1776
  sceneItemOperations.sceneItemsOperation((builder) => builder.hide());
1739
1777
  }, children: [jsxRuntime.jsx(uiReact.VertexIcon, { slot: "icon", name: "visibility-hidden", size: "sm" }), jsxRuntime.jsx("div", { className: "pl-2", children: "Hide All Parts" })] }));
@@ -1742,13 +1780,13 @@ const VertexHideAllMenuItem = () => {
1742
1780
  const VertexHidePartMenuItem = () => {
1743
1781
  const viewerHTMLElement = recoil.useRecoilValue(viewerElement);
1744
1782
  const currentItem = recoil.useRecoilValue(contextMenuItem);
1745
- 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
+ });
1746
1786
  return (jsxRuntime.jsxs(uiReact.VertexMenuItem, { "data-testid": "hide-menu-option", onClick: () => {
1747
1787
  var _a;
1748
1788
  const isRow = contextMenuItemIsRow(currentItem);
1749
- const itemId = isRow
1750
- ? (_a = currentItem === null || currentItem === void 0 ? void 0 : currentItem.node.id) === null || _a === void 0 ? void 0 : _a.hex
1751
- : 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;
1752
1790
  if (itemId != null) {
1753
1791
  sceneItemOperations.sceneItemsOperation((builder) => builder.hide(), [itemId]);
1754
1792
  }
@@ -1758,13 +1796,17 @@ const VertexHidePartMenuItem = () => {
1758
1796
  const VertexHideSelectedMenuItem = () => {
1759
1797
  const viewerHTMLElement = recoil.useRecoilValue(viewerElement);
1760
1798
  const selectedItems = recoil.useRecoilValue(selectionSelectedItemIds);
1761
- 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
+ });
1762
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" })] }));
1763
1803
  };
1764
1804
 
1765
1805
  const VertexShowAllMenuItem = () => {
1766
1806
  const viewerHTMLElement = recoil.useRecoilValue(viewerElement);
1767
- 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
+ });
1768
1810
  return (jsxRuntime.jsxs(uiReact.VertexMenuItem, { "data-testid": "show-all-menu-option", onClick: () => {
1769
1811
  sceneItemOperations.sceneItemsOperation((builder) => builder.show());
1770
1812
  }, children: [jsxRuntime.jsx(uiReact.VertexIcon, { slot: "icon", name: "visibility-visible", size: "sm" }), jsxRuntime.jsx("div", { className: "pl-2", children: "Show All Parts" })] }));
@@ -1773,13 +1815,13 @@ const VertexShowAllMenuItem = () => {
1773
1815
  const VertexShowOnlyMenuItem = () => {
1774
1816
  const viewerHTMLElement = recoil.useRecoilValue(viewerElement);
1775
1817
  const currentItem = recoil.useRecoilValue(contextMenuItem);
1776
- 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
+ });
1777
1821
  return (jsxRuntime.jsxs(uiReact.VertexMenuItem, { "data-testid": "show-only-menu-option", onClick: () => {
1778
1822
  var _a;
1779
1823
  const isRow = contextMenuItemIsRow(currentItem);
1780
- const itemId = isRow
1781
- ? (_a = currentItem === null || currentItem === void 0 ? void 0 : currentItem.node.id) === null || _a === void 0 ? void 0 : _a.hex
1782
- : 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;
1783
1825
  if (itemId != null) {
1784
1826
  sceneItemOperations.showOnlyItem(itemId);
1785
1827
  }
@@ -1789,7 +1831,9 @@ const VertexShowOnlyMenuItem = () => {
1789
1831
  const VertexShowOnlySelectedMenuItem = () => {
1790
1832
  const viewerHTMLElement = recoil.useRecoilValue(viewerElement);
1791
1833
  const selectedItems = recoil.useRecoilValue(selectionSelectedItemIds);
1792
- 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
+ });
1793
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" })] }));
1794
1838
  };
1795
1839
 
@@ -1874,16 +1918,14 @@ const DefaultSceneTreeContextMenu = () => {
1874
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, {})] }));
1875
1919
  };
1876
1920
 
1877
- const VertexSceneTreeContextMenu = ({ children }) => {
1921
+ const VertexSceneTreeContextMenu = ({ children, }) => {
1878
1922
  const sceneTreeActions = useSceneTreeActions();
1879
1923
  const sceneTreeHTMLElement = recoil.useRecoilValue(sceneTreeElement);
1880
1924
  const hasDefinedChildren = children != null && children !== false;
1881
1925
  return (jsxRuntime.jsx(VertexContextMenu, { menuType: "scene-tree", targetElement: sceneTreeHTMLElement, onOpen: async (event, _pt) => {
1882
1926
  const pointerEvent = event;
1883
1927
  await sceneTreeActions.setContextMenuItem(pointerEvent.clientY);
1884
- }, disableBackdrop: true, children: hasDefinedChildren
1885
- ? (children)
1886
- : (jsxRuntime.jsx(DefaultSceneTreeContextMenu, {})) }));
1928
+ }, disableBackdrop: true, children: hasDefinedChildren ? children : jsxRuntime.jsx(DefaultSceneTreeContextMenu, {}) }));
1887
1929
  };
1888
1930
 
1889
1931
  const DefaultViewerContextMenu = () => {
@@ -1893,9 +1935,7 @@ const DefaultViewerContextMenu = () => {
1893
1935
  const VertexViewerContextMenu = ({ children }) => {
1894
1936
  const viewerHTMLElement = recoil.useRecoilValue(viewerElement);
1895
1937
  const hasDefinedChildren = children != null && children !== false;
1896
- return (jsxRuntime.jsx(VertexContextMenu, { menuType: "viewer", targetElement: viewerHTMLElement, disableBackdrop: true, children: hasDefinedChildren
1897
- ? (children)
1898
- : (jsxRuntime.jsx(DefaultViewerContextMenu, {})) }));
1938
+ return (jsxRuntime.jsx(VertexContextMenu, { menuType: "viewer", targetElement: viewerHTMLElement, disableBackdrop: true, children: hasDefinedChildren ? children : jsxRuntime.jsx(DefaultViewerContextMenu, {}) }));
1899
1939
  };
1900
1940
 
1901
1941
  const sdkConfig = recoil.atom({
@@ -1945,6 +1985,24 @@ function styleFromFontFace(fontFace) {
1945
1985
  }
1946
1986
  }
1947
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
+
1948
2006
  const DEFAULT_NAME_COLUMN = {
1949
2007
  binding: '{{row.node.name}}',
1950
2008
  label: 'Name',
@@ -2023,24 +2081,6 @@ const VertexSceneTreeTableLayout = (sdkProps) => {
2023
2081
  }) })));
2024
2082
  };
2025
2083
 
2026
- const VertexSceneTreeExpandAll = () => {
2027
- const sceneTreeHTMLElement = recoil.useRecoilValue(sceneTreeElement);
2028
- 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: () => {
2029
- sceneTreeHTMLElement === null || sceneTreeHTMLElement === void 0 ? void 0 : sceneTreeHTMLElement.expandAll();
2030
- } }) }));
2031
- };
2032
-
2033
- const VertexSceneTreeCollapseAll = () => {
2034
- const sceneTreeHTMLElement = recoil.useRecoilValue(sceneTreeElement);
2035
- 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: () => {
2036
- sceneTreeHTMLElement === null || sceneTreeHTMLElement === void 0 ? void 0 : sceneTreeHTMLElement.collapseAll();
2037
- } }) }));
2038
- };
2039
-
2040
- function VertexSceneTreeToolbar() {
2041
- 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, {})] }) }));
2042
- }
2043
-
2044
2084
  const VertexSceneTree = (_a) => {
2045
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"]);
2046
2086
  const config = recoil.useRecoilValue(sdkConfig);
@@ -2074,13 +2114,13 @@ const VertexSceneTree = (_a) => {
2074
2114
  }
2075
2115
  onPointerDown === null || onPointerDown === void 0 ? void 0 : onPointerDown(event);
2076
2116
  };
2077
- return (jsxRuntime.jsxs(viewerReact.VertexSceneTree, Object.assign({ id: id !== null && id !== void 0 ? id : 'vertex-scene-tree', "data-testid": "vertex-scene-tree", config: config, ref: callbackRef, className: classNames('shrink-0', className), style: Object.assign(Object.assign(Object.assign({}, styleFromOptionalFont(font)), styleFromOptionalBackgroundColors(backgroundColors)), style), onConnectionError: (e) => {
2078
- logger.error('Scene Tree Connection Error: ', e.detail);
2079
- }, viewer: viewer, onPointerDown: handlePointerDown, onClick: handleClick, rowData: (row) => {
2080
- var _a;
2081
- const providedRowData = (_a = rowData === null || rowData === void 0 ? void 0 : rowData(row)) !== null && _a !== void 0 ? _a : {};
2082
- return Object.assign({ handleExpansion: wrappedExpansionHandler, handleSelection: wrappedSelectionHandler, handleVisibility: wrappedVisibilityHandler }, providedRowData);
2083
- } }, sdkProps, { children: [jsxRuntime.jsx(VertexSceneTreeToolbar, {}), jsxRuntime.jsx(VertexSceneTreeTableLayout, {}), children] })));
2117
+ return (jsxRuntime.jsx("div", { className: "flex flex-col w-full h-full", children: jsxRuntime.jsx("div", { className: "flex group h-full", children: jsxRuntime.jsxs(viewerReact.VertexSceneTree, Object.assign({ id: id !== null && id !== void 0 ? id : 'vertex-scene-tree', "data-testid": "vertex-scene-tree", config: config, ref: callbackRef, className: classNames('flex-1', className), style: Object.assign(Object.assign(Object.assign({}, styleFromOptionalFont(font)), styleFromOptionalBackgroundColors(backgroundColors)), style), onConnectionError: (e) => {
2118
+ logger.error('Scene Tree Connection Error: ', e.detail);
2119
+ }, viewer: viewer, onPointerDown: handlePointerDown, onClick: handleClick, rowData: (row) => {
2120
+ var _a;
2121
+ const providedRowData = (_a = rowData === null || rowData === void 0 ? void 0 : rowData(row)) !== null && _a !== void 0 ? _a : {};
2122
+ return Object.assign({ handleExpansion: wrappedExpansionHandler, handleSelection: wrappedSelectionHandler, handleVisibility: wrappedVisibilityHandler }, providedRowData);
2123
+ } }, sdkProps, { children: [jsxRuntime.jsx(VertexSceneTreeToolbar, {}), jsxRuntime.jsx(VertexSceneTreeTableLayout, {}), children] })) }) }));
2084
2124
  };
2085
2125
 
2086
2126
  const useSynchronizedProp = (state, value) => {
@@ -2537,8 +2577,8 @@ const VertexViewerToolkitRootConfig = ({ config, children, }) => {
2537
2577
  };
2538
2578
 
2539
2579
  var index = /*#__PURE__*/Object.freeze({
2540
- __proto__: null,
2541
- get AssemblyFontFace () { return AssemblyFontFace; }
2580
+ __proto__: null,
2581
+ get AssemblyFontFace () { return AssemblyFontFace; }
2542
2582
  });
2543
2583
 
2544
2584
  exports.CrossSection = index$3;
@@ -2553,6 +2593,7 @@ exports.VertexHideAllMenuItem = VertexHideAllMenuItem;
2553
2593
  exports.VertexHidePartMenuItem = VertexHidePartMenuItem;
2554
2594
  exports.VertexHideSelectedMenuItem = VertexHideSelectedMenuItem;
2555
2595
  exports.VertexPanButton = VertexPanButton;
2596
+ exports.VertexResizableContent = VertexResizableContent;
2556
2597
  exports.VertexRotateButton = VertexRotateButton;
2557
2598
  exports.VertexSceneTree = VertexSceneTree;
2558
2599
  exports.VertexSceneTreeContextMenu = VertexSceneTreeContextMenu;