@aics/vole-app 2.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +33 -0
- package/LICENSE.txt +26 -0
- package/README.md +45 -0
- package/es/aics-image-viewer/assets/fonts/open-sans/open-sans-500.eot +0 -0
- package/es/aics-image-viewer/assets/fonts/open-sans/open-sans-500.js +2337 -0
- package/es/aics-image-viewer/assets/fonts/open-sans/open-sans-500.svg +604 -0
- package/es/aics-image-viewer/assets/fonts/open-sans/open-sans-500.ttf +0 -0
- package/es/aics-image-viewer/assets/fonts/open-sans/open-sans-500.woff +0 -0
- package/es/aics-image-viewer/assets/fonts/open-sans/open-sans-500.woff2 +0 -0
- package/es/aics-image-viewer/assets/fonts/open-sans/open-sans-700.eot +0 -0
- package/es/aics-image-viewer/assets/fonts/open-sans/open-sans-700.js +2336 -0
- package/es/aics-image-viewer/assets/fonts/open-sans/open-sans-700.svg +604 -0
- package/es/aics-image-viewer/assets/fonts/open-sans/open-sans-700.ttf +0 -0
- package/es/aics-image-viewer/assets/fonts/open-sans/open-sans-700.woff +0 -0
- package/es/aics-image-viewer/assets/fonts/open-sans/open-sans-700.woff2 +0 -0
- package/es/aics-image-viewer/assets/fonts/open-sans/open-sans-regular.eot +0 -0
- package/es/aics-image-viewer/assets/fonts/open-sans/open-sans-regular.js +2337 -0
- package/es/aics-image-viewer/assets/fonts/open-sans/open-sans-regular.svg +604 -0
- package/es/aics-image-viewer/assets/fonts/open-sans/open-sans-regular.ttf +0 -0
- package/es/aics-image-viewer/assets/fonts/open-sans/open-sans-regular.woff +0 -0
- package/es/aics-image-viewer/assets/fonts/open-sans/open-sans-regular.woff2 +0 -0
- package/es/aics-image-viewer/assets/icons/axes.js +20 -0
- package/es/aics-image-viewer/assets/icons/boundingBox.js +18 -0
- package/es/aics-image-viewer/assets/icons/camera.js +15 -0
- package/es/aics-image-viewer/assets/icons/channels.js +15 -0
- package/es/aics-image-viewer/assets/icons/closePanel.js +18 -0
- package/es/aics-image-viewer/assets/icons/download.js +17 -0
- package/es/aics-image-viewer/assets/icons/dropdownArrow.js +15 -0
- package/es/aics-image-viewer/assets/icons/index.js +24 -0
- package/es/aics-image-viewer/assets/icons/metadata.js +15 -0
- package/es/aics-image-viewer/assets/icons/preferences.js +15 -0
- package/es/aics-image-viewer/assets/icons/resetView.js +16 -0
- package/es/aics-image-viewer/assets/icons/svg.d.js +0 -0
- package/es/aics-image-viewer/assets/icons/turnTable.js +18 -0
- package/es/aics-image-viewer/assets/styles/animatedEllipsis.css +21 -0
- package/es/aics-image-viewer/assets/styles/globals.css +35 -0
- package/es/aics-image-viewer/assets/styles/noui-slider-override.css +1 -0
- package/es/aics-image-viewer/assets/styles/variables.css +1 -0
- package/es/aics-image-viewer/components/App/ChannelUpdater.js +96 -0
- package/es/aics-image-viewer/components/App/index.js +849 -0
- package/es/aics-image-viewer/components/App/styles.css +60 -0
- package/es/aics-image-viewer/components/App/types.js +1 -0
- package/es/aics-image-viewer/components/AxisClipSliders/index.js +285 -0
- package/es/aics-image-viewer/components/AxisClipSliders/styles.css +257 -0
- package/es/aics-image-viewer/components/BottomPanel/index.js +70 -0
- package/es/aics-image-viewer/components/BottomPanel/styles.css +85 -0
- package/es/aics-image-viewer/components/CellViewerCanvasWrapper/index.js +113 -0
- package/es/aics-image-viewer/components/CellViewerCanvasWrapper/styles.css +12 -0
- package/es/aics-image-viewer/components/ChannelsWidget.js +100 -0
- package/es/aics-image-viewer/components/ChannelsWidgetRow/index.js +158 -0
- package/es/aics-image-viewer/components/ChannelsWidgetRow/styles.css +38 -0
- package/es/aics-image-viewer/components/ColorPicker.js +120 -0
- package/es/aics-image-viewer/components/ControlPanel/index.js +180 -0
- package/es/aics-image-viewer/components/ControlPanel/styles.css +169 -0
- package/es/aics-image-viewer/components/CustomizeWidget.js +46 -0
- package/es/aics-image-viewer/components/ErrorAlert/index.js +144 -0
- package/es/aics-image-viewer/components/ErrorAlert/styles.css +22 -0
- package/es/aics-image-viewer/components/GlobalVolumeControls.js +38 -0
- package/es/aics-image-viewer/components/MetadataViewer/index.js +99 -0
- package/es/aics-image-viewer/components/MetadataViewer/styles.css +81 -0
- package/es/aics-image-viewer/components/StyleProvider/index.js +210 -0
- package/es/aics-image-viewer/components/TfEditor/index.js +584 -0
- package/es/aics-image-viewer/components/TfEditor/styles.css +88 -0
- package/es/aics-image-viewer/components/Toolbar/DownloadButton.js +55 -0
- package/es/aics-image-viewer/components/Toolbar/ViewModeRadioButtons.js +22 -0
- package/es/aics-image-viewer/components/Toolbar/index.js +274 -0
- package/es/aics-image-viewer/components/Toolbar/styles.css +241 -0
- package/es/aics-image-viewer/components/ViewerStateProvider/ResetStateProvider.js +160 -0
- package/es/aics-image-viewer/components/ViewerStateProvider/index.js +261 -0
- package/es/aics-image-viewer/components/ViewerStateProvider/types.js +1 -0
- package/es/aics-image-viewer/components/shared/NumericInput/index.js +147 -0
- package/es/aics-image-viewer/components/shared/NumericInput/styles.css +64 -0
- package/es/aics-image-viewer/components/shared/SharedCheckBox.js +17 -0
- package/es/aics-image-viewer/components/shared/SliderRow/index.js +31 -0
- package/es/aics-image-viewer/components/shared/SliderRow/styles.css +19 -0
- package/es/aics-image-viewer/components/shared/SmarterSlider.js +40 -0
- package/es/aics-image-viewer/components/shared/ViewerIcon.js +22 -0
- package/es/aics-image-viewer/shared/colorPalette.js +19 -0
- package/es/aics-image-viewer/shared/constants.js +164 -0
- package/es/aics-image-viewer/shared/enums.js +18 -0
- package/es/aics-image-viewer/shared/types.js +6 -0
- package/es/aics-image-viewer/shared/utils/colorRepresentations.js +16 -0
- package/es/aics-image-viewer/shared/utils/controlPointsToLut.js +182 -0
- package/es/aics-image-viewer/shared/utils/hooks.js +51 -0
- package/es/aics-image-viewer/shared/utils/httpClient.js +57 -0
- package/es/aics-image-viewer/shared/utils/playControls.js +97 -0
- package/es/aics-image-viewer/shared/utils/sceneStore.js +140 -0
- package/es/aics-image-viewer/shared/utils/sliderValuesToImageValues.js +36 -0
- package/es/aics-image-viewer/shared/utils/test/viewerChannelSettings.test.js +132 -0
- package/es/aics-image-viewer/shared/utils/utilsService.js +54 -0
- package/es/aics-image-viewer/shared/utils/viewerChannelSettings.js +152 -0
- package/es/aics-image-viewer/shared/utils/viewerState.js +69 -0
- package/es/aics-image-viewer/shared/utils/webgl-debug.js +1103 -0
- package/es/index.js +4 -0
- package/package.json +130 -0
- package/type-declarations/aics-image-viewer/assets/icons/index.d.ts +14 -0
- package/type-declarations/aics-image-viewer/components/App/ChannelUpdater.d.ts +16 -0
- package/type-declarations/aics-image-viewer/components/App/index.d.ts +6 -0
- package/type-declarations/aics-image-viewer/components/App/types.d.ts +45 -0
- package/type-declarations/aics-image-viewer/components/AxisClipSliders/index.d.ts +24 -0
- package/type-declarations/aics-image-viewer/components/BottomPanel/index.d.ts +11 -0
- package/type-declarations/aics-image-viewer/components/CellViewerCanvasWrapper/index.d.ts +33 -0
- package/type-declarations/aics-image-viewer/components/ChannelsWidget.d.ts +19 -0
- package/type-declarations/aics-image-viewer/components/ChannelsWidgetRow/index.d.ts +17 -0
- package/type-declarations/aics-image-viewer/components/ColorPicker.d.ts +13 -0
- package/type-declarations/aics-image-viewer/components/ControlPanel/index.d.ts +20 -0
- package/type-declarations/aics-image-viewer/components/CustomizeWidget.d.ts +15 -0
- package/type-declarations/aics-image-viewer/components/ErrorAlert/index.d.ts +12 -0
- package/type-declarations/aics-image-viewer/components/GlobalVolumeControls.d.ts +21 -0
- package/type-declarations/aics-image-viewer/components/MetadataViewer/index.d.ts +7 -0
- package/type-declarations/aics-image-viewer/components/StyleProvider/index.d.ts +5 -0
- package/type-declarations/aics-image-viewer/components/TfEditor/index.d.ts +19 -0
- package/type-declarations/aics-image-viewer/components/Toolbar/DownloadButton.d.ts +8 -0
- package/type-declarations/aics-image-viewer/components/Toolbar/ViewModeRadioButtons.d.ts +8 -0
- package/type-declarations/aics-image-viewer/components/Toolbar/index.d.ts +31 -0
- package/type-declarations/aics-image-viewer/components/ViewerStateProvider/ResetStateProvider.d.ts +34 -0
- package/type-declarations/aics-image-viewer/components/ViewerStateProvider/index.d.ts +33 -0
- package/type-declarations/aics-image-viewer/components/ViewerStateProvider/types.d.ts +105 -0
- package/type-declarations/aics-image-viewer/components/shared/NumericInput/index.d.ts +19 -0
- package/type-declarations/aics-image-viewer/components/shared/SharedCheckBox.d.ts +9 -0
- package/type-declarations/aics-image-viewer/components/shared/SliderRow/index.d.ts +17 -0
- package/type-declarations/aics-image-viewer/components/shared/SmarterSlider.d.ts +5 -0
- package/type-declarations/aics-image-viewer/components/shared/ViewerIcon.d.ts +9 -0
- package/type-declarations/aics-image-viewer/shared/constants.d.ts +40 -0
- package/type-declarations/aics-image-viewer/shared/enums.d.ts +15 -0
- package/type-declarations/aics-image-viewer/shared/types.d.ts +15 -0
- package/type-declarations/aics-image-viewer/shared/utils/colorRepresentations.d.ts +10 -0
- package/type-declarations/aics-image-viewer/shared/utils/controlPointsToLut.d.ts +53 -0
- package/type-declarations/aics-image-viewer/shared/utils/hooks.d.ts +14 -0
- package/type-declarations/aics-image-viewer/shared/utils/playControls.d.ts +27 -0
- package/type-declarations/aics-image-viewer/shared/utils/sceneStore.d.ts +17 -0
- package/type-declarations/aics-image-viewer/shared/utils/sliderValuesToImageValues.d.ts +10 -0
- package/type-declarations/aics-image-viewer/shared/utils/viewerChannelSettings.d.ts +46 -0
- package/type-declarations/aics-image-viewer/shared/utils/viewerState.d.ts +10 -0
- package/type-declarations/index.d.ts +7 -0
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
|
|
2
|
+
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
3
|
+
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
4
|
+
function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
|
|
5
|
+
function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t["return"] || t["return"](); } finally { if (u) throw o; } } }; }
|
|
6
|
+
function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
|
|
7
|
+
function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
|
|
8
|
+
function _classCallCheck(a, n) { if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function"); }
|
|
9
|
+
function _defineProperties(e, r) { for (var t = 0; t < r.length; t++) { var o = r[t]; o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, _toPropertyKey(o.key), o); } }
|
|
10
|
+
function _createClass(e, r, t) { return r && _defineProperties(e.prototype, r), t && _defineProperties(e, t), Object.defineProperty(e, "prototype", { writable: !1 }), e; }
|
|
11
|
+
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; }
|
|
12
|
+
function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
|
|
13
|
+
import { isEqual } from "lodash";
|
|
14
|
+
import { getDefaultViewerState, getDefaultCameraState, getDefaultChannelState, getDefaultViewerChannelSettings, getDefaultChannelColor } from "../../shared/constants";
|
|
15
|
+
import { ViewMode } from "../../shared/enums";
|
|
16
|
+
import { overrideViewerState, overrideChannelStates, getEnabledChannelIndices, initializeOneChannelSetting } from "../../shared/utils/viewerState";
|
|
17
|
+
/**
|
|
18
|
+
* Provides reset functionality for the viewer and channel states.
|
|
19
|
+
*/
|
|
20
|
+
var ResetStateProvider = /*#__PURE__*/function () {
|
|
21
|
+
function ResetStateProvider(viewerStateRef) {
|
|
22
|
+
_classCallCheck(this, ResetStateProvider);
|
|
23
|
+
this.ref = viewerStateRef;
|
|
24
|
+
this.savedViewerState = {};
|
|
25
|
+
this.channelsToReset = new Set();
|
|
26
|
+
this.channelsToResetOnLoad = new Set();
|
|
27
|
+
this.savedViewerChannelSettings = undefined;
|
|
28
|
+
this.useDefaultViewerChannelSettings = false;
|
|
29
|
+
this.resetToSavedViewerState = this.resetToSavedViewerState.bind(this);
|
|
30
|
+
this.resetToDefaultViewerState = this.resetToDefaultViewerState.bind(this);
|
|
31
|
+
this.resetToState = this.resetToState.bind(this);
|
|
32
|
+
this.setSavedViewerState = this.setSavedViewerState.bind(this);
|
|
33
|
+
this.setSavedViewerChannelSettings = this.setSavedViewerChannelSettings.bind(this);
|
|
34
|
+
this.getChannelsAwaitingReset = this.getChannelsAwaitingReset.bind(this);
|
|
35
|
+
this.getChannelsAwaitingResetOnLoad = this.getChannelsAwaitingResetOnLoad.bind(this);
|
|
36
|
+
this.onResetChannel = this.onResetChannel.bind(this);
|
|
37
|
+
this.getCurrentViewerChannelSettings = this.getCurrentViewerChannelSettings.bind(this);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Setup Callbacks ////////////////////////////////////////////////////////////////////
|
|
41
|
+
return _createClass(ResetStateProvider, [{
|
|
42
|
+
key: "setSavedViewerState",
|
|
43
|
+
value: function setSavedViewerState(state) {
|
|
44
|
+
this.savedViewerState = state;
|
|
45
|
+
}
|
|
46
|
+
}, {
|
|
47
|
+
key: "setSavedViewerChannelSettings",
|
|
48
|
+
value: function setSavedViewerChannelSettings(settings) {
|
|
49
|
+
this.savedViewerChannelSettings = settings;
|
|
50
|
+
}
|
|
51
|
+
}, {
|
|
52
|
+
key: "getChannelsAwaitingReset",
|
|
53
|
+
value: function getChannelsAwaitingReset() {
|
|
54
|
+
return this.channelsToReset;
|
|
55
|
+
}
|
|
56
|
+
}, {
|
|
57
|
+
key: "getChannelsAwaitingResetOnLoad",
|
|
58
|
+
value: function getChannelsAwaitingResetOnLoad() {
|
|
59
|
+
return this.channelsToResetOnLoad;
|
|
60
|
+
}
|
|
61
|
+
}, {
|
|
62
|
+
key: "onResetChannel",
|
|
63
|
+
value: function onResetChannel(channelIndex) {
|
|
64
|
+
this.channelsToReset["delete"](channelIndex);
|
|
65
|
+
this.channelsToResetOnLoad["delete"](channelIndex);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Returns the current viewer channel settings that the viewer should use when
|
|
70
|
+
* resetting channels to an initial state.
|
|
71
|
+
*/
|
|
72
|
+
}, {
|
|
73
|
+
key: "getCurrentViewerChannelSettings",
|
|
74
|
+
value: function getCurrentViewerChannelSettings() {
|
|
75
|
+
if (this.useDefaultViewerChannelSettings) {
|
|
76
|
+
return getDefaultViewerChannelSettings();
|
|
77
|
+
}
|
|
78
|
+
return this.savedViewerChannelSettings;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Helper method. Resets the viewer and all channels to the provided state. If new data needs to
|
|
83
|
+
* be loaded, handles setup so the reset will be applied to each channel as it loads in.
|
|
84
|
+
*/
|
|
85
|
+
}, {
|
|
86
|
+
key: "resetToState",
|
|
87
|
+
value: function resetToState(newState, newChannelStates) {
|
|
88
|
+
var _this$ref$current = this.ref.current,
|
|
89
|
+
changeViewerSetting = _this$ref$current.changeViewerSetting,
|
|
90
|
+
setChannelSettings = _this$ref$current.setChannelSettings,
|
|
91
|
+
channelSettings = _this$ref$current.channelSettings,
|
|
92
|
+
viewMode = _this$ref$current.viewMode,
|
|
93
|
+
time = _this$ref$current.time,
|
|
94
|
+
slice = _this$ref$current.slice;
|
|
95
|
+
|
|
96
|
+
// Needs reset on reload if one of the view modes is 2D while the other is 3D,
|
|
97
|
+
// if the timestamp is different, or if we're on a different z slice.
|
|
98
|
+
// TODO: Handle stopping playback? Requires playback to be part of ViewerStateContext
|
|
99
|
+
var isInDifferentViewMode = viewMode !== newState.viewMode && (viewMode === ViewMode.xy || newState.viewMode === ViewMode.xy);
|
|
100
|
+
var isAtDifferentTime = time !== newState.time;
|
|
101
|
+
var isAtDifferentZSlice = newState.viewMode === ViewMode.xy && !isEqual(newState.slice.z, slice.z);
|
|
102
|
+
var willNeedResetOnLoad = isInDifferentViewMode || isAtDifferentTime || isAtDifferentZSlice;
|
|
103
|
+
overrideViewerState(changeViewerSetting, newState);
|
|
104
|
+
overrideChannelStates(setChannelSettings, channelSettings, newChannelStates);
|
|
105
|
+
this.channelsToReset = new Set(Array(newChannelStates.length).keys());
|
|
106
|
+
if (willNeedResetOnLoad) {
|
|
107
|
+
var enabledChannelsAndResetState = getEnabledChannelIndices(newChannelStates);
|
|
108
|
+
this.channelsToResetOnLoad = new Set(enabledChannelsAndResetState);
|
|
109
|
+
var _iterator = _createForOfIteratorHelper(enabledChannelsAndResetState),
|
|
110
|
+
_step;
|
|
111
|
+
try {
|
|
112
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
113
|
+
var channelIndex = _step.value;
|
|
114
|
+
this.channelsToReset["delete"](channelIndex);
|
|
115
|
+
}
|
|
116
|
+
} catch (err) {
|
|
117
|
+
_iterator.e(err);
|
|
118
|
+
} finally {
|
|
119
|
+
_iterator.f();
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/** Resets to the initial saved state of the viewer, as shown to the user on load. */
|
|
125
|
+
}, {
|
|
126
|
+
key: "resetToSavedViewerState",
|
|
127
|
+
value: function resetToSavedViewerState() {
|
|
128
|
+
var _this = this;
|
|
129
|
+
var channelSettings = this.ref.current.channelSettings;
|
|
130
|
+
var newViewerState = _objectSpread(_objectSpread({}, getDefaultViewerState()), {}, {
|
|
131
|
+
cameraState: getDefaultCameraState(this.savedViewerState.viewMode || ViewMode.threeD)
|
|
132
|
+
}, this.savedViewerState);
|
|
133
|
+
var newChannelSettings = channelSettings.map(function (_, index) {
|
|
134
|
+
var initialChannelSetting = initializeOneChannelSetting(channelSettings[index].name, index, getDefaultChannelColor(index), _this.savedViewerChannelSettings);
|
|
135
|
+
return initialChannelSetting;
|
|
136
|
+
});
|
|
137
|
+
this.resetToState(newViewerState, newChannelSettings);
|
|
138
|
+
this.useDefaultViewerChannelSettings = false;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/** Reset to global default viewer state, as if loading the volume with no parameters. */
|
|
142
|
+
}, {
|
|
143
|
+
key: "resetToDefaultViewerState",
|
|
144
|
+
value: function resetToDefaultViewerState() {
|
|
145
|
+
var channelSettings = this.ref.current.channelSettings;
|
|
146
|
+
var defaultViewerState = _objectSpread(_objectSpread({}, getDefaultViewerState()), {}, {
|
|
147
|
+
cameraState: getDefaultCameraState(ViewMode.threeD)
|
|
148
|
+
});
|
|
149
|
+
var defaultChannelStates = channelSettings.map(function (_, index) {
|
|
150
|
+
return getDefaultChannelState(index);
|
|
151
|
+
});
|
|
152
|
+
for (var i = 0; i < Math.min(3, defaultChannelStates.length); i++) {
|
|
153
|
+
defaultChannelStates[i].volumeEnabled = true;
|
|
154
|
+
}
|
|
155
|
+
this.resetToState(defaultViewerState, defaultChannelStates);
|
|
156
|
+
this.useDefaultViewerChannelSettings = true;
|
|
157
|
+
}
|
|
158
|
+
}]);
|
|
159
|
+
}();
|
|
160
|
+
export { ResetStateProvider as default };
|
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t["return"] || t["return"](); } finally { if (u) throw o; } } }; }
|
|
2
|
+
function _slicedToArray(r, e) { return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest(); }
|
|
3
|
+
function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
|
|
4
|
+
function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
|
|
5
|
+
function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
|
|
6
|
+
function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t["return"] && (u = t["return"](), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
|
|
7
|
+
function _arrayWithHoles(r) { if (Array.isArray(r)) return r; }
|
|
8
|
+
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
9
|
+
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
10
|
+
function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
|
|
11
|
+
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; }
|
|
12
|
+
function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
|
|
13
|
+
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
|
|
14
|
+
import React, { useCallback, useContext, useEffect, useMemo, useReducer, useRef } from "react";
|
|
15
|
+
import { getDefaultViewerChannelSettings, getDefaultViewerState } from "../../shared/constants";
|
|
16
|
+
import { RenderMode, ViewMode } from "../../shared/enums";
|
|
17
|
+
import { useConstructor } from "../../shared/utils/hooks";
|
|
18
|
+
import ResetStateProvider from "./ResetStateProvider";
|
|
19
|
+
var isObject = function isObject(val) {
|
|
20
|
+
return _typeof(val) === "object" && val !== null && !Array.isArray(val);
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
// Some viewer settings require custom change behaviors to change related settings simultaneously or guard against
|
|
24
|
+
// entering an illegal state (e.g. autorotate must not be on in pathtrace mode). Those behaviors are defined here.
|
|
25
|
+
var VIEWER_SETTINGS_CHANGE_HANDLERS = {
|
|
26
|
+
// View mode: if we're switching to 2d, switch to volumetric rendering
|
|
27
|
+
viewMode: function viewMode(prevSettings, _viewMode) {
|
|
28
|
+
var switchToVolumetric = _viewMode !== ViewMode.threeD && prevSettings.renderMode === RenderMode.pathTrace;
|
|
29
|
+
return _objectSpread(_objectSpread({}, prevSettings), {}, {
|
|
30
|
+
viewMode: _viewMode,
|
|
31
|
+
renderMode: switchToVolumetric ? RenderMode.volumetric : prevSettings.renderMode
|
|
32
|
+
});
|
|
33
|
+
},
|
|
34
|
+
// Render mode: if we're switching to pathtrace, turn off autorotate
|
|
35
|
+
// Also, do not allow pathtrace mode in any mode other than 3D.
|
|
36
|
+
renderMode: function renderMode(prevSettings, _renderMode) {
|
|
37
|
+
if (_renderMode === RenderMode.pathTrace && prevSettings.viewMode !== ViewMode.threeD) {
|
|
38
|
+
return _objectSpread({}, prevSettings);
|
|
39
|
+
}
|
|
40
|
+
return _objectSpread(_objectSpread({}, prevSettings), {}, {
|
|
41
|
+
renderMode: _renderMode,
|
|
42
|
+
autorotate: _renderMode === RenderMode.pathTrace ? false : prevSettings.autorotate
|
|
43
|
+
});
|
|
44
|
+
},
|
|
45
|
+
// Autorotate: do not enable autorotate while in pathtrace mode
|
|
46
|
+
autorotate: function autorotate(prevSettings, _autorotate) {
|
|
47
|
+
return _objectSpread(_objectSpread({}, prevSettings), {}, {
|
|
48
|
+
// The button should theoretically be unclickable while in pathtrace mode, but this provides extra security
|
|
49
|
+
autorotate: prevSettings.renderMode === RenderMode.pathTrace ? false : _autorotate
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
var viewerSettingsReducer = function viewerSettingsReducer(viewerSettings, _ref) {
|
|
54
|
+
var key = _ref.key,
|
|
55
|
+
value = _ref.value;
|
|
56
|
+
var changeHandler = VIEWER_SETTINGS_CHANGE_HANDLERS[key];
|
|
57
|
+
if (changeHandler) {
|
|
58
|
+
// This setting has a custom change handler. Let it handle creating a new state object.
|
|
59
|
+
return changeHandler(viewerSettings, value);
|
|
60
|
+
} else {
|
|
61
|
+
var setting = viewerSettings[key];
|
|
62
|
+
if (isObject(setting) && isObject(value)) {
|
|
63
|
+
// This setting is an object, and we may be updating it with a partial object.
|
|
64
|
+
return _objectSpread(_objectSpread({}, viewerSettings), {}, _defineProperty({}, key, _objectSpread(_objectSpread({}, setting), value)));
|
|
65
|
+
} else {
|
|
66
|
+
// This setting is regular. Update it the regular way.
|
|
67
|
+
return _objectSpread(_objectSpread({}, viewerSettings), {}, _defineProperty({}, key, value));
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
var ChannelSettingActionType = /*#__PURE__*/function (ChannelSettingActionType) {
|
|
72
|
+
ChannelSettingActionType["UniformUpdate"] = "UniformUpdate";
|
|
73
|
+
ChannelSettingActionType["ArrayUpdate"] = "ArrayUpdate";
|
|
74
|
+
ChannelSettingActionType["Init"] = "Init";
|
|
75
|
+
return ChannelSettingActionType;
|
|
76
|
+
}(ChannelSettingActionType || {});
|
|
77
|
+
/** Set channel setting `key` on one or more channels specified by `index` to value `value`. */
|
|
78
|
+
/** Set the values of channel setting `key` for all channels from an array of values ordered by channel index */
|
|
79
|
+
/** Initialize list of channel states */
|
|
80
|
+
var channelSettingsReducer = function channelSettingsReducer(channelSettings, action) {
|
|
81
|
+
if (action.type === ChannelSettingActionType.Init) {
|
|
82
|
+
// ChannelSettingInitAction
|
|
83
|
+
return action.value;
|
|
84
|
+
} else if (action.type === ChannelSettingActionType.ArrayUpdate) {
|
|
85
|
+
// ChannelSettingArrayUpdateAction
|
|
86
|
+
return channelSettings.map(function (channel, idx) {
|
|
87
|
+
return action.value[idx] ? _objectSpread(_objectSpread({}, channel), {}, _defineProperty({}, action.key, action.value[idx])) : channel;
|
|
88
|
+
});
|
|
89
|
+
} else {
|
|
90
|
+
// type is ChannelSettingActionType.UniformUpdate
|
|
91
|
+
if (Array.isArray(action.index)) {
|
|
92
|
+
// ChannelSettingUniformUpdateAction on potentially multiple channels
|
|
93
|
+
return channelSettings.map(function (channel, idx) {
|
|
94
|
+
return action.index.includes(idx) ? _objectSpread(_objectSpread({}, channel), action.value) : channel;
|
|
95
|
+
});
|
|
96
|
+
} else {
|
|
97
|
+
// ChannelSettingUniformUpdateAction on a single channel
|
|
98
|
+
var newSettings = channelSettings.slice();
|
|
99
|
+
if (action.index >= 0 && action.index < channelSettings.length) {
|
|
100
|
+
newSettings[action.index] = _objectSpread(_objectSpread({}, newSettings[action.index]), action.value);
|
|
101
|
+
}
|
|
102
|
+
return newSettings;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
var nullfn = function nullfn() {};
|
|
107
|
+
var DEFAULT_VIEWER_CONTEXT = _objectSpread(_objectSpread({}, getDefaultViewerState()), {}, {
|
|
108
|
+
channelSettings: [],
|
|
109
|
+
changeViewerSetting: nullfn,
|
|
110
|
+
setChannelSettings: nullfn,
|
|
111
|
+
changeChannelSetting: nullfn,
|
|
112
|
+
applyColorPresets: nullfn,
|
|
113
|
+
resetToSavedViewerState: nullfn,
|
|
114
|
+
resetToDefaultViewerState: nullfn,
|
|
115
|
+
setSavedViewerChannelSettings: nullfn,
|
|
116
|
+
getCurrentViewerChannelSettings: function getCurrentViewerChannelSettings() {
|
|
117
|
+
return getDefaultViewerChannelSettings();
|
|
118
|
+
},
|
|
119
|
+
getChannelsAwaitingReset: function getChannelsAwaitingReset() {
|
|
120
|
+
return new Set();
|
|
121
|
+
},
|
|
122
|
+
getChannelsAwaitingResetOnLoad: function getChannelsAwaitingResetOnLoad() {
|
|
123
|
+
return new Set();
|
|
124
|
+
},
|
|
125
|
+
onResetChannel: nullfn
|
|
126
|
+
});
|
|
127
|
+
export var ALL_VIEWER_STATE_KEYS = Object.keys(DEFAULT_VIEWER_CONTEXT);
|
|
128
|
+
var DEFAULT_VIEWER_CONTEXT_OUTER = {
|
|
129
|
+
ref: {
|
|
130
|
+
current: DEFAULT_VIEWER_CONTEXT
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
export var ViewerStateContext = /*#__PURE__*/React.createContext(DEFAULT_VIEWER_CONTEXT_OUTER);
|
|
134
|
+
|
|
135
|
+
/** Provides a central store for the state of the viewer, and the methods to update it. */
|
|
136
|
+
var ViewerStateProvider = function ViewerStateProvider(props) {
|
|
137
|
+
var _useReducer = useReducer(viewerSettingsReducer, _objectSpread({}, getDefaultViewerState())),
|
|
138
|
+
_useReducer2 = _slicedToArray(_useReducer, 2),
|
|
139
|
+
viewerSettings = _useReducer2[0],
|
|
140
|
+
viewerDispatch = _useReducer2[1];
|
|
141
|
+
var _useReducer3 = useReducer(channelSettingsReducer, []),
|
|
142
|
+
_useReducer4 = _slicedToArray(_useReducer3, 2),
|
|
143
|
+
channelSettings = _useReducer4[0],
|
|
144
|
+
channelDispatch = _useReducer4[1];
|
|
145
|
+
// Provide viewer state via a ref, so that closures that run asynchronously can capture the ref instead of the
|
|
146
|
+
// specific values they need and always have the most up-to-date state.
|
|
147
|
+
var ref = useRef(DEFAULT_VIEWER_CONTEXT);
|
|
148
|
+
var resetProvider = useConstructor(function () {
|
|
149
|
+
return new ResetStateProvider(ref);
|
|
150
|
+
});
|
|
151
|
+
useEffect(function () {
|
|
152
|
+
resetProvider.setSavedViewerState(props.viewerSettings || {});
|
|
153
|
+
}, [props.viewerSettings]);
|
|
154
|
+
var changeViewerSetting = useCallback(function (key, value) {
|
|
155
|
+
return viewerDispatch({
|
|
156
|
+
key: key,
|
|
157
|
+
value: value
|
|
158
|
+
});
|
|
159
|
+
}, []);
|
|
160
|
+
var changeChannelSetting = useCallback(function (index, value) {
|
|
161
|
+
channelDispatch({
|
|
162
|
+
type: ChannelSettingActionType.UniformUpdate,
|
|
163
|
+
index: index,
|
|
164
|
+
value: value
|
|
165
|
+
});
|
|
166
|
+
}, []);
|
|
167
|
+
var applyColorPresets = useCallback(function (value) {
|
|
168
|
+
return channelDispatch({
|
|
169
|
+
type: ChannelSettingActionType.ArrayUpdate,
|
|
170
|
+
key: "color",
|
|
171
|
+
value: value
|
|
172
|
+
});
|
|
173
|
+
}, []);
|
|
174
|
+
var setChannelSettings = useCallback(function (channels) {
|
|
175
|
+
return channelDispatch({
|
|
176
|
+
type: ChannelSettingActionType.Init,
|
|
177
|
+
value: channels
|
|
178
|
+
});
|
|
179
|
+
}, []);
|
|
180
|
+
|
|
181
|
+
// Sync viewer settings prop with state
|
|
182
|
+
// React docs seem to be fine with syncing state with props directly in the render function, but that caused an
|
|
183
|
+
// infinite render loop, so now it's in a `useMemo`:
|
|
184
|
+
// https://react.dev/learn/you-might-not-need-an-effect#adjusting-some-state-when-a-prop-changes
|
|
185
|
+
useMemo(function () {
|
|
186
|
+
if (props.viewerSettings) {
|
|
187
|
+
for (var _i = 0, _arr = Object.keys(props.viewerSettings); _i < _arr.length; _i++) {
|
|
188
|
+
var key = _arr[_i];
|
|
189
|
+
if (viewerSettings[key] !== props.viewerSettings[key]) {
|
|
190
|
+
changeViewerSetting(key, props.viewerSettings[key]);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}, [props.viewerSettings]);
|
|
195
|
+
var context = useMemo(function () {
|
|
196
|
+
ref.current = _objectSpread(_objectSpread({}, viewerSettings), {}, {
|
|
197
|
+
channelSettings: channelSettings,
|
|
198
|
+
changeViewerSetting: changeViewerSetting,
|
|
199
|
+
setChannelSettings: setChannelSettings,
|
|
200
|
+
changeChannelSetting: changeChannelSetting,
|
|
201
|
+
applyColorPresets: applyColorPresets,
|
|
202
|
+
// Reset-related callbacks
|
|
203
|
+
setSavedViewerChannelSettings: resetProvider.setSavedViewerChannelSettings,
|
|
204
|
+
getCurrentViewerChannelSettings: resetProvider.getCurrentViewerChannelSettings,
|
|
205
|
+
getChannelsAwaitingReset: resetProvider.getChannelsAwaitingReset,
|
|
206
|
+
getChannelsAwaitingResetOnLoad: resetProvider.getChannelsAwaitingResetOnLoad,
|
|
207
|
+
onResetChannel: resetProvider.onResetChannel,
|
|
208
|
+
resetToSavedViewerState: resetProvider.resetToSavedViewerState,
|
|
209
|
+
resetToDefaultViewerState: resetProvider.resetToDefaultViewerState
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
// `ref` is wrapped in another object to ensure that the context updates when state does.
|
|
213
|
+
// (`ref` on its own would always compare equal to itself and the context would never update.)
|
|
214
|
+
return {
|
|
215
|
+
ref: ref
|
|
216
|
+
};
|
|
217
|
+
}, [viewerSettings, channelSettings]);
|
|
218
|
+
return /*#__PURE__*/React.createElement(ViewerStateContext.Provider, {
|
|
219
|
+
value: context
|
|
220
|
+
}, props.children);
|
|
221
|
+
};
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Higher-order component that connects a component to the viewer state context.
|
|
225
|
+
*
|
|
226
|
+
* Accepts a `component` and an array of `keys` from the viewer state context, and returns a new memoized component
|
|
227
|
+
* which "subscribes" to only those fields of state, and will not re-render if other fields change. This works by
|
|
228
|
+
* creating a component which is "split in two" as described
|
|
229
|
+
* [here](https://react.dev/reference/react/memo#updating-a-memoized-component-using-a-context).
|
|
230
|
+
*
|
|
231
|
+
* NOTE that while higher-order components don't seem to be explicitly considered an anti-pattern, they don't appear in
|
|
232
|
+
* modern documentation because they are "[not commonly used in modern React
|
|
233
|
+
* code](https://legacy.reactjs.org/docs/higher-order-components.html)." React-redux, which inspired this "connect"
|
|
234
|
+
* pattern, has also generally moved away from this pattern [in favor of a hooks-based
|
|
235
|
+
* approach](https://react-redux.js.org/api/hooks). I too would love to use hooks to connect to viewer state, but there
|
|
236
|
+
* is currently no way to hook into context without agreeing to re-render on every change. I feel okay using a higher-
|
|
237
|
+
* order component in this case because, analogous to a custom hook, it extends a provided primitive HOC (`memo`).
|
|
238
|
+
*/
|
|
239
|
+
export function connectToViewerState(component, keys) {
|
|
240
|
+
var MemoedComponent = /*#__PURE__*/React.memo(component);
|
|
241
|
+
var ConnectedComponent = function ConnectedComponent(props) {
|
|
242
|
+
var viewerState = useContext(ViewerStateContext);
|
|
243
|
+
var mergedProps = _objectSpread({}, props);
|
|
244
|
+
var _iterator = _createForOfIteratorHelper(keys),
|
|
245
|
+
_step;
|
|
246
|
+
try {
|
|
247
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
248
|
+
var key = _step.value;
|
|
249
|
+
mergedProps[key] = viewerState.ref.current[key];
|
|
250
|
+
}
|
|
251
|
+
} catch (err) {
|
|
252
|
+
_iterator.e(err);
|
|
253
|
+
} finally {
|
|
254
|
+
_iterator.f();
|
|
255
|
+
}
|
|
256
|
+
return /*#__PURE__*/React.createElement(MemoedComponent, mergedProps);
|
|
257
|
+
};
|
|
258
|
+
ConnectedComponent.displayName = "Connected(".concat(component.displayName || component.name, ")");
|
|
259
|
+
return ConnectedComponent;
|
|
260
|
+
}
|
|
261
|
+
export default ViewerStateProvider;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
function _slicedToArray(r, e) { return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest(); }
|
|
2
|
+
function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
|
|
3
|
+
function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
|
|
4
|
+
function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
|
|
5
|
+
function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t["return"] && (u = t["return"](), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
|
|
6
|
+
function _arrayWithHoles(r) { if (Array.isArray(r)) return r; }
|
|
7
|
+
import React from "react";
|
|
8
|
+
import { CaretDownOutlined, CaretUpOutlined } from "@ant-design/icons";
|
|
9
|
+
import { useRefWithSetter } from "../../../shared/utils/hooks";
|
|
10
|
+
import "./styles.css";
|
|
11
|
+
/**
|
|
12
|
+
* Fully-controlled numeric input (value must be supplied from state in parent).
|
|
13
|
+
* Changeable with arrow keys, typing values, or clickable arrows. Inspired by
|
|
14
|
+
* ant's `InputNumber`, but conforms to our style and behavior expectations.
|
|
15
|
+
*/
|
|
16
|
+
var NumericInput = function NumericInput(_ref) {
|
|
17
|
+
var value = _ref.value,
|
|
18
|
+
_ref$step = _ref.step,
|
|
19
|
+
step = _ref$step === void 0 ? 1 : _ref$step,
|
|
20
|
+
_ref$precision = _ref.precision,
|
|
21
|
+
precision = _ref$precision === void 0 ? step : _ref$precision,
|
|
22
|
+
_ref$min = _ref.min,
|
|
23
|
+
min = _ref$min === void 0 ? 0 : _ref$min,
|
|
24
|
+
_ref$max = _ref.max,
|
|
25
|
+
max = _ref$max === void 0 ? Number.MAX_SAFE_INTEGER : _ref$max,
|
|
26
|
+
_ref$disabled = _ref.disabled,
|
|
27
|
+
disabled = _ref$disabled === void 0 ? false : _ref$disabled,
|
|
28
|
+
_ref$className = _ref.className,
|
|
29
|
+
className = _ref$className === void 0 ? "" : _ref$className,
|
|
30
|
+
onChange = _ref.onChange;
|
|
31
|
+
// While the input has focus, allow invalid input, just don't call `onChange` with it
|
|
32
|
+
var _React$useState = React.useState(false),
|
|
33
|
+
_React$useState2 = _slicedToArray(_React$useState, 2),
|
|
34
|
+
hasFocus = _React$useState2[0],
|
|
35
|
+
_setHasFocus = _React$useState2[1];
|
|
36
|
+
// State doesn't update before focus handler runs - keep a ref following focus state
|
|
37
|
+
var _useRefWithSetter = useRefWithSetter(_setHasFocus, hasFocus),
|
|
38
|
+
_useRefWithSetter2 = _slicedToArray(_useRefWithSetter, 2),
|
|
39
|
+
hasFocusRef = _useRefWithSetter2[0],
|
|
40
|
+
setHasFocus = _useRefWithSetter2[1];
|
|
41
|
+
|
|
42
|
+
// Hold the potentially invalid contents of the focused input here
|
|
43
|
+
var _React$useState3 = React.useState(""),
|
|
44
|
+
_React$useState4 = _slicedToArray(_React$useState3, 2),
|
|
45
|
+
textContent = _React$useState4[0],
|
|
46
|
+
setTextContent = _React$useState4[1];
|
|
47
|
+
var inputRef = React.useRef(null);
|
|
48
|
+
var clamp = function clamp(newValue) {
|
|
49
|
+
return Math.min(Math.max(newValue, min), max);
|
|
50
|
+
};
|
|
51
|
+
var roundToPrecision = function roundToPrecision(newValue) {
|
|
52
|
+
return clamp(Math.round(newValue / precision) * precision);
|
|
53
|
+
};
|
|
54
|
+
var shouldChange = function shouldChange(newValue) {
|
|
55
|
+
return !(isNaN(newValue) || newValue === value || disabled);
|
|
56
|
+
};
|
|
57
|
+
var displayedValue = roundToPrecision(value);
|
|
58
|
+
var onFocus = function onFocus() {
|
|
59
|
+
if (!hasFocusRef.current) {
|
|
60
|
+
// propagate current value to `textContent` on focus
|
|
61
|
+
setTextContent(displayedValue.toString());
|
|
62
|
+
setHasFocus(true);
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
var changeByStep = function changeByStep(up) {
|
|
66
|
+
var _inputRef$current;
|
|
67
|
+
var delta = up ? step : -step;
|
|
68
|
+
var newValue = clamp(displayedValue + delta);
|
|
69
|
+
if (shouldChange(newValue)) {
|
|
70
|
+
onChange(newValue);
|
|
71
|
+
setTextContent(newValue.toString());
|
|
72
|
+
// let the focus handler know we've taken care of things, so it won't restore the previous value
|
|
73
|
+
setHasFocus(true);
|
|
74
|
+
}
|
|
75
|
+
(_inputRef$current = inputRef.current) === null || _inputRef$current === void 0 || _inputRef$current.focus();
|
|
76
|
+
};
|
|
77
|
+
var onKeyDown = function onKeyDown(event) {
|
|
78
|
+
var key = event.key;
|
|
79
|
+
if (["Up", "ArrowUp", "Down", "ArrowDown"].includes(key)) {
|
|
80
|
+
changeByStep(key === "Up" || key === "ArrowUp");
|
|
81
|
+
event.preventDefault();
|
|
82
|
+
} else if (key === "Enter") {
|
|
83
|
+
var _inputRef$current2;
|
|
84
|
+
(_inputRef$current2 = inputRef.current) === null || _inputRef$current2 === void 0 || _inputRef$current2.blur();
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
var handleTyping = function handleTyping(inputStr) {
|
|
88
|
+
setTextContent(inputStr);
|
|
89
|
+
|
|
90
|
+
// if the user clears all text, assume they mean 0 (or the extremum closest to it)
|
|
91
|
+
// this is likely not completely general, but should be reasonable for any of our purposes
|
|
92
|
+
var inputNum = inputStr === "" ? 0 : parseFloat(inputStr);
|
|
93
|
+
var newValue = roundToPrecision(inputNum);
|
|
94
|
+
if (shouldChange(newValue)) {
|
|
95
|
+
onChange(newValue);
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
var fullClassName = "numinput" + (disabled ? " numinput-disabled" : "") + (className && " ".concat(className));
|
|
99
|
+
return /*#__PURE__*/React.createElement("div", {
|
|
100
|
+
className: fullClassName,
|
|
101
|
+
onKeyDown: onKeyDown
|
|
102
|
+
}, /*#__PURE__*/React.createElement("input", {
|
|
103
|
+
value: hasFocus ? textContent : displayedValue,
|
|
104
|
+
step: step,
|
|
105
|
+
min: min,
|
|
106
|
+
max: max,
|
|
107
|
+
disabled: disabled,
|
|
108
|
+
className: "numinput-input",
|
|
109
|
+
autoComplete: "off",
|
|
110
|
+
role: "spinbutton",
|
|
111
|
+
"aria-valuenow": displayedValue,
|
|
112
|
+
"aria-valuemin": min,
|
|
113
|
+
"aria-valuemax": max,
|
|
114
|
+
ref: inputRef,
|
|
115
|
+
onChange: function onChange(_ref2) {
|
|
116
|
+
var target = _ref2.target;
|
|
117
|
+
return handleTyping(target.value);
|
|
118
|
+
},
|
|
119
|
+
onFocus: onFocus,
|
|
120
|
+
onBlur: function onBlur() {
|
|
121
|
+
return setHasFocus(false);
|
|
122
|
+
}
|
|
123
|
+
}), /*#__PURE__*/React.createElement("div", {
|
|
124
|
+
className: "numinput-controls"
|
|
125
|
+
}, /*#__PURE__*/React.createElement("div", {
|
|
126
|
+
className: "numinput-controls-button numinput-controls-button-up",
|
|
127
|
+
role: "button",
|
|
128
|
+
"aria-label": "Increase Value",
|
|
129
|
+
"aria-disabled": disabled,
|
|
130
|
+
onClick: function onClick() {
|
|
131
|
+
return changeByStep(true);
|
|
132
|
+
}
|
|
133
|
+
}, /*#__PURE__*/React.createElement(CaretUpOutlined, {
|
|
134
|
+
className: "numinput-controls-button-icon"
|
|
135
|
+
})), /*#__PURE__*/React.createElement("div", {
|
|
136
|
+
className: "numinput-controls-button numinput-controls-button-down",
|
|
137
|
+
role: "button",
|
|
138
|
+
"aria-label": "Decrease Value",
|
|
139
|
+
"aria-disabled": disabled,
|
|
140
|
+
onClick: function onClick() {
|
|
141
|
+
return changeByStep(false);
|
|
142
|
+
}
|
|
143
|
+
}, /*#__PURE__*/React.createElement(CaretDownOutlined, {
|
|
144
|
+
className: "numinput-controls-button-icon"
|
|
145
|
+
}))));
|
|
146
|
+
};
|
|
147
|
+
export default NumericInput;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
.numinput{
|
|
2
|
+
height:23px;
|
|
3
|
+
width:52px;
|
|
4
|
+
position:relative;
|
|
5
|
+
display:inline-block;
|
|
6
|
+
box-sizing:border-box;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
.numinput input{
|
|
10
|
+
color:var(--color-text-body);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.numinput.numinput-disabled{
|
|
14
|
+
opacity:0.5;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.numinput .numinput-input{
|
|
18
|
+
width:40px;
|
|
19
|
+
height:100%;
|
|
20
|
+
font-size:12px;
|
|
21
|
+
text-align:right;
|
|
22
|
+
padding-right:6px;
|
|
23
|
+
background-color:transparent;
|
|
24
|
+
border:1px solid #4b4b4b;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.numinput .numinput-input:focus{
|
|
28
|
+
outline:none;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.numinput .numinput-controls{
|
|
32
|
+
width:12px;
|
|
33
|
+
height:100%;
|
|
34
|
+
position:absolute;
|
|
35
|
+
display:inline-block;
|
|
36
|
+
border:1px solid #4b4b4b;
|
|
37
|
+
border-left-width:0;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.numinput .numinput-controls-button{
|
|
41
|
+
width:100%;
|
|
42
|
+
height:50%;
|
|
43
|
+
line-height:0;
|
|
44
|
+
transition:all 0.3s linear;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.numinput .numinput-controls-button.numinput-controls-button-up{
|
|
48
|
+
border-bottom:1px solid #4b4b4b;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.numinput .numinput-controls-button .numinput-controls-button-icon{
|
|
52
|
+
font-size:9px;
|
|
53
|
+
margin:1px;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
.numinput:not(.numinput-disabled) .numinput-controls-button{
|
|
57
|
+
cursor:pointer;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.numinput:not(.numinput-disabled) .numinput-controls-button:hover,
|
|
61
|
+
.numinput:not(.numinput-disabled) .numinput-controls-button:focus{
|
|
62
|
+
background-color:#9e6aff;
|
|
63
|
+
color:white;
|
|
64
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { Checkbox } from "antd";
|
|
3
|
+
var SharedCheckbox = function SharedCheckbox(props) {
|
|
4
|
+
var onCheckAllChange = function onCheckAllChange(_ref) {
|
|
5
|
+
var target = _ref.target;
|
|
6
|
+
return props.onChange(target.checked, props.allOptions);
|
|
7
|
+
};
|
|
8
|
+
var indeterminate = !!props.checkedList.length && props.checkedList.length < props.allOptions.length;
|
|
9
|
+
var checkAll = props.checkedList.length === props.allOptions.length;
|
|
10
|
+
return /*#__PURE__*/React.createElement(Checkbox, {
|
|
11
|
+
indeterminate: indeterminate,
|
|
12
|
+
onChange: onCheckAllChange,
|
|
13
|
+
checked: checkAll,
|
|
14
|
+
style: props.style
|
|
15
|
+
}, props.children);
|
|
16
|
+
};
|
|
17
|
+
export default SharedCheckbox;
|