kitchen-simulator 11.0.0-react-18 → 11.0.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.
Files changed (71) hide show
  1. package/es/LiteKitchenConfigurator.js +42 -11
  2. package/es/LiteRenderer.js +2 -24
  3. package/es/actions/export.js +25 -12
  4. package/es/analytics/ga4.js +188 -0
  5. package/es/catalog/utils/item-loader.js +4 -4
  6. package/es/class/item.js +29 -7
  7. package/es/class/line.js +1 -3
  8. package/es/components/content.js +20 -5
  9. package/es/components/export.js +6 -4
  10. package/es/components/style/form-number-input.js +7 -5
  11. package/es/components/style/form-submit-button.js +25 -0
  12. package/es/components/viewer2d/group.js +6 -5
  13. package/es/components/viewer2d/item.js +9 -9
  14. package/es/components/viewer2d/line.js +18 -47
  15. package/es/components/viewer2d/rulerX.js +9 -8
  16. package/es/components/viewer2d/rulerY.js +9 -8
  17. package/es/components/viewer2d/scene.js +9 -9
  18. package/es/components/viewer2d/state.js +1 -1
  19. package/es/components/viewer2d/utils.js +0 -6
  20. package/es/components/viewer2d/viewer2d.js +35 -31
  21. package/es/components/viewer3d/ruler-utils/layer3D.js +2 -2
  22. package/es/components/viewer3d/scene-creator.js +40 -75
  23. package/es/components/viewer3d/viewer3d-first-person.js +13 -8
  24. package/es/components/viewer3d/viewer3d.js +19 -15
  25. package/es/devLiteRenderer.js +913 -0
  26. package/es/events/external/handleExternalEvent.js +1 -0
  27. package/es/events/external/handleExternalEvent.util.js +330 -347
  28. package/es/events/external/handlers.changeDoorStyle.js +5 -3
  29. package/es/events/external/handlers.loadProject.js +5 -3
  30. package/es/events/external/handlers.syncScene.js +1 -1
  31. package/es/mappings/external-events/mappers/ccdfMapper.js +14 -8
  32. package/es/shared/domain/cabinet-warning.js +15 -0
  33. package/es/utils/geometry.js +4 -7
  34. package/es/utils/helper.js +81 -22
  35. package/es/utils/skinPanelEngine.js +5 -9
  36. package/lib/LiteKitchenConfigurator.js +42 -11
  37. package/lib/LiteRenderer.js +3 -25
  38. package/lib/actions/export.js +35 -39
  39. package/lib/analytics/ga4.js +194 -0
  40. package/lib/catalog/utils/item-loader.js +3 -3
  41. package/lib/class/item.js +29 -7
  42. package/lib/class/line.js +1 -3
  43. package/lib/components/content.js +19 -4
  44. package/lib/components/export.js +6 -16
  45. package/lib/components/style/form-number-input.js +7 -5
  46. package/lib/components/style/form-submit-button.js +35 -0
  47. package/lib/components/viewer2d/group.js +6 -5
  48. package/lib/components/viewer2d/item.js +8 -8
  49. package/lib/components/viewer2d/line.js +18 -47
  50. package/lib/components/viewer2d/rulerX.js +9 -8
  51. package/lib/components/viewer2d/rulerY.js +9 -8
  52. package/lib/components/viewer2d/scene.js +9 -9
  53. package/lib/components/viewer2d/state.js +1 -1
  54. package/lib/components/viewer2d/utils.js +0 -7
  55. package/lib/components/viewer2d/viewer2d.js +33 -29
  56. package/lib/components/viewer3d/ruler-utils/layer3D.js +2 -2
  57. package/lib/components/viewer3d/scene-creator.js +39 -75
  58. package/lib/components/viewer3d/viewer3d-first-person.js +13 -8
  59. package/lib/components/viewer3d/viewer3d.js +19 -15
  60. package/lib/devLiteRenderer.js +917 -0
  61. package/lib/events/external/handleExternalEvent.js +1 -0
  62. package/lib/events/external/handleExternalEvent.util.js +330 -347
  63. package/lib/events/external/handlers.changeDoorStyle.js +5 -3
  64. package/lib/events/external/handlers.loadProject.js +5 -3
  65. package/lib/events/external/handlers.syncScene.js +1 -1
  66. package/lib/mappings/external-events/mappers/ccdfMapper.js +14 -8
  67. package/lib/shared/domain/cabinet-warning.js +20 -0
  68. package/lib/utils/geometry.js +4 -7
  69. package/lib/utils/helper.js +82 -24
  70. package/lib/utils/skinPanelEngine.js +4 -8
  71. package/package.json +21 -6
@@ -1,6 +1,7 @@
1
1
  import _extends from "@babel/runtime/helpers/esm/extends";
2
- import _defineProperty from "@babel/runtime/helpers/esm/defineProperty";
3
2
  import _objectWithoutProperties from "@babel/runtime/helpers/esm/objectWithoutProperties";
3
+ import _toConsumableArray from "@babel/runtime/helpers/esm/toConsumableArray";
4
+ import _defineProperty from "@babel/runtime/helpers/esm/defineProperty";
4
5
  import _classCallCheck from "@babel/runtime/helpers/esm/classCallCheck";
5
6
  import _createClass from "@babel/runtime/helpers/esm/createClass";
6
7
  import _possibleConstructorReturn from "@babel/runtime/helpers/esm/possibleConstructorReturn";
@@ -313,20 +314,41 @@ var LiteKitchenConfigurator = /*#__PURE__*/function (_Component) {
313
314
  var el = document.getElementById('add_appliances_inactive');
314
315
  if (el !== null && el !== void 0 && (_el$parentElement0 = el.parentElement) !== null && _el$parentElement0 !== void 0 && _el$parentElement0.parentElement) el.parentElement.parentElement.style.zIndex = 6;
315
316
  }
317
+ }, {
318
+ key: "getChildContext",
319
+ value: function getChildContext() {
320
+ var _this2 = this;
321
+ return _objectSpread(_objectSpread({}, objectsMap(actions, function (actionNamespace) {
322
+ return _this2.props[actionNamespace];
323
+ })), {}, {
324
+ translator: this.props.translator,
325
+ catalog: this.props.catalog
326
+ });
327
+ }
316
328
  }, {
317
329
  key: "componentDidMount",
318
330
  value: function componentDidMount() {
319
331
  window.forRedo = [];
332
+ var store = this.context.store;
333
+ var _this$props = this.props,
334
+ stateExtractor = _this$props.stateExtractor,
335
+ plugins = _this$props.plugins;
336
+
337
+ // keep old behavior: run plugins once on mount
338
+ var newplugins = _toConsumableArray(plugins);
339
+ newplugins.forEach(function (newplugin) {
340
+ return newplugin(store, stateExtractor);
341
+ });
320
342
  }
321
343
  }, {
322
344
  key: "componentDidUpdate",
323
345
  value: function componentDidUpdate(prevProps) {
324
346
  var _extractedState$getIn;
325
- var _this$props = this.props,
326
- externalEvent = _this$props.externalEvent,
327
- extractedState = _this$props.extractedState,
328
- projectActions = _this$props.projectActions,
329
- catalog = _this$props.catalog;
347
+ var _this$props2 = this.props,
348
+ externalEvent = _this$props2.externalEvent,
349
+ extractedState = _this$props2.extractedState,
350
+ projectActions = _this$props2.projectActions,
351
+ catalog = _this$props2.catalog;
330
352
 
331
353
  // same behavior: handle external event when it changes
332
354
  if (prevProps.externalEvent !== externalEvent) {
@@ -385,11 +407,11 @@ var LiteKitchenConfigurator = /*#__PURE__*/function (_Component) {
385
407
  }, {
386
408
  key: "render",
387
409
  value: function render() {
388
- var _this$props2 = this.props,
389
- width = _this$props2.width,
390
- height = _this$props2.height,
391
- extractedState = _this$props2.extractedState,
392
- props = _objectWithoutProperties(_this$props2, _excluded);
410
+ var _this$props3 = this.props,
411
+ width = _this$props3.width,
412
+ height = _this$props3.height,
413
+ extractedState = _this$props3.extractedState,
414
+ props = _objectWithoutProperties(_this$props3, _excluded);
393
415
  var _this$state = this.state,
394
416
  savePopupVisible = _this$state.savePopupVisible,
395
417
  quotePopupVisible = _this$state.quotePopupVisible,
@@ -455,6 +477,15 @@ LiteKitchenConfigurator.propTypes = {
455
477
  // ✅ injected by connect
456
478
  externalEvent: PropTypes.object
457
479
  };
480
+ LiteKitchenConfigurator.contextTypes = {
481
+ store: PropTypes.object.isRequired
482
+ };
483
+ LiteKitchenConfigurator.childContextTypes = _objectSpread(_objectSpread({}, objectsMap(actions, function () {
484
+ return PropTypes.object;
485
+ })), {}, {
486
+ translator: PropTypes.object,
487
+ catalog: PropTypes.object
488
+ });
458
489
  LiteKitchenConfigurator.defaultProps = {
459
490
  translator: new Translator(),
460
491
  catalog: new Catalog(),
@@ -11,7 +11,7 @@ function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length)
11
11
  import React, { useCallback, useEffect, useMemo, useRef } from 'react';
12
12
  import PropTypes from 'prop-types';
13
13
  import { Provider } from 'react-redux';
14
- import { createStore, bindActionCreators } from 'redux';
14
+ import { createStore } from 'redux';
15
15
  import { Map } from 'immutable';
16
16
  import * as Sentry from '@sentry/react';
17
17
  import * as THREE from 'three';
@@ -20,14 +20,11 @@ import { State } from "./models";
20
20
  import PlannerReducer from "./reducers/reducer";
21
21
  import AppContext from "./AppContext";
22
22
  import Catalog from "./catalog/catalog";
23
- import actions from "./actions/export";
24
- import Translator from "./translator/translator";
25
23
  import * as Areas from "./catalog/areas/area/planner-element";
26
24
  import * as Lines from "./catalog/lines/wall/planner-element";
27
25
  import { buildHoleElements, registerDynamicHoles } from "./mappings/holesToCatalog";
28
26
  import { ConsoleDebugger, Keyboard } from "./plugins/export";
29
27
  import LiteKitchenConfigurator from "./LiteKitchenConfigurator";
30
- import { objectsMap } from "./utils/objects-utils";
31
28
  var isBrowser = typeof window !== 'undefined';
32
29
  if (isBrowser) window.THREE = THREE;
33
30
 
@@ -277,26 +274,7 @@ export default function LiteRenderer(props) {
277
274
  var _ref = configData || {},
278
275
  logoImg = _ref.logoImg,
279
276
  companyUrl = _ref.companyUrl;
280
-
281
- // Build the context value with bound action creators + translator + catalog
282
- var translatorRef = useRef(null);
283
- if (!translatorRef.current) translatorRef.current = new Translator();
284
- var contextValue = useMemo(function () {
285
- var store = storeRef.current;
286
- var boundActions = objectsMap(actions, function (actionNamespace) {
287
- return bindActionCreators(actions[actionNamespace], store.dispatch);
288
- });
289
- return _objectSpread(_objectSpread({}, boundActions), {}, {
290
- translator: translatorRef.current,
291
- catalog: catalogRef.current
292
- });
293
- }, []);
294
-
295
- // Update catalog in context when it changes
296
- contextValue.catalog = catalogRef.current;
297
- return /*#__PURE__*/React.createElement(AppContext.Provider, {
298
- value: contextValue
299
- }, /*#__PURE__*/React.createElement(Provider, {
277
+ return /*#__PURE__*/React.createElement(AppContext.Provider, null, /*#__PURE__*/React.createElement(Provider, {
300
278
  store: storeRef.current
301
279
  }, /*#__PURE__*/React.createElement(LiteKitchenConfigurator, _extends({
302
280
  catalog: catalogRef.current,
@@ -8,16 +8,29 @@ import * as verticesActions from "./vertices-actions";
8
8
  import * as itemsActions from "./items-actions";
9
9
  import * as areaActions from "./area-actions";
10
10
  import * as groupsActions from "./groups-actions";
11
- export { projectActions, viewer2DActions, viewer3DActions, linesActions, holesActions, sceneActions, verticesActions, itemsActions, areaActions, groupsActions };
11
+
12
+ export {
13
+ projectActions,
14
+ viewer2DActions,
15
+ viewer3DActions,
16
+ linesActions,
17
+ holesActions,
18
+ sceneActions,
19
+ verticesActions,
20
+ itemsActions,
21
+ areaActions,
22
+ groupsActions
23
+ };
24
+
12
25
  export default {
13
- projectActions: projectActions,
14
- viewer2DActions: viewer2DActions,
15
- viewer3DActions: viewer3DActions,
16
- linesActions: linesActions,
17
- holesActions: holesActions,
18
- sceneActions: sceneActions,
19
- verticesActions: verticesActions,
20
- itemsActions: itemsActions,
21
- areaActions: areaActions,
22
- groupsActions: groupsActions
23
- };
26
+ projectActions,
27
+ viewer2DActions,
28
+ viewer3DActions,
29
+ linesActions,
30
+ holesActions,
31
+ sceneActions,
32
+ verticesActions,
33
+ itemsActions,
34
+ areaActions,
35
+ groupsActions
36
+ };
@@ -0,0 +1,188 @@
1
+ import _defineProperty from "@babel/runtime/helpers/esm/defineProperty";
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
+ import ReactGA from 'react-ga4';
5
+
6
+ // ---------- Helpers ----------
7
+ function nowMs() {
8
+ return Date.now();
9
+ }
10
+ function getClientName() {
11
+ return sessionStorage.getItem('visualizerName');
12
+ }
13
+ function isDesktopUA() {
14
+ // Lightweight heuristic; GA4 also provides device.category. This flag can help ad-hoc filtering.
15
+ var ua = navigator.userAgent.toLowerCase();
16
+ var isMobile = /mobi|android|iphone|ipad|ipod|windows phone/.test(ua);
17
+ return !isMobile;
18
+ }
19
+
20
+ // ---------- Keys for storage ----------
21
+ var SSN_KEYS = {
22
+ sessionStartMs: 'ga4_session_start_ms',
23
+ introChoiceMs: 'ga4_intro_choice_ms',
24
+ firstCabinetPlaced: 'ga4_first_cabinet_placed',
25
+ contextBooted: 'ga4_context_booted',
26
+ enteredCanvasSent: 'ga4_entered_canvas_sent'
27
+ };
28
+
29
+ // ---------- Core GA wrapper ----------
30
+ export var GA = {
31
+ init: function init(_ref) {
32
+ var measurementId = _ref.measurementId;
33
+ ReactGA.initialize([{
34
+ trackingId: measurementId
35
+ }], {
36
+ testMode: false
37
+ });
38
+ },
39
+ resetSessionKeys: function resetSessionKeys() {
40
+ Object.values(SSN_KEYS).forEach(function (key) {
41
+ sessionStorage.removeItem(key);
42
+ });
43
+ },
44
+ /**
45
+ * Must be called ONCE per page load, *before* other events.
46
+ * Sets user properties (project_entry, cross_auth) and sends an initial page_view with client_name.
47
+ */
48
+ bootSessionContext: function bootSessionContext(_ref2) {
49
+ var projectEntry = _ref2.projectEntry,
50
+ crossAuth = _ref2.crossAuth;
51
+ try {
52
+ var resolvedClient = getClientName();
53
+
54
+ // Persist session start for timing metrics (if not already set for this tab)
55
+ if (!sessionStorage.getItem(SSN_KEYS.sessionStartMs)) {
56
+ sessionStorage.setItem(SSN_KEYS.sessionStartMs, String(nowMs()));
57
+ }
58
+
59
+ // Mark context as booted to avoid duplicate property sets on hot reloads
60
+ if (!sessionStorage.getItem(SSN_KEYS.contextBooted)) {
61
+ sessionStorage.setItem(SSN_KEYS.contextBooted, '1');
62
+
63
+ // Set GA4 user_properties (user-scoped dimensions)
64
+ ReactGA.gtag('set', 'user_properties', {
65
+ project_entry: projectEntry,
66
+ // user scope dimension
67
+ cross_auth: crossAuth // user scope dimension (boolean serialized)
68
+ });
69
+ }
70
+
71
+ // Send first page_view hit enriched with event-scoped client_name
72
+ ReactGA.send({
73
+ hitType: 'pageview',
74
+ page: window.location.pathname + window.location.search,
75
+ // @ts-expect-error react-ga4 passes along additional params into gtag
76
+ client_name: resolvedClient
77
+ });
78
+ } catch (e) {
79
+ // eslint-disable-next-line no-console
80
+ console.warn('GA.bootSessionContext error', e);
81
+ }
82
+ },
83
+ // Utility to derive cross_auth from URL (token or details query params)
84
+ deriveCrossAuthFromUrl: function deriveCrossAuthFromUrl(search) {
85
+ var sp = new URLSearchParams(search);
86
+ return sp.has('token') || sp.has('details');
87
+ },
88
+ // Utility to derive project entry (best-effort). You can also pass explicitly from router logic.
89
+ deriveProjectEntry: function deriveProjectEntry() {
90
+ var projectId = sessionStorage.getItem('projectId');
91
+
92
+ // If a project id exists, consider it "open_existing"; otherwise fallback to "new"
93
+ if (projectId) return 'open_existing';
94
+ return 'new';
95
+ },
96
+ // ---------- Event API ----------
97
+ events: {
98
+ /**
99
+ * intro_choice(option) — records the user's entry choice.
100
+ * Also stores a timestamp for later time_to_canvas calculation.
101
+ */
102
+ introChoice: function introChoice(option, extra) {
103
+ var client_name = getClientName();
104
+ sessionStorage.setItem(SSN_KEYS.introChoiceMs, String(nowMs()));
105
+ ReactGA.event('intro_choice', _objectSpread({
106
+ client_name: client_name,
107
+ option: option
108
+ }, extra || {}));
109
+ },
110
+ /**
111
+ * entered_canvas(time_to_canvas) — compute (now - intro_choice)
112
+ */
113
+ enteredCanvas: function enteredCanvas() {
114
+ // fire only once per tab/session
115
+ if (sessionStorage.getItem(SSN_KEYS.enteredCanvasSent)) return;
116
+ var client_name = getClientName();
117
+ var introMs = Number(sessionStorage.getItem(SSN_KEYS.introChoiceMs) || 0);
118
+ var timeSec = introMs ? Math.max(0, Math.round((Date.now() - introMs) / 1000)) : undefined;
119
+ ReactGA.event('entered_canvas', _objectSpread({
120
+ client_name: client_name
121
+ }, typeof timeSec === 'number' ? {
122
+ time_to_canvas: timeSec
123
+ } : {}));
124
+ sessionStorage.setItem(SSN_KEYS.enteredCanvasSent, '1'); // 👈 lock it
125
+ },
126
+ /**
127
+ * cabinet_placed(time_to_first_cabinet) — send only for the *first* cabinet of the session.
128
+ */
129
+ cabinetPlaced: function cabinetPlaced() {
130
+ var already = sessionStorage.getItem(SSN_KEYS.firstCabinetPlaced);
131
+ var client_name = getClientName();
132
+ var params = {
133
+ client_name: client_name
134
+ };
135
+ if (!already) {
136
+ var startMs = Number(sessionStorage.getItem(SSN_KEYS.sessionStartMs) || 0);
137
+ var timeSec = startMs ? Math.max(0, Math.round((nowMs() - startMs) / 1000)) : undefined;
138
+ if (typeof timeSec === 'number') params.time_to_first_cabinet = timeSec; // custom metric (seconds)
139
+ sessionStorage.setItem(SSN_KEYS.firstCabinetPlaced, '1');
140
+ }
141
+ ReactGA.event('cabinet_placed', params);
142
+ },
143
+ /**
144
+ * door_changed(door_id)
145
+ */
146
+ doorChanged: function doorChanged(door_id) {
147
+ var client_name = getClientName();
148
+ ReactGA.event('door_changed', {
149
+ client_name: client_name,
150
+ door_id: door_id
151
+ });
152
+ },
153
+ /**
154
+ * project_saved(project_id, save_method) — mark as conversion in GA UI.
155
+ */
156
+ projectSaved: function projectSaved(project_id, save_method) {
157
+ var client_name = getClientName();
158
+ ReactGA.event('project_saved', {
159
+ client_name: client_name,
160
+ project_id: project_id,
161
+ save_method: save_method
162
+ });
163
+ },
164
+ /**
165
+ * assistance_requested(method, project_id) — mark as conversion in GA UI.
166
+ */
167
+ assistanceRequested: function assistanceRequested(method, project_id) {
168
+ var client_name = getClientName();
169
+ ReactGA.event('assistance_requested', {
170
+ client_name: client_name,
171
+ method: method,
172
+ project_id: project_id
173
+ });
174
+ },
175
+ /**
176
+ * add_to_cart(project_id, sku_count, price_total) — mark as conversion in GA UI.
177
+ */
178
+ addToCart: function addToCart(project_id, sku_count, price_total) {
179
+ var client_name = getClientName();
180
+ ReactGA.event('add_to_cart', {
181
+ client_name: client_name,
182
+ project_id: project_id,
183
+ sku_count: sku_count,
184
+ price_total: price_total
185
+ });
186
+ }
187
+ }
188
+ };
@@ -12,8 +12,8 @@ import { ARROW_COLOR, BASE_CABINET_LAYOUTPOS, OBJTYPE_GROUP, OBJTYPE_MESH, SHADE
12
12
  import { Item } from "../../models";
13
13
  import * as GeomUtils from "./geom-utils";
14
14
  import { loadGLTF } from "./load-obj";
15
- import { animateDoor, getSkuAliasFromCatalogElement, isEmpty, translateDrawer } from "../../utils/helper";
16
- import { isWarningItem } from "../../components/viewer2d/utils";
15
+ import { animateDoor, getCatalogCabinetSku, isEmpty, translateDrawer } from "../../utils/helper";
16
+ import { isWarningCabinet } from "../../shared/domain/cabinet-warning";
17
17
  import { orderCabinetAssemblyKeys } from "../cabinet/cabinet-assembly-order";
18
18
  var INITIAL_NORMAL_MAP = '';
19
19
 
@@ -124,7 +124,7 @@ export function render2DItem(element, layer, scene, sizeinfo, layoutpos, is_corn
124
124
  var rowCount = 0; //parseInt((element.type.length / lineCount - 0.51).toFixed(), 10);
125
125
 
126
126
  // Get SKU Alias
127
- var objSKU = getSkuAliasFromCatalogElement(this, element);
127
+ var objSKU = getCatalogCabinetSku(element);
128
128
  if (rowCount > 0) {
129
129
  for (var _x = 0; _x < rowCount; _x++) {
130
130
  splitStr.push(objSKU.slice(lineCount * _x, lineCount * (_x + 1)));
@@ -293,7 +293,7 @@ export function render2DItem(element, layer, scene, sizeinfo, layoutpos, is_corn
293
293
  }), /*#__PURE__*/React.createElement("g", {
294
294
  transform: "translate(".concat(padding_width, ",").concat(padding_depth, ")")
295
295
  }, txtContent)), element.category === 'cabinet' && /*#__PURE__*/React.createElement("g", {
296
- visibility: isWarningItem(element) ? 'visible' : 'hidden'
296
+ visibility: isWarningCabinet(element) ? 'visible' : 'hidden'
297
297
  }, warning_buttons)));
298
298
  } else {
299
299
  rendered = /*#__PURE__*/React.createElement("g", {
package/es/class/item.js CHANGED
@@ -105,9 +105,16 @@ var Item = /*#__PURE__*/function () {
105
105
  }
106
106
  if (item.category === 'cabinet') {
107
107
  if (isDuplication && refItem) {
108
+ var _refItem$ccdf, _refItem$get;
108
109
  item = item.merge({
109
110
  doorStyle: refItem.doorStyle
110
111
  });
112
+ // When duplicating, preserve the instance-selected CCDF from the source cabinet.
113
+ var refCcdf = (_refItem$ccdf = refItem === null || refItem === void 0 ? void 0 : refItem.ccdf) !== null && _refItem$ccdf !== void 0 ? _refItem$ccdf : refItem === null || refItem === void 0 || (_refItem$get = refItem.get) === null || _refItem$get === void 0 ? void 0 : _refItem$get.call(refItem, 'ccdf');
114
+ refCcdf = toJSIfNeeded(refCcdf);
115
+ if (!isEmpty(refCcdf)) item = item.merge({
116
+ ccdf: refCcdf
117
+ });
111
118
  } else {
112
119
  var _layer$doorStyle, _temp, _ref, _temp$doorStyles$cds$, _temp2, _temp3, _state5;
113
120
  var layer = state.getIn(['scene', 'layers', layerID]);
@@ -254,8 +261,7 @@ var Item = /*#__PURE__*/function () {
254
261
  var doorFinishId = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : null;
255
262
  var layerID = state.getIn(['scene', 'selectedLayer']);
256
263
  var layer = state.getIn(['scene', 'layers', layerID]);
257
- var desiredDoorFinishId = doorFinishId !== null && doorFinishId !== void 0 ? doorFinishId : this.__getDesiredDoorFinishId(layer);
258
- if (!Array.isArray(ccdf_list) || !desiredDoorFinishId) return {
264
+ if (!Array.isArray(ccdf_list)) return {
259
265
  updatedState: state
260
266
  };
261
267
 
@@ -267,9 +273,27 @@ var Item = /*#__PURE__*/function () {
267
273
  } else if (applyScope === DOORSTYLE_SCOPE_MULTIPLE) {
268
274
  idSet = new Set(targetItemIDs);
269
275
  }
276
+
277
+ // If host returns an empty ccdf_list, remove assets3d of persisted ccdf from affected instances.
278
+ // This keeps SYNC payload from sending stale `items[].ccdf`.
279
+ if (ccdf_list.length === 0) {
280
+ layer.items.forEach(function (it) {
281
+ var _idSet;
282
+ var should = applyScope === DOORSTYLE_SCOPE_ALL ? true : (_idSet = idSet) === null || _idSet === void 0 ? void 0 : _idSet.has(it.id);
283
+ if (!should) return;
284
+ state = state.deleteIn(['scene', 'layers', layerID, 'items', it.id, 'ccdf', 'assets3d']);
285
+ });
286
+ return {
287
+ updatedState: state
288
+ };
289
+ }
290
+ var desiredDoorFinishId = doorFinishId !== null && doorFinishId !== void 0 ? doorFinishId : this.__getDesiredDoorFinishId(layer);
291
+ if (!desiredDoorFinishId) return {
292
+ updatedState: state
293
+ };
270
294
  layer.items.forEach(function (it) {
271
- var _idSet, _picked$door_finish_i;
272
- var should = applyScope === DOORSTYLE_SCOPE_ALL ? true : (_idSet = idSet) === null || _idSet === void 0 ? void 0 : _idSet.has(it.id);
295
+ var _idSet2, _picked$door_finish_i;
296
+ var should = applyScope === DOORSTYLE_SCOPE_ALL ? true : (_idSet2 = idSet) === null || _idSet2 === void 0 ? void 0 : _idSet2.has(it.id);
273
297
  if (!should) return;
274
298
 
275
299
  // Join key: scene_cabinet_id (instance id).
@@ -567,9 +591,7 @@ var Item = /*#__PURE__*/function () {
567
591
  break;
568
592
  }
569
593
  if (onInternalEvent && duplicatedElement) {
570
- var _state$get;
571
- var catalog = (_state$get = state.get('catalog')) === null || _state$get === void 0 ? void 0 : _state$get.toJS();
572
- var jsElement = updatePayloadOfInternalEvent(duplicatedElement, layer, catalog);
594
+ var jsElement = updatePayloadOfInternalEvent(duplicatedElement, layer);
573
595
  onInternalEvent({
574
596
  type: INTERNAL_EVENT_DRAW_ELEMENT,
575
597
  value: jsElement
package/es/class/line.js CHANGED
@@ -427,7 +427,6 @@ var Line = /*#__PURE__*/function () {
427
427
  }, {
428
428
  key: "beginDrawingLine",
429
429
  value: function beginDrawingLine(state, layerID, x, y, onInternalEvent) {
430
- var _state$get;
431
430
  // if end drawing by created area
432
431
  if (state.mode == MODE_IDLE) {
433
432
  return {
@@ -481,8 +480,7 @@ var Line = /*#__PURE__*/function () {
481
480
  drawingSupport: drawingSupport
482
481
  });
483
482
  var layer = state.getIn(['scene', 'layers', layerID]);
484
- var catalog = (_state$get = state.get('catalog')) === null || _state$get === void 0 ? void 0 : _state$get.toJS();
485
- var payload = updatePayloadOfInternalEvent(line, layer, catalog);
483
+ var payload = updatePayloadOfInternalEvent(line, layer);
486
484
  if (onInternalEvent) onInternalEvent({
487
485
  type: INTERNAL_EVENT_START_DRAW_WALL,
488
486
  value: payload
@@ -1,4 +1,4 @@
1
- import React, { useEffect } from 'react';
1
+ import React, { useEffect, useRef } from 'react';
2
2
  import PropTypes from 'prop-types';
3
3
  import Viewer2D from "./viewer2d/viewer2d";
4
4
  import Viewer3D from "./viewer3d/viewer3d";
@@ -20,11 +20,23 @@ export default function Content(_ref) {
20
20
  var mode = state.get('mode');
21
21
 
22
22
  // Internal Event for unselect_all
23
+ var prevSelectedCountRef = useRef(null);
23
24
  useEffect(function () {
24
- if (state.getIn(['scene', 'layers', 'layer-1', 'selected', 'vertices']).size + state.getIn(['scene', 'layers', 'layer-1', 'selected', 'lines']).size + state.getIn(['scene', 'layers', 'layer-1', 'selected', 'holes']).size + state.getIn(['scene', 'layers', 'layer-1', 'selected', 'areas']).size + state.getIn(['scene', 'layers', 'layer-1', 'selected', 'items']).size < 1) onInternalEvent === null || onInternalEvent === void 0 || onInternalEvent({
25
- type: constants.INTERNAL_EVENT_UNSELECT_ALL,
26
- value: null
27
- });
25
+ var selectedCount = state.getIn(['scene', 'layers', 'layer-1', 'selected', 'vertices']).size + state.getIn(['scene', 'layers', 'layer-1', 'selected', 'lines']).size + state.getIn(['scene', 'layers', 'layer-1', 'selected', 'holes']).size + state.getIn(['scene', 'layers', 'layer-1', 'selected', 'areas']).size + state.getIn(['scene', 'layers', 'layer-1', 'selected', 'items']).size;
26
+
27
+ // Skip the initial mount/hydration; only emit when selection transitions from non-empty -> empty.
28
+ if (prevSelectedCountRef.current === null) {
29
+ prevSelectedCountRef.current = selectedCount;
30
+ return;
31
+ }
32
+ var prevSelectedCount = prevSelectedCountRef.current;
33
+ prevSelectedCountRef.current = selectedCount;
34
+ if (prevSelectedCount > 0 && selectedCount < 1) {
35
+ onInternalEvent === null || onInternalEvent === void 0 || onInternalEvent({
36
+ type: constants.INTERNAL_EVENT_UNSELECT_ALL,
37
+ value: null
38
+ });
39
+ }
28
40
  }, [state.getIn(['scene', 'layers', 'layer-1', 'selected'])]);
29
41
  switch (mode) {
30
42
  // this mode is when view elevation
@@ -131,4 +143,7 @@ Content.propTypes = {
131
143
  height: PropTypes.number.isRequired,
132
144
  replaceCabinet: PropTypes.func.isRequired,
133
145
  onInternalEvent: PropTypes.func.isRequired
146
+ };
147
+ Content.contextTypes = {
148
+ projectActions: PropTypes.object.isRequired
134
149
  };
@@ -1,5 +1,7 @@
1
1
  import Content from "./content";
2
- export { Content };
3
- export default {
4
- Content: Content
5
- };
2
+ import Viewer2DComponents from "./viewer2d/export";
3
+ import StyleComponents from "./style/export";
4
+
5
+ export { Content, Viewer2DComponents, StyleComponents };
6
+
7
+ export default { Content, Viewer2DComponents, StyleComponents };
@@ -3,14 +3,12 @@ import _createClass from "@babel/runtime/helpers/esm/createClass";
3
3
  import _possibleConstructorReturn from "@babel/runtime/helpers/esm/possibleConstructorReturn";
4
4
  import _getPrototypeOf from "@babel/runtime/helpers/esm/getPrototypeOf";
5
5
  import _inherits from "@babel/runtime/helpers/esm/inherits";
6
- import _defineProperty from "@babel/runtime/helpers/esm/defineProperty";
7
6
  import _taggedTemplateLiteral from "@babel/runtime/helpers/esm/taggedTemplateLiteral";
8
7
  var _templateObject;
9
8
  function _callSuper(t, o, e) { return o = _getPrototypeOf(o), _possibleConstructorReturn(t, _isNativeReflectConstruct() ? Reflect.construct(o, e || [], _getPrototypeOf(t).constructor) : o.apply(t, e)); }
10
9
  function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); } catch (t) {} return (_isNativeReflectConstruct = function _isNativeReflectConstruct() { return !!t; })(); }
11
10
  import React, { Component } from 'react';
12
11
  import PropTypes from 'prop-types';
13
- import AppContext from "../../AppContext";
14
12
  import { KEYBOARD_BUTTON_CODE, TEXT_COLOR_NEUTRAL_0, SECONDARY_PURPLE_COLOR, DEFAULT_FONT_FAMILY } from "../../constants";
15
13
  import styled from 'styled-components';
16
14
  import { isValidNumber } from "../../utils/helper";
@@ -40,8 +38,8 @@ var FormNumberInput = /*#__PURE__*/function (_Component) {
40
38
  }
41
39
  }
42
40
  }, {
43
- key: "UNSAFE_componentWillReceiveProps",
44
- value: function UNSAFE_componentWillReceiveProps(nextProps) {
41
+ key: "componentWillReceiveProps",
42
+ value: function componentWillReceiveProps(nextProps) {
45
43
  if (this.props.value !== nextProps.value || this.props.focus !== nextProps.focus) {
46
44
  this.setState({
47
45
  showedValue: nextProps.value,
@@ -155,7 +153,6 @@ var FormNumberInput = /*#__PURE__*/function (_Component) {
155
153
  }
156
154
  }]);
157
155
  }(Component);
158
- _defineProperty(FormNumberInput, "contextType", AppContext);
159
156
  export { FormNumberInput as default };
160
157
  FormNumberInput.propTypes = {
161
158
  value: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
@@ -170,6 +167,11 @@ FormNumberInput.propTypes = {
170
167
  labelName: PropTypes.string,
171
168
  isCeiling: PropTypes.string
172
169
  };
170
+ FormNumberInput.contextTypes = {
171
+ translator: PropTypes.object.isRequired,
172
+ projectActions: PropTypes.object.isRequired,
173
+ linesActions: PropTypes.object.isRequired
174
+ };
173
175
  FormNumberInput.defaultProps = {
174
176
  value: 0,
175
177
  style: {},
@@ -0,0 +1,25 @@
1
+ import _extends from "@babel/runtime/helpers/esm/extends";
2
+ import _objectWithoutProperties from "@babel/runtime/helpers/esm/objectWithoutProperties";
3
+ var _excluded = ["children"];
4
+ import React from 'react';
5
+ import Button from "./button";
6
+ import * as SharedStyle from "../../shared-style";
7
+ var STYLE = {
8
+ borderColor: '#415375',
9
+ backgroundColor: '#415375',
10
+ color: SharedStyle.COLORS.white
11
+ };
12
+ var STYLE_HOVER = {
13
+ borderColor: '#1f3149',
14
+ backgroundColor: '#1f3149',
15
+ color: SharedStyle.COLORS.white
16
+ };
17
+ export default function FormSubmitButton(_ref) {
18
+ var children = _ref.children,
19
+ rest = _objectWithoutProperties(_ref, _excluded);
20
+ return /*#__PURE__*/React.createElement(Button, _extends({
21
+ type: "submit",
22
+ style: STYLE,
23
+ styleHover: STYLE_HOVER
24
+ }, rest), children);
25
+ }
@@ -1,6 +1,5 @@
1
- import React, { useContext } from 'react';
1
+ import React from 'react';
2
2
  import PropTypes from 'prop-types';
3
- import AppContext from "../../AppContext";
4
3
  import If from "../../utils/react-if";
5
4
  import * as sharedStyles from "../../shared-style";
6
5
  var cx = 0;
@@ -11,13 +10,12 @@ var STYLE_CIRCLE = {
11
10
  stroke: sharedStyles.MATERIAL_COLORS[500].orange,
12
11
  cursor: 'default'
13
12
  };
14
- export default function Group(_ref) {
13
+ export default function Group(_ref, _ref2) {
15
14
  var layer = _ref.layer,
16
15
  group = _ref.group,
17
16
  scene = _ref.scene,
18
17
  catalog = _ref.catalog;
19
- var _useContext = useContext(AppContext),
20
- translator = _useContext.translator;
18
+ var translator = _ref2.translator;
21
19
  return /*#__PURE__*/React.createElement("g", {
22
20
  "data-element-root": true,
23
21
  "data-prototype": group.prototype,
@@ -49,4 +47,7 @@ Group.propTypes = {
49
47
  layer: PropTypes.object.isRequired,
50
48
  scene: PropTypes.object.isRequired,
51
49
  catalog: PropTypes.object.isRequired
50
+ };
51
+ Group.contextTypes = {
52
+ translator: PropTypes.object.isRequired
52
53
  };