@nebula.js/stardust 2.7.0 → 2.8.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/CHANGELOG.md CHANGED
@@ -3,6 +3,10 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ # [2.8.0](https://github.com/qlik-oss/nebula.js/compare/v2.7.0...v2.8.0) (2022-03-25)
7
+
8
+ **Note:** Version bump only for package @nebula.js/stardust
9
+
6
10
  # [2.7.0](https://github.com/qlik-oss/nebula.js/compare/v2.6.1...v2.7.0) (2022-03-21)
7
11
 
8
12
  ### Bug Fixes
package/core/esm/dev.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*
2
- * @nebula.js/stardust v2.7.0
2
+ * @nebula.js/stardust v2.8.0
3
3
  * Copyright (c) 2022 QlikTech International AB
4
4
  * Released under the MIT license.
5
5
  */
@@ -7,7 +7,7 @@
7
7
  import React, { useState as useState$1, useEffect as useEffect$1, useReducer, forwardRef, useMemo as useMemo$1, useImperativeHandle as useImperativeHandle$1, useCallback, useLayoutEffect as useLayoutEffect$1, createElement, PureComponent, useRef, useContext } from 'react';
8
8
  import ReactDOM from 'react-dom';
9
9
  import { createGenerateClassName, StylesProvider, ThemeProvider, makeStyles, useTheme as useTheme$1 } from '@material-ui/styles';
10
- import { Checkbox, Grid, FormControlLabel, Typography, IconButton, makeStyles as makeStyles$1, Popover, MenuList, MenuItem, ListItemIcon, Divider, OutlinedInput, InputAdornment, Badge, List, ListItem, Button, Box, Icon, CircularProgress, Paper } from '@material-ui/core';
10
+ import { Checkbox, Radio, Grid, FormControlLabel, Typography, IconButton, makeStyles as makeStyles$1, Popover, MenuList, MenuItem, ListItemIcon, Divider, OutlinedInput, InputAdornment, Badge, List, ListItem, Button, Box, Icon, CircularProgress, Paper } from '@material-ui/core';
11
11
 
12
12
  var runtime = {exports: {}};
13
13
 
@@ -5275,7 +5275,7 @@ function useAppSelections(app) {
5275
5275
  return [appSelections, navState];
5276
5276
  }
5277
5277
 
5278
- const NEBULA_VERSION_HASH = "b1d7" ;
5278
+ const NEBULA_VERSION_HASH = "0577" ;
5279
5279
  let counter = 0;
5280
5280
  const NebulaApp = forwardRef((_ref, ref) => {
5281
5281
  let {
@@ -5335,7 +5335,7 @@ function boot(_ref2) {
5335
5335
  const appRef = React.createRef();
5336
5336
  const element = document.createElement('div');
5337
5337
  element.style.display = 'none';
5338
- element.setAttribute('data-nebulajs-version', "2.7.0" );
5338
+ element.setAttribute('data-nebulajs-version', "2.8.0" );
5339
5339
  element.setAttribute('data-app-id', app.id);
5340
5340
  document.body.appendChild(element);
5341
5341
  ReactDOM.render( /*#__PURE__*/React.createElement(NebulaApp, {
@@ -6502,13 +6502,22 @@ function getSelectedValues(pages) {
6502
6502
  return flatten(elementNbrs);
6503
6503
  }
6504
6504
  function applySelectionsOnPages(pages, elmNumbers) {
6505
+ let clearAllButElmNumbers = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
6506
+
6505
6507
  const getNewSelectionState = qState => elmNumbers.length <= 1 && isStateSelected(qState) ? 'A' : 'S';
6506
6508
 
6507
6509
  const matrices = pages.map(page => {
6508
6510
  const qMatrix = page.qMatrix.map(p => {
6509
6511
  const [p0] = p;
6510
6512
  const selectionMatchesElement = elmNumbers.includes(p0.qElemNumber);
6511
- const qState = selectionMatchesElement ? getNewSelectionState(p0.qState) : p0.qState;
6513
+ let qState;
6514
+
6515
+ if (clearAllButElmNumbers) {
6516
+ qState = selectionMatchesElement ? 'S' : 'A';
6517
+ } else {
6518
+ qState = selectionMatchesElement ? getNewSelectionState(p0.qState) : p0.qState;
6519
+ }
6520
+
6512
6521
  return [_objectSpread2(_objectSpread2({}, p0), {}, {
6513
6522
  qState
6514
6523
  }), p.slice(1)];
@@ -6611,7 +6620,8 @@ function useSelectionsInteractions(_ref) {
6611
6620
  rangeSelect = true,
6612
6621
  checkboxes = false,
6613
6622
  selectDisabled,
6614
- doc = document
6623
+ doc = document,
6624
+ isSingleSelect = false
6615
6625
  } = _ref;
6616
6626
  const [instantPages, setInstantPages] = useState$1(pages);
6617
6627
  const [mouseDown, setMouseDown] = useState$1(false);
@@ -6619,10 +6629,7 @@ function useSelectionsInteractions(_ref) {
6619
6629
  const [selected, setSelected] = useState$1([]);
6620
6630
  const [isRangeSelection, setIsRangeSelection] = useState$1(false);
6621
6631
  const [preSelected, setPreSelected] = useState$1([]);
6622
- const elemNumbersOrdered = getElemNumbersFromPages(pages);
6623
-
6624
- const getIsSingleSelect = () => !!(layout && layout.qListObject.qDimensionInfo.qIsOneAndOnlyOne); // Select values for real, by calling the backend.
6625
-
6632
+ const elemNumbersOrdered = getElemNumbersFromPages(pages); // Select values for real, by calling the backend.
6626
6633
 
6627
6634
  const select = async function () {
6628
6635
  let elemNumbers = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
@@ -6633,7 +6640,6 @@ function useSelectionsInteractions(_ref) {
6633
6640
  }
6634
6641
 
6635
6642
  setSelectingValues(true);
6636
- const isSingleSelect = getIsSingleSelect();
6637
6643
  const filtered = additive ? elemNumbers.filter(n => !selected.includes(n)) : elemNumbers;
6638
6644
  await selectValues({
6639
6645
  selections,
@@ -6662,6 +6668,8 @@ function useSelectionsInteractions(_ref) {
6662
6668
  const selectManually = function () {
6663
6669
  let elementIds = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
6664
6670
  let additive = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
6671
+ setIsRangeSelection(false); // range is not supported for manual select
6672
+
6665
6673
  setMouseDown(true);
6666
6674
  preSelect(elementIds, additive || isRangeSelection);
6667
6675
  const p = select(elementIds, additive || isRangeSelection);
@@ -6690,7 +6698,7 @@ function useSelectionsInteractions(_ref) {
6690
6698
  const onMouseUp = useCallback(event => {
6691
6699
  const elemNumber = +event.currentTarget.getAttribute('data-n');
6692
6700
 
6693
- if (getIsSingleSelect() || !rangeSelect || !mouseDown || selectingValues || preSelected.length === 1 && preSelected[0] === elemNumber // prevent toggling again on mouseup
6701
+ if (isSingleSelect || !rangeSelect || !mouseDown || selectingValues || preSelected.length === 1 && preSelected[0] === elemNumber // prevent toggling again on mouseup
6694
6702
  ) {
6695
6703
  return;
6696
6704
  }
@@ -6701,9 +6709,10 @@ function useSelectionsInteractions(_ref) {
6701
6709
  // Ensure we end interactions when mouseup happens outside the Listbox.
6702
6710
  setMouseDown(false);
6703
6711
  setSelectingValues(false);
6712
+ setIsRangeSelection(false);
6704
6713
  }, []);
6705
6714
  const onMouseEnter = useCallback(event => {
6706
- if (getIsSingleSelect() || !mouseDown || selectingValues || selectDisabled()) {
6715
+ if (isSingleSelect || !mouseDown || selectingValues || selectDisabled()) {
6707
6716
  return;
6708
6717
  }
6709
6718
 
@@ -6743,7 +6752,7 @@ function useSelectionsInteractions(_ref) {
6743
6752
  } // Render pre-selections before they have been selected in Engine.
6744
6753
 
6745
6754
 
6746
- const newPages = applySelectionsOnPages(pages, preSelected);
6755
+ const newPages = applySelectionsOnPages(pages, preSelected, isSingleSelect);
6747
6756
  setInstantPages(newPages);
6748
6757
  }, [preSelected]);
6749
6758
  const interactionEvents = {};
@@ -6786,7 +6795,7 @@ var Tick = (props => SvgIcon(tick(props)));
6786
6795
 
6787
6796
  const CheckboxChecked = "url(\"data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath" + " fill-rule='evenodd' clip-rule='evenodd' d='M12 5c-.28 0-.53.11-.71.29L7 9.59l-2.29-2.3a1.003 " + "1.003 0 00-1.42 1.42l3 3c.18.18.43.29.71.29s.53-.11.71-.29l5-5A1.003 1.003 0 0012 5z' fill='%23fff'/%3E%3C/svg%3E\")";
6788
6797
 
6789
- const useStyles$c = makeStyles(theme => ({
6798
+ const useStyles$d = makeStyles(theme => ({
6790
6799
  cbIcon: {
6791
6800
  borderRadius: 3,
6792
6801
  width: 16,
@@ -6823,7 +6832,7 @@ function ListboxCheckbox(_ref) {
6823
6832
  label,
6824
6833
  dense
6825
6834
  } = _ref;
6826
- const styles = useStyles$c();
6835
+ const styles = useStyles$d();
6827
6836
  return /*#__PURE__*/React.createElement(Checkbox, {
6828
6837
  edge: "start",
6829
6838
  checked: checked,
@@ -6910,6 +6919,41 @@ function getSegmentsFromRanges(label, ranges) {
6910
6919
  return labels;
6911
6920
  }
6912
6921
 
6922
+ const useStyles$c = makeStyles(() => ({
6923
+ denseRadioButton: {
6924
+ height: '100%',
6925
+ boxSizing: 'border-box',
6926
+ '& svg': {
6927
+ width: '0.7em',
6928
+ height: '0.7em'
6929
+ }
6930
+ },
6931
+ radioButton: {
6932
+ right: '5px'
6933
+ }
6934
+ }));
6935
+ function ListBoxRadioButton(_ref) {
6936
+ let {
6937
+ checked,
6938
+ label,
6939
+ dense
6940
+ } = _ref;
6941
+ const styles = useStyles$c();
6942
+ return /*#__PURE__*/React.createElement(Radio, {
6943
+ checked: checked,
6944
+ value: label,
6945
+ name: label,
6946
+ inputProps: {
6947
+ 'aria-labelledby': label
6948
+ },
6949
+ className: dense ? styles.denseRadioButton : styles.radioButton,
6950
+ style: {
6951
+ backgroundColor: 'transparent'
6952
+ },
6953
+ disableRipple: true
6954
+ });
6955
+ }
6956
+
6913
6957
  const KEYS = Object.freeze({
6914
6958
  ENTER: 13,
6915
6959
  ESCAPE: 27,
@@ -7140,6 +7184,7 @@ const useStyles$b = makeStyles(theme => ({
7140
7184
  checkboxLabel: {
7141
7185
  margin: 0,
7142
7186
  width: '100%',
7187
+ height: '100%',
7143
7188
  // For checkboxes the first child is the checkbox container, second is the label container.
7144
7189
  '& > span:nth-child(2)': _objectSpread2(_objectSpread2({}, ellipsis), {}, {
7145
7190
  display: 'flex',
@@ -7202,6 +7247,7 @@ const useStyles$b = makeStyles(theme => ({
7202
7247
  color: '#828282'
7203
7248
  }
7204
7249
  }));
7250
+
7205
7251
  function RowColumn(_ref) {
7206
7252
  let {
7207
7253
  index,
@@ -7219,6 +7265,7 @@ function RowColumn(_ref) {
7219
7265
  checkboxes = false,
7220
7266
  dense = false,
7221
7267
  frequencyMode = 'N',
7268
+ isSingleSelect,
7222
7269
  actions,
7223
7270
  frequencyMax = '',
7224
7271
  histogram = false,
@@ -7309,6 +7356,11 @@ function RowColumn(_ref) {
7309
7356
  checked: isSelected,
7310
7357
  dense: dense
7311
7358
  });
7359
+ const rb = /*#__PURE__*/React.createElement(ListBoxRadioButton, {
7360
+ label: lbl,
7361
+ checked: isSelected,
7362
+ dense: dense
7363
+ });
7312
7364
  const labelTag = typeof lbl === 'string' ? getValueField({
7313
7365
  lbl,
7314
7366
  color,
@@ -7316,7 +7368,7 @@ function RowColumn(_ref) {
7316
7368
  }) : lbl;
7317
7369
  return /*#__PURE__*/React.createElement(FormControlLabel, {
7318
7370
  color: color,
7319
- control: cb,
7371
+ control: isSingleSelect ? rb : cb,
7320
7372
  className: classes.checkboxLabel,
7321
7373
  label: labelTag,
7322
7374
  key: qElemNumber
@@ -7477,6 +7529,7 @@ function ListBox(_ref2) {
7477
7529
  selectDisabled = () => false
7478
7530
  } = _ref2;
7479
7531
  const [layout] = useLayout$1(model);
7532
+ const isSingleSelect = !!(layout && layout.qListObject.qDimensionInfo.qIsOneAndOnlyOne);
7480
7533
  const [pages, setPages] = useState$1(null);
7481
7534
  const [isLoadingData, setIsLoadingData] = useState$1(false);
7482
7535
  const {
@@ -7490,7 +7543,8 @@ function ListBox(_ref2) {
7490
7543
  rangeSelect,
7491
7544
  checkboxes,
7492
7545
  selectDisabled,
7493
- doc: document
7546
+ doc: document,
7547
+ isSingleSelect
7494
7548
  });
7495
7549
  const loaderRef = useRef(null);
7496
7550
  const local = useRef({
@@ -7624,6 +7678,7 @@ function ListBox(_ref2) {
7624
7678
  checkboxes,
7625
7679
  dense,
7626
7680
  frequencyMode,
7681
+ isSingleSelect,
7627
7682
  actions: {
7628
7683
  select,
7629
7684
  confirm: () => selections && selections.confirm.call(selections),
@@ -8232,7 +8287,6 @@ function ListBoxSearch(_ref) {
8232
8287
  let {
8233
8288
  model,
8234
8289
  keyboard,
8235
- autoFocus = true,
8236
8290
  dense = false
8237
8291
  } = _ref;
8238
8292
  const {
@@ -8266,7 +8320,6 @@ function ListBoxSearch(_ref) {
8266
8320
  size: dense ? 'small' : 'normal'
8267
8321
  })),
8268
8322
  className: ['search', classes.root, dense && classes.dense].filter(Boolean).join(' '),
8269
- autoFocus: autoFocus,
8270
8323
  margin: "dense",
8271
8324
  fullWidth: true,
8272
8325
  placeholder: translator.get('Listbox.Search'),
@@ -8274,7 +8327,7 @@ function ListBoxSearch(_ref) {
8274
8327
  onChange: onChange,
8275
8328
  onKeyDown: onKeyDown,
8276
8329
  inputProps: {
8277
- tabIndex: !keyboard.enabled || keyboard.active ? 0 : -1
8330
+ tabIndex: keyboard && (!keyboard.enabled || keyboard.active) ? 0 : -1
8278
8331
  }
8279
8332
  });
8280
8333
  }
@@ -9918,7 +9971,19 @@ function ListBoxInline(_ref) {
9918
9971
  break;
9919
9972
  }
9920
9973
 
9921
- const getListdefFrequencyMode = () => histogram && frequencyMode === 'N' ? 'V' : frequencyMode;
9974
+ const getListdefFrequencyMode = () => histogram && frequencyMode === 'N' ? 'V' : frequencyMode; // Hook that will trigger update when used in useEffects.
9975
+ // Modified from: https://medium.com/@teh_builder/ref-objects-inside-useeffect-hooks-eb7c15198780
9976
+
9977
+
9978
+ const useRefWithCallback = () => {
9979
+ const [ref, setInternalRef] = useState$1({});
9980
+ const setRef = useCallback(node => {
9981
+ setInternalRef({
9982
+ current: node
9983
+ });
9984
+ }, [setInternalRef]);
9985
+ return [ref, setRef];
9986
+ };
9922
9987
 
9923
9988
  const listdef = _objectSpread2({
9924
9989
  qInfo: {
@@ -9989,10 +10054,10 @@ function ListBoxInline(_ref) {
9989
10054
  keyboardNavigation
9990
10055
  } = useContext(InstanceContext);
9991
10056
  const moreAlignTo = useRef();
10057
+ const [searchContainer, searchContainerRef] = useRefWithCallback();
9992
10058
  const [layout] = useLayout$1(model);
9993
10059
  const [showToolbar, setShowToolbar] = useState$1(false);
9994
10060
  const [showSearch, setShowSearch] = useState$1(false);
9995
- const [autoFocusSearch, setAutoFocusSearch] = useState$1(focusSearch);
9996
10061
  const [keyboardActive, setKeyboardActive] = useState$1(false);
9997
10062
  const handleKeyDown = getListboxInlineKeyboardNavigation({
9998
10063
  setKeyboardActive
@@ -10020,6 +10085,17 @@ function ListBoxInline(_ref) {
10020
10085
  setShowToolbar(selections.isActive());
10021
10086
  }
10022
10087
  }, [selections]);
10088
+ useEffect$1(() => {
10089
+ if (!searchContainer || !searchContainer.current) {
10090
+ return;
10091
+ } // Focus search field on toggle-show or when focusSearch is true.
10092
+
10093
+
10094
+ if (search && focusSearch || search === 'toggle' && showSearch) {
10095
+ const input = searchContainer.current.querySelector('input');
10096
+ input && input.focus();
10097
+ }
10098
+ }, [searchContainer && searchContainer.current, showSearch, search, focusSearch]);
10023
10099
 
10024
10100
  if (!model || !layout || !translator) {
10025
10101
  return null;
@@ -10039,7 +10115,6 @@ function ListBoxInline(_ref) {
10039
10115
  const onShowSearch = () => {
10040
10116
  const newValue = !showSearch;
10041
10117
  setShowSearch(newValue);
10042
- setAutoFocusSearch(newValue);
10043
10118
  };
10044
10119
 
10045
10120
  const getSearchOrUnlock = () => search === 'toggle' && !hasSelections ? /*#__PURE__*/React.createElement(IconButton, {
@@ -10107,10 +10182,10 @@ function ListBoxInline(_ref) {
10107
10182
  onCancel: () => {}
10108
10183
  }
10109
10184
  }))), searchVisible && /*#__PURE__*/React.createElement(Grid, {
10110
- item: true
10185
+ item: true,
10186
+ ref: searchContainerRef
10111
10187
  }, /*#__PURE__*/React.createElement(ListBoxSearch, {
10112
10188
  model: model,
10113
- autoFocus: autoFocusSearch,
10114
10189
  dense: dense,
10115
10190
  keyboard: keyboard
10116
10191
  })), /*#__PURE__*/React.createElement(Grid, {
@@ -10538,7 +10613,7 @@ const setValue = (data, reference, value) => {
10538
10613
  dataContainer = dataContainer[step];
10539
10614
  }
10540
10615
 
10541
- if (typeof value !== 'undefined') {
10616
+ if (typeof value !== 'undefined' && propertyName !== '__proto__' && propertyName !== 'constructor') {
10542
10617
  dataContainer[propertyName] = value;
10543
10618
  } else {
10544
10619
  delete dataContainer[propertyName];
@@ -17538,7 +17613,7 @@ function nuked() {
17538
17613
  */
17539
17614
 
17540
17615
  /**
17541
- * @typedef { false | true | 'toggle' } SearchMode
17616
+ * @typedef { boolean | 'toggle' } SearchMode
17542
17617
  */
17543
17618
 
17544
17619
  /**