@nebula.js/stardust 3.1.0-alpha.2 → 3.1.0-alpha.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,5 +1,5 @@
1
1
  /*
2
- * @nebula.js/stardust v3.1.0-alpha.2
2
+ * @nebula.js/stardust v3.1.0-alpha.3
3
3
  * Copyright (c) 2022 QlikTech International AB
4
4
  * Released under the MIT license.
5
5
  */
@@ -2756,7 +2756,9 @@
2756
2756
  }
2757
2757
  );
2758
2758
  },
2759
- uiColor(c) {
2759
+ uiColor(c, shift) {
2760
+ // eslint-disable-next-line no-param-reassign
2761
+ shift = !!shift;
2760
2762
  if (c.index < 0 || typeof c.index === 'undefined') {
2761
2763
  return c.color;
2762
2764
  }
@@ -2766,10 +2768,10 @@
2766
2768
  if (!uiPalette) {
2767
2769
  return c.color;
2768
2770
  }
2769
- if (typeof uiPalette.colors[c.index] === 'undefined') {
2771
+ if (typeof uiPalette.colors[c.index - shift] === 'undefined') {
2770
2772
  return c.color;
2771
2773
  }
2772
- return uiPalette.colors[c.index];
2774
+ return uiPalette.colors[c.index - shift];
2773
2775
  }
2774
2776
  };
2775
2777
  }
@@ -2992,7 +2994,7 @@
2992
2994
  }
2993
2995
  return ret;
2994
2996
  }
2995
- function getObject$1(root, steps) {
2997
+ function getObject$2(root, steps) {
2996
2998
  let obj = root;
2997
2999
  for (let i = 0; i < steps.length; i++) {
2998
3000
  if (obj[steps[i]]) {
@@ -3006,7 +3008,7 @@
3006
3008
  function searchPathArray(pathArray, attribute, theme) {
3007
3009
  const attributeArray = attribute.split('.');
3008
3010
  for (let i = 0; i < pathArray.length; i++) {
3009
- const restult = getObject$1(theme, [...pathArray[i], ...attributeArray]);
3011
+ const restult = getObject$2(theme, [...pathArray[i], ...attributeArray]);
3010
3012
  if (restult !== undefined) return restult;
3011
3013
  }
3012
3014
  return undefined;
@@ -3175,10 +3177,12 @@
3175
3177
  * @param {object} c
3176
3178
  * @param {number=} c.index
3177
3179
  * @param {string=} c.color
3180
+ * @param {boolean=} supportNone Shifts the palette index by one to account for the "none" color
3178
3181
  * @returns {string} The resolved color.
3179
3182
  *
3180
3183
  * @example
3181
3184
  * theme.getColorPickerColor({ index: 1 });
3185
+ * theme.getColorPickerColor({ index: 1 }, true);
3182
3186
  * theme.getColorPickerColor({ color: 'red' });
3183
3187
  */
3184
3188
  getColorPickerColor() {
@@ -11926,7 +11930,7 @@
11926
11930
  return cache[key];
11927
11931
  }
11928
11932
 
11929
- const NEBULA_VERSION_HASH = "de86" ;
11933
+ const NEBULA_VERSION_HASH = "d1ab" ;
11930
11934
  ClassNameGenerator$1.configure(componentName => {
11931
11935
  return "njs-".concat(NEBULA_VERSION_HASH, "-").concat(componentName.replace('Mui', ''));
11932
11936
  });
@@ -11935,7 +11939,8 @@
11935
11939
  language: null,
11936
11940
  theme: null,
11937
11941
  translator: null,
11938
- constraints: {}
11942
+ constraints: {},
11943
+ themeApi: null
11939
11944
  });
11940
11945
 
11941
11946
  var createKeyStore = (function () {
@@ -12444,7 +12449,7 @@
12444
12449
  const appRef = React.createRef();
12445
12450
  const element = document.createElement('div');
12446
12451
  element.style.display = 'none';
12447
- element.setAttribute('data-nebulajs-version', "3.1.0-alpha.2" );
12452
+ element.setAttribute('data-nebulajs-version', "3.1.0-alpha.3" );
12448
12453
  element.setAttribute('data-app-id', app.id);
12449
12454
  document.body.appendChild(element);
12450
12455
  ReactDOM.render( /*#__PURE__*/React.createElement(NebulaApp, {
@@ -12463,6 +12468,9 @@
12463
12468
  addCell(id, cell) {
12464
12469
  cells[id] = cell;
12465
12470
  },
12471
+ removeCell(id) {
12472
+ delete cells[id];
12473
+ },
12466
12474
  add(component) {
12467
12475
  (async () => {
12468
12476
  await rendered;
@@ -18899,7 +18907,7 @@
18899
18907
  const barPadPx = 4;
18900
18908
  const barBorderWidthPx = 1;
18901
18909
  const barWithCheckboxLeftPadPx = 29;
18902
- const frequencyTextNone = '0';
18910
+ const frequencyTextNone = '-';
18903
18911
  const getSelectedStyle = _ref => {
18904
18912
  let {
18905
18913
  theme
@@ -18917,13 +18925,14 @@
18917
18925
  };
18918
18926
  };
18919
18927
  const Root$1 = styled$1('div')(_ref2 => {
18928
+ var _theme$listBox$conten, _theme$listBox, _theme$listBox$conten2, _theme$listBox$conten3, _theme$listBox2, _theme$listBox2$conte, _theme$listBox3, _theme$listBox3$conte, _theme$listBox4, _theme$listBox4$conte;
18920
18929
  let {
18921
18930
  theme
18922
18931
  } = _ref2;
18923
18932
  return {
18924
18933
  ["& .".concat(classes$a.row)]: {
18925
18934
  flexWrap: 'nowrap',
18926
- color: theme.palette.text.primary
18935
+ color: (_theme$listBox$conten = (_theme$listBox = theme.listBox) === null || _theme$listBox === void 0 ? void 0 : (_theme$listBox$conten2 = _theme$listBox.content) === null || _theme$listBox$conten2 === void 0 ? void 0 : _theme$listBox$conten2.color) !== null && _theme$listBox$conten !== void 0 ? _theme$listBox$conten : theme.palette.text.primary
18927
18936
  },
18928
18937
  ["& .".concat(classes$a.rowBorderBottom)]: {
18929
18938
  borderBottom: "1px solid ".concat(theme.palette.divider)
@@ -18931,7 +18940,7 @@
18931
18940
  ["& .".concat(classes$a.column)]: {
18932
18941
  flexWrap: 'nowrap',
18933
18942
  borderRight: "1px solid ".concat(theme.palette.divider),
18934
- color: theme.palette.text.primary
18943
+ color: (_theme$listBox$conten3 = (_theme$listBox2 = theme.listBox) === null || _theme$listBox2 === void 0 ? void 0 : (_theme$listBox2$conte = _theme$listBox2.content) === null || _theme$listBox2$conte === void 0 ? void 0 : _theme$listBox2$conte.color) !== null && _theme$listBox$conten3 !== void 0 ? _theme$listBox$conten3 : theme.palette.text.primary
18935
18944
  },
18936
18945
  ["& .".concat(classes$a.fieldRoot)]: {
18937
18946
  '&:focus': {
@@ -18952,12 +18961,15 @@
18952
18961
  paddingRight: '9px'
18953
18962
  },
18954
18963
  // The leaf node, containing the label text.
18955
- ["& .".concat(classes$a.labelText)]: _objectSpread2({
18964
+ ["& .".concat(classes$a.labelText)]: _objectSpread2(_objectSpread2({
18956
18965
  flexBasis: 'max-content',
18957
18966
  lineHeight: '16px',
18958
18967
  userSelect: 'none',
18959
18968
  whiteSpace: 'pre'
18960
- }, ellipsis),
18969
+ }, ellipsis), {}, {
18970
+ fontSize: (_theme$listBox3 = theme.listBox) === null || _theme$listBox3 === void 0 ? void 0 : (_theme$listBox3$conte = _theme$listBox3.content) === null || _theme$listBox3$conte === void 0 ? void 0 : _theme$listBox3$conte.fontSize,
18971
+ fontFamily: (_theme$listBox4 = theme.listBox) === null || _theme$listBox4 === void 0 ? void 0 : (_theme$listBox4$conte = _theme$listBox4.content) === null || _theme$listBox4$conte === void 0 ? void 0 : _theme$listBox4$conte.fontFamily
18972
+ }),
18961
18973
  ["& .".concat(classes$a.labelDense)]: {
18962
18974
  fontSize: 12
18963
18975
  },
@@ -19063,7 +19075,7 @@
19063
19075
  column = false,
19064
19076
  checkboxes = false,
19065
19077
  dense = false,
19066
- frequencyMode = 'N',
19078
+ freqIsAllowed,
19067
19079
  isSingleSelect,
19068
19080
  actions,
19069
19081
  frequencyMax = '',
@@ -19256,7 +19268,7 @@
19256
19268
  color: 'inherit'
19257
19269
  }) : getFieldWithRanges({
19258
19270
  lbls: labels
19259
- })), frequencyMode !== 'N' && /*#__PURE__*/React.createElement(Grid$1, {
19271
+ })), freqIsAllowed && /*#__PURE__*/React.createElement(Grid$1, {
19260
19272
  item: true,
19261
19273
  style: {
19262
19274
  display: 'flex',
@@ -19285,6 +19297,7 @@
19285
19297
  const scrollBarThumbHover = '#555';
19286
19298
  const scrollBarBackground = '#f1f1f1';
19287
19299
  const MINIMUM_BATCH_SIZE = 100;
19300
+ const FREQUENCY_MIN_SHOW_WIDTH = 80;
19288
19301
  const classes$9 = {
19289
19302
  styledScrollbars: "".concat(PREFIX$9, "-styledScrollbars")
19290
19303
  };
@@ -19335,7 +19348,7 @@
19335
19348
  height,
19336
19349
  width,
19337
19350
  listLayout = 'vertical',
19338
- frequencyMode = 'N',
19351
+ frequencyMode,
19339
19352
  histogram = false,
19340
19353
  checkboxes = false,
19341
19354
  update = undefined,
@@ -19475,6 +19488,14 @@
19475
19488
  const h = Math.max(...ps.map(page => page.qArea.qTop + page.qArea.qHeight));
19476
19489
  return hasFilteredValues ? h : count;
19477
19490
  };
19491
+ const getFrequencyAllowed = () => {
19492
+ const widthPermitsFreq = width > FREQUENCY_MIN_SHOW_WIDTH;
19493
+ const {
19494
+ frequencyEnabled = false
19495
+ } = layout.qListObject;
19496
+ const hasValidFreqOption = !['none', undefined].includes(frequencyMode);
19497
+ return widthPermitsFreq && (hasValidFreqOption || frequencyEnabled);
19498
+ };
19478
19499
  const listCount = pages && pages.length && calculatePagesHeight ? getCalculatedHeight(pages) : count;
19479
19500
  onSetListCount === null || onSetListCount === void 0 ? void 0 : onSetListCount(listCount);
19480
19501
  const dense = (_layout$layoutOptions = (_layout$layoutOptions2 = layout.layoutOptions) === null || _layout$layoutOptions2 === void 0 ? void 0 : _layout$layoutOptions2.dense) !== null && _layout$layoutOptions !== void 0 ? _layout$layoutOptions : false;
@@ -19491,6 +19512,7 @@
19491
19512
  const {
19492
19513
  frequencyMax
19493
19514
  } = layout;
19515
+ const freqIsAllowed = getFrequencyAllowed();
19494
19516
  return /*#__PURE__*/React.createElement(InfiniteLoader, {
19495
19517
  isItemLoaded: isItemLoaded,
19496
19518
  itemCount: listCount || 1 // must be more than 0 or loadMoreItems will never be called again
@@ -19524,6 +19546,7 @@
19524
19546
  checkboxes,
19525
19547
  dense,
19526
19548
  frequencyMode,
19549
+ freqIsAllowed,
19527
19550
  isSingleSelect,
19528
19551
  actions: {
19529
19552
  select,
@@ -20110,7 +20133,25 @@
20110
20133
  var SearchIcon = (props => SvgIcon(search(props)));
20111
20134
 
20112
20135
  const TREE_PATH = '/qListObjectDef';
20113
- function ListBoxSearch(_ref) {
20136
+ const StyledInputAdornment = styled$1(InputAdornment$1)(_ref => {
20137
+ var _theme$listBox, _theme$listBox$conten;
20138
+ let {
20139
+ theme
20140
+ } = _ref;
20141
+ return {
20142
+ color: (_theme$listBox = theme.listBox) === null || _theme$listBox === void 0 ? void 0 : (_theme$listBox$conten = _theme$listBox.content) === null || _theme$listBox$conten === void 0 ? void 0 : _theme$listBox$conten.color
20143
+ };
20144
+ });
20145
+ const StyledOutlinedInput = styled$1(OutlinedInput$1)(_ref2 => {
20146
+ var _theme$listBox2, _theme$listBox2$conte;
20147
+ let {
20148
+ theme
20149
+ } = _ref2;
20150
+ return {
20151
+ color: (_theme$listBox2 = theme.listBox) === null || _theme$listBox2 === void 0 ? void 0 : (_theme$listBox2$conte = _theme$listBox2.content) === null || _theme$listBox2$conte === void 0 ? void 0 : _theme$listBox2$conte.color
20152
+ };
20153
+ });
20154
+ function ListBoxSearch(_ref3) {
20114
20155
  let {
20115
20156
  selections,
20116
20157
  model,
@@ -20118,7 +20159,7 @@
20118
20159
  listCount,
20119
20160
  dense = false,
20120
20161
  visible = true
20121
- } = _ref;
20162
+ } = _ref3;
20122
20163
  const {
20123
20164
  translator
20124
20165
  } = react.exports.useContext(InstanceContext);
@@ -20187,8 +20228,8 @@
20187
20228
  if (!visible) {
20188
20229
  return null;
20189
20230
  }
20190
- return /*#__PURE__*/React.createElement(OutlinedInput$1, {
20191
- startAdornment: /*#__PURE__*/React.createElement(InputAdornment$1, {
20231
+ return /*#__PURE__*/React.createElement(StyledOutlinedInput, {
20232
+ startAdornment: /*#__PURE__*/React.createElement(StyledInputAdornment, {
20192
20233
  position: "start"
20193
20234
  }, /*#__PURE__*/React.createElement(SearchIcon, {
20194
20235
  size: dense ? 'small' : 'normal'
@@ -20197,6 +20238,7 @@
20197
20238
  sx: [{
20198
20239
  border: 'none',
20199
20240
  borderRadius: 0,
20241
+ backgroundColor: 'transparent',
20200
20242
  '& fieldset': {
20201
20243
  border: "1px solid ".concat(theme.palette.divider),
20202
20244
  borderWidth: '1px 0 1px 0',
@@ -21835,28 +21877,65 @@
21835
21877
  style: {}
21836
21878
  };
21837
21879
 
21880
+ const addListboxTheme = themeApi => {
21881
+ const getListboxStyle = prop => themeApi.getStyle('object', '', "listBox.".concat(prop));
21882
+ return {
21883
+ backgroundColor: getListboxStyle('backgroundColor'),
21884
+ title: {
21885
+ main: {
21886
+ color: getListboxStyle('title.main.color'),
21887
+ fontSize: getListboxStyle('title.main.fontSize'),
21888
+ fontFamily: getListboxStyle('title.main.fontFamily')
21889
+ }
21890
+ },
21891
+ content: {
21892
+ color: getListboxStyle('content.color'),
21893
+ fontSize: getListboxStyle('content.fontSize'),
21894
+ fontFamily: getListboxStyle('content.fontFamily')
21895
+ }
21896
+ };
21897
+ };
21898
+
21838
21899
  const PREFIX$4 = 'ListBoxInline';
21839
21900
  const classes$4 = {
21840
21901
  listBoxHeader: "".concat(PREFIX$4, "-listBoxHeader"),
21841
21902
  screenReaderOnly: "".concat(PREFIX$4, "-screenReaderOnly")
21842
21903
  };
21843
- const StyledGrid$3 = styled$1(Grid$1)(() => ({
21844
- ["& .".concat(classes$4.listBoxHeader)]: {
21845
- alignSelf: 'center',
21846
- display: 'inline-flex'
21847
- },
21848
- ["& .".concat(classes$4.screenReaderOnly)]: {
21849
- position: 'absolute',
21850
- height: 0,
21851
- width: 0,
21852
- overflow: 'hidden'
21853
- }
21854
- }));
21855
- function ListBoxInline(_ref) {
21904
+ const StyledGrid$3 = styled$1(Grid$1)(_ref => {
21905
+ var _theme$listBox$backgr, _theme$listBox;
21906
+ let {
21907
+ theme
21908
+ } = _ref;
21909
+ return {
21910
+ backgroundColor: (_theme$listBox$backgr = (_theme$listBox = theme.listBox) === null || _theme$listBox === void 0 ? void 0 : _theme$listBox.backgroundColor) !== null && _theme$listBox$backgr !== void 0 ? _theme$listBox$backgr : theme.palette.background.default,
21911
+ ["& .".concat(classes$4.listBoxHeader)]: {
21912
+ alignSelf: 'center',
21913
+ display: 'inline-flex'
21914
+ },
21915
+ ["& .".concat(classes$4.screenReaderOnly)]: {
21916
+ position: 'absolute',
21917
+ height: 0,
21918
+ width: 0,
21919
+ overflow: 'hidden'
21920
+ }
21921
+ };
21922
+ });
21923
+ const Title = styled$1(Typography$1)(_ref2 => {
21924
+ var _theme$listBox2, _theme$listBox2$title, _theme$listBox2$title2, _theme$listBox3, _theme$listBox3$title, _theme$listBox3$title2, _theme$listBox4, _theme$listBox4$title, _theme$listBox4$title2;
21925
+ let {
21926
+ theme
21927
+ } = _ref2;
21928
+ return {
21929
+ color: (_theme$listBox2 = theme.listBox) === null || _theme$listBox2 === void 0 ? void 0 : (_theme$listBox2$title = _theme$listBox2.title) === null || _theme$listBox2$title === void 0 ? void 0 : (_theme$listBox2$title2 = _theme$listBox2$title.main) === null || _theme$listBox2$title2 === void 0 ? void 0 : _theme$listBox2$title2.color,
21930
+ fontSize: (_theme$listBox3 = theme.listBox) === null || _theme$listBox3 === void 0 ? void 0 : (_theme$listBox3$title = _theme$listBox3.title) === null || _theme$listBox3$title === void 0 ? void 0 : (_theme$listBox3$title2 = _theme$listBox3$title.main) === null || _theme$listBox3$title2 === void 0 ? void 0 : _theme$listBox3$title2.fontSize,
21931
+ fontFamily: (_theme$listBox4 = theme.listBox) === null || _theme$listBox4 === void 0 ? void 0 : (_theme$listBox4$title = _theme$listBox4.title) === null || _theme$listBox4$title === void 0 ? void 0 : (_theme$listBox4$title2 = _theme$listBox4$title.main) === null || _theme$listBox4$title2 === void 0 ? void 0 : _theme$listBox4$title2.fontFamily
21932
+ };
21933
+ });
21934
+ function ListBoxInline(_ref3) {
21856
21935
  var _layout$layoutOptions, _layout$layoutOptions2;
21857
21936
  let {
21858
21937
  options = {}
21859
- } = _ref;
21938
+ } = _ref3;
21860
21939
  const {
21861
21940
  direction,
21862
21941
  frequencyMode,
@@ -21899,8 +21978,10 @@
21899
21978
  }, [model]);
21900
21979
  const {
21901
21980
  translator,
21902
- keyboardNavigation
21981
+ keyboardNavigation,
21982
+ themeApi
21903
21983
  } = react.exports.useContext(InstanceContext);
21984
+ theme.listBox = addListboxTheme(themeApi);
21904
21985
  const moreAlignTo = react.exports.useRef();
21905
21986
  const [searchContainer, searchContainerRef] = useRefWithCallback();
21906
21987
  const [layout] = useLayout$1(model);
@@ -22015,7 +22096,7 @@
22015
22096
  })) : getSearchOrUnlock()), /*#__PURE__*/React.createElement(Grid$1, {
22016
22097
  item: true,
22017
22098
  className: classes$4.listBoxHeader
22018
- }, /*#__PURE__*/React.createElement(Typography$1, {
22099
+ }, /*#__PURE__*/React.createElement(Title, {
22019
22100
  variant: "h6",
22020
22101
  noWrap: true
22021
22102
  }, layout.title || layout.qListObject.qDimensionInfo.qFallbackTitle)), /*#__PURE__*/React.createElement(Grid$1, {
@@ -22072,11 +22153,11 @@
22072
22153
  ref: moreAlignTo
22073
22154
  }), /*#__PURE__*/React.createElement("div", {
22074
22155
  className: classes$4.screenReaderOnly
22075
- }, translator.get('Listbox.ScreenReaderInstructions')), /*#__PURE__*/React.createElement(AutoSizer, null, _ref2 => {
22156
+ }, translator.get('Listbox.ScreenReaderInstructions')), /*#__PURE__*/React.createElement(AutoSizer, null, _ref4 => {
22076
22157
  let {
22077
22158
  height,
22078
22159
  width
22079
- } = _ref2;
22160
+ } = _ref4;
22080
22161
  return /*#__PURE__*/React.createElement(ListBox, {
22081
22162
  model: model,
22082
22163
  selections: selections,
@@ -22116,6 +22197,9 @@
22116
22197
  if (options.dense) {
22117
22198
  throw new Error('Option "dense" is not applicable for existing objects.');
22118
22199
  }
22200
+ if (options.frequencyMode) {
22201
+ throw new Error('Option "frequencyMode" is not applicable for existing objects.');
22202
+ }
22119
22203
  react.exports.useEffect(() => {
22120
22204
  async function fetchObject() {
22121
22205
  const modelFromStore = modelStore.get(qId);
@@ -24099,7 +24183,7 @@
24099
24183
  const bgImageDef = bgComp === null || bgComp === void 0 ? void 0 : bgComp.bgImage;
24100
24184
  if (bgImageDef) {
24101
24185
  let url = '';
24102
- if (bgImageDef.mode === 'media') {
24186
+ if (bgImageDef.mode === 'media' || bgComp.useImage === 'media') {
24103
24187
  var _bgImageDef$mediaUrl, _bgImageDef$mediaUrl$;
24104
24188
  url = bgImageDef !== null && bgImageDef !== void 0 && (_bgImageDef$mediaUrl = bgImageDef.mediaUrl) !== null && _bgImageDef$mediaUrl !== void 0 && (_bgImageDef$mediaUrl$ = _bgImageDef$mediaUrl.qStaticContentUrl) !== null && _bgImageDef$mediaUrl$ !== void 0 && _bgImageDef$mediaUrl$.qUrl ? decodeURIComponent(bgImageDef.mediaUrl.qStaticContentUrl.qUrl) : undefined;
24105
24189
  url = resolveImageUrl(app, url);
@@ -24123,7 +24207,7 @@
24123
24207
  if (bgColor.useColorExpression) {
24124
24208
  return theme.validateColor(bgColor.colorExpression);
24125
24209
  }
24126
- return bgColor.color && bgColor.color.color !== 'none' ? theme.getColorPickerColor(bgColor.color) : undefined;
24210
+ return bgColor.color && bgColor.color.color !== 'none' ? theme.getColorPickerColor(bgColor.color, true) : undefined;
24127
24211
  }
24128
24212
  return undefined;
24129
24213
  };
@@ -24415,6 +24499,7 @@
24415
24499
  disableCellPadding = false
24416
24500
  } = halo.context || {};
24417
24501
  const {
24502
+ theme: themeName,
24418
24503
  translator,
24419
24504
  language,
24420
24505
  keyboardNavigation
@@ -24431,11 +24516,8 @@
24431
24516
  const [contentRef, contentRect, contentNode] = useRect$1();
24432
24517
  const [snOptions, setSnOptions] = react.exports.useState(initialSnOptions);
24433
24518
  const [snPlugins, setSnPlugins] = react.exports.useState(initialSnPlugins);
24434
- const [clickOutElement, setClickOutElement] = react.exports.useState();
24435
- const clickOutElements = [{
24436
- current: clickOutElement
24437
- }, '.njs-action-toolbar-popover']; // elements which will not trigger the click out listener
24438
- const [selections] = useObjectSelections(app, model, clickOutElements);
24519
+ const cellElementId = "njs-cell-".concat(currentId);
24520
+ const [selections] = useObjectSelections(app, model, ["#".concat(cellElementId), '.njs-action-toolbar-popover']); // elements which will not trigger the click out listener
24439
24521
  const [hovering, setHover] = react.exports.useState(false);
24440
24522
  const hoveringDebouncer = react.exports.useRef({
24441
24523
  enter: null,
@@ -24453,17 +24535,11 @@
24453
24535
  react.exports.useEffect(() => {
24454
24536
  eventmixin(focusHandler.current);
24455
24537
  }, []);
24456
- react.exports.useEffect(() => {
24457
- if (!contentNode) {
24458
- return;
24459
- }
24460
- setClickOutElement(cellNode);
24461
- }, [cellRect]);
24462
24538
  react.exports.useEffect(() => {
24463
24539
  const bgComp = layout !== null && layout !== void 0 && layout.components ? layout.components.find(comp => comp.key === 'general') : null;
24464
24540
  setBgColor(resolveBgColor(bgComp, halo.public.theme));
24465
24541
  setBgImage(resolveBgImage(bgComp, halo.app));
24466
- }, [layout, halo.public.theme, halo.app]);
24542
+ }, [layout, halo.public.theme, halo.app, themeName]);
24467
24543
  focusHandler.current.blurCallback = resetFocus => {
24468
24544
  halo.root.toggleFocusOfCells();
24469
24545
  if (resetFocus && contentNode) {
@@ -24654,7 +24730,7 @@
24654
24730
  width: '100%',
24655
24731
  height: '100%',
24656
24732
  overflow: 'hidden',
24657
- backgroundColor: bgColor,
24733
+ backgroundColor: bgColor || 'unset',
24658
24734
  backgroundImage: bgImage && bgImage.url ? "url(".concat(bgImage.url, ")") : undefined,
24659
24735
  backgroundRepeat: 'no-repeat',
24660
24736
  backgroundSize: bgImage && bgImage.size,
@@ -24664,6 +24740,7 @@
24664
24740
  square: true,
24665
24741
  className: CellElement.className,
24666
24742
  ref: cellRef,
24743
+ id: cellElementId,
24667
24744
  onMouseEnter: handleOnMouseEnter,
24668
24745
  onMouseLeave: handleOnMouseLeave
24669
24746
  }, /*#__PURE__*/React.createElement(Grid$1, {
@@ -24703,7 +24780,7 @@
24703
24780
  }));
24704
24781
  });
24705
24782
 
24706
- function glue(_ref) {
24783
+ function glue$1(_ref) {
24707
24784
  let {
24708
24785
  halo,
24709
24786
  element,
@@ -24809,7 +24886,7 @@
24809
24886
  });
24810
24887
  }
24811
24888
 
24812
- const noopi = () => {};
24889
+ const noopi$1 = () => {};
24813
24890
  function viz() {
24814
24891
  let {
24815
24892
  model,
@@ -24817,7 +24894,7 @@
24817
24894
  initialError,
24818
24895
  onDestroy = async () => {}
24819
24896
  } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
24820
- let unmountCell = noopi;
24897
+ let unmountCell = noopi$1;
24821
24898
  let cellRef = null;
24822
24899
  let mountedReference = null;
24823
24900
  let onMount = null;
@@ -24867,6 +24944,11 @@
24867
24944
  * @type {string}
24868
24945
  */
24869
24946
  id: model.id,
24947
+ /**
24948
+ * This visualizations Enigma model, a representation of the generic object.
24949
+ * @type {string}
24950
+ */
24951
+ model,
24870
24952
  /**
24871
24953
  * Destroys the visualization and removes it from the the DOM.
24872
24954
  * @example
@@ -24879,7 +24961,7 @@
24879
24961
  async destroy() {
24880
24962
  await onDestroy();
24881
24963
  unmountCell();
24882
- unmountCell = noopi;
24964
+ unmountCell = noopi$1;
24883
24965
  },
24884
24966
  /**
24885
24967
  * Converts the visualization to a different registered type
@@ -24918,7 +25000,7 @@
24918
25000
  throw new Error('Already mounted');
24919
25001
  }
24920
25002
  mountedReference = element;
24921
- [unmountCell, cellRef] = glue({
25003
+ [unmountCell, cellRef] = glue$1({
24922
25004
  halo,
24923
25005
  element,
24924
25006
  model,
@@ -25058,6 +25140,350 @@
25058
25140
  }, halo, error, onDestroy);
25059
25141
  }
25060
25142
 
25143
+ async function getObject$1(_ref, halo) {
25144
+ let {
25145
+ id,
25146
+ options,
25147
+ plugins,
25148
+ element
25149
+ } = _ref;
25150
+ const key = "".concat(id);
25151
+ let rpc = rpcRequestModelStore.get(key);
25152
+ if (!rpc) {
25153
+ rpc = halo.app.getObject(id);
25154
+ rpcRequestModelStore.set(key, rpc);
25155
+ }
25156
+ const model = await rpc;
25157
+ modelStore.set(key, model);
25158
+ return init(model, {
25159
+ options,
25160
+ plugins,
25161
+ element
25162
+ }, halo);
25163
+ }
25164
+
25165
+ /**
25166
+ * @interface
25167
+ * @extends HTMLElement
25168
+ * @experimental
25169
+ * @since 3.1.0
25170
+ */
25171
+ const SheetElement = {
25172
+ /** @type {'njs-sheet'} */
25173
+ className: 'njs-sheet'
25174
+ };
25175
+ function getCellRenderer(cell, halo, initialSnOptions, initialSnPlugins, initialError, onMount) {
25176
+ const {
25177
+ x,
25178
+ y,
25179
+ width,
25180
+ height
25181
+ } = cell.bounds;
25182
+ return /*#__PURE__*/React.createElement("div", {
25183
+ style: {
25184
+ left: "".concat(x, "%"),
25185
+ top: "".concat(y, "%"),
25186
+ width: "".concat(width, "%"),
25187
+ height: "".concat(height, "%"),
25188
+ position: 'absolute'
25189
+ }
25190
+ }, /*#__PURE__*/React.createElement(Cell, {
25191
+ ref: cell.cellRef,
25192
+ halo: halo,
25193
+ model: cell.model,
25194
+ currentId: cell.currentId,
25195
+ initialSnOptions: initialSnOptions,
25196
+ initialSnPlugins: initialSnPlugins,
25197
+ initialError: initialError,
25198
+ onMount: onMount
25199
+ }));
25200
+ }
25201
+ function Sheet(_ref) {
25202
+ let {
25203
+ model,
25204
+ halo,
25205
+ initialSnOptions,
25206
+ initialSnPlugins,
25207
+ initialError,
25208
+ onMount
25209
+ } = _ref;
25210
+ const {
25211
+ root
25212
+ } = halo;
25213
+ const [layout] = useLayout$1(model);
25214
+ const {
25215
+ theme: themeName
25216
+ } = react.exports.useContext(InstanceContext);
25217
+ const [cells, setCells] = react.exports.useState([]);
25218
+ const [bgColor, setBgColor] = react.exports.useState(undefined);
25219
+ const [bgImage, setBgImage] = react.exports.useState(undefined);
25220
+ const [deepHash, setDeepHash] = react.exports.useState('');
25221
+
25222
+ /// For each object
25223
+ react.exports.useEffect(() => {
25224
+ if (layout) {
25225
+ const hash = JSON.stringify(layout.cells);
25226
+ if (hash === deepHash) {
25227
+ return;
25228
+ }
25229
+ setDeepHash(hash);
25230
+ const fetchObjects = async () => {
25231
+ /*
25232
+ Need to always fetch and evaluate everything as the sheet need to support multiple instances of the same object?
25233
+ No, there is no way to add the same chart twice, so the optimization should be worth it.
25234
+ */
25235
+
25236
+ // Clear the cell list
25237
+ cells.forEach(c => {
25238
+ root.removeCell(c.currentId);
25239
+ });
25240
+ const lCells = layout.cells;
25241
+ // TODO - should try reuse existing objects on subsequent renders
25242
+ // Non-id updates should only change the "css"
25243
+ const cs = await Promise.all(lCells.map(async c => {
25244
+ let mounted;
25245
+ const mountedPromise = new Promise(resolve => {
25246
+ mounted = resolve;
25247
+ });
25248
+ const cell = cells.find(ce => ce.id === c.name);
25249
+ if (cell) {
25250
+ cell.bounds = c.bounds;
25251
+ delete cell.mountedPromise;
25252
+ return cell;
25253
+ }
25254
+ const vs = await getObject$1({
25255
+ id: c.name
25256
+ }, halo);
25257
+ return {
25258
+ model: vs.model,
25259
+ id: c.name,
25260
+ bounds: c.bounds,
25261
+ cellRef: React.createRef(),
25262
+ currentId: uid(),
25263
+ mounted,
25264
+ mountedPromise
25265
+ };
25266
+ }));
25267
+ cs.forEach(c => root.addCell(c.currentId, c.cellRef));
25268
+ setCells(cs);
25269
+ };
25270
+ fetchObjects();
25271
+ }
25272
+ }, [layout]);
25273
+ const cellRenderers = react.exports.useMemo(() => cells ? cells.map(c => getCellRenderer(c, halo, initialSnOptions, initialSnPlugins, initialError, c.mounted)) : [], [cells]);
25274
+ react.exports.useEffect(() => {
25275
+ const bgComp = layout !== null && layout !== void 0 && layout.components ? layout.components.find(comp => comp.key === 'general') : null;
25276
+ setBgColor(resolveBgColor(bgComp, halo.public.theme));
25277
+ setBgImage(resolveBgImage(bgComp, halo.app));
25278
+ }, [layout, halo.public.theme, halo.app, themeName]);
25279
+
25280
+ /* TODO
25281
+ - sheet title + bg + logo etc + as option
25282
+ - sheet exposed classnames for theming
25283
+ */
25284
+
25285
+ const height = !layout || Number.isNaN(layout.height) ? '100%' : "".concat(Number(layout.height), "%");
25286
+ const promises = cells.map(c => c.mountedPromise);
25287
+ const ps = promises.filter(p => !!p);
25288
+ if (ps.length) {
25289
+ Promise.all(promises).then(() => {
25290
+ // TODO - correct? Currently called each time a new cell is mounted?
25291
+ onMount();
25292
+ });
25293
+ }
25294
+ return /*#__PURE__*/React.createElement("div", {
25295
+ className: SheetElement.className,
25296
+ style: {
25297
+ width: "100%",
25298
+ height,
25299
+ position: 'relative',
25300
+ backgroundColor: bgColor,
25301
+ backgroundImage: bgImage && bgImage.url ? "url(".concat(bgImage.url, ")") : undefined,
25302
+ backgroundRepeat: 'no-repeat',
25303
+ backgroundSize: bgImage && bgImage.size,
25304
+ backgroundPosition: bgImage && bgImage.pos
25305
+ }
25306
+ }, cellRenderers);
25307
+ }
25308
+
25309
+ function glue(_ref) {
25310
+ let {
25311
+ halo,
25312
+ element,
25313
+ model,
25314
+ initialSnOptions,
25315
+ initialSnPlugins,
25316
+ onMount,
25317
+ initialError
25318
+ } = _ref;
25319
+ const {
25320
+ root
25321
+ } = halo;
25322
+ const sheetRef = React.createRef();
25323
+ const portal = ReactDOM.createPortal( /*#__PURE__*/React.createElement(Sheet, {
25324
+ ref: sheetRef,
25325
+ halo: halo,
25326
+ model: model,
25327
+ initialSnOptions: initialSnOptions,
25328
+ initialSnPlugins: initialSnPlugins,
25329
+ initialError: initialError,
25330
+ onMount: onMount
25331
+ }), element, model.id);
25332
+ const unmount = () => {
25333
+ root.remove(portal);
25334
+ model.removeListener('closed', unmount);
25335
+ };
25336
+ model.on('closed', unmount);
25337
+ root.add(portal);
25338
+ return [unmount, sheetRef];
25339
+ }
25340
+
25341
+ const noopi = () => {};
25342
+ function sheet() {
25343
+ let {
25344
+ model,
25345
+ halo,
25346
+ initialError,
25347
+ onDestroy = async () => {}
25348
+ } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
25349
+ let unmountSheet = noopi;
25350
+ let sheetRef = null;
25351
+ let mountedReference = null;
25352
+ let onMount = null;
25353
+ const mounted = new Promise(resolve => {
25354
+ onMount = resolve;
25355
+ });
25356
+ let initialSnOptions = {};
25357
+ let initialSnPlugins = [];
25358
+ const setSnOptions = async opts => {
25359
+ if (mountedReference) {
25360
+ (async () => {
25361
+ await mounted;
25362
+ sheetRef.current.setSnOptions(_objectSpread2(_objectSpread2({}, initialSnOptions), opts));
25363
+ })();
25364
+ } else {
25365
+ // Handle setting options before mount
25366
+ initialSnOptions = _objectSpread2(_objectSpread2({}, initialSnOptions), opts);
25367
+ }
25368
+ };
25369
+ const setSnPlugins = async plugins => {
25370
+ validatePlugins(plugins);
25371
+ if (mountedReference) {
25372
+ (async () => {
25373
+ await mounted;
25374
+ sheetRef.current.setSnPlugins(plugins);
25375
+ })();
25376
+ } else {
25377
+ // Handle setting plugins before mount
25378
+ initialSnPlugins = plugins;
25379
+ }
25380
+ };
25381
+
25382
+ /**
25383
+ * @class
25384
+ * @alias Sheet
25385
+ * @classdesc A controller to further modify a visualization after it has been rendered.
25386
+ * @experimental
25387
+ * @since 3.1.0
25388
+ * @example
25389
+ * const sheet = await embed(app).render({
25390
+ * element,
25391
+ * id: "jD5Gd"
25392
+ * });
25393
+ * sheet.destroy();
25394
+ */
25395
+ const api = /** @lends Sheet# */{
25396
+ /**
25397
+ * The id of this sheets's generic object.
25398
+ * @type {string}
25399
+ */
25400
+ id: model.id,
25401
+ /**
25402
+ * This sheets Enigma model, a representation of the generic object.
25403
+ * @type {string}
25404
+ */
25405
+ model,
25406
+ /**
25407
+ * Destroys the sheet and removes it from the the DOM.
25408
+ * @example
25409
+ * const sheet = await embed(app).render({
25410
+ * element,
25411
+ * id: "jD5Gd"
25412
+ * });
25413
+ * sheet.destroy();
25414
+ */
25415
+ async destroy() {
25416
+ await onDestroy();
25417
+ unmountSheet();
25418
+ unmountSheet = noopi;
25419
+ },
25420
+ // ===== unexposed experimental API - use at own risk ======
25421
+ __DO_NOT_USE__: {
25422
+ mount(element) {
25423
+ if (mountedReference) {
25424
+ throw new Error('Already mounted');
25425
+ }
25426
+ mountedReference = element;
25427
+ [unmountSheet, sheetRef] = glue({
25428
+ halo,
25429
+ element,
25430
+ model,
25431
+ initialSnOptions,
25432
+ initialSnPlugins,
25433
+ initialError,
25434
+ onMount
25435
+ });
25436
+ return mounted;
25437
+ },
25438
+ async applyProperties(props) {
25439
+ const current = await model.getEffectiveProperties();
25440
+ const patches = getPatches('/', props, current);
25441
+ if (patches.length) {
25442
+ return model.applyPatches(patches, true);
25443
+ }
25444
+ return undefined;
25445
+ },
25446
+ options(opts) {
25447
+ setSnOptions(opts);
25448
+ },
25449
+ plugins(plugins) {
25450
+ setSnPlugins(plugins);
25451
+ },
25452
+ exportImage() {
25453
+ throw new Error('Not implemented');
25454
+ },
25455
+ takeSnapshot() {
25456
+ throw new Error('Not implemented');
25457
+ },
25458
+ getModel() {
25459
+ return model;
25460
+ }
25461
+ }
25462
+ };
25463
+ return api;
25464
+ }
25465
+
25466
+ /* eslint no-underscore-dangle:0 */
25467
+ async function initSheet(model, optional, halo, initialError) {
25468
+ let onDestroy = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : async () => {};
25469
+ const api = sheet({
25470
+ model,
25471
+ halo,
25472
+ initialError,
25473
+ onDestroy
25474
+ });
25475
+ if (optional.options) {
25476
+ api.__DO_NOT_USE__.options(optional.options);
25477
+ }
25478
+ if (optional.plugins) {
25479
+ api.__DO_NOT_USE__.plugins(optional.plugins);
25480
+ }
25481
+ if (optional.element) {
25482
+ await api.__DO_NOT_USE__.mount(optional.element);
25483
+ }
25484
+ return api;
25485
+ }
25486
+
25061
25487
  /**
25062
25488
  * @interface BaseConfig
25063
25489
  * @description Basic rendering configuration for rendering an object
@@ -25088,6 +25514,13 @@
25088
25514
  }
25089
25515
  const model = await rpc;
25090
25516
  modelStore.set(key, model);
25517
+ if (model.genericType === 'sheet') {
25518
+ return initSheet(model, {
25519
+ options,
25520
+ plugins,
25521
+ element
25522
+ }, halo);
25523
+ }
25091
25524
  return init(model, {
25092
25525
  options,
25093
25526
  plugins,
@@ -28957,6 +29390,7 @@
28957
29390
  themes: configuration.themes,
28958
29391
  root
28959
29392
  });
29393
+ currentContext.themeApi = appTheme$1.externalAPI;
28960
29394
  const publicAPIs = {
28961
29395
  galaxy: /** @lends Galaxy */{
28962
29396
  /** @type {Translator} */
@@ -29002,9 +29436,10 @@
29002
29436
  */
29003
29437
  const api = /** @lends Embed# */{
29004
29438
  /**
29005
- * Renders a visualization into an HTMLElement.
29439
+ * Renders a visualization or sheet into an HTMLElement.
29440
+ * Support for sense sheets is experimental.
29006
29441
  * @param {CreateConfig | GetConfig} cfg - The render configuration.
29007
- * @returns {Promise<Viz>} A controller to the rendered visualization.
29442
+ * @returns {Promise<Viz|Sheet>} A controller to the rendered visualization or sheet.
29008
29443
  * @example
29009
29444
  * // render from existing object
29010
29445
  * n.render({
@@ -29288,7 +29723,7 @@
29288
29723
  var enigmaMocker_dev = {exports: {}};
29289
29724
 
29290
29725
  /*
29291
- * @nebula.js/enigma-mocker v3.1.0-alpha.1
29726
+ * @nebula.js/enigma-mocker v3.1.0-alpha.2
29292
29727
  * Copyright (c) 2022 QlikTech International AB
29293
29728
  * Released under the MIT license.
29294
29729
  */
@@ -29662,7 +30097,7 @@
29662
30097
  throw new Error("Generic object has multiple IDs, qInfo.qId: ".concat(qId, ", id: ").concat(id));
29663
30098
  }
29664
30099
  qId = qId || id || "object - ".concat(+Date.now());
29665
- const mock = _objectSpread2({
30100
+ const mock = _objectSpread2(_objectSpread2({
29666
30101
  id: qId,
29667
30102
  session: getPropValue(session, {
29668
30103
  defaultValue: true
@@ -29677,7 +30112,9 @@
29677
30112
  delay
29678
30113
  })
29679
30114
  });
29680
- }, {}));
30115
+ }, {})), {}, {
30116
+ genericType: genericObject.type
30117
+ });
29681
30118
  return {
29682
30119
  [qId]: mock
29683
30120
  };