@ni/nimble-components 27.2.3 → 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 (65) hide show
  1. package/dist/all-components-bundle.js +809 -806
  2. package/dist/all-components-bundle.js.map +1 -1
  3. package/dist/all-components-bundle.min.js +93 -93
  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/mapping/icon/index.d.ts +1 -1
  9. package/dist/esm/mapping/icon/index.js +1 -1
  10. package/dist/esm/mapping/icon/index.js.map +1 -1
  11. package/dist/esm/mapping/spinner/index.d.ts +1 -1
  12. package/dist/esm/mapping/spinner/index.js +1 -1
  13. package/dist/esm/mapping/spinner/index.js.map +1 -1
  14. package/dist/esm/mapping/text/index.d.ts +1 -1
  15. package/dist/esm/mapping/text/index.js +1 -1
  16. package/dist/esm/mapping/text/index.js.map +1 -1
  17. package/dist/esm/table/testing/table.pageobject.d.ts +2 -2
  18. package/dist/esm/table/testing/table.pageobject.js +3 -3
  19. package/dist/esm/table/testing/table.pageobject.js.map +1 -1
  20. package/dist/esm/table-column/enum-base/types.d.ts +1 -1
  21. package/dist/esm/table-column/enum-base/types.js +1 -1
  22. package/dist/esm/table-column/enum-base/types.js.map +1 -1
  23. package/dist/esm/table-column/{icon → mapping}/cell-view/index.d.ts +4 -4
  24. package/dist/esm/table-column/{icon → mapping}/cell-view/index.js +11 -11
  25. package/dist/esm/table-column/mapping/cell-view/index.js.map +1 -0
  26. package/dist/esm/table-column/mapping/cell-view/styles.js.map +1 -0
  27. package/dist/esm/table-column/mapping/cell-view/template.d.ts +2 -0
  28. package/dist/esm/table-column/mapping/cell-view/template.js.map +1 -0
  29. package/dist/esm/table-column/{icon → mapping}/group-header-view/index.d.ts +4 -4
  30. package/dist/esm/table-column/{icon → mapping}/group-header-view/index.js +10 -8
  31. package/dist/esm/table-column/mapping/group-header-view/index.js.map +1 -0
  32. package/dist/esm/table-column/mapping/group-header-view/styles.js.map +1 -0
  33. package/dist/esm/table-column/mapping/group-header-view/template.d.ts +2 -0
  34. package/dist/esm/table-column/mapping/group-header-view/template.js.map +1 -0
  35. package/dist/esm/table-column/{icon → mapping}/index.d.ts +9 -8
  36. package/dist/esm/table-column/{icon → mapping}/index.js +14 -13
  37. package/dist/esm/table-column/mapping/index.js.map +1 -0
  38. package/dist/esm/table-column/{icon/models/table-column-icon-validator.d.ts → mapping/models/table-column-mapping-validator.d.ts} +3 -3
  39. package/dist/esm/table-column/{icon/models/table-column-icon-validator.js → mapping/models/table-column-mapping-validator.js} +9 -9
  40. package/dist/esm/table-column/mapping/models/table-column-mapping-validator.js.map +1 -0
  41. package/dist/esm/table-column/{icon/testing/table-column-icon.pageobject.d.ts → mapping/testing/table-column-mapping.pageobject.d.ts} +2 -2
  42. package/dist/esm/table-column/{icon/testing/table-column-icon.pageobject.js → mapping/testing/table-column-mapping.pageobject.js} +3 -3
  43. package/dist/esm/table-column/mapping/testing/table-column-mapping.pageobject.js.map +1 -0
  44. package/dist/esm/table-column/{icon → mapping}/types.d.ts +1 -1
  45. package/dist/esm/table-column/{icon → mapping}/types.js +1 -1
  46. package/dist/esm/table-column/mapping/types.js.map +1 -0
  47. package/package.json +1 -1
  48. package/dist/esm/table-column/icon/cell-view/index.js.map +0 -1
  49. package/dist/esm/table-column/icon/cell-view/styles.js.map +0 -1
  50. package/dist/esm/table-column/icon/cell-view/template.d.ts +0 -2
  51. package/dist/esm/table-column/icon/cell-view/template.js.map +0 -1
  52. package/dist/esm/table-column/icon/group-header-view/index.js.map +0 -1
  53. package/dist/esm/table-column/icon/group-header-view/styles.js.map +0 -1
  54. package/dist/esm/table-column/icon/group-header-view/template.d.ts +0 -2
  55. package/dist/esm/table-column/icon/group-header-view/template.js.map +0 -1
  56. package/dist/esm/table-column/icon/index.js.map +0 -1
  57. package/dist/esm/table-column/icon/models/table-column-icon-validator.js.map +0 -1
  58. package/dist/esm/table-column/icon/testing/table-column-icon.pageobject.js.map +0 -1
  59. package/dist/esm/table-column/icon/types.js.map +0 -1
  60. /package/dist/esm/table-column/{icon → mapping}/cell-view/styles.d.ts +0 -0
  61. /package/dist/esm/table-column/{icon → mapping}/cell-view/styles.js +0 -0
  62. /package/dist/esm/table-column/{icon → mapping}/cell-view/template.js +0 -0
  63. /package/dist/esm/table-column/{icon → mapping}/group-header-view/styles.d.ts +0 -0
  64. /package/dist/esm/table-column/{icon → mapping}/group-header-view/styles.js +0 -0
  65. /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 Thu, 02 May 2024 18:40:05 GMT
16336
+ * Generated on Mon, 06 May 2024 18:46:24 GMT
16337
16337
  */
16338
16338
 
16339
16339
  const Information100DarkUi = "#a46eff";
@@ -24915,7 +24915,7 @@
24915
24915
 
24916
24916
  /**
24917
24917
  * Defines a mapping from one data value ('key' property) to display text ('text' property).
24918
- * 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
24919
24919
  * how a specific data value should be displayed as text in that column's cells.
24920
24920
  */
24921
24921
  class MappingText extends Mapping$1 {
@@ -24934,7 +24934,7 @@
24934
24934
  }
24935
24935
  /**
24936
24936
  * Maps a data value to an icon.
24937
- * 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
24938
24938
  * how specific data values should be displayed as icons in that column's cells.
24939
24939
  */
24940
24940
  class MappingIcon extends Mapping$1 {
@@ -25001,7 +25001,7 @@
25001
25001
 
25002
25002
  /**
25003
25003
  * Maps data values to a spinner.
25004
- * 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
25005
25005
  * which specific data values should be displayed as spinners in that column's cells.
25006
25006
  */
25007
25007
  class MappingSpinner extends Mapping$1 {
@@ -68847,598 +68847,6 @@ img.ProseMirror-separator {
68847
68847
  .withPrefix('nimble')
68848
68848
  .register(nimbleTableColumnDurationText());
68849
68849
 
68850
- // Avoiding a wrapping <template> and be careful about starting and ending whitespace
68851
- // so the template can be composed into other column header templates
68852
- // prettier-ignore
68853
- const template$9 = html `<span
68854
- ${overflow('hasOverflow')}
68855
- class="header-content"
68856
- title=${x => (x.hasOverflow && x.headerTextContent ? x.headerTextContent : null)}
68857
- >
68858
- <slot ${ref('contentSlot')}></slot>
68859
- <slot ${slotted({ property: 'unitElements', filter: elements() })} name="unit"></slot>
68860
- </span>`;
68861
-
68862
- /**
68863
- * The group header view for displaying number fields as text.
68864
- */
68865
- class TableColumnNumberTextGroupHeaderView extends TableColumnTextGroupHeaderViewBase {
68866
- updateText() {
68867
- this.text = this.columnConfig?.formatter?.format(this.groupHeaderValue) ?? '';
68868
- }
68869
- }
68870
- const tableColumnNumberTextGroupHeaderView = TableColumnNumberTextGroupHeaderView.compose({
68871
- baseName: 'table-column-number-text-group-header-view',
68872
- template: template$b,
68873
- styles: styles$c
68874
- });
68875
- DesignSystem.getOrCreate()
68876
- .withPrefix('nimble')
68877
- .register(tableColumnNumberTextGroupHeaderView());
68878
- const tableColumnNumberTextGroupHeaderTag = 'nimble-table-column-number-text-group-header-view';
68879
-
68880
- /**
68881
- * A cell view for displaying number fields as text
68882
- */
68883
- class TableColumnNumberTextCellView extends TableColumnTextCellViewBase {
68884
- columnConfigChanged() {
68885
- super.columnConfigChanged();
68886
- this.alignment = this.columnConfig?.alignment ?? TextCellViewBaseAlignment.left;
68887
- }
68888
- updateText() {
68889
- this.text = this.columnConfig?.formatter?.format(this.cellRecord?.value) ?? '';
68890
- }
68891
- }
68892
- const numberTextCellView = TableColumnNumberTextCellView.compose({
68893
- baseName: 'table-column-number-text-cell-view',
68894
- template: template$a,
68895
- styles: styles$b
68896
- });
68897
- DesignSystem.getOrCreate().withPrefix('nimble').register(numberTextCellView());
68898
- const tableColumnNumberTextCellViewTag = 'nimble-table-column-number-text-cell-view';
68899
-
68900
- /**
68901
- * Formatting scheme for the number-text table column
68902
- */
68903
- const NumberTextFormat = {
68904
- default: undefined,
68905
- decimal: 'decimal'
68906
- };
68907
- /**
68908
- * The aligment of the value in the number-text table column.
68909
- * The `default` alignment is determined by the column's `NumberTextFormat`.
68910
- */
68911
- const NumberTextAlignment = {
68912
- default: undefined,
68913
- left: 'left',
68914
- right: 'right'
68915
- };
68916
-
68917
- /**
68918
- * The base class for unit formats.
68919
- */
68920
- class UnitFormat {
68921
- /**
68922
- * Formats a number value to a string.
68923
- * For nullish values or values that result in an exception being thrown, empty string is returned
68924
- */
68925
- format(value) {
68926
- if (typeof value !== 'number') {
68927
- return '';
68928
- }
68929
- try {
68930
- return this.tryFormat(value);
68931
- }
68932
- catch {
68933
- return '';
68934
- }
68935
- }
68936
- }
68937
-
68938
- /**
68939
- * A class that knows how to format a numeric value as a string that includes units.
68940
- */
68941
- class ScaledUnitFormat {
68942
- constructor(scaledUnitFormatFactoryOptions) {
68943
- this.locale = scaledUnitFormatFactoryOptions.locale;
68944
- this.intlNumberFormatOptions = scaledUnitFormatFactoryOptions.intlNumberFormatOptions;
68945
- }
68946
- }
68947
-
68948
- /**
68949
- * A formatter for units that can be formatted/translated by Intl.NumberFormat
68950
- */
68951
- class IntlNumberFormatScaledUnitFormat extends ScaledUnitFormat {
68952
- constructor(scaledUnitFormatFactoryOptions, unitSpecificIntlNumberFormatOptions) {
68953
- super(scaledUnitFormatFactoryOptions);
68954
- this.formatter = new Intl.NumberFormat(this.locale, {
68955
- ...unitSpecificIntlNumberFormatOptions,
68956
- // Application configured options override unit specific options
68957
- ...this.intlNumberFormatOptions
68958
- });
68959
- }
68960
- static createFactory(unitSpecificIntlNumberFormatOptions) {
68961
- return (scaledUnitFormatFactoryOptions) => new IntlNumberFormatScaledUnitFormat(scaledUnitFormatFactoryOptions, unitSpecificIntlNumberFormatOptions);
68962
- }
68963
- format(value) {
68964
- return this.formatter.format(value);
68965
- }
68966
- }
68967
-
68968
- /**
68969
- * A unit that represents a scaled version of a base unit.
68970
- */
68971
- class ScaledUnit {
68972
- constructor(scaleFactor, scaledUnitFormatFactory) {
68973
- this.scaleFactor = scaleFactor;
68974
- this.scaledUnitFormatFactory = scaledUnitFormatFactory;
68975
- }
68976
- isBase() {
68977
- return this.scaleFactor === 1;
68978
- }
68979
- }
68980
-
68981
- /**
68982
- * A unit scale consisting of a set of scaled units.
68983
- */
68984
- class UnitScale {
68985
- constructor(supportedScaledUnits) {
68986
- this.supportedScaledUnits = supportedScaledUnits;
68987
- const unitsSorted = supportedScaledUnits.every((curr, i, arr) => i === 0 || arr[i - 1].scaleFactor < curr.scaleFactor);
68988
- if (!unitsSorted) {
68989
- throw new Error('Supported scaled units must have unique and ordered scale factors');
68990
- }
68991
- const baseScaledUnit = supportedScaledUnits.find(x => x.isBase());
68992
- if (!baseScaledUnit) {
68993
- throw new Error('Supported scaled units must include a base scaled unit (scale factor=1)');
68994
- }
68995
- this.supportedScaledUnits = supportedScaledUnits;
68996
- this.baseScaledUnit = baseScaledUnit;
68997
- }
68998
- // Note that for the sake of reducing complexity in the implementation,
68999
- // we do NOT consider the effects of rounding when picking the unit to
69000
- // use for a given value. If formatting results in rounding, a value
69001
- // may be shown with an unexpected unit. Examples:
69002
- // - 999 bytes with two significant digits => "1000 bytes" (instead of "1 kB")
69003
- // - 0.00000000000000001 volts (= 0.01 fV) with one fractional digit => "0 fV" (instead of "0 volts")
69004
- scaleNumber(number) {
69005
- const magnitude = Math.abs(number);
69006
- const onlyBaseScaledUnit = this.supportedScaledUnits.length === 1;
69007
- if (onlyBaseScaledUnit
69008
- || magnitude === 0
69009
- || magnitude === Infinity
69010
- || Number.isNaN(magnitude)) {
69011
- return { scaledValue: number, scaledUnit: this.baseScaledUnit };
69012
- }
69013
- for (let i = this.supportedScaledUnits.length - 1; i >= 0; i -= 1) {
69014
- const scaledUnit = this.supportedScaledUnits[i];
69015
- if (magnitude / scaledUnit.scaleFactor >= 1) {
69016
- return {
69017
- scaledValue: number / scaledUnit.scaleFactor,
69018
- scaledUnit
69019
- };
69020
- }
69021
- }
69022
- const smallestUnit = this.supportedScaledUnits[0];
69023
- return {
69024
- scaledValue: number / smallestUnit.scaleFactor,
69025
- scaledUnit: smallestUnit
69026
- };
69027
- }
69028
- }
69029
-
69030
- /**
69031
- * Unit scale that is used to passthrough a number without applying scaling or units
69032
- */
69033
- class PassthroughUnitScale extends UnitScale {
69034
- constructor() {
69035
- super([
69036
- new ScaledUnit(10 ** 0, IntlNumberFormatScaledUnitFormat.createFactory({}))
69037
- ]);
69038
- }
69039
- }
69040
- const passthroughUnitScale = new PassthroughUnitScale();
69041
-
69042
- // Workaround to avoid ts errors about signDisplay not accepting the value 'negative'.
69043
- // It has been supported by browsers since 8/23, but TypeScript still hasn't
69044
- // added it to the type definitions. See https://github.com/microsoft/TypeScript/issues/56269
69045
- const signDisplay = 'negative';
69046
- /**
69047
- * Format for numbers with units to show in a tabular form.
69048
- * Large and tiny numbers are shown exponentially and the rest as decimal.
69049
- */
69050
- class DefaultUnitFormat extends UnitFormat {
69051
- constructor(locale, { unitScale = passthroughUnitScale } = {
69052
- unitScale: passthroughUnitScale
69053
- }) {
69054
- super();
69055
- // Format options to use by default. It renders the number with a maximum of 6 signficant digits (including zero before decimal point).
69056
- this.defaultIntlNumberFormatOptions = {
69057
- maximumSignificantDigits: DefaultUnitFormat.maximumDigits,
69058
- maximumFractionDigits: DefaultUnitFormat.maximumDigits - 1,
69059
- roundingPriority: 'lessPrecision',
69060
- signDisplay
69061
- };
69062
- this.defaultScaledUnitFormatters = new Map();
69063
- // Format options for numbers that should be displayed in exponential notation. This should be used
69064
- // for numbers with magintudes over 'exponentialUpperBound' or under 'exponentialLowerBound'.
69065
- this.exponentialIntlNumberFormatOptions = {
69066
- maximumSignificantDigits: DefaultUnitFormat.maximumDigits,
69067
- notation: 'scientific',
69068
- signDisplay
69069
- };
69070
- for (const unit of unitScale.supportedScaledUnits) {
69071
- this.defaultScaledUnitFormatters.set(unit.scaleFactor, unit.scaledUnitFormatFactory({
69072
- locale,
69073
- intlNumberFormatOptions: this.defaultIntlNumberFormatOptions
69074
- }));
69075
- }
69076
- this.exponentialScaledUnitFormatter = unitScale.baseScaledUnit.scaledUnitFormatFactory({
69077
- locale,
69078
- intlNumberFormatOptions: this.exponentialIntlNumberFormatOptions
69079
- });
69080
- this.unitScale = unitScale;
69081
- }
69082
- resolvedOptions() {
69083
- return {
69084
- unitScale: this.unitScale
69085
- };
69086
- }
69087
- tryFormat(number) {
69088
- const { scaledValue, scaledUnit } = this.unitScale.scaleNumber(number);
69089
- const absoluteValue = Math.abs(scaledValue);
69090
- const useExponential = absoluteValue !== 0
69091
- && (absoluteValue >= DefaultUnitFormat.exponentialUpperBound
69092
- || absoluteValue < DefaultUnitFormat.exponentialLowerBound);
69093
- return useExponential
69094
- ? this.exponentialScaledUnitFormatter.format(number)
69095
- : this.defaultScaledUnitFormatters
69096
- .get(scaledUnit.scaleFactor)
69097
- .format(scaledValue);
69098
- }
69099
- }
69100
- // The maximum number of digits that should be rendered for any given value.
69101
- DefaultUnitFormat.maximumDigits = 6;
69102
- // Use exponential notation for numbers that will be rendered with 3 leading 0s or more.
69103
- // Because a maximum of 6 digits are rendered, showing more than 3 leading 0s is not ideal
69104
- // because then at least half of the displayed digits will be leading 0s.
69105
- DefaultUnitFormat.exponentialLowerBound = 0.000995;
69106
- // Use exponential formatting for numbers whose magnitude cannot otherwise be displayed
69107
- // with 6 digits or less.
69108
- DefaultUnitFormat.exponentialUpperBound = 999999.5;
69109
-
69110
- /**
69111
- * Format for decimal numbers with units.
69112
- */
69113
- class DecimalUnitFormat extends UnitFormat {
69114
- constructor(locale, { minimumFractionDigits = 0, maximumFractionDigits = Math.max(3, minimumFractionDigits), unitScale = passthroughUnitScale } = {
69115
- minimumFractionDigits: 0,
69116
- maximumFractionDigits: 3,
69117
- unitScale: passthroughUnitScale
69118
- }) {
69119
- super();
69120
- this.scaledUnitFormatters = new Map();
69121
- // Workaround to avoid a ts error about signDisplay not accepting the value 'negative'.
69122
- // It has been supported by browsers since 8/23, but TypeScript still hasn't
69123
- // added it to the type definitions. See https://github.com/microsoft/TypeScript/issues/56269
69124
- const signDisplay = 'negative';
69125
- const intlNumberFormatOptions = {
69126
- maximumFractionDigits,
69127
- minimumFractionDigits,
69128
- signDisplay
69129
- };
69130
- for (const scaledUnit of unitScale.supportedScaledUnits) {
69131
- this.scaledUnitFormatters.set(scaledUnit.scaleFactor, scaledUnit.scaledUnitFormatFactory({
69132
- locale,
69133
- intlNumberFormatOptions
69134
- }));
69135
- }
69136
- this.unitScale = unitScale;
69137
- this.minimumFractionDigits = minimumFractionDigits;
69138
- this.maximumFractionDigits = maximumFractionDigits;
69139
- }
69140
- resolvedOptions() {
69141
- return {
69142
- unitScale: this.unitScale,
69143
- maximumFractionDigits: this.maximumFractionDigits,
69144
- minimumFractionDigits: this.minimumFractionDigits
69145
- };
69146
- }
69147
- tryFormat(number) {
69148
- const { scaledValue, scaledUnit } = this.unitScale.scaleNumber(number);
69149
- const scaledUnitFormatter = this.scaledUnitFormatters.get(scaledUnit.scaleFactor);
69150
- return scaledUnitFormatter.format(scaledValue);
69151
- }
69152
- }
69153
-
69154
- /**
69155
- * Format for numbers (with optional units) in a number-text table column.
69156
- */
69157
- class NumberTextUnitFormat extends UnitFormat {
69158
- constructor(locale, options) {
69159
- super();
69160
- this._resolvedOptions = this.resolveOptions(options);
69161
- this.resolvedUnitFormat = this.resolveUnitFormat(locale, this._resolvedOptions);
69162
- }
69163
- resolvedOptions() {
69164
- return { ...this._resolvedOptions };
69165
- }
69166
- optionsMatch(targetOptions) {
69167
- const targetResolvedOptions = this.resolveOptions(targetOptions);
69168
- return (this._resolvedOptions.decimalDigits
69169
- === targetResolvedOptions.decimalDigits
69170
- && this._resolvedOptions.decimalMaximumDigits
69171
- === targetResolvedOptions.decimalMaximumDigits
69172
- && this._resolvedOptions.numberTextFormat
69173
- === targetResolvedOptions.numberTextFormat
69174
- && this._resolvedOptions.unitScale === targetResolvedOptions.unitScale);
69175
- }
69176
- tryFormat(number) {
69177
- return this.resolvedUnitFormat.format(number);
69178
- }
69179
- resolveUnitFormat(locale, options) {
69180
- const { numberTextFormat, decimalMaximumDigits, decimalDigits, unitScale } = options;
69181
- if (numberTextFormat === NumberTextFormat.default) {
69182
- return new DefaultUnitFormat(locale, {
69183
- unitScale
69184
- });
69185
- }
69186
- if (typeof decimalDigits === 'number') {
69187
- return new DecimalUnitFormat(locale, {
69188
- minimumFractionDigits: decimalDigits,
69189
- maximumFractionDigits: decimalDigits,
69190
- unitScale
69191
- });
69192
- }
69193
- return new DecimalUnitFormat(locale, {
69194
- minimumFractionDigits: 0,
69195
- maximumFractionDigits: decimalMaximumDigits,
69196
- unitScale
69197
- });
69198
- }
69199
- resolveOptions(options) {
69200
- if (!options || options.numberTextFormat === NumberTextFormat.default) {
69201
- return {
69202
- numberTextFormat: NumberTextFormat.default,
69203
- decimalDigits: undefined,
69204
- decimalMaximumDigits: undefined,
69205
- unitScale: options?.unitScale ?? passthroughUnitScale
69206
- };
69207
- }
69208
- const hasDecimalDigits = typeof options.decimalDigits === 'number';
69209
- const hasDecimalMaximumDigits = typeof options.decimalMaximumDigits === 'number';
69210
- if (hasDecimalDigits && hasDecimalMaximumDigits) {
69211
- throw new Error('decimalDigits and decimalMaximumDigits are mutually exclusive. Do not specify both.');
69212
- }
69213
- if (!hasDecimalDigits && !hasDecimalMaximumDigits) {
69214
- return {
69215
- numberTextFormat: NumberTextFormat.decimal,
69216
- decimalDigits: NumberTextUnitFormat.defaultDecimalDigits,
69217
- decimalMaximumDigits: undefined,
69218
- unitScale: options.unitScale ?? passthroughUnitScale
69219
- };
69220
- }
69221
- return {
69222
- numberTextFormat: NumberTextFormat.decimal,
69223
- decimalDigits: options.decimalDigits,
69224
- decimalMaximumDigits: options.decimalMaximumDigits,
69225
- unitScale: options.unitScale ?? passthroughUnitScale
69226
- };
69227
- }
69228
- }
69229
- NumberTextUnitFormat.defaultDecimalDigits = 2;
69230
-
69231
- const numberTextValidityFlagNames = [
69232
- 'invalidDecimalDigits',
69233
- 'invalidDecimalMaximumDigits',
69234
- 'decimalDigitsMutuallyExclusiveWithDecimalMaximumDigits',
69235
- 'moreThanOneUnitSpecified'
69236
- ];
69237
- // The maximum and minimum allowed configuration for 'maximumFractionDigits'
69238
- // and 'minimumFractionDigits' on the NumberFormat.
69239
- const minimumValidDecimalDigits = 0;
69240
- const maximumValidDecimalDigits = 20;
69241
- /**
69242
- * Validator for TableColumnNumberText.
69243
- */
69244
- class TableColumnNumberTextValidator extends ColumnValidator {
69245
- constructor() {
69246
- super(numberTextValidityFlagNames);
69247
- }
69248
- validateDecimalDigits(format, decimalDigits) {
69249
- const shouldValidateDecimalDigitsValue = format === NumberTextFormat.decimal
69250
- && typeof decimalDigits === 'number';
69251
- const invalid = shouldValidateDecimalDigitsValue
69252
- ? this.isInvalidDecimalDigitsValue(decimalDigits)
69253
- : false;
69254
- this.setConditionValue('invalidDecimalDigits', invalid);
69255
- }
69256
- validateDecimalMaximumDigits(format, decimalMaximumDigits) {
69257
- const shouldValidateDecimalDigitsValue = format === NumberTextFormat.decimal
69258
- && typeof decimalMaximumDigits === 'number';
69259
- const invalid = shouldValidateDecimalDigitsValue
69260
- ? this.isInvalidDecimalDigitsValue(decimalMaximumDigits)
69261
- : false;
69262
- this.setConditionValue('invalidDecimalMaximumDigits', invalid);
69263
- }
69264
- validateNoMutuallyExclusiveProperties(format, decimalDigits, decimalMaximumDigits) {
69265
- const shouldValidateMutuallyExclusiveProperties = format === NumberTextFormat.decimal;
69266
- const invalid = shouldValidateMutuallyExclusiveProperties
69267
- ? typeof decimalDigits === 'number'
69268
- && typeof decimalMaximumDigits === 'number'
69269
- : false;
69270
- this.setConditionValue('decimalDigitsMutuallyExclusiveWithDecimalMaximumDigits', invalid);
69271
- }
69272
- validateAtMostOneUnit(unitElements) {
69273
- const invalid = unitElements.length > 1;
69274
- this.setConditionValue('moreThanOneUnitSpecified', invalid);
69275
- }
69276
- isInvalidDecimalDigitsValue(decimalDigits) {
69277
- return (decimalDigits < minimumValidDecimalDigits
69278
- || decimalDigits > maximumValidDecimalDigits);
69279
- }
69280
- }
69281
-
69282
- /**
69283
- * The base class for an element that provides a unit scale for scaled unit conversions
69284
- */
69285
- class Unit extends FoundationElement {
69286
- }
69287
- __decorate$1([
69288
- observable
69289
- ], Unit.prototype, "resolvedUnitScale", void 0);
69290
-
69291
- /**
69292
- * The table column for displaying numbers as text.
69293
- */
69294
- class TableColumnNumberText extends mixinTextBase((TableColumnTextBase)) {
69295
- constructor() {
69296
- super(...arguments);
69297
- this.langSubscriber = {
69298
- handleChange: () => {
69299
- this.updateColumnConfig();
69300
- }
69301
- };
69302
- this.unitSubscriber = {
69303
- handleChange: () => {
69304
- this.updateColumnConfig();
69305
- }
69306
- };
69307
- }
69308
- connectedCallback() {
69309
- super.connectedCallback();
69310
- lang.subscribe(this.langSubscriber, this);
69311
- this.updateColumnConfig();
69312
- }
69313
- disconnectedCallback() {
69314
- super.disconnectedCallback();
69315
- lang.unsubscribe(this.langSubscriber, this);
69316
- }
69317
- placeholderChanged() {
69318
- this.updateColumnConfig();
69319
- }
69320
- getColumnInternalsOptions() {
69321
- return {
69322
- cellRecordFieldNames: ['value'],
69323
- cellViewTag: tableColumnNumberTextCellViewTag,
69324
- groupHeaderViewTag: tableColumnNumberTextGroupHeaderTag,
69325
- delegatedEvents: [],
69326
- sortOperation: TableColumnSortOperation.basic,
69327
- validator: new TableColumnNumberTextValidator()
69328
- };
69329
- }
69330
- updateUnitNotifier() {
69331
- if (this.unitNotifier) {
69332
- this.unitNotifier.unsubscribe(this.unitSubscriber);
69333
- this.unitNotifier = undefined;
69334
- }
69335
- if (this.unit) {
69336
- const notifier = Observable.getNotifier(this.unit);
69337
- notifier.subscribe(this.unitSubscriber, 'resolvedUnitScale');
69338
- this.unitNotifier = notifier;
69339
- }
69340
- }
69341
- formatChanged() {
69342
- this.updateColumnConfig();
69343
- }
69344
- alignmentChanged() {
69345
- this.updateColumnConfig();
69346
- }
69347
- decimalDigitsChanged() {
69348
- this.updateColumnConfig();
69349
- }
69350
- decimalMaximumDigitsChanged() {
69351
- this.updateColumnConfig();
69352
- }
69353
- unitElementsChanged() {
69354
- void this.updateUnit();
69355
- }
69356
- async updateUnit() {
69357
- this.unit = undefined;
69358
- if (this.unitElements) {
69359
- await waitUntilCustomElementsDefinedAsync(this.unitElements);
69360
- this.unit = this.unitElements.find((x) => x instanceof Unit);
69361
- }
69362
- this.updateUnitNotifier();
69363
- }
69364
- unitChanged() {
69365
- this.updateColumnConfig();
69366
- }
69367
- updateColumnConfig() {
69368
- const validator = this.columnInternals.validator;
69369
- validator.validateDecimalDigits(this.format, this.decimalDigits);
69370
- validator.validateDecimalMaximumDigits(this.format, this.decimalMaximumDigits);
69371
- validator.validateNoMutuallyExclusiveProperties(this.format, this.decimalDigits, this.decimalMaximumDigits);
69372
- validator.validateAtMostOneUnit(this.unitElements ?? []);
69373
- if (validator.isValid()) {
69374
- const columnConfig = {
69375
- formatter: this.createFormatter(),
69376
- alignment: this.determineCellContentAlignment(),
69377
- placeholder: this.placeholder
69378
- };
69379
- this.columnInternals.columnConfig = columnConfig;
69380
- }
69381
- else {
69382
- this.columnInternals.columnConfig = undefined;
69383
- }
69384
- }
69385
- createFormatter() {
69386
- const unitScale = this.unit?.resolvedUnitScale;
69387
- return new NumberTextUnitFormat(lang.getValueFor(this), {
69388
- // Attribute values sometimes resolve to either null or undefined
69389
- // See https://github.com/microsoft/fast/issues/6630
69390
- numberTextFormat: this.format ?? undefined,
69391
- decimalDigits: this.decimalDigits ?? undefined,
69392
- decimalMaximumDigits: this.decimalMaximumDigits ?? undefined,
69393
- unitScale
69394
- });
69395
- }
69396
- determineCellContentAlignment() {
69397
- if (this.alignment === NumberTextAlignment.left) {
69398
- return TextCellViewBaseAlignment.left;
69399
- }
69400
- if (this.alignment === NumberTextAlignment.right) {
69401
- return TextCellViewBaseAlignment.right;
69402
- }
69403
- // Look at format and decimal max digits and unit to determine the default alignment
69404
- if (this.format === NumberTextFormat.decimal
69405
- && typeof this.decimalMaximumDigits !== 'number'
69406
- && !this.unit) {
69407
- return TextCellViewBaseAlignment.right;
69408
- }
69409
- return TextCellViewBaseAlignment.left;
69410
- }
69411
- }
69412
- __decorate$1([
69413
- attr
69414
- ], TableColumnNumberText.prototype, "format", void 0);
69415
- __decorate$1([
69416
- attr
69417
- ], TableColumnNumberText.prototype, "alignment", void 0);
69418
- __decorate$1([
69419
- attr({ attribute: 'decimal-digits', converter: nullableNumberConverter })
69420
- ], TableColumnNumberText.prototype, "decimalDigits", void 0);
69421
- __decorate$1([
69422
- attr({
69423
- attribute: 'decimal-maximum-digits',
69424
- converter: nullableNumberConverter
69425
- })
69426
- ], TableColumnNumberText.prototype, "decimalMaximumDigits", void 0);
69427
- __decorate$1([
69428
- observable
69429
- ], TableColumnNumberText.prototype, "unitElements", void 0);
69430
- __decorate$1([
69431
- observable
69432
- ], TableColumnNumberText.prototype, "unit", void 0);
69433
- const nimbleTableColumnNumberText = TableColumnNumberText.compose({
69434
- baseName: 'table-column-number-text',
69435
- template: template$9,
69436
- styles: styles$e
69437
- });
69438
- DesignSystem.getOrCreate()
69439
- .withPrefix('nimble')
69440
- .register(nimbleTableColumnNumberText());
69441
-
69442
68850
  /**
69443
68851
  * Converts a Mapping key (which is a string when configured in HTML) to the
69444
68852
  * given keyType. The converted value can then be used to compare against
@@ -69549,7 +68957,7 @@ img.ProseMirror-separator {
69549
68957
  }
69550
68958
  `;
69551
68959
 
69552
- const template$8 = html `${template$d}<slot ${slotted('mappings')} name="mapping"></slot>`;
68960
+ const template$9 = html `${template$d}<slot ${slotted('mappings')} name="mapping"></slot>`;
69553
68961
 
69554
68962
  const enumBaseValidityFlagNames = [
69555
68963
  'invalidMappingKeyValueForType',
@@ -69589,18 +68997,18 @@ img.ProseMirror-separator {
69589
68997
  }
69590
68998
  }
69591
68999
 
69592
- const iconValidityFlagNames = [
69000
+ const mappingColumnValidityFlagNames = [
69593
69001
  ...enumBaseValidityFlagNames,
69594
69002
  'unsupportedMappingType',
69595
69003
  'invalidIconName',
69596
69004
  'missingTextValue'
69597
69005
  ];
69598
69006
  /**
69599
- * Validator for TableColumnIcon
69007
+ * Validator for TableColumnMapping
69600
69008
  */
69601
- class TableColumnIconValidator extends TableColumnEnumBaseValidator {
69009
+ class TableColumnMappingValidator extends TableColumnEnumBaseValidator {
69602
69010
  constructor() {
69603
- super(iconValidityFlagNames);
69011
+ super(mappingColumnValidityFlagNames);
69604
69012
  }
69605
69013
  static isIconMappingElement(mapping) {
69606
69014
  return mapping instanceof MappingIcon;
@@ -69622,18 +69030,18 @@ img.ProseMirror-separator {
69622
69030
  }
69623
69031
  validateIconNames(mappings) {
69624
69032
  const invalid = mappings
69625
- .filter(TableColumnIconValidator.isIconMappingElement)
69626
- .some(TableColumnIconValidator.hasUnresolvedIcon);
69033
+ .filter(TableColumnMappingValidator.isIconMappingElement)
69034
+ .some(TableColumnMappingValidator.hasUnresolvedIcon);
69627
69035
  this.setConditionValue('invalidIconName', invalid);
69628
69036
  }
69629
69037
  validateNoMissingText(mappings) {
69630
69038
  const invalid = mappings
69631
- .filter(TableColumnIconValidator.isSupportedMappingElement)
69039
+ .filter(TableColumnMappingValidator.isSupportedMappingElement)
69632
69040
  .some(mapping => mapping.text === undefined);
69633
69041
  this.setConditionValue('missingTextValue', invalid);
69634
69042
  }
69635
69043
  validateMappingTypes(mappings) {
69636
- const valid = mappings.every(TableColumnIconValidator.isSupportedMappingElement);
69044
+ const valid = mappings.every(TableColumnMappingValidator.isSupportedMappingElement);
69637
69045
  this.setConditionValue('unsupportedMappingType', !valid);
69638
69046
  }
69639
69047
  }
@@ -69663,7 +69071,7 @@ img.ProseMirror-separator {
69663
69071
  `;
69664
69072
 
69665
69073
  // prettier-ignore
69666
- const template$7 = html `
69074
+ const template$8 = html `
69667
69075
  ${when(x => x.visualizationTemplate, html `
69668
69076
  <span class="reserve-icon-size">
69669
69077
  ${x => x.visualizationTemplate}
@@ -69737,262 +69145,857 @@ img.ProseMirror-separator {
69737
69145
  </${spinnerTag}>
69738
69146
  `;
69739
69147
  /**
69740
- * Mapping configuration corresponding to a spinner mapping
69148
+ * Mapping configuration corresponding to a spinner mapping
69149
+ */
69150
+ class MappingSpinnerConfig extends MappingConfig {
69151
+ constructor(text, textHidden) {
69152
+ super(text);
69153
+ this.textHidden = textHidden;
69154
+ this.spinnerTemplate = spinnerTemplate;
69155
+ }
69156
+ }
69157
+
69158
+ /**
69159
+ * Mapping configuration corresponding to a text mapping
69160
+ */
69161
+ class MappingTextConfig extends MappingConfig {
69162
+ }
69163
+
69164
+ /**
69165
+ * The group header view for the mapping column
69166
+ */
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;
69176
+ }
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;
69183
+ }
69184
+ else if (mappingConfig instanceof MappingSpinnerConfig) {
69185
+ this.text = mappingConfig.text ?? '';
69186
+ this.visualizationTemplate = mappingConfig.spinnerTemplate;
69187
+ }
69188
+ else if (mappingConfig instanceof MappingTextConfig) {
69189
+ this.text = mappingConfig.text ?? '';
69190
+ }
69191
+ }
69192
+ resetState() {
69193
+ this.text = '';
69194
+ this.visualizationTemplate = undefined;
69195
+ this.severity = IconSeverity.default;
69196
+ }
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
+ `;
69255
+
69256
+ /**
69257
+ * The cell view for the mapping column
69258
+ */
69259
+ class TableColumnMappingCellView extends TableCellView {
69260
+ constructor() {
69261
+ super(...arguments);
69262
+ this.textHidden = false;
69263
+ /** @internal */
69264
+ this.hasOverflow = false;
69265
+ }
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.
69741
69607
  */
69742
- class MappingSpinnerConfig extends MappingConfig {
69743
- constructor(text, textHidden) {
69744
- super(text);
69745
- this.textHidden = textHidden;
69746
- this.spinnerTemplate = spinnerTemplate;
69608
+ class DefaultUnitFormat extends UnitFormat {
69609
+ constructor(locale, { unitScale = passthroughUnitScale } = {
69610
+ unitScale: passthroughUnitScale
69611
+ }) {
69612
+ super();
69613
+ // Format options to use by default. It renders the number with a maximum of 6 signficant digits (including zero before decimal point).
69614
+ this.defaultIntlNumberFormatOptions = {
69615
+ maximumSignificantDigits: DefaultUnitFormat.maximumDigits,
69616
+ maximumFractionDigits: DefaultUnitFormat.maximumDigits - 1,
69617
+ roundingPriority: 'lessPrecision',
69618
+ signDisplay
69619
+ };
69620
+ this.defaultScaledUnitFormatters = new Map();
69621
+ // Format options for numbers that should be displayed in exponential notation. This should be used
69622
+ // for numbers with magintudes over 'exponentialUpperBound' or under 'exponentialLowerBound'.
69623
+ this.exponentialIntlNumberFormatOptions = {
69624
+ maximumSignificantDigits: DefaultUnitFormat.maximumDigits,
69625
+ notation: 'scientific',
69626
+ signDisplay
69627
+ };
69628
+ for (const unit of unitScale.supportedScaledUnits) {
69629
+ this.defaultScaledUnitFormatters.set(unit.scaleFactor, unit.scaledUnitFormatFactory({
69630
+ locale,
69631
+ intlNumberFormatOptions: this.defaultIntlNumberFormatOptions
69632
+ }));
69633
+ }
69634
+ this.exponentialScaledUnitFormatter = unitScale.baseScaledUnit.scaledUnitFormatFactory({
69635
+ locale,
69636
+ intlNumberFormatOptions: this.exponentialIntlNumberFormatOptions
69637
+ });
69638
+ this.unitScale = unitScale;
69639
+ }
69640
+ resolvedOptions() {
69641
+ return {
69642
+ unitScale: this.unitScale
69643
+ };
69644
+ }
69645
+ tryFormat(number) {
69646
+ const { scaledValue, scaledUnit } = this.unitScale.scaleNumber(number);
69647
+ const absoluteValue = Math.abs(scaledValue);
69648
+ const useExponential = absoluteValue !== 0
69649
+ && (absoluteValue >= DefaultUnitFormat.exponentialUpperBound
69650
+ || absoluteValue < DefaultUnitFormat.exponentialLowerBound);
69651
+ return useExponential
69652
+ ? this.exponentialScaledUnitFormatter.format(number)
69653
+ : this.defaultScaledUnitFormatters
69654
+ .get(scaledUnit.scaleFactor)
69655
+ .format(scaledValue);
69747
69656
  }
69748
69657
  }
69658
+ // The maximum number of digits that should be rendered for any given value.
69659
+ DefaultUnitFormat.maximumDigits = 6;
69660
+ // Use exponential notation for numbers that will be rendered with 3 leading 0s or more.
69661
+ // Because a maximum of 6 digits are rendered, showing more than 3 leading 0s is not ideal
69662
+ // because then at least half of the displayed digits will be leading 0s.
69663
+ DefaultUnitFormat.exponentialLowerBound = 0.000995;
69664
+ // Use exponential formatting for numbers whose magnitude cannot otherwise be displayed
69665
+ // with 6 digits or less.
69666
+ DefaultUnitFormat.exponentialUpperBound = 999999.5;
69749
69667
 
69750
69668
  /**
69751
- * Mapping configuration corresponding to a text mapping
69669
+ * Format for decimal numbers with units.
69752
69670
  */
69753
- class MappingTextConfig extends MappingConfig {
69671
+ class DecimalUnitFormat extends UnitFormat {
69672
+ constructor(locale, { minimumFractionDigits = 0, maximumFractionDigits = Math.max(3, minimumFractionDigits), unitScale = passthroughUnitScale } = {
69673
+ minimumFractionDigits: 0,
69674
+ maximumFractionDigits: 3,
69675
+ unitScale: passthroughUnitScale
69676
+ }) {
69677
+ super();
69678
+ this.scaledUnitFormatters = new Map();
69679
+ // Workaround to avoid a ts error about signDisplay not accepting the value 'negative'.
69680
+ // It has been supported by browsers since 8/23, but TypeScript still hasn't
69681
+ // added it to the type definitions. See https://github.com/microsoft/TypeScript/issues/56269
69682
+ const signDisplay = 'negative';
69683
+ const intlNumberFormatOptions = {
69684
+ maximumFractionDigits,
69685
+ minimumFractionDigits,
69686
+ signDisplay
69687
+ };
69688
+ for (const scaledUnit of unitScale.supportedScaledUnits) {
69689
+ this.scaledUnitFormatters.set(scaledUnit.scaleFactor, scaledUnit.scaledUnitFormatFactory({
69690
+ locale,
69691
+ intlNumberFormatOptions
69692
+ }));
69693
+ }
69694
+ this.unitScale = unitScale;
69695
+ this.minimumFractionDigits = minimumFractionDigits;
69696
+ this.maximumFractionDigits = maximumFractionDigits;
69697
+ }
69698
+ resolvedOptions() {
69699
+ return {
69700
+ unitScale: this.unitScale,
69701
+ maximumFractionDigits: this.maximumFractionDigits,
69702
+ minimumFractionDigits: this.minimumFractionDigits
69703
+ };
69704
+ }
69705
+ tryFormat(number) {
69706
+ const { scaledValue, scaledUnit } = this.unitScale.scaleNumber(number);
69707
+ const scaledUnitFormatter = this.scaledUnitFormatters.get(scaledUnit.scaleFactor);
69708
+ return scaledUnitFormatter.format(scaledValue);
69709
+ }
69754
69710
  }
69755
69711
 
69756
69712
  /**
69757
- * The group header view for the icon column
69713
+ * Format for numbers (with optional units) in a number-text table column.
69758
69714
  */
69759
- class TableColumnIconGroupHeaderView extends TableColumnTextGroupHeaderViewBase {
69760
- constructor() {
69761
- super(...arguments);
69762
- this.textHidden = false;
69715
+ class NumberTextUnitFormat extends UnitFormat {
69716
+ constructor(locale, options) {
69717
+ super();
69718
+ this._resolvedOptions = this.resolveOptions(options);
69719
+ this.resolvedUnitFormat = this.resolveUnitFormat(locale, this._resolvedOptions);
69763
69720
  }
69764
- updateText() {
69765
- this.resetState();
69766
- if (!this.columnConfig) {
69767
- return;
69721
+ resolvedOptions() {
69722
+ return { ...this._resolvedOptions };
69723
+ }
69724
+ optionsMatch(targetOptions) {
69725
+ const targetResolvedOptions = this.resolveOptions(targetOptions);
69726
+ return (this._resolvedOptions.decimalDigits
69727
+ === targetResolvedOptions.decimalDigits
69728
+ && this._resolvedOptions.decimalMaximumDigits
69729
+ === targetResolvedOptions.decimalMaximumDigits
69730
+ && this._resolvedOptions.numberTextFormat
69731
+ === targetResolvedOptions.numberTextFormat
69732
+ && this._resolvedOptions.unitScale === targetResolvedOptions.unitScale);
69733
+ }
69734
+ tryFormat(number) {
69735
+ return this.resolvedUnitFormat.format(number);
69736
+ }
69737
+ resolveUnitFormat(locale, options) {
69738
+ const { numberTextFormat, decimalMaximumDigits, decimalDigits, unitScale } = options;
69739
+ if (numberTextFormat === NumberTextFormat.default) {
69740
+ return new DefaultUnitFormat(locale, {
69741
+ unitScale
69742
+ });
69768
69743
  }
69769
- const value = this.groupHeaderValue;
69770
- const mappingConfig = this.columnConfig.mappingConfigs.get(value);
69771
- if (mappingConfig instanceof MappingIconConfig) {
69772
- this.severity = mappingConfig.severity;
69773
- this.text = mappingConfig.text ?? '';
69774
- this.visualizationTemplate = mappingConfig.iconTemplate;
69744
+ if (typeof decimalDigits === 'number') {
69745
+ return new DecimalUnitFormat(locale, {
69746
+ minimumFractionDigits: decimalDigits,
69747
+ maximumFractionDigits: decimalDigits,
69748
+ unitScale
69749
+ });
69775
69750
  }
69776
- else if (mappingConfig instanceof MappingSpinnerConfig) {
69777
- this.text = mappingConfig.text ?? '';
69778
- this.visualizationTemplate = mappingConfig.spinnerTemplate;
69751
+ return new DecimalUnitFormat(locale, {
69752
+ minimumFractionDigits: 0,
69753
+ maximumFractionDigits: decimalMaximumDigits,
69754
+ unitScale
69755
+ });
69756
+ }
69757
+ resolveOptions(options) {
69758
+ if (!options || options.numberTextFormat === NumberTextFormat.default) {
69759
+ return {
69760
+ numberTextFormat: NumberTextFormat.default,
69761
+ decimalDigits: undefined,
69762
+ decimalMaximumDigits: undefined,
69763
+ unitScale: options?.unitScale ?? passthroughUnitScale
69764
+ };
69779
69765
  }
69780
- else if (mappingConfig instanceof MappingTextConfig) {
69781
- this.text = mappingConfig.text ?? '';
69766
+ const hasDecimalDigits = typeof options.decimalDigits === 'number';
69767
+ const hasDecimalMaximumDigits = typeof options.decimalMaximumDigits === 'number';
69768
+ if (hasDecimalDigits && hasDecimalMaximumDigits) {
69769
+ throw new Error('decimalDigits and decimalMaximumDigits are mutually exclusive. Do not specify both.');
69782
69770
  }
69783
- }
69784
- resetState() {
69785
- this.text = '';
69786
- this.visualizationTemplate = undefined;
69787
- this.severity = IconSeverity.default;
69771
+ if (!hasDecimalDigits && !hasDecimalMaximumDigits) {
69772
+ return {
69773
+ numberTextFormat: NumberTextFormat.decimal,
69774
+ decimalDigits: NumberTextUnitFormat.defaultDecimalDigits,
69775
+ decimalMaximumDigits: undefined,
69776
+ unitScale: options.unitScale ?? passthroughUnitScale
69777
+ };
69778
+ }
69779
+ return {
69780
+ numberTextFormat: NumberTextFormat.decimal,
69781
+ decimalDigits: options.decimalDigits,
69782
+ decimalMaximumDigits: options.decimalMaximumDigits,
69783
+ unitScale: options.unitScale ?? passthroughUnitScale
69784
+ };
69788
69785
  }
69789
69786
  }
69790
- __decorate$1([
69791
- observable
69792
- ], TableColumnIconGroupHeaderView.prototype, "severity", void 0);
69793
- __decorate$1([
69794
- observable
69795
- ], TableColumnIconGroupHeaderView.prototype, "visualizationTemplate", void 0);
69796
- const iconGroupHeaderView = TableColumnIconGroupHeaderView.compose({
69797
- baseName: 'table-column-icon-group-header-view',
69798
- template: template$7,
69799
- styles: styles$9
69800
- });
69801
- DesignSystem.getOrCreate().withPrefix('nimble').register(iconGroupHeaderView());
69802
- const tableColumnIconGroupHeaderViewTag = 'nimble-table-column-icon-group-header-view';
69803
-
69804
- const styles$8 = css `
69805
- ${display('inline-flex')}
69806
-
69807
- :host {
69808
- gap: ${smallPadding};
69809
- align-items: center;
69810
- }
69811
-
69812
- .reserve-icon-size {
69813
- flex-shrink: 0;
69814
- width: ${iconSize};
69815
- height: ${iconSize};
69816
- }
69817
-
69818
- .text {
69819
- flex-shrink: 1;
69820
- font: ${bodyFont};
69821
- color: ${bodyFontColor};
69822
- white-space: nowrap;
69823
- overflow: hidden;
69824
- text-overflow: ellipsis;
69825
- }
69826
- `;
69827
-
69828
- // prettier-ignore
69829
- const template$6 = html `
69830
- ${when(x => x.visualizationTemplate, html `
69831
- <span class="reserve-icon-size">
69832
- ${x => x.visualizationTemplate}
69833
- </span>
69834
- `)}
69835
- ${when(x => !x.textHidden, html `
69836
- <span
69837
- ${overflow('hasOverflow')}
69838
- title=${x => (x.hasOverflow && x.text ? x.text : null)}
69839
- class="text"
69840
- >
69841
- ${x => x.text}
69842
- </span>
69843
- `)}
69844
- `;
69787
+ NumberTextUnitFormat.defaultDecimalDigits = 2;
69845
69788
 
69789
+ const numberTextValidityFlagNames = [
69790
+ 'invalidDecimalDigits',
69791
+ 'invalidDecimalMaximumDigits',
69792
+ 'decimalDigitsMutuallyExclusiveWithDecimalMaximumDigits',
69793
+ 'moreThanOneUnitSpecified'
69794
+ ];
69795
+ // The maximum and minimum allowed configuration for 'maximumFractionDigits'
69796
+ // and 'minimumFractionDigits' on the NumberFormat.
69797
+ const minimumValidDecimalDigits = 0;
69798
+ const maximumValidDecimalDigits = 20;
69846
69799
  /**
69847
- * The cell view for the icon column
69800
+ * Validator for TableColumnNumberText.
69848
69801
  */
69849
- class TableColumnIconCellView extends TableCellView {
69802
+ class TableColumnNumberTextValidator extends ColumnValidator {
69850
69803
  constructor() {
69851
- super(...arguments);
69852
- this.textHidden = false;
69853
- /** @internal */
69854
- this.hasOverflow = false;
69804
+ super(numberTextValidityFlagNames);
69855
69805
  }
69856
- columnConfigChanged() {
69857
- this.updateState();
69806
+ validateDecimalDigits(format, decimalDigits) {
69807
+ const shouldValidateDecimalDigitsValue = format === NumberTextFormat.decimal
69808
+ && typeof decimalDigits === 'number';
69809
+ const invalid = shouldValidateDecimalDigitsValue
69810
+ ? this.isInvalidDecimalDigitsValue(decimalDigits)
69811
+ : false;
69812
+ this.setConditionValue('invalidDecimalDigits', invalid);
69858
69813
  }
69859
- cellRecordChanged() {
69860
- this.updateState();
69814
+ validateDecimalMaximumDigits(format, decimalMaximumDigits) {
69815
+ const shouldValidateDecimalDigitsValue = format === NumberTextFormat.decimal
69816
+ && typeof decimalMaximumDigits === 'number';
69817
+ const invalid = shouldValidateDecimalDigitsValue
69818
+ ? this.isInvalidDecimalDigitsValue(decimalMaximumDigits)
69819
+ : false;
69820
+ this.setConditionValue('invalidDecimalMaximumDigits', invalid);
69861
69821
  }
69862
- updateState() {
69863
- this.resetState();
69864
- if (!this.columnConfig || !this.cellRecord) {
69865
- return;
69866
- }
69867
- const value = this.cellRecord.value;
69868
- if (value === undefined || value === null) {
69869
- return;
69870
- }
69871
- const mappingConfig = this.columnConfig.mappingConfigs.get(value);
69872
- if (mappingConfig instanceof MappingIconConfig) {
69873
- this.severity = mappingConfig.severity;
69874
- this.text = mappingConfig.text;
69875
- this.visualizationTemplate = mappingConfig.iconTemplate;
69876
- this.textHidden = mappingConfig.textHidden;
69877
- }
69878
- else if (mappingConfig instanceof MappingSpinnerConfig) {
69879
- this.text = mappingConfig.text;
69880
- this.visualizationTemplate = mappingConfig.spinnerTemplate;
69881
- this.textHidden = mappingConfig.textHidden;
69882
- }
69883
- else if (mappingConfig instanceof MappingTextConfig) {
69884
- this.text = mappingConfig.text;
69885
- this.textHidden = false;
69886
- }
69822
+ validateNoMutuallyExclusiveProperties(format, decimalDigits, decimalMaximumDigits) {
69823
+ const shouldValidateMutuallyExclusiveProperties = format === NumberTextFormat.decimal;
69824
+ const invalid = shouldValidateMutuallyExclusiveProperties
69825
+ ? typeof decimalDigits === 'number'
69826
+ && typeof decimalMaximumDigits === 'number'
69827
+ : false;
69828
+ this.setConditionValue('decimalDigitsMutuallyExclusiveWithDecimalMaximumDigits', invalid);
69887
69829
  }
69888
- resetState() {
69889
- this.text = undefined;
69890
- this.textHidden = false;
69891
- this.visualizationTemplate = undefined;
69892
- this.severity = IconSeverity.default;
69830
+ validateAtMostOneUnit(unitElements) {
69831
+ const invalid = unitElements.length > 1;
69832
+ this.setConditionValue('moreThanOneUnitSpecified', invalid);
69833
+ }
69834
+ isInvalidDecimalDigitsValue(decimalDigits) {
69835
+ return (decimalDigits < minimumValidDecimalDigits
69836
+ || decimalDigits > maximumValidDecimalDigits);
69893
69837
  }
69894
69838
  }
69895
- __decorate$1([
69896
- observable
69897
- ], TableColumnIconCellView.prototype, "severity", void 0);
69898
- __decorate$1([
69899
- observable
69900
- ], TableColumnIconCellView.prototype, "text", void 0);
69901
- __decorate$1([
69902
- observable
69903
- ], TableColumnIconCellView.prototype, "visualizationTemplate", void 0);
69904
- __decorate$1([
69905
- observable
69906
- ], TableColumnIconCellView.prototype, "textHidden", void 0);
69907
- __decorate$1([
69908
- observable
69909
- ], TableColumnIconCellView.prototype, "hasOverflow", void 0);
69910
- const iconCellView = TableColumnIconCellView.compose({
69911
- baseName: 'table-column-icon-cell-view',
69912
- template: template$6,
69913
- styles: styles$8
69914
- });
69915
- DesignSystem.getOrCreate().withPrefix('nimble').register(iconCellView());
69916
- const tableColumnIconCellViewTag = 'nimble-table-column-icon-cell-view';
69917
69839
 
69918
69840
  /**
69919
- * Width mode for the icon column
69841
+ * The base class for an element that provides a unit scale for scaled unit conversions
69920
69842
  */
69921
- const TableColumnMappingWidthMode = {
69922
- default: undefined,
69923
- iconSize: 'icon-size'
69924
- };
69843
+ class Unit extends FoundationElement {
69844
+ }
69845
+ __decorate$1([
69846
+ observable
69847
+ ], Unit.prototype, "resolvedUnitScale", void 0);
69925
69848
 
69926
69849
  /**
69927
- * Table column that maps values to icons / spinners
69850
+ * The table column for displaying numbers as text.
69928
69851
  */
69929
- class TableColumnIcon extends mixinGroupableColumnAPI(mixinFractionalWidthColumnAPI((TableColumnEnumBase))) {
69930
- minPixelWidthChanged() {
69931
- if (this.widthMode !== TableColumnMappingWidthMode.iconSize) {
69932
- this.columnInternals.minPixelWidth = this.getConfiguredMinPixelWidth();
69933
- }
69852
+ class TableColumnNumberText extends mixinTextBase((TableColumnTextBase)) {
69853
+ constructor() {
69854
+ super(...arguments);
69855
+ this.langSubscriber = {
69856
+ handleChange: () => {
69857
+ this.updateColumnConfig();
69858
+ }
69859
+ };
69860
+ this.unitSubscriber = {
69861
+ handleChange: () => {
69862
+ this.updateColumnConfig();
69863
+ }
69864
+ };
69865
+ }
69866
+ connectedCallback() {
69867
+ super.connectedCallback();
69868
+ lang.subscribe(this.langSubscriber, this);
69869
+ this.updateColumnConfig();
69870
+ }
69871
+ disconnectedCallback() {
69872
+ super.disconnectedCallback();
69873
+ lang.unsubscribe(this.langSubscriber, this);
69874
+ }
69875
+ placeholderChanged() {
69876
+ this.updateColumnConfig();
69934
69877
  }
69935
69878
  getColumnInternalsOptions() {
69936
69879
  return {
69937
69880
  cellRecordFieldNames: ['value'],
69938
- cellViewTag: tableColumnIconCellViewTag,
69939
- groupHeaderViewTag: tableColumnIconGroupHeaderViewTag,
69881
+ cellViewTag: tableColumnNumberTextCellViewTag,
69882
+ groupHeaderViewTag: tableColumnNumberTextGroupHeaderTag,
69940
69883
  delegatedEvents: [],
69941
69884
  sortOperation: TableColumnSortOperation.basic,
69942
- validator: new TableColumnIconValidator()
69943
- };
69944
- }
69945
- createColumnConfig(mappingConfigs) {
69946
- return {
69947
- mappingConfigs
69885
+ validator: new TableColumnNumberTextValidator()
69948
69886
  };
69949
69887
  }
69950
- createMappingConfig(mapping) {
69951
- if (mapping instanceof MappingIcon) {
69952
- return new MappingIconConfig(mapping.resolvedIcon, mapping.severity, mapping.text, mapping.textHidden);
69888
+ updateUnitNotifier() {
69889
+ if (this.unitNotifier) {
69890
+ this.unitNotifier.unsubscribe(this.unitSubscriber);
69891
+ this.unitNotifier = undefined;
69953
69892
  }
69954
- if (mapping instanceof MappingSpinner) {
69955
- return new MappingSpinnerConfig(mapping.text, mapping.textHidden);
69893
+ if (this.unit) {
69894
+ const notifier = Observable.getNotifier(this.unit);
69895
+ notifier.subscribe(this.unitSubscriber, 'resolvedUnitScale');
69896
+ this.unitNotifier = notifier;
69956
69897
  }
69957
- if (mapping instanceof MappingText) {
69958
- return new MappingTextConfig(mapping.text);
69898
+ }
69899
+ formatChanged() {
69900
+ this.updateColumnConfig();
69901
+ }
69902
+ alignmentChanged() {
69903
+ this.updateColumnConfig();
69904
+ }
69905
+ decimalDigitsChanged() {
69906
+ this.updateColumnConfig();
69907
+ }
69908
+ decimalMaximumDigitsChanged() {
69909
+ this.updateColumnConfig();
69910
+ }
69911
+ unitElementsChanged() {
69912
+ void this.updateUnit();
69913
+ }
69914
+ async updateUnit() {
69915
+ this.unit = undefined;
69916
+ if (this.unitElements) {
69917
+ await waitUntilCustomElementsDefinedAsync(this.unitElements);
69918
+ this.unit = this.unitElements.find((x) => x instanceof Unit);
69959
69919
  }
69960
- // Getting here would indicate a programming error, b/c validation will prevent
69961
- // this function from running when there is an unsupported mapping.
69962
- throw new Error('Unsupported mapping');
69920
+ this.updateUnitNotifier();
69963
69921
  }
69964
- widthModeChanged() {
69965
- if (this.widthMode === TableColumnMappingWidthMode.iconSize) {
69966
- this.columnInternals.resizingDisabled = true;
69967
- this.columnInternals.hideHeaderIndicators = true;
69968
- this.columnInternals.pixelWidth = singleIconColumnWidth;
69969
- this.columnInternals.minPixelWidth = singleIconColumnWidth;
69922
+ unitChanged() {
69923
+ this.updateColumnConfig();
69924
+ }
69925
+ updateColumnConfig() {
69926
+ const validator = this.columnInternals.validator;
69927
+ validator.validateDecimalDigits(this.format, this.decimalDigits);
69928
+ validator.validateDecimalMaximumDigits(this.format, this.decimalMaximumDigits);
69929
+ validator.validateNoMutuallyExclusiveProperties(this.format, this.decimalDigits, this.decimalMaximumDigits);
69930
+ validator.validateAtMostOneUnit(this.unitElements ?? []);
69931
+ if (validator.isValid()) {
69932
+ const columnConfig = {
69933
+ formatter: this.createFormatter(),
69934
+ alignment: this.determineCellContentAlignment(),
69935
+ placeholder: this.placeholder
69936
+ };
69937
+ this.columnInternals.columnConfig = columnConfig;
69970
69938
  }
69971
69939
  else {
69972
- this.columnInternals.resizingDisabled = false;
69973
- this.columnInternals.hideHeaderIndicators = false;
69974
- this.columnInternals.pixelWidth = undefined;
69975
- this.columnInternals.minPixelWidth = this.getConfiguredMinPixelWidth();
69940
+ this.columnInternals.columnConfig = undefined;
69976
69941
  }
69977
69942
  }
69978
- getConfiguredMinPixelWidth() {
69979
- if (typeof this.minPixelWidth === 'number') {
69980
- return this.minPixelWidth;
69943
+ createFormatter() {
69944
+ const unitScale = this.unit?.resolvedUnitScale;
69945
+ return new NumberTextUnitFormat(lang.getValueFor(this), {
69946
+ // Attribute values sometimes resolve to either null or undefined
69947
+ // See https://github.com/microsoft/fast/issues/6630
69948
+ numberTextFormat: this.format ?? undefined,
69949
+ decimalDigits: this.decimalDigits ?? undefined,
69950
+ decimalMaximumDigits: this.decimalMaximumDigits ?? undefined,
69951
+ unitScale
69952
+ });
69953
+ }
69954
+ determineCellContentAlignment() {
69955
+ if (this.alignment === NumberTextAlignment.left) {
69956
+ return TextCellViewBaseAlignment.left;
69981
69957
  }
69982
- return defaultMinPixelWidth;
69958
+ if (this.alignment === NumberTextAlignment.right) {
69959
+ return TextCellViewBaseAlignment.right;
69960
+ }
69961
+ // Look at format and decimal max digits and unit to determine the default alignment
69962
+ if (this.format === NumberTextFormat.decimal
69963
+ && typeof this.decimalMaximumDigits !== 'number'
69964
+ && !this.unit) {
69965
+ return TextCellViewBaseAlignment.right;
69966
+ }
69967
+ return TextCellViewBaseAlignment.left;
69983
69968
  }
69984
69969
  }
69985
69970
  __decorate$1([
69986
- attr({ attribute: 'width-mode' })
69987
- ], TableColumnIcon.prototype, "widthMode", void 0);
69988
- const nimbleTableColumnIcon = TableColumnIcon.compose({
69989
- baseName: 'table-column-icon',
69990
- template: template$8,
69991
- styles: styles$a
69971
+ attr
69972
+ ], TableColumnNumberText.prototype, "format", void 0);
69973
+ __decorate$1([
69974
+ attr
69975
+ ], TableColumnNumberText.prototype, "alignment", void 0);
69976
+ __decorate$1([
69977
+ attr({ attribute: 'decimal-digits', converter: nullableNumberConverter })
69978
+ ], TableColumnNumberText.prototype, "decimalDigits", void 0);
69979
+ __decorate$1([
69980
+ attr({
69981
+ attribute: 'decimal-maximum-digits',
69982
+ converter: nullableNumberConverter
69983
+ })
69984
+ ], TableColumnNumberText.prototype, "decimalMaximumDigits", void 0);
69985
+ __decorate$1([
69986
+ observable
69987
+ ], TableColumnNumberText.prototype, "unitElements", void 0);
69988
+ __decorate$1([
69989
+ observable
69990
+ ], TableColumnNumberText.prototype, "unit", void 0);
69991
+ const nimbleTableColumnNumberText = TableColumnNumberText.compose({
69992
+ baseName: 'table-column-number-text',
69993
+ template: template$6,
69994
+ styles: styles$e
69992
69995
  });
69993
69996
  DesignSystem.getOrCreate()
69994
69997
  .withPrefix('nimble')
69995
- .register(nimbleTableColumnIcon());
69998
+ .register(nimbleTableColumnNumberText());
69996
69999
 
69997
70000
  /**
69998
70001
  * A cell view for displaying string fields as text