@ni/nimble-components 27.2.2 → 28.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 (69) hide show
  1. package/dist/all-components-bundle.js +730 -719
  2. package/dist/all-components-bundle.js.map +1 -1
  3. package/dist/all-components-bundle.min.js +105 -98
  4. package/dist/all-components-bundle.min.js.map +1 -1
  5. package/dist/esm/all-components.d.ts +1 -1
  6. package/dist/esm/all-components.js +1 -1
  7. package/dist/esm/all-components.js.map +1 -1
  8. package/dist/esm/anchor-menu-item/styles.js +8 -5
  9. package/dist/esm/anchor-menu-item/styles.js.map +1 -1
  10. package/dist/esm/mapping/icon/index.d.ts +1 -1
  11. package/dist/esm/mapping/icon/index.js +1 -1
  12. package/dist/esm/mapping/icon/index.js.map +1 -1
  13. package/dist/esm/mapping/spinner/index.d.ts +1 -1
  14. package/dist/esm/mapping/spinner/index.js +1 -1
  15. package/dist/esm/mapping/spinner/index.js.map +1 -1
  16. package/dist/esm/mapping/text/index.d.ts +1 -1
  17. package/dist/esm/mapping/text/index.js +1 -1
  18. package/dist/esm/mapping/text/index.js.map +1 -1
  19. package/dist/esm/menu/styles.js +6 -0
  20. package/dist/esm/menu/styles.js.map +1 -1
  21. package/dist/esm/table/testing/table.pageobject.d.ts +2 -2
  22. package/dist/esm/table/testing/table.pageobject.js +3 -3
  23. package/dist/esm/table/testing/table.pageobject.js.map +1 -1
  24. package/dist/esm/table-column/enum-base/types.d.ts +1 -1
  25. package/dist/esm/table-column/enum-base/types.js +1 -1
  26. package/dist/esm/table-column/enum-base/types.js.map +1 -1
  27. package/dist/esm/table-column/{icon → mapping}/cell-view/index.d.ts +4 -4
  28. package/dist/esm/table-column/{icon → mapping}/cell-view/index.js +11 -11
  29. package/dist/esm/table-column/mapping/cell-view/index.js.map +1 -0
  30. package/dist/esm/table-column/mapping/cell-view/styles.js.map +1 -0
  31. package/dist/esm/table-column/mapping/cell-view/template.d.ts +2 -0
  32. package/dist/esm/table-column/mapping/cell-view/template.js.map +1 -0
  33. package/dist/esm/table-column/{icon → mapping}/group-header-view/index.d.ts +4 -4
  34. package/dist/esm/table-column/{icon → mapping}/group-header-view/index.js +10 -8
  35. package/dist/esm/table-column/mapping/group-header-view/index.js.map +1 -0
  36. package/dist/esm/table-column/mapping/group-header-view/styles.js.map +1 -0
  37. package/dist/esm/table-column/mapping/group-header-view/template.d.ts +2 -0
  38. package/dist/esm/table-column/mapping/group-header-view/template.js.map +1 -0
  39. package/dist/esm/table-column/{icon → mapping}/index.d.ts +9 -8
  40. package/dist/esm/table-column/{icon → mapping}/index.js +14 -13
  41. package/dist/esm/table-column/mapping/index.js.map +1 -0
  42. package/dist/esm/table-column/{icon/models/table-column-icon-validator.d.ts → mapping/models/table-column-mapping-validator.d.ts} +3 -3
  43. package/dist/esm/table-column/{icon/models/table-column-icon-validator.js → mapping/models/table-column-mapping-validator.js} +9 -9
  44. package/dist/esm/table-column/mapping/models/table-column-mapping-validator.js.map +1 -0
  45. package/dist/esm/table-column/{icon/testing/table-column-icon.pageobject.d.ts → mapping/testing/table-column-mapping.pageobject.d.ts} +2 -2
  46. package/dist/esm/table-column/{icon/testing/table-column-icon.pageobject.js → mapping/testing/table-column-mapping.pageobject.js} +3 -3
  47. package/dist/esm/table-column/mapping/testing/table-column-mapping.pageobject.js.map +1 -0
  48. package/dist/esm/table-column/{icon → mapping}/types.d.ts +1 -1
  49. package/dist/esm/table-column/{icon → mapping}/types.js +1 -1
  50. package/dist/esm/table-column/mapping/types.js.map +1 -0
  51. package/package.json +5 -4
  52. package/dist/esm/table-column/icon/cell-view/index.js.map +0 -1
  53. package/dist/esm/table-column/icon/cell-view/styles.js.map +0 -1
  54. package/dist/esm/table-column/icon/cell-view/template.d.ts +0 -2
  55. package/dist/esm/table-column/icon/cell-view/template.js.map +0 -1
  56. package/dist/esm/table-column/icon/group-header-view/index.js.map +0 -1
  57. package/dist/esm/table-column/icon/group-header-view/styles.js.map +0 -1
  58. package/dist/esm/table-column/icon/group-header-view/template.d.ts +0 -2
  59. package/dist/esm/table-column/icon/group-header-view/template.js.map +0 -1
  60. package/dist/esm/table-column/icon/index.js.map +0 -1
  61. package/dist/esm/table-column/icon/models/table-column-icon-validator.js.map +0 -1
  62. package/dist/esm/table-column/icon/testing/table-column-icon.pageobject.js.map +0 -1
  63. package/dist/esm/table-column/icon/types.js.map +0 -1
  64. /package/dist/esm/table-column/{icon → mapping}/cell-view/styles.d.ts +0 -0
  65. /package/dist/esm/table-column/{icon → mapping}/cell-view/styles.js +0 -0
  66. /package/dist/esm/table-column/{icon → mapping}/cell-view/template.js +0 -0
  67. /package/dist/esm/table-column/{icon → mapping}/group-header-view/styles.d.ts +0 -0
  68. /package/dist/esm/table-column/{icon → mapping}/group-header-view/styles.js +0 -0
  69. /package/dist/esm/table-column/{icon → mapping}/group-header-view/template.js +0 -0
@@ -16333,7 +16333,7 @@
16333
16333
 
16334
16334
  /**
16335
16335
  * Do not edit directly
16336
- * Generated on Wed, 01 May 2024 21:32:12 GMT
16336
+ * Generated on Mon, 06 May 2024 18:46:24 GMT
16337
16337
  */
16338
16338
 
16339
16339
  const Information100DarkUi = "#a46eff";
@@ -17732,11 +17732,6 @@
17732
17732
  font: ${bodyFont};
17733
17733
  }
17734
17734
 
17735
- :host(:focus-within:not(:active)) {
17736
- outline: 2px solid ${borderHoverColor};
17737
- outline-offset: -2px;
17738
- }
17739
-
17740
17735
  :host(:hover) {
17741
17736
  background: ${fillHoverColor};
17742
17737
  }
@@ -17767,6 +17762,13 @@
17767
17762
  cursor: pointer;
17768
17763
  text-decoration: none;
17769
17764
  outline: none;
17765
+ padding-left: 8px;
17766
+ padding-right: 8px;
17767
+ }
17768
+
17769
+ a${focusVisible} {
17770
+ outline: 2px solid ${borderHoverColor};
17771
+ outline-offset: -2px;
17770
17772
  }
17771
17773
 
17772
17774
  :host([disabled]) a {
@@ -17917,6 +17919,7 @@
17917
17919
  DesignSystem.getOrCreate()
17918
17920
  .withPrefix('nimble')
17919
17921
  .register(nimbleAnchorMenuItem());
17922
+ const anchorMenuItemTag = 'nimble-anchor-menu-item';
17920
17923
 
17921
17924
  const styles$T = css `
17922
17925
  ${display('inline-flex')}
@@ -24912,7 +24915,7 @@
24912
24915
 
24913
24916
  /**
24914
24917
  * Defines a mapping from one data value ('key' property) to display text ('text' property).
24915
- * One or more may be added as children of a nimble-table-column-icon element to define
24918
+ * One or more may be added as children of a nimble-table-column-mapping element to define
24916
24919
  * how a specific data value should be displayed as text in that column's cells.
24917
24920
  */
24918
24921
  class MappingText extends Mapping$1 {
@@ -24931,7 +24934,7 @@
24931
24934
  }
24932
24935
  /**
24933
24936
  * Maps a data value to an icon.
24934
- * One or more may be added as children of a nimble-table-column-icon element to define
24937
+ * One or more may be added as children of a nimble-table-column-mapping element to define
24935
24938
  * how specific data values should be displayed as icons in that column's cells.
24936
24939
  */
24937
24940
  class MappingIcon extends Mapping$1 {
@@ -24998,7 +25001,7 @@
24998
25001
 
24999
25002
  /**
25000
25003
  * Maps data values to a spinner.
25001
- * One or more may be added as children of a nimble-table-column-icon element to define
25004
+ * One or more may be added as children of a nimble-table-column-mapping element to define
25002
25005
  * which specific data values should be displayed as spinners in that column's cells.
25003
25006
  */
25004
25007
  class MappingSpinner extends Mapping$1 {
@@ -25038,6 +25041,7 @@
25038
25041
 
25039
25042
  :host([slot='submenu']) {
25040
25043
  margin: 0 ${mediumPadding};
25044
+ cursor: default;
25041
25045
  }
25042
25046
 
25043
25047
  ::slotted(*) {
@@ -25062,6 +25066,10 @@
25062
25066
  padding-top: ${smallPadding};
25063
25067
  padding-bottom: ${smallPadding};
25064
25068
  }
25069
+
25070
+ ::slotted(${anchorMenuItemTag}) {
25071
+ padding: 0px;
25072
+ }
25065
25073
  `.withBehaviors(themeBehavior(Theme.color, css `
25066
25074
  slot {
25067
25075
  background: ${hexToRgbaCssColor(White, 0.15)};
@@ -68839,211 +68847,769 @@ img.ProseMirror-separator {
68839
68847
  .withPrefix('nimble')
68840
68848
  .register(nimbleTableColumnDurationText());
68841
68849
 
68842
- // Avoiding a wrapping <template> and be careful about starting and ending whitespace
68843
- // so the template can be composed into other column header templates
68844
- // prettier-ignore
68845
- const template$9 = html `<span
68846
- ${overflow('hasOverflow')}
68847
- class="header-content"
68848
- title=${x => (x.hasOverflow && x.headerTextContent ? x.headerTextContent : null)}
68849
- >
68850
- <slot ${ref('contentSlot')}></slot>
68851
- <slot ${slotted({ property: 'unitElements', filter: elements() })} name="unit"></slot>
68852
- </span>`;
68850
+ /**
68851
+ * Converts a Mapping key (which is a string when configured in HTML) to the
68852
+ * given keyType. The converted value can then be used to compare against
68853
+ * values in the table data.
68854
+ */
68855
+ const resolveKeyWithType = (key, keyType) => {
68856
+ if (keyType === 'number') {
68857
+ const converted = nullableNumberConverter.fromView(key);
68858
+ return converted === null ? undefined : converted;
68859
+ }
68860
+ if (keyType === 'boolean') {
68861
+ if (key === false || key === 'false') {
68862
+ return false;
68863
+ }
68864
+ if (key === true || key === 'true') {
68865
+ return true;
68866
+ }
68867
+ return undefined;
68868
+ }
68869
+ return key?.toString() ?? undefined;
68870
+ };
68853
68871
 
68854
68872
  /**
68855
- * The group header view for displaying number fields as text.
68873
+ * Base class for table columns that map values to content
68856
68874
  */
68857
- class TableColumnNumberTextGroupHeaderView extends TableColumnTextGroupHeaderViewBase {
68858
- updateText() {
68859
- this.text = this.columnConfig?.formatter?.format(this.groupHeaderValue) ?? '';
68875
+ class TableColumnEnumBase extends TableColumn {
68876
+ constructor() {
68877
+ super(...arguments);
68878
+ /** @internal */
68879
+ this.mappingNotifiers = [];
68880
+ /** @internal */
68881
+ this.mappings = [];
68882
+ this.keyType = 'string';
68883
+ }
68884
+ /**
68885
+ * @internal
68886
+ *
68887
+ * Triggers a request to update the columnConfig when any observable property on
68888
+ * a mapping is updated.
68889
+ */
68890
+ handleChange(source, args) {
68891
+ if (source instanceof Mapping$1 && typeof args === 'string') {
68892
+ this.updateColumnConfig();
68893
+ }
68894
+ }
68895
+ /**
68896
+ * Called when any Mapping related state has changed.
68897
+ */
68898
+ updateColumnConfig() {
68899
+ this.columnInternals.validator.validate(this.mappings, this.keyType);
68900
+ this.columnInternals.columnConfig = this.checkValidity()
68901
+ ? this.createColumnConfig(this.getMappingConfigs())
68902
+ : undefined;
68903
+ }
68904
+ getMappingConfigs() {
68905
+ const mappingConfigs = new Map();
68906
+ this.mappings.forEach(mapping => {
68907
+ const key = resolveKeyWithType(mapping.key, this.keyType);
68908
+ if (key === undefined) {
68909
+ throw Error('Key was invalid for type. Validation should have prevented this.');
68910
+ }
68911
+ const mappingConfig = this.createMappingConfig(mapping);
68912
+ mappingConfigs.set(key, mappingConfig);
68913
+ });
68914
+ return mappingConfigs;
68915
+ }
68916
+ fieldNameChanged() {
68917
+ this.columnInternals.dataRecordFieldNames = [this.fieldName];
68918
+ this.columnInternals.operandDataRecordFieldName = this.fieldName;
68919
+ }
68920
+ mappingsChanged() {
68921
+ this.updateColumnConfig();
68922
+ this.observeMappings();
68923
+ }
68924
+ keyTypeChanged() {
68925
+ this.updateColumnConfig();
68926
+ }
68927
+ removeMappingObservers() {
68928
+ this.mappingNotifiers.forEach(notifier => {
68929
+ notifier.unsubscribe(this);
68930
+ });
68931
+ this.mappingNotifiers = [];
68932
+ }
68933
+ observeMappings() {
68934
+ this.removeMappingObservers();
68935
+ for (const mapping of this.mappings) {
68936
+ const notifier = Observable.getNotifier(mapping);
68937
+ notifier.subscribe(this);
68938
+ this.mappingNotifiers.push(notifier);
68939
+ }
68860
68940
  }
68861
68941
  }
68862
- const tableColumnNumberTextGroupHeaderView = TableColumnNumberTextGroupHeaderView.compose({
68863
- baseName: 'table-column-number-text-group-header-view',
68864
- template: template$b,
68865
- styles: styles$c
68866
- });
68867
- DesignSystem.getOrCreate()
68868
- .withPrefix('nimble')
68869
- .register(tableColumnNumberTextGroupHeaderView());
68870
- const tableColumnNumberTextGroupHeaderTag = 'nimble-table-column-number-text-group-header-view';
68942
+ __decorate$1([
68943
+ observable
68944
+ ], TableColumnEnumBase.prototype, "mappings", void 0);
68945
+ __decorate$1([
68946
+ attr({ attribute: 'field-name' })
68947
+ ], TableColumnEnumBase.prototype, "fieldName", void 0);
68948
+ __decorate$1([
68949
+ attr({ attribute: 'key-type' })
68950
+ ], TableColumnEnumBase.prototype, "keyType", void 0);
68951
+
68952
+ const styles$a = css `
68953
+ ${styles$e}
68871
68954
 
68955
+ slot[name='mapping'] {
68956
+ display: none;
68957
+ }
68958
+ `;
68959
+
68960
+ const template$9 = html `${template$d}<slot ${slotted('mappings')} name="mapping"></slot>`;
68961
+
68962
+ const enumBaseValidityFlagNames = [
68963
+ 'invalidMappingKeyValueForType',
68964
+ 'duplicateMappingKey',
68965
+ 'missingKeyValue'
68966
+ ];
68872
68967
  /**
68873
- * A cell view for displaying number fields as text
68968
+ * Validator base class for table columns containing mappings. Implementations MUST include enumBaseValidityFlagNames in validity flag names set.
68874
68969
  */
68875
- class TableColumnNumberTextCellView extends TableColumnTextCellViewBase {
68876
- columnConfigChanged() {
68877
- super.columnConfigChanged();
68878
- this.alignment = this.columnConfig?.alignment ?? TextCellViewBaseAlignment.left;
68970
+ class TableColumnEnumBaseValidator extends ColumnValidator {
68971
+ constructor(configValidityKeys) {
68972
+ super(configValidityKeys);
68879
68973
  }
68880
- updateText() {
68881
- this.text = this.columnConfig?.formatter?.format(this.cellRecord?.value) ?? '';
68974
+ validate(mappings, keyType) {
68975
+ this.untrackAll();
68976
+ const keys = mappings.map(mapping => mapping.key);
68977
+ this.validateKeyValuesForType(keys, keyType);
68978
+ this.validateUniqueKeys(keys, keyType);
68979
+ this.validateNoMissingKeys(mappings);
68980
+ }
68981
+ validateKeyValuesForType(keys, keyType) {
68982
+ // Ignore undefined keys, because validateNoMissingKeys covers that case.
68983
+ // We should only set 'invalidMappingKeyValueForType' when there is a key,
68984
+ // but it isn't appropriate for the type.
68985
+ const invalid = keys.some(key => key !== undefined
68986
+ && resolveKeyWithType(key, keyType) === undefined);
68987
+ this.setConditionValue('invalidMappingKeyValueForType', invalid);
68988
+ }
68989
+ validateUniqueKeys(keys, keyType) {
68990
+ const typedKeys = keys.map(x => resolveKeyWithType(x, keyType));
68991
+ const invalid = new Set(typedKeys).size !== typedKeys.length;
68992
+ this.setConditionValue('duplicateMappingKey', invalid);
68993
+ }
68994
+ validateNoMissingKeys(mappings) {
68995
+ const invalid = mappings.some(mapping => mapping.key === undefined);
68996
+ this.setConditionValue('missingKeyValue', invalid);
68882
68997
  }
68883
68998
  }
68884
- const numberTextCellView = TableColumnNumberTextCellView.compose({
68885
- baseName: 'table-column-number-text-cell-view',
68886
- template: template$a,
68887
- styles: styles$b
68888
- });
68889
- DesignSystem.getOrCreate().withPrefix('nimble').register(numberTextCellView());
68890
- const tableColumnNumberTextCellViewTag = 'nimble-table-column-number-text-cell-view';
68891
68999
 
69000
+ const mappingColumnValidityFlagNames = [
69001
+ ...enumBaseValidityFlagNames,
69002
+ 'unsupportedMappingType',
69003
+ 'invalidIconName',
69004
+ 'missingTextValue'
69005
+ ];
68892
69006
  /**
68893
- * Formatting scheme for the number-text table column
69007
+ * Validator for TableColumnMapping
68894
69008
  */
68895
- const NumberTextFormat = {
68896
- default: undefined,
68897
- decimal: 'decimal'
68898
- };
69009
+ class TableColumnMappingValidator extends TableColumnEnumBaseValidator {
69010
+ constructor() {
69011
+ super(mappingColumnValidityFlagNames);
69012
+ }
69013
+ static isIconMappingElement(mapping) {
69014
+ return mapping instanceof MappingIcon;
69015
+ }
69016
+ static isSupportedMappingElement(mapping) {
69017
+ return (mapping instanceof MappingIcon
69018
+ || mapping instanceof MappingSpinner
69019
+ || mapping instanceof MappingText);
69020
+ }
69021
+ static hasUnresolvedIcon(mappingIcon) {
69022
+ return (typeof mappingIcon.icon === 'string'
69023
+ && mappingIcon.resolvedIcon === undefined);
69024
+ }
69025
+ validate(mappings, keyType) {
69026
+ super.validate(mappings, keyType);
69027
+ this.validateMappingTypes(mappings);
69028
+ this.validateIconNames(mappings);
69029
+ this.validateNoMissingText(mappings);
69030
+ }
69031
+ validateIconNames(mappings) {
69032
+ const invalid = mappings
69033
+ .filter(TableColumnMappingValidator.isIconMappingElement)
69034
+ .some(TableColumnMappingValidator.hasUnresolvedIcon);
69035
+ this.setConditionValue('invalidIconName', invalid);
69036
+ }
69037
+ validateNoMissingText(mappings) {
69038
+ const invalid = mappings
69039
+ .filter(TableColumnMappingValidator.isSupportedMappingElement)
69040
+ .some(mapping => mapping.text === undefined);
69041
+ this.setConditionValue('missingTextValue', invalid);
69042
+ }
69043
+ validateMappingTypes(mappings) {
69044
+ const valid = mappings.every(TableColumnMappingValidator.isSupportedMappingElement);
69045
+ this.setConditionValue('unsupportedMappingType', !valid);
69046
+ }
69047
+ }
69048
+
69049
+ const styles$9 = css `
69050
+ ${display('inline-flex')}
69051
+
69052
+ :host {
69053
+ gap: ${smallPadding};
69054
+ align-items: center;
69055
+ }
69056
+
69057
+ .reserve-icon-size {
69058
+ flex-shrink: 0;
69059
+ width: ${iconSize};
69060
+ height: ${iconSize};
69061
+ }
69062
+
69063
+ .text {
69064
+ flex-shrink: 1;
69065
+ font: ${bodyFont};
69066
+ color: ${bodyFontColor};
69067
+ white-space: nowrap;
69068
+ overflow: hidden;
69069
+ text-overflow: ellipsis;
69070
+ }
69071
+ `;
69072
+
69073
+ // prettier-ignore
69074
+ const template$8 = html `
69075
+ ${when(x => x.visualizationTemplate, html `
69076
+ <span class="reserve-icon-size">
69077
+ ${x => x.visualizationTemplate}
69078
+ </span>
69079
+ `)}
69080
+ <span
69081
+ ${overflow('hasOverflow')}
69082
+ title="${x => (x.hasOverflow && x.text ? x.text : null)}"
69083
+ class="text"
69084
+ >${x => x.text}</span>
69085
+ `;
69086
+
68899
69087
  /**
68900
- * The aligment of the value in the number-text table column.
68901
- * The `default` alignment is determined by the column's `NumberTextFormat`.
69088
+ * Predefined icon appearance states
69089
+ * @public
68902
69090
  */
68903
- const NumberTextAlignment = {
69091
+ const IconSeverity = {
68904
69092
  default: undefined,
68905
- left: 'left',
68906
- right: 'right'
69093
+ error: 'error',
69094
+ warning: 'warning',
69095
+ success: 'success',
69096
+ information: 'information'
68907
69097
  };
68908
69098
 
68909
69099
  /**
68910
- * The base class for unit formats.
69100
+ * Common state shared across Mapping Config
68911
69101
  */
68912
- class UnitFormat {
68913
- /**
68914
- * Formats a number value to a string.
68915
- * For nullish values or values that result in an exception being thrown, empty string is returned
68916
- */
68917
- format(value) {
68918
- if (typeof value !== 'number') {
68919
- return '';
68920
- }
68921
- try {
68922
- return this.tryFormat(value);
68923
- }
68924
- catch {
68925
- return '';
68926
- }
69102
+ class MappingConfig {
69103
+ constructor(text) {
69104
+ this.text = text;
68927
69105
  }
68928
69106
  }
68929
69107
 
69108
+ // Create an empty template containing only a space because creating a ViewTemplate
69109
+ // with an empty string throws an exception at runtime.
69110
+ // prettier-ignore
69111
+ const emptyTemplate = html ` `;
69112
+ const createIconTemplate = (icon) => {
69113
+ if (icon === undefined) {
69114
+ return emptyTemplate;
69115
+ }
69116
+ return html `
69117
+ <${icon}
69118
+ title="${x => (x.textHidden ? x.text : '')}"
69119
+ role="img"
69120
+ aria-label="${x => x.text}"
69121
+ aria-hidden="${x => (x.textHidden ? 'false' : 'true')}"
69122
+ severity="${x => x.severity}"
69123
+ >
69124
+ </${icon}>
69125
+ `;
69126
+ };
68930
69127
  /**
68931
- * A class that knows how to format a numeric value as a string that includes units.
69128
+ * Mapping configuration corresponding to a icon mapping
68932
69129
  */
68933
- class ScaledUnitFormat {
68934
- constructor(scaledUnitFormatFactoryOptions) {
68935
- this.locale = scaledUnitFormatFactoryOptions.locale;
68936
- this.intlNumberFormatOptions = scaledUnitFormatFactoryOptions.intlNumberFormatOptions;
69130
+ class MappingIconConfig extends MappingConfig {
69131
+ constructor(resolvedIcon, severity, text, textHidden) {
69132
+ super(text);
69133
+ this.severity = severity;
69134
+ this.textHidden = textHidden;
69135
+ this.iconTemplate = createIconTemplate(resolvedIcon);
68937
69136
  }
68938
69137
  }
68939
69138
 
69139
+ const spinnerTemplate = html `
69140
+ <${spinnerTag}
69141
+ title="${x => (x.textHidden ? x.text : '')}"
69142
+ aria-label="${x => x.text}"
69143
+ aria-hidden="${x => (x.textHidden ? 'false' : 'true')}"
69144
+ >
69145
+ </${spinnerTag}>
69146
+ `;
68940
69147
  /**
68941
- * A formatter for units that can be formatted/translated by Intl.NumberFormat
69148
+ * Mapping configuration corresponding to a spinner mapping
68942
69149
  */
68943
- class IntlNumberFormatScaledUnitFormat extends ScaledUnitFormat {
68944
- constructor(scaledUnitFormatFactoryOptions, unitSpecificIntlNumberFormatOptions) {
68945
- super(scaledUnitFormatFactoryOptions);
68946
- this.formatter = new Intl.NumberFormat(this.locale, {
68947
- ...unitSpecificIntlNumberFormatOptions,
68948
- // Application configured options override unit specific options
68949
- ...this.intlNumberFormatOptions
68950
- });
68951
- }
68952
- static createFactory(unitSpecificIntlNumberFormatOptions) {
68953
- return (scaledUnitFormatFactoryOptions) => new IntlNumberFormatScaledUnitFormat(scaledUnitFormatFactoryOptions, unitSpecificIntlNumberFormatOptions);
68954
- }
68955
- format(value) {
68956
- return this.formatter.format(value);
69150
+ class MappingSpinnerConfig extends MappingConfig {
69151
+ constructor(text, textHidden) {
69152
+ super(text);
69153
+ this.textHidden = textHidden;
69154
+ this.spinnerTemplate = spinnerTemplate;
68957
69155
  }
68958
69156
  }
68959
69157
 
68960
69158
  /**
68961
- * A unit that represents a scaled version of a base unit.
69159
+ * Mapping configuration corresponding to a text mapping
68962
69160
  */
68963
- class ScaledUnit {
68964
- constructor(scaleFactor, scaledUnitFormatFactory) {
68965
- this.scaleFactor = scaleFactor;
68966
- this.scaledUnitFormatFactory = scaledUnitFormatFactory;
68967
- }
68968
- isBase() {
68969
- return this.scaleFactor === 1;
68970
- }
69161
+ class MappingTextConfig extends MappingConfig {
68971
69162
  }
68972
69163
 
68973
69164
  /**
68974
- * A unit scale consisting of a set of scaled units.
69165
+ * The group header view for the mapping column
68975
69166
  */
68976
- class UnitScale {
68977
- constructor(supportedScaledUnits) {
68978
- this.supportedScaledUnits = supportedScaledUnits;
68979
- const unitsSorted = supportedScaledUnits.every((curr, i, arr) => i === 0 || arr[i - 1].scaleFactor < curr.scaleFactor);
68980
- if (!unitsSorted) {
68981
- throw new Error('Supported scaled units must have unique and ordered scale factors');
69167
+ class TableColumnMappingGroupHeaderView extends TableColumnTextGroupHeaderViewBase {
69168
+ constructor() {
69169
+ super(...arguments);
69170
+ this.textHidden = false;
69171
+ }
69172
+ updateText() {
69173
+ this.resetState();
69174
+ if (!this.columnConfig) {
69175
+ return;
68982
69176
  }
68983
- const baseScaledUnit = supportedScaledUnits.find(x => x.isBase());
68984
- if (!baseScaledUnit) {
68985
- throw new Error('Supported scaled units must include a base scaled unit (scale factor=1)');
69177
+ const value = this.groupHeaderValue;
69178
+ const mappingConfig = this.columnConfig.mappingConfigs.get(value);
69179
+ if (mappingConfig instanceof MappingIconConfig) {
69180
+ this.severity = mappingConfig.severity;
69181
+ this.text = mappingConfig.text ?? '';
69182
+ this.visualizationTemplate = mappingConfig.iconTemplate;
68986
69183
  }
68987
- this.supportedScaledUnits = supportedScaledUnits;
68988
- this.baseScaledUnit = baseScaledUnit;
68989
- }
68990
- // Note that for the sake of reducing complexity in the implementation,
68991
- // we do NOT consider the effects of rounding when picking the unit to
68992
- // use for a given value. If formatting results in rounding, a value
68993
- // may be shown with an unexpected unit. Examples:
68994
- // - 999 bytes with two significant digits => "1000 bytes" (instead of "1 kB")
68995
- // - 0.00000000000000001 volts (= 0.01 fV) with one fractional digit => "0 fV" (instead of "0 volts")
68996
- scaleNumber(number) {
68997
- const magnitude = Math.abs(number);
68998
- const onlyBaseScaledUnit = this.supportedScaledUnits.length === 1;
68999
- if (onlyBaseScaledUnit
69000
- || magnitude === 0
69001
- || magnitude === Infinity
69002
- || Number.isNaN(magnitude)) {
69003
- return { scaledValue: number, scaledUnit: this.baseScaledUnit };
69184
+ else if (mappingConfig instanceof MappingSpinnerConfig) {
69185
+ this.text = mappingConfig.text ?? '';
69186
+ this.visualizationTemplate = mappingConfig.spinnerTemplate;
69004
69187
  }
69005
- for (let i = this.supportedScaledUnits.length - 1; i >= 0; i -= 1) {
69006
- const scaledUnit = this.supportedScaledUnits[i];
69007
- if (magnitude / scaledUnit.scaleFactor >= 1) {
69008
- return {
69009
- scaledValue: number / scaledUnit.scaleFactor,
69010
- scaledUnit
69011
- };
69012
- }
69188
+ else if (mappingConfig instanceof MappingTextConfig) {
69189
+ this.text = mappingConfig.text ?? '';
69013
69190
  }
69014
- const smallestUnit = this.supportedScaledUnits[0];
69015
- return {
69016
- scaledValue: number / smallestUnit.scaleFactor,
69017
- scaledUnit: smallestUnit
69018
- };
69191
+ }
69192
+ resetState() {
69193
+ this.text = '';
69194
+ this.visualizationTemplate = undefined;
69195
+ this.severity = IconSeverity.default;
69019
69196
  }
69020
69197
  }
69198
+ __decorate$1([
69199
+ observable
69200
+ ], TableColumnMappingGroupHeaderView.prototype, "severity", void 0);
69201
+ __decorate$1([
69202
+ observable
69203
+ ], TableColumnMappingGroupHeaderView.prototype, "visualizationTemplate", void 0);
69204
+ const mappingGroupHeaderView = TableColumnMappingGroupHeaderView.compose({
69205
+ baseName: 'table-column-mapping-group-header-view',
69206
+ template: template$8,
69207
+ styles: styles$9
69208
+ });
69209
+ DesignSystem.getOrCreate()
69210
+ .withPrefix('nimble')
69211
+ .register(mappingGroupHeaderView());
69212
+ const tableColumnMappingGroupHeaderViewTag = 'nimble-table-column-mapping-group-header-view';
69213
+
69214
+ const styles$8 = css `
69215
+ ${display('inline-flex')}
69216
+
69217
+ :host {
69218
+ gap: ${smallPadding};
69219
+ align-items: center;
69220
+ }
69221
+
69222
+ .reserve-icon-size {
69223
+ flex-shrink: 0;
69224
+ width: ${iconSize};
69225
+ height: ${iconSize};
69226
+ }
69227
+
69228
+ .text {
69229
+ flex-shrink: 1;
69230
+ font: ${bodyFont};
69231
+ color: ${bodyFontColor};
69232
+ white-space: nowrap;
69233
+ overflow: hidden;
69234
+ text-overflow: ellipsis;
69235
+ }
69236
+ `;
69237
+
69238
+ // prettier-ignore
69239
+ const template$7 = html `
69240
+ ${when(x => x.visualizationTemplate, html `
69241
+ <span class="reserve-icon-size">
69242
+ ${x => x.visualizationTemplate}
69243
+ </span>
69244
+ `)}
69245
+ ${when(x => !x.textHidden, html `
69246
+ <span
69247
+ ${overflow('hasOverflow')}
69248
+ title=${x => (x.hasOverflow && x.text ? x.text : null)}
69249
+ class="text"
69250
+ >
69251
+ ${x => x.text}
69252
+ </span>
69253
+ `)}
69254
+ `;
69021
69255
 
69022
69256
  /**
69023
- * Unit scale that is used to passthrough a number without applying scaling or units
69257
+ * The cell view for the mapping column
69024
69258
  */
69025
- class PassthroughUnitScale extends UnitScale {
69259
+ class TableColumnMappingCellView extends TableCellView {
69026
69260
  constructor() {
69027
- super([
69028
- new ScaledUnit(10 ** 0, IntlNumberFormatScaledUnitFormat.createFactory({}))
69029
- ]);
69261
+ super(...arguments);
69262
+ this.textHidden = false;
69263
+ /** @internal */
69264
+ this.hasOverflow = false;
69030
69265
  }
69031
- }
69032
- const passthroughUnitScale = new PassthroughUnitScale();
69033
-
69034
- // Workaround to avoid ts errors about signDisplay not accepting the value 'negative'.
69035
- // It has been supported by browsers since 8/23, but TypeScript still hasn't
69036
- // added it to the type definitions. See https://github.com/microsoft/TypeScript/issues/56269
69037
- const signDisplay = 'negative';
69038
- /**
69039
- * Format for numbers with units to show in a tabular form.
69040
- * Large and tiny numbers are shown exponentially and the rest as decimal.
69041
- */
69042
- class DefaultUnitFormat extends UnitFormat {
69043
- constructor(locale, { unitScale = passthroughUnitScale } = {
69044
- unitScale: passthroughUnitScale
69045
- }) {
69046
- super();
69266
+ columnConfigChanged() {
69267
+ this.updateState();
69268
+ }
69269
+ cellRecordChanged() {
69270
+ this.updateState();
69271
+ }
69272
+ updateState() {
69273
+ this.resetState();
69274
+ if (!this.columnConfig || !this.cellRecord) {
69275
+ return;
69276
+ }
69277
+ const value = this.cellRecord.value;
69278
+ if (value === undefined || value === null) {
69279
+ return;
69280
+ }
69281
+ const mappingConfig = this.columnConfig.mappingConfigs.get(value);
69282
+ if (mappingConfig instanceof MappingIconConfig) {
69283
+ this.severity = mappingConfig.severity;
69284
+ this.text = mappingConfig.text;
69285
+ this.visualizationTemplate = mappingConfig.iconTemplate;
69286
+ this.textHidden = mappingConfig.textHidden;
69287
+ }
69288
+ else if (mappingConfig instanceof MappingSpinnerConfig) {
69289
+ this.text = mappingConfig.text;
69290
+ this.visualizationTemplate = mappingConfig.spinnerTemplate;
69291
+ this.textHidden = mappingConfig.textHidden;
69292
+ }
69293
+ else if (mappingConfig instanceof MappingTextConfig) {
69294
+ this.text = mappingConfig.text;
69295
+ this.textHidden = false;
69296
+ }
69297
+ }
69298
+ resetState() {
69299
+ this.text = undefined;
69300
+ this.textHidden = false;
69301
+ this.visualizationTemplate = undefined;
69302
+ this.severity = IconSeverity.default;
69303
+ }
69304
+ }
69305
+ __decorate$1([
69306
+ observable
69307
+ ], TableColumnMappingCellView.prototype, "severity", void 0);
69308
+ __decorate$1([
69309
+ observable
69310
+ ], TableColumnMappingCellView.prototype, "text", void 0);
69311
+ __decorate$1([
69312
+ observable
69313
+ ], TableColumnMappingCellView.prototype, "visualizationTemplate", void 0);
69314
+ __decorate$1([
69315
+ observable
69316
+ ], TableColumnMappingCellView.prototype, "textHidden", void 0);
69317
+ __decorate$1([
69318
+ observable
69319
+ ], TableColumnMappingCellView.prototype, "hasOverflow", void 0);
69320
+ const mappingCellView = TableColumnMappingCellView.compose({
69321
+ baseName: 'table-column-mapping-cell-view',
69322
+ template: template$7,
69323
+ styles: styles$8
69324
+ });
69325
+ DesignSystem.getOrCreate().withPrefix('nimble').register(mappingCellView());
69326
+ const tableColumnMappingCellViewTag = 'nimble-table-column-mapping-cell-view';
69327
+
69328
+ /**
69329
+ * Width mode for the mapping column
69330
+ */
69331
+ const TableColumnMappingWidthMode = {
69332
+ default: undefined,
69333
+ iconSize: 'icon-size'
69334
+ };
69335
+
69336
+ /**
69337
+ * Table column that maps number, boolean, or string values to an icon, a spinner,
69338
+ * text, or an icon/spinner with text.
69339
+ */
69340
+ class TableColumnMapping extends mixinGroupableColumnAPI(mixinFractionalWidthColumnAPI((TableColumnEnumBase))) {
69341
+ minPixelWidthChanged() {
69342
+ if (this.widthMode !== TableColumnMappingWidthMode.iconSize) {
69343
+ this.columnInternals.minPixelWidth = this.getConfiguredMinPixelWidth();
69344
+ }
69345
+ }
69346
+ getColumnInternalsOptions() {
69347
+ return {
69348
+ cellRecordFieldNames: ['value'],
69349
+ cellViewTag: tableColumnMappingCellViewTag,
69350
+ groupHeaderViewTag: tableColumnMappingGroupHeaderViewTag,
69351
+ delegatedEvents: [],
69352
+ sortOperation: TableColumnSortOperation.basic,
69353
+ validator: new TableColumnMappingValidator()
69354
+ };
69355
+ }
69356
+ createColumnConfig(mappingConfigs) {
69357
+ return {
69358
+ mappingConfigs
69359
+ };
69360
+ }
69361
+ createMappingConfig(mapping) {
69362
+ if (mapping instanceof MappingIcon) {
69363
+ return new MappingIconConfig(mapping.resolvedIcon, mapping.severity, mapping.text, mapping.textHidden);
69364
+ }
69365
+ if (mapping instanceof MappingSpinner) {
69366
+ return new MappingSpinnerConfig(mapping.text, mapping.textHidden);
69367
+ }
69368
+ if (mapping instanceof MappingText) {
69369
+ return new MappingTextConfig(mapping.text);
69370
+ }
69371
+ // Getting here would indicate a programming error, b/c validation will prevent
69372
+ // this function from running when there is an unsupported mapping.
69373
+ throw new Error('Unsupported mapping');
69374
+ }
69375
+ widthModeChanged() {
69376
+ if (this.widthMode === TableColumnMappingWidthMode.iconSize) {
69377
+ this.columnInternals.resizingDisabled = true;
69378
+ this.columnInternals.hideHeaderIndicators = true;
69379
+ this.columnInternals.pixelWidth = singleIconColumnWidth;
69380
+ this.columnInternals.minPixelWidth = singleIconColumnWidth;
69381
+ }
69382
+ else {
69383
+ this.columnInternals.resizingDisabled = false;
69384
+ this.columnInternals.hideHeaderIndicators = false;
69385
+ this.columnInternals.pixelWidth = undefined;
69386
+ this.columnInternals.minPixelWidth = this.getConfiguredMinPixelWidth();
69387
+ }
69388
+ }
69389
+ getConfiguredMinPixelWidth() {
69390
+ if (typeof this.minPixelWidth === 'number') {
69391
+ return this.minPixelWidth;
69392
+ }
69393
+ return defaultMinPixelWidth;
69394
+ }
69395
+ }
69396
+ __decorate$1([
69397
+ attr({ attribute: 'width-mode' })
69398
+ ], TableColumnMapping.prototype, "widthMode", void 0);
69399
+ const nimbleTableColumnMapping = TableColumnMapping.compose({
69400
+ baseName: 'table-column-mapping',
69401
+ template: template$9,
69402
+ styles: styles$a
69403
+ });
69404
+ DesignSystem.getOrCreate()
69405
+ .withPrefix('nimble')
69406
+ .register(nimbleTableColumnMapping());
69407
+
69408
+ // Avoiding a wrapping <template> and be careful about starting and ending whitespace
69409
+ // so the template can be composed into other column header templates
69410
+ // prettier-ignore
69411
+ const template$6 = html `<span
69412
+ ${overflow('hasOverflow')}
69413
+ class="header-content"
69414
+ title=${x => (x.hasOverflow && x.headerTextContent ? x.headerTextContent : null)}
69415
+ >
69416
+ <slot ${ref('contentSlot')}></slot>
69417
+ <slot ${slotted({ property: 'unitElements', filter: elements() })} name="unit"></slot>
69418
+ </span>`;
69419
+
69420
+ /**
69421
+ * The group header view for displaying number fields as text.
69422
+ */
69423
+ class TableColumnNumberTextGroupHeaderView extends TableColumnTextGroupHeaderViewBase {
69424
+ updateText() {
69425
+ this.text = this.columnConfig?.formatter?.format(this.groupHeaderValue) ?? '';
69426
+ }
69427
+ }
69428
+ const tableColumnNumberTextGroupHeaderView = TableColumnNumberTextGroupHeaderView.compose({
69429
+ baseName: 'table-column-number-text-group-header-view',
69430
+ template: template$b,
69431
+ styles: styles$c
69432
+ });
69433
+ DesignSystem.getOrCreate()
69434
+ .withPrefix('nimble')
69435
+ .register(tableColumnNumberTextGroupHeaderView());
69436
+ const tableColumnNumberTextGroupHeaderTag = 'nimble-table-column-number-text-group-header-view';
69437
+
69438
+ /**
69439
+ * A cell view for displaying number fields as text
69440
+ */
69441
+ class TableColumnNumberTextCellView extends TableColumnTextCellViewBase {
69442
+ columnConfigChanged() {
69443
+ super.columnConfigChanged();
69444
+ this.alignment = this.columnConfig?.alignment ?? TextCellViewBaseAlignment.left;
69445
+ }
69446
+ updateText() {
69447
+ this.text = this.columnConfig?.formatter?.format(this.cellRecord?.value) ?? '';
69448
+ }
69449
+ }
69450
+ const numberTextCellView = TableColumnNumberTextCellView.compose({
69451
+ baseName: 'table-column-number-text-cell-view',
69452
+ template: template$a,
69453
+ styles: styles$b
69454
+ });
69455
+ DesignSystem.getOrCreate().withPrefix('nimble').register(numberTextCellView());
69456
+ const tableColumnNumberTextCellViewTag = 'nimble-table-column-number-text-cell-view';
69457
+
69458
+ /**
69459
+ * Formatting scheme for the number-text table column
69460
+ */
69461
+ const NumberTextFormat = {
69462
+ default: undefined,
69463
+ decimal: 'decimal'
69464
+ };
69465
+ /**
69466
+ * The aligment of the value in the number-text table column.
69467
+ * The `default` alignment is determined by the column's `NumberTextFormat`.
69468
+ */
69469
+ const NumberTextAlignment = {
69470
+ default: undefined,
69471
+ left: 'left',
69472
+ right: 'right'
69473
+ };
69474
+
69475
+ /**
69476
+ * The base class for unit formats.
69477
+ */
69478
+ class UnitFormat {
69479
+ /**
69480
+ * Formats a number value to a string.
69481
+ * For nullish values or values that result in an exception being thrown, empty string is returned
69482
+ */
69483
+ format(value) {
69484
+ if (typeof value !== 'number') {
69485
+ return '';
69486
+ }
69487
+ try {
69488
+ return this.tryFormat(value);
69489
+ }
69490
+ catch {
69491
+ return '';
69492
+ }
69493
+ }
69494
+ }
69495
+
69496
+ /**
69497
+ * A class that knows how to format a numeric value as a string that includes units.
69498
+ */
69499
+ class ScaledUnitFormat {
69500
+ constructor(scaledUnitFormatFactoryOptions) {
69501
+ this.locale = scaledUnitFormatFactoryOptions.locale;
69502
+ this.intlNumberFormatOptions = scaledUnitFormatFactoryOptions.intlNumberFormatOptions;
69503
+ }
69504
+ }
69505
+
69506
+ /**
69507
+ * A formatter for units that can be formatted/translated by Intl.NumberFormat
69508
+ */
69509
+ class IntlNumberFormatScaledUnitFormat extends ScaledUnitFormat {
69510
+ constructor(scaledUnitFormatFactoryOptions, unitSpecificIntlNumberFormatOptions) {
69511
+ super(scaledUnitFormatFactoryOptions);
69512
+ this.formatter = new Intl.NumberFormat(this.locale, {
69513
+ ...unitSpecificIntlNumberFormatOptions,
69514
+ // Application configured options override unit specific options
69515
+ ...this.intlNumberFormatOptions
69516
+ });
69517
+ }
69518
+ static createFactory(unitSpecificIntlNumberFormatOptions) {
69519
+ return (scaledUnitFormatFactoryOptions) => new IntlNumberFormatScaledUnitFormat(scaledUnitFormatFactoryOptions, unitSpecificIntlNumberFormatOptions);
69520
+ }
69521
+ format(value) {
69522
+ return this.formatter.format(value);
69523
+ }
69524
+ }
69525
+
69526
+ /**
69527
+ * A unit that represents a scaled version of a base unit.
69528
+ */
69529
+ class ScaledUnit {
69530
+ constructor(scaleFactor, scaledUnitFormatFactory) {
69531
+ this.scaleFactor = scaleFactor;
69532
+ this.scaledUnitFormatFactory = scaledUnitFormatFactory;
69533
+ }
69534
+ isBase() {
69535
+ return this.scaleFactor === 1;
69536
+ }
69537
+ }
69538
+
69539
+ /**
69540
+ * A unit scale consisting of a set of scaled units.
69541
+ */
69542
+ class UnitScale {
69543
+ constructor(supportedScaledUnits) {
69544
+ this.supportedScaledUnits = supportedScaledUnits;
69545
+ const unitsSorted = supportedScaledUnits.every((curr, i, arr) => i === 0 || arr[i - 1].scaleFactor < curr.scaleFactor);
69546
+ if (!unitsSorted) {
69547
+ throw new Error('Supported scaled units must have unique and ordered scale factors');
69548
+ }
69549
+ const baseScaledUnit = supportedScaledUnits.find(x => x.isBase());
69550
+ if (!baseScaledUnit) {
69551
+ throw new Error('Supported scaled units must include a base scaled unit (scale factor=1)');
69552
+ }
69553
+ this.supportedScaledUnits = supportedScaledUnits;
69554
+ this.baseScaledUnit = baseScaledUnit;
69555
+ }
69556
+ // Note that for the sake of reducing complexity in the implementation,
69557
+ // we do NOT consider the effects of rounding when picking the unit to
69558
+ // use for a given value. If formatting results in rounding, a value
69559
+ // may be shown with an unexpected unit. Examples:
69560
+ // - 999 bytes with two significant digits => "1000 bytes" (instead of "1 kB")
69561
+ // - 0.00000000000000001 volts (= 0.01 fV) with one fractional digit => "0 fV" (instead of "0 volts")
69562
+ scaleNumber(number) {
69563
+ const magnitude = Math.abs(number);
69564
+ const onlyBaseScaledUnit = this.supportedScaledUnits.length === 1;
69565
+ if (onlyBaseScaledUnit
69566
+ || magnitude === 0
69567
+ || magnitude === Infinity
69568
+ || Number.isNaN(magnitude)) {
69569
+ return { scaledValue: number, scaledUnit: this.baseScaledUnit };
69570
+ }
69571
+ for (let i = this.supportedScaledUnits.length - 1; i >= 0; i -= 1) {
69572
+ const scaledUnit = this.supportedScaledUnits[i];
69573
+ if (magnitude / scaledUnit.scaleFactor >= 1) {
69574
+ return {
69575
+ scaledValue: number / scaledUnit.scaleFactor,
69576
+ scaledUnit
69577
+ };
69578
+ }
69579
+ }
69580
+ const smallestUnit = this.supportedScaledUnits[0];
69581
+ return {
69582
+ scaledValue: number / smallestUnit.scaleFactor,
69583
+ scaledUnit: smallestUnit
69584
+ };
69585
+ }
69586
+ }
69587
+
69588
+ /**
69589
+ * Unit scale that is used to passthrough a number without applying scaling or units
69590
+ */
69591
+ class PassthroughUnitScale extends UnitScale {
69592
+ constructor() {
69593
+ super([
69594
+ new ScaledUnit(10 ** 0, IntlNumberFormatScaledUnitFormat.createFactory({}))
69595
+ ]);
69596
+ }
69597
+ }
69598
+ const passthroughUnitScale = new PassthroughUnitScale();
69599
+
69600
+ // Workaround to avoid ts errors about signDisplay not accepting the value 'negative'.
69601
+ // It has been supported by browsers since 8/23, but TypeScript still hasn't
69602
+ // added it to the type definitions. See https://github.com/microsoft/TypeScript/issues/56269
69603
+ const signDisplay = 'negative';
69604
+ /**
69605
+ * Format for numbers with units to show in a tabular form.
69606
+ * Large and tiny numbers are shown exponentially and the rest as decimal.
69607
+ */
69608
+ class DefaultUnitFormat extends UnitFormat {
69609
+ constructor(locale, { unitScale = passthroughUnitScale } = {
69610
+ unitScale: passthroughUnitScale
69611
+ }) {
69612
+ super();
69047
69613
  // Format options to use by default. It renders the number with a maximum of 6 signficant digits (including zero before decimal point).
69048
69614
  this.defaultIntlNumberFormatOptions = {
69049
69615
  maximumSignificantDigits: DefaultUnitFormat.maximumDigits,
@@ -69424,568 +69990,13 @@ img.ProseMirror-separator {
69424
69990
  ], TableColumnNumberText.prototype, "unit", void 0);
69425
69991
  const nimbleTableColumnNumberText = TableColumnNumberText.compose({
69426
69992
  baseName: 'table-column-number-text',
69427
- template: template$9,
69993
+ template: template$6,
69428
69994
  styles: styles$e
69429
69995
  });
69430
69996
  DesignSystem.getOrCreate()
69431
69997
  .withPrefix('nimble')
69432
69998
  .register(nimbleTableColumnNumberText());
69433
69999
 
69434
- /**
69435
- * Converts a Mapping key (which is a string when configured in HTML) to the
69436
- * given keyType. The converted value can then be used to compare against
69437
- * values in the table data.
69438
- */
69439
- const resolveKeyWithType = (key, keyType) => {
69440
- if (keyType === 'number') {
69441
- const converted = nullableNumberConverter.fromView(key);
69442
- return converted === null ? undefined : converted;
69443
- }
69444
- if (keyType === 'boolean') {
69445
- if (key === false || key === 'false') {
69446
- return false;
69447
- }
69448
- if (key === true || key === 'true') {
69449
- return true;
69450
- }
69451
- return undefined;
69452
- }
69453
- return key?.toString() ?? undefined;
69454
- };
69455
-
69456
- /**
69457
- * Base class for table columns that map values to content
69458
- */
69459
- class TableColumnEnumBase extends TableColumn {
69460
- constructor() {
69461
- super(...arguments);
69462
- /** @internal */
69463
- this.mappingNotifiers = [];
69464
- /** @internal */
69465
- this.mappings = [];
69466
- this.keyType = 'string';
69467
- }
69468
- /**
69469
- * @internal
69470
- *
69471
- * Triggers a request to update the columnConfig when any observable property on
69472
- * a mapping is updated.
69473
- */
69474
- handleChange(source, args) {
69475
- if (source instanceof Mapping$1 && typeof args === 'string') {
69476
- this.updateColumnConfig();
69477
- }
69478
- }
69479
- /**
69480
- * Called when any Mapping related state has changed.
69481
- */
69482
- updateColumnConfig() {
69483
- this.columnInternals.validator.validate(this.mappings, this.keyType);
69484
- this.columnInternals.columnConfig = this.checkValidity()
69485
- ? this.createColumnConfig(this.getMappingConfigs())
69486
- : undefined;
69487
- }
69488
- getMappingConfigs() {
69489
- const mappingConfigs = new Map();
69490
- this.mappings.forEach(mapping => {
69491
- const key = resolveKeyWithType(mapping.key, this.keyType);
69492
- if (key === undefined) {
69493
- throw Error('Key was invalid for type. Validation should have prevented this.');
69494
- }
69495
- const mappingConfig = this.createMappingConfig(mapping);
69496
- mappingConfigs.set(key, mappingConfig);
69497
- });
69498
- return mappingConfigs;
69499
- }
69500
- fieldNameChanged() {
69501
- this.columnInternals.dataRecordFieldNames = [this.fieldName];
69502
- this.columnInternals.operandDataRecordFieldName = this.fieldName;
69503
- }
69504
- mappingsChanged() {
69505
- this.updateColumnConfig();
69506
- this.observeMappings();
69507
- }
69508
- keyTypeChanged() {
69509
- this.updateColumnConfig();
69510
- }
69511
- removeMappingObservers() {
69512
- this.mappingNotifiers.forEach(notifier => {
69513
- notifier.unsubscribe(this);
69514
- });
69515
- this.mappingNotifiers = [];
69516
- }
69517
- observeMappings() {
69518
- this.removeMappingObservers();
69519
- for (const mapping of this.mappings) {
69520
- const notifier = Observable.getNotifier(mapping);
69521
- notifier.subscribe(this);
69522
- this.mappingNotifiers.push(notifier);
69523
- }
69524
- }
69525
- }
69526
- __decorate$1([
69527
- observable
69528
- ], TableColumnEnumBase.prototype, "mappings", void 0);
69529
- __decorate$1([
69530
- attr({ attribute: 'field-name' })
69531
- ], TableColumnEnumBase.prototype, "fieldName", void 0);
69532
- __decorate$1([
69533
- attr({ attribute: 'key-type' })
69534
- ], TableColumnEnumBase.prototype, "keyType", void 0);
69535
-
69536
- const styles$a = css `
69537
- ${styles$e}
69538
-
69539
- slot[name='mapping'] {
69540
- display: none;
69541
- }
69542
- `;
69543
-
69544
- const template$8 = html `${template$d}<slot ${slotted('mappings')} name="mapping"></slot>`;
69545
-
69546
- const enumBaseValidityFlagNames = [
69547
- 'invalidMappingKeyValueForType',
69548
- 'duplicateMappingKey',
69549
- 'missingKeyValue'
69550
- ];
69551
- /**
69552
- * Validator base class for table columns containing mappings. Implementations MUST include enumBaseValidityFlagNames in validity flag names set.
69553
- */
69554
- class TableColumnEnumBaseValidator extends ColumnValidator {
69555
- constructor(configValidityKeys) {
69556
- super(configValidityKeys);
69557
- }
69558
- validate(mappings, keyType) {
69559
- this.untrackAll();
69560
- const keys = mappings.map(mapping => mapping.key);
69561
- this.validateKeyValuesForType(keys, keyType);
69562
- this.validateUniqueKeys(keys, keyType);
69563
- this.validateNoMissingKeys(mappings);
69564
- }
69565
- validateKeyValuesForType(keys, keyType) {
69566
- // Ignore undefined keys, because validateNoMissingKeys covers that case.
69567
- // We should only set 'invalidMappingKeyValueForType' when there is a key,
69568
- // but it isn't appropriate for the type.
69569
- const invalid = keys.some(key => key !== undefined
69570
- && resolveKeyWithType(key, keyType) === undefined);
69571
- this.setConditionValue('invalidMappingKeyValueForType', invalid);
69572
- }
69573
- validateUniqueKeys(keys, keyType) {
69574
- const typedKeys = keys.map(x => resolveKeyWithType(x, keyType));
69575
- const invalid = new Set(typedKeys).size !== typedKeys.length;
69576
- this.setConditionValue('duplicateMappingKey', invalid);
69577
- }
69578
- validateNoMissingKeys(mappings) {
69579
- const invalid = mappings.some(mapping => mapping.key === undefined);
69580
- this.setConditionValue('missingKeyValue', invalid);
69581
- }
69582
- }
69583
-
69584
- const iconValidityFlagNames = [
69585
- ...enumBaseValidityFlagNames,
69586
- 'unsupportedMappingType',
69587
- 'invalidIconName',
69588
- 'missingTextValue'
69589
- ];
69590
- /**
69591
- * Validator for TableColumnIcon
69592
- */
69593
- class TableColumnIconValidator extends TableColumnEnumBaseValidator {
69594
- constructor() {
69595
- super(iconValidityFlagNames);
69596
- }
69597
- static isIconMappingElement(mapping) {
69598
- return mapping instanceof MappingIcon;
69599
- }
69600
- static isSupportedMappingElement(mapping) {
69601
- return (mapping instanceof MappingIcon
69602
- || mapping instanceof MappingSpinner
69603
- || mapping instanceof MappingText);
69604
- }
69605
- static hasUnresolvedIcon(mappingIcon) {
69606
- return (typeof mappingIcon.icon === 'string'
69607
- && mappingIcon.resolvedIcon === undefined);
69608
- }
69609
- validate(mappings, keyType) {
69610
- super.validate(mappings, keyType);
69611
- this.validateMappingTypes(mappings);
69612
- this.validateIconNames(mappings);
69613
- this.validateNoMissingText(mappings);
69614
- }
69615
- validateIconNames(mappings) {
69616
- const invalid = mappings
69617
- .filter(TableColumnIconValidator.isIconMappingElement)
69618
- .some(TableColumnIconValidator.hasUnresolvedIcon);
69619
- this.setConditionValue('invalidIconName', invalid);
69620
- }
69621
- validateNoMissingText(mappings) {
69622
- const invalid = mappings
69623
- .filter(TableColumnIconValidator.isSupportedMappingElement)
69624
- .some(mapping => mapping.text === undefined);
69625
- this.setConditionValue('missingTextValue', invalid);
69626
- }
69627
- validateMappingTypes(mappings) {
69628
- const valid = mappings.every(TableColumnIconValidator.isSupportedMappingElement);
69629
- this.setConditionValue('unsupportedMappingType', !valid);
69630
- }
69631
- }
69632
-
69633
- const styles$9 = css `
69634
- ${display('inline-flex')}
69635
-
69636
- :host {
69637
- gap: ${smallPadding};
69638
- align-items: center;
69639
- }
69640
-
69641
- .reserve-icon-size {
69642
- flex-shrink: 0;
69643
- width: ${iconSize};
69644
- height: ${iconSize};
69645
- }
69646
-
69647
- .text {
69648
- flex-shrink: 1;
69649
- font: ${bodyFont};
69650
- color: ${bodyFontColor};
69651
- white-space: nowrap;
69652
- overflow: hidden;
69653
- text-overflow: ellipsis;
69654
- }
69655
- `;
69656
-
69657
- // prettier-ignore
69658
- const template$7 = html `
69659
- ${when(x => x.visualizationTemplate, html `
69660
- <span class="reserve-icon-size">
69661
- ${x => x.visualizationTemplate}
69662
- </span>
69663
- `)}
69664
- <span
69665
- ${overflow('hasOverflow')}
69666
- title="${x => (x.hasOverflow && x.text ? x.text : null)}"
69667
- class="text"
69668
- >${x => x.text}</span>
69669
- `;
69670
-
69671
- /**
69672
- * Predefined icon appearance states
69673
- * @public
69674
- */
69675
- const IconSeverity = {
69676
- default: undefined,
69677
- error: 'error',
69678
- warning: 'warning',
69679
- success: 'success',
69680
- information: 'information'
69681
- };
69682
-
69683
- /**
69684
- * Common state shared across Mapping Config
69685
- */
69686
- class MappingConfig {
69687
- constructor(text) {
69688
- this.text = text;
69689
- }
69690
- }
69691
-
69692
- // Create an empty template containing only a space because creating a ViewTemplate
69693
- // with an empty string throws an exception at runtime.
69694
- // prettier-ignore
69695
- const emptyTemplate = html ` `;
69696
- const createIconTemplate = (icon) => {
69697
- if (icon === undefined) {
69698
- return emptyTemplate;
69699
- }
69700
- return html `
69701
- <${icon}
69702
- title="${x => (x.textHidden ? x.text : '')}"
69703
- role="img"
69704
- aria-label="${x => x.text}"
69705
- aria-hidden="${x => (x.textHidden ? 'false' : 'true')}"
69706
- severity="${x => x.severity}"
69707
- >
69708
- </${icon}>
69709
- `;
69710
- };
69711
- /**
69712
- * Mapping configuration corresponding to a icon mapping
69713
- */
69714
- class MappingIconConfig extends MappingConfig {
69715
- constructor(resolvedIcon, severity, text, textHidden) {
69716
- super(text);
69717
- this.severity = severity;
69718
- this.textHidden = textHidden;
69719
- this.iconTemplate = createIconTemplate(resolvedIcon);
69720
- }
69721
- }
69722
-
69723
- const spinnerTemplate = html `
69724
- <${spinnerTag}
69725
- title="${x => (x.textHidden ? x.text : '')}"
69726
- aria-label="${x => x.text}"
69727
- aria-hidden="${x => (x.textHidden ? 'false' : 'true')}"
69728
- >
69729
- </${spinnerTag}>
69730
- `;
69731
- /**
69732
- * Mapping configuration corresponding to a spinner mapping
69733
- */
69734
- class MappingSpinnerConfig extends MappingConfig {
69735
- constructor(text, textHidden) {
69736
- super(text);
69737
- this.textHidden = textHidden;
69738
- this.spinnerTemplate = spinnerTemplate;
69739
- }
69740
- }
69741
-
69742
- /**
69743
- * Mapping configuration corresponding to a text mapping
69744
- */
69745
- class MappingTextConfig extends MappingConfig {
69746
- }
69747
-
69748
- /**
69749
- * The group header view for the icon column
69750
- */
69751
- class TableColumnIconGroupHeaderView extends TableColumnTextGroupHeaderViewBase {
69752
- constructor() {
69753
- super(...arguments);
69754
- this.textHidden = false;
69755
- }
69756
- updateText() {
69757
- this.resetState();
69758
- if (!this.columnConfig) {
69759
- return;
69760
- }
69761
- const value = this.groupHeaderValue;
69762
- const mappingConfig = this.columnConfig.mappingConfigs.get(value);
69763
- if (mappingConfig instanceof MappingIconConfig) {
69764
- this.severity = mappingConfig.severity;
69765
- this.text = mappingConfig.text ?? '';
69766
- this.visualizationTemplate = mappingConfig.iconTemplate;
69767
- }
69768
- else if (mappingConfig instanceof MappingSpinnerConfig) {
69769
- this.text = mappingConfig.text ?? '';
69770
- this.visualizationTemplate = mappingConfig.spinnerTemplate;
69771
- }
69772
- else if (mappingConfig instanceof MappingTextConfig) {
69773
- this.text = mappingConfig.text ?? '';
69774
- }
69775
- }
69776
- resetState() {
69777
- this.text = '';
69778
- this.visualizationTemplate = undefined;
69779
- this.severity = IconSeverity.default;
69780
- }
69781
- }
69782
- __decorate$1([
69783
- observable
69784
- ], TableColumnIconGroupHeaderView.prototype, "severity", void 0);
69785
- __decorate$1([
69786
- observable
69787
- ], TableColumnIconGroupHeaderView.prototype, "visualizationTemplate", void 0);
69788
- const iconGroupHeaderView = TableColumnIconGroupHeaderView.compose({
69789
- baseName: 'table-column-icon-group-header-view',
69790
- template: template$7,
69791
- styles: styles$9
69792
- });
69793
- DesignSystem.getOrCreate().withPrefix('nimble').register(iconGroupHeaderView());
69794
- const tableColumnIconGroupHeaderViewTag = 'nimble-table-column-icon-group-header-view';
69795
-
69796
- const styles$8 = css `
69797
- ${display('inline-flex')}
69798
-
69799
- :host {
69800
- gap: ${smallPadding};
69801
- align-items: center;
69802
- }
69803
-
69804
- .reserve-icon-size {
69805
- flex-shrink: 0;
69806
- width: ${iconSize};
69807
- height: ${iconSize};
69808
- }
69809
-
69810
- .text {
69811
- flex-shrink: 1;
69812
- font: ${bodyFont};
69813
- color: ${bodyFontColor};
69814
- white-space: nowrap;
69815
- overflow: hidden;
69816
- text-overflow: ellipsis;
69817
- }
69818
- `;
69819
-
69820
- // prettier-ignore
69821
- const template$6 = html `
69822
- ${when(x => x.visualizationTemplate, html `
69823
- <span class="reserve-icon-size">
69824
- ${x => x.visualizationTemplate}
69825
- </span>
69826
- `)}
69827
- ${when(x => !x.textHidden, html `
69828
- <span
69829
- ${overflow('hasOverflow')}
69830
- title=${x => (x.hasOverflow && x.text ? x.text : null)}
69831
- class="text"
69832
- >
69833
- ${x => x.text}
69834
- </span>
69835
- `)}
69836
- `;
69837
-
69838
- /**
69839
- * The cell view for the icon column
69840
- */
69841
- class TableColumnIconCellView extends TableCellView {
69842
- constructor() {
69843
- super(...arguments);
69844
- this.textHidden = false;
69845
- /** @internal */
69846
- this.hasOverflow = false;
69847
- }
69848
- columnConfigChanged() {
69849
- this.updateState();
69850
- }
69851
- cellRecordChanged() {
69852
- this.updateState();
69853
- }
69854
- updateState() {
69855
- this.resetState();
69856
- if (!this.columnConfig || !this.cellRecord) {
69857
- return;
69858
- }
69859
- const value = this.cellRecord.value;
69860
- if (value === undefined || value === null) {
69861
- return;
69862
- }
69863
- const mappingConfig = this.columnConfig.mappingConfigs.get(value);
69864
- if (mappingConfig instanceof MappingIconConfig) {
69865
- this.severity = mappingConfig.severity;
69866
- this.text = mappingConfig.text;
69867
- this.visualizationTemplate = mappingConfig.iconTemplate;
69868
- this.textHidden = mappingConfig.textHidden;
69869
- }
69870
- else if (mappingConfig instanceof MappingSpinnerConfig) {
69871
- this.text = mappingConfig.text;
69872
- this.visualizationTemplate = mappingConfig.spinnerTemplate;
69873
- this.textHidden = mappingConfig.textHidden;
69874
- }
69875
- else if (mappingConfig instanceof MappingTextConfig) {
69876
- this.text = mappingConfig.text;
69877
- this.textHidden = false;
69878
- }
69879
- }
69880
- resetState() {
69881
- this.text = undefined;
69882
- this.textHidden = false;
69883
- this.visualizationTemplate = undefined;
69884
- this.severity = IconSeverity.default;
69885
- }
69886
- }
69887
- __decorate$1([
69888
- observable
69889
- ], TableColumnIconCellView.prototype, "severity", void 0);
69890
- __decorate$1([
69891
- observable
69892
- ], TableColumnIconCellView.prototype, "text", void 0);
69893
- __decorate$1([
69894
- observable
69895
- ], TableColumnIconCellView.prototype, "visualizationTemplate", void 0);
69896
- __decorate$1([
69897
- observable
69898
- ], TableColumnIconCellView.prototype, "textHidden", void 0);
69899
- __decorate$1([
69900
- observable
69901
- ], TableColumnIconCellView.prototype, "hasOverflow", void 0);
69902
- const iconCellView = TableColumnIconCellView.compose({
69903
- baseName: 'table-column-icon-cell-view',
69904
- template: template$6,
69905
- styles: styles$8
69906
- });
69907
- DesignSystem.getOrCreate().withPrefix('nimble').register(iconCellView());
69908
- const tableColumnIconCellViewTag = 'nimble-table-column-icon-cell-view';
69909
-
69910
- /**
69911
- * Width mode for the icon column
69912
- */
69913
- const TableColumnMappingWidthMode = {
69914
- default: undefined,
69915
- iconSize: 'icon-size'
69916
- };
69917
-
69918
- /**
69919
- * Table column that maps values to icons / spinners
69920
- */
69921
- class TableColumnIcon extends mixinGroupableColumnAPI(mixinFractionalWidthColumnAPI((TableColumnEnumBase))) {
69922
- minPixelWidthChanged() {
69923
- if (this.widthMode !== TableColumnMappingWidthMode.iconSize) {
69924
- this.columnInternals.minPixelWidth = this.getConfiguredMinPixelWidth();
69925
- }
69926
- }
69927
- getColumnInternalsOptions() {
69928
- return {
69929
- cellRecordFieldNames: ['value'],
69930
- cellViewTag: tableColumnIconCellViewTag,
69931
- groupHeaderViewTag: tableColumnIconGroupHeaderViewTag,
69932
- delegatedEvents: [],
69933
- sortOperation: TableColumnSortOperation.basic,
69934
- validator: new TableColumnIconValidator()
69935
- };
69936
- }
69937
- createColumnConfig(mappingConfigs) {
69938
- return {
69939
- mappingConfigs
69940
- };
69941
- }
69942
- createMappingConfig(mapping) {
69943
- if (mapping instanceof MappingIcon) {
69944
- return new MappingIconConfig(mapping.resolvedIcon, mapping.severity, mapping.text, mapping.textHidden);
69945
- }
69946
- if (mapping instanceof MappingSpinner) {
69947
- return new MappingSpinnerConfig(mapping.text, mapping.textHidden);
69948
- }
69949
- if (mapping instanceof MappingText) {
69950
- return new MappingTextConfig(mapping.text);
69951
- }
69952
- // Getting here would indicate a programming error, b/c validation will prevent
69953
- // this function from running when there is an unsupported mapping.
69954
- throw new Error('Unsupported mapping');
69955
- }
69956
- widthModeChanged() {
69957
- if (this.widthMode === TableColumnMappingWidthMode.iconSize) {
69958
- this.columnInternals.resizingDisabled = true;
69959
- this.columnInternals.hideHeaderIndicators = true;
69960
- this.columnInternals.pixelWidth = singleIconColumnWidth;
69961
- this.columnInternals.minPixelWidth = singleIconColumnWidth;
69962
- }
69963
- else {
69964
- this.columnInternals.resizingDisabled = false;
69965
- this.columnInternals.hideHeaderIndicators = false;
69966
- this.columnInternals.pixelWidth = undefined;
69967
- this.columnInternals.minPixelWidth = this.getConfiguredMinPixelWidth();
69968
- }
69969
- }
69970
- getConfiguredMinPixelWidth() {
69971
- if (typeof this.minPixelWidth === 'number') {
69972
- return this.minPixelWidth;
69973
- }
69974
- return defaultMinPixelWidth;
69975
- }
69976
- }
69977
- __decorate$1([
69978
- attr({ attribute: 'width-mode' })
69979
- ], TableColumnIcon.prototype, "widthMode", void 0);
69980
- const nimbleTableColumnIcon = TableColumnIcon.compose({
69981
- baseName: 'table-column-icon',
69982
- template: template$8,
69983
- styles: styles$a
69984
- });
69985
- DesignSystem.getOrCreate()
69986
- .withPrefix('nimble')
69987
- .register(nimbleTableColumnIcon());
69988
-
69989
70000
  /**
69990
70001
  * A cell view for displaying string fields as text
69991
70002
  */