@tylertech/forge 3.4.2 → 3.5.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/custom-elements.json +1157 -132
  2. package/dist/label-value/forge-label-value.css +2 -0
  3. package/dist/lib.js +174 -1
  4. package/dist/lib.js.map +4 -4
  5. package/dist/vscode.css-custom-data.json +156 -0
  6. package/dist/vscode.html-custom-data.json +142 -0
  7. package/esm/app-bar/search/app-bar-search.js +1 -1
  8. package/esm/autocomplete/autocomplete-core.js +4 -2
  9. package/esm/autocomplete/autocomplete.js +1 -5
  10. package/esm/button-toggle/button-toggle/button-toggle-core.js +0 -1
  11. package/esm/chips/chip/chip.js +1 -1
  12. package/esm/core/utils/a11y-utils.d.ts +20 -1
  13. package/esm/core/utils/a11y-utils.js +26 -1
  14. package/esm/file-picker/file-picker-adapter.d.ts +2 -0
  15. package/esm/file-picker/file-picker-adapter.js +6 -0
  16. package/esm/file-picker/file-picker-core.js +1 -0
  17. package/esm/icon-button/icon-button.js +1 -1
  18. package/esm/index.d.ts +2 -0
  19. package/esm/index.js +8 -0
  20. package/esm/key/index.d.ts +7 -0
  21. package/esm/key/index.js +7 -0
  22. package/esm/key/key/index.d.ts +7 -0
  23. package/esm/key/key/index.js +11 -0
  24. package/esm/key/key/key.d.ts +30 -0
  25. package/esm/key/key/key.js +43 -0
  26. package/esm/key/key-item/index.d.ts +7 -0
  27. package/esm/key/key-item/index.js +11 -0
  28. package/esm/key/key-item/key-item.d.ts +47 -0
  29. package/esm/key/key-item/key-item.js +86 -0
  30. package/esm/label-value/label-value.js +1 -1
  31. package/esm/list-dropdown/list-dropdown-aware.d.ts +1 -0
  32. package/esm/list-dropdown/list-dropdown-aware.js +11 -0
  33. package/esm/meter/index.d.ts +7 -0
  34. package/esm/meter/index.js +7 -0
  35. package/esm/meter/meter/index.d.ts +7 -0
  36. package/esm/meter/meter/index.js +11 -0
  37. package/esm/meter/meter/meter.d.ts +187 -0
  38. package/esm/meter/meter/meter.js +359 -0
  39. package/esm/meter/meter-group/index.d.ts +7 -0
  40. package/esm/meter/meter-group/index.js +11 -0
  41. package/esm/meter/meter-group/meter-group.d.ts +108 -0
  42. package/esm/meter/meter-group/meter-group.js +198 -0
  43. package/esm/select/select/select.d.ts +3 -1
  44. package/esm/split-view/split-view-panel/split-view-panel.js +1 -1
  45. package/package.json +2 -1
  46. package/sass/core/styles/tokens/app-bar/search/_tokens.scss +1 -1
  47. package/sass/core/styles/tokens/key/key/_tokens.scss +17 -0
  48. package/sass/core/styles/tokens/key/key-item/_tokens.scss +22 -0
  49. package/sass/core/styles/tokens/meter/meter/_tokens.scss +30 -0
  50. package/sass/core/styles/tokens/meter/meter-group/_tokens.scss +26 -0
  51. package/sass/core/styles/typography/index.scss +1 -1
  52. package/sass/icon-button/icon-button.scss +20 -1
  53. package/sass/key/key/_core.scss +20 -0
  54. package/sass/key/key/_token-utils.scss +30 -0
  55. package/sass/key/key/index.scss +6 -0
  56. package/sass/key/key/key.scss +26 -0
  57. package/sass/key/key-item/_core.scss +69 -0
  58. package/sass/key/key-item/_token-utils.scss +30 -0
  59. package/sass/key/key-item/index.scss +6 -0
  60. package/sass/key/key-item/key-item.scss +60 -0
  61. package/sass/label-value/_core.scss +2 -0
  62. package/sass/meter/meter/_core.scss +206 -0
  63. package/sass/meter/meter/_token-utils.scss +30 -0
  64. package/sass/meter/meter/index.scss +6 -0
  65. package/sass/meter/meter/meter.scss +218 -0
  66. package/sass/meter/meter-group/_core.scss +83 -0
  67. package/sass/meter/meter-group/_token-utils.scss +30 -0
  68. package/sass/meter/meter-group/index.scss +6 -0
  69. package/sass/meter/meter-group/meter-group.scss +111 -0
@@ -0,0 +1,187 @@
1
+ /**
2
+ * @license
3
+ * Copyright Tyler Technologies, Inc.
4
+ * License: Apache-2.0
5
+ */
6
+ import { LitElement, PropertyValues, TemplateResult } from 'lit';
7
+ import { Theme } from '../../constants';
8
+ export type MeterDirection = 'horizontal' | 'vertical';
9
+ export type MeterDensity = 'default' | 'small' | 'medium' | 'large';
10
+ export type MeterShape = 'default' | 'round' | 'squared';
11
+ export type MeterInnerShape = 'default' | 'inherit';
12
+ export type MeterStatus = 'optimal' | 'suboptimal' | 'least-optimal';
13
+ export type MeterTheme = Theme | 'default';
14
+ export type MeterValueMode = 'manual' | 'percentage' | 'value';
15
+ /**
16
+ * @tag forge-meter
17
+ *
18
+ * @summary Meters display a scalar value within a defined range.
19
+ *
20
+ * @attribute {string} aria-valuetext - Defines a text alternative for the current value. Set this if it would be inaccurate to read the value as a percentage.
21
+ *
22
+ * @state vertical - Applied when the meter is oriented vertically.
23
+ * @state optimum-value - Applied when the value is within the optimum range.
24
+ * @state suboptimum-value - Applied when the value is within the suboptimum range.
25
+ * @state least-optimum-value - Applied when the value is within the least optimum range.
26
+ *
27
+ * @cssproperty --forge-meter-background - The background color of the meter.
28
+ * @cssproperty --forge-meter-color - The color of the meter's bar.
29
+ * @cssproperty --forge-meter-height - The block size of the meter.
30
+ * @cssproperty --forge-meter-shape - The border radius of the meter.
31
+ * @cssproperty --forge-meter-bar-inner-shape - The border radius of the meter's bar.
32
+ * @cssproperty --forge-meter-tickmarks - The number of tickmarks to display.
33
+ * @cssproperty --forge-meter-tickmark-opacity - The opacity of the tickmarks.
34
+ * @cssproperty --forge-meter-transition-duration - The duration of transitions.
35
+ * @cssproperty --forge-meter-transition-timing - The timing function of transitions.
36
+ * @cssproperty --forge-theme-success - The color of the bar when the value is optimal.
37
+ * @cssproperty --forge-theme-success-container-low - The color of the track when the value is optimal.
38
+ * @cssproperty --forge-theme-warning - The color of the bar when the value is suboptimal.
39
+ * @cssproperty --forge-theme-warning-container-low - The color of the track when the value is suboptimal.
40
+ * @cssproperty --forge-theme-error - The color of the bar when the value is least optimal.
41
+ * @cssproperty --forge-theme-error-container-low - The color of the track when the value is least optimal.
42
+ *
43
+ * @csspart root - The root container element.
44
+ * @csspart track - The element comprising the meter's background.
45
+ * @csspart bar - The bar representing the value.
46
+ *
47
+ * @slot - The default slot for the meter's label.
48
+ * @slot value - A textual representation of the meter's value.
49
+ */
50
+ export declare class MeterComponent extends LitElement {
51
+ static styles: import("lit").CSSResult;
52
+ static formAssociated: boolean;
53
+ /**
54
+ * The current value of the meter.
55
+ * @default 0
56
+ * @attribute
57
+ */
58
+ value: number;
59
+ /**
60
+ * The minimum value of the meter.
61
+ * @default 0
62
+ * @attribute
63
+ */
64
+ min: number;
65
+ /**
66
+ * The maximum value of the meter.
67
+ * @default 1
68
+ * @attribute
69
+ */
70
+ max: number;
71
+ /**
72
+ * The low value threshold.
73
+ * @default 0
74
+ * @attribute
75
+ */
76
+ low: number | null | undefined;
77
+ /**
78
+ * The high value threshold.
79
+ * @default 1
80
+ * @attribute
81
+ */
82
+ high: number | null | undefined;
83
+ /**
84
+ * Indicates the region of the optimum value.
85
+ * @default 1
86
+ * @attribute
87
+ */
88
+ optimum: number | null | undefined;
89
+ /**
90
+ * Whether to display tickmarks.
91
+ * @default false
92
+ * @attribute
93
+ */
94
+ tickmarks: boolean;
95
+ /**
96
+ * Whether the current value is displayed as a percentage or raw value. When set to `'manual'`
97
+ * the value text is not shown automatically but can still be set manually via the value slot.
98
+ * @default 'manual'
99
+ * @attribute value-mode
100
+ */
101
+ valueMode: MeterValueMode;
102
+ /**
103
+ * Whether the meter is oriented horizontally or vertically.
104
+ * @default 'horizontal'
105
+ * @attribute
106
+ */
107
+ direction: MeterDirection;
108
+ /**
109
+ * The shape of the meter.
110
+ * @default 'default'
111
+ * @attribute
112
+ */
113
+ shape: MeterShape;
114
+ /**
115
+ * The shape of the bar.
116
+ * @default 'default'
117
+ * @attribute inner-shape
118
+ */
119
+ innerShape: MeterInnerShape;
120
+ /**
121
+ * The density of the meter.
122
+ * @default 'medium'
123
+ * @attribute
124
+ */
125
+ density: MeterDensity;
126
+ /**
127
+ * The theme of the meter.
128
+ * @default 'default'
129
+ * @attribute
130
+ */
131
+ theme: MeterTheme;
132
+ /**
133
+ * Whether the theme is muted.
134
+ * @default false
135
+ * @attribute
136
+ */
137
+ muted: boolean;
138
+ /**
139
+ * Gets the percentage of the meter that's filled.
140
+ * @readonly
141
+ */
142
+ get percentage(): number;
143
+ get labels(): NodeList;
144
+ get form(): HTMLFormElement | null;
145
+ private _percentage;
146
+ private _status;
147
+ private _segmented;
148
+ private _grouped;
149
+ private _hasSlottedContent;
150
+ private _defaultNodes;
151
+ private _valueNodes;
152
+ private _internals;
153
+ constructor();
154
+ connectedCallback(): void;
155
+ willUpdate(changedProperties: PropertyValues<this>): void;
156
+ render(): TemplateResult;
157
+ /**
158
+ * Determines the percentage of the meter that's filled and whether the value is optimal,
159
+ * suboptimal, or least optimal.
160
+ */
161
+ private _getStatus;
162
+ /**
163
+ * Determines whether low and high ranges are set. The meter is segmented if either the low or
164
+ * high property is defined.
165
+ *
166
+ * When the meter is segmented the default or themed color scheme is replaced by semantic colors
167
+ * corresponding to optimal, suboptimal, and least optimal values.
168
+ */
169
+ private _getSegmented;
170
+ /**
171
+ * Checks if the meter is part of a group and inherits the min and max values.
172
+ */
173
+ private _getGrouped;
174
+ /**
175
+ * Checks whether the meter has any slotted content.
176
+ */
177
+ private _handleSlotChange;
178
+ /**
179
+ * Updates the internal state of the meter based on the current status.
180
+ */
181
+ private _setValueState;
182
+ }
183
+ declare global {
184
+ interface HTMLElementTagNameMap {
185
+ 'forge-meter': MeterComponent;
186
+ }
187
+ }
@@ -0,0 +1,359 @@
1
+ /**
2
+ * @license
3
+ * Copyright Tyler Technologies, Inc.
4
+ * License: Apache-2.0
5
+ */
6
+ import { __decorate } from "tslib";
7
+ import { LitElement, html, unsafeCSS } from 'lit';
8
+ import { customElement, property, queryAssignedNodes, state } from 'lit/decorators.js';
9
+ import { classMap } from 'lit/directives/class-map.js';
10
+ import { styleMap } from 'lit/directives/style-map.js';
11
+ import { setDefaultAria, toggleState } from '../../core/utils/a11y-utils';
12
+ const styles = ':host{display:inline}.forge-meter{--_meter-background:var(--forge-meter-background, var(--forge-theme-tertiary-container-low, #e8ebff));--_meter-color:var(--forge-meter-color, var(--forge-theme-tertiary, #3d5afe));--_meter-height:var(--forge-meter-height, var(--forge-spacing-medium, 16px));--_meter-shape:var(--forge-meter-shape, calc(var(--forge-shape-medium, 4px) * var(--forge-shape-factor, 1)));--_meter-inner-shape:var(--forge-meter-inner-shape, 0);--_meter-inner-elevation:var(--forge-meter-inner-elevation, 0px 2px 4px -1px rgba(0, 0, 0, 0.2), 0px 4px 5px 0px rgba(0, 0, 0, 0.14), 0px 1px 10px 0px rgba(0, 0, 0, 0.12));--_meter-tickmarks:var(--forge-meter-tickmarks, 10);--_meter-tickmark-opacity:var(--forge-meter-tickmark-opacity, 54%);--_meter-transition-duration:var(--forge-meter-transition-duration, var(--forge-animation-duration-short4, 200ms));--_meter-transition-timing:var(--forge-meter-transition-timing, var(--forge-animation-easing-standard, cubic-bezier(0.2, 0, 0, 1)))}.forge-meter{box-sizing:border-box}.forge-meter .heading{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:var(--forge-typography-label1-font-family, var(--forge-typography-font-family, \"Roboto\", sans-serif));font-size:var(--forge-typography-label1-font-size, calc(var(--forge-typography-font-size, 1rem) * var(--forge-typography-label-font-size-scale, .75)));font-weight:var(--forge-typography-label1-font-weight,400);line-height:var(--forge-typography-label1-line-height, calc(var(--forge-typography-font-size, 1rem) * var(--forge-typography-label-line-height-scale, 1.25)));letter-spacing:var(--forge-typography-label1-letter-spacing, .0357142857em);text-transform:var(--forge-typography-label1-text-transform,inherit);text-decoration:var(--forge-typography-label1-text-decoration,inherit);display:flex;align-items:center;justify-content:space-between;line-height:normal}.forge-meter .heading.not-empty{margin-bottom:var(--forge-spacing-xxsmall,4px)}.forge-meter .label{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.forge-meter .value{color:var(--forge-theme-text-medium,rgba(0,0,0,.6))}.forge-meter .track{position:relative;block-size:var(--_meter-height);border-radius:var(--_meter-shape);overflow:hidden;background:var(--_meter-background)}.forge-meter .track.segmented{--_meter-background:var(--forge-meter-background, var(--forge-theme-warning-container-low, #f9e9e0));--_meter-color:var(--forge-meter-color, var(--forge-theme-warning, #d14900));transition-property:background;transition-duration:var(--_meter-transition-duration);transition-timing-function:var(--_meter-transition-timing)}.forge-meter .track.segmented.least-optimal{--_meter-background:var(--forge-meter-background, var(--forge-theme-error-container-low, #f6e0e4));--_meter-color:var(--forge-meter-color, var(--forge-theme-error, #b00020))}.forge-meter .track.segmented.optimal{--_meter-background:var(--forge-meter-background, var(--forge-theme-success-container-low, #e6efe6));--_meter-color:var(--forge-meter-color, var(--forge-theme-success, #2e7d32))}.forge-meter .track.segmented .bar{transition-property:translate,box-shadow,background;transition-duration:var(--_meter-transition-duration);transition-timing-function:var(--_meter-transition-timing)}.forge-meter .track.lowest{--_meter-inner-elevation:var(--forge-meter-inner-elevation, 0)}.forge-meter .track.tickmarks::after{content:\"\";position:relative;display:block;width:100%;height:100%;margin-left:2px;background:repeating-linear-gradient(90deg,var(--_meter-color) 0,var(--_meter-color) 1px,var(--_meter-background) 1px,var(--_meter-background) 2px,transparent 2px,transparent calc(100% / (var(--_meter-tickmarks) + 1) + 0px));background-position-x:-2px;opacity:var(--_meter-tickmark-opacity);pointer-events:none;transition-property:background;transition-duration:var(--_meter-transition-duration);transition-timing-function:var(--_meter-transition-timing)}.forge-meter .bar{position:absolute;left:-100%;width:100%;height:100%;border-radius:var(--_meter-inner-shape);box-shadow:var(--_meter-inner-elevation);background:var(--_meter-color);translate:var(--_meter-percentage) 0;transition-property:translate,box-shadow;transition-duration:var(--_meter-transition-duration);transition-timing-function:var(--_meter-transition-timing)}.forge-meter.grouped{display:block;position:absolute;z-index:var(--_meter-z-index);top:0;left:var(--_meter-inset);width:calc(var(--_meter-percentage) + var(--_meter-group-height) * .5);height:100%;border-radius:var(--_meter-inner-shape);border-top-left-radius:0;border-bottom-left-radius:0;margin-left:calc(-1 * var(--_meter-group-height) * .5);background:var(--_meter-color);box-shadow:var(--_meter-inner-elevation)}.forge-meter.grouped.muted{--_meter-color:var(--forge-meter-color, var(--forge-theme-tertiary-container-high, #b5c0ff))}.forge-meter.density--small{--_meter-height:var(--forge-meter-height, var(--forge-spacing-xsmall, 8px))}.forge-meter.density--medium{--_meter-height:var(--forge-meter-height, var(--forge-spacing-medium, 16px))}.forge-meter.density--large{--_meter-height:var(--forge-meter-height, var(--forge-spacing-large, 24px))}.forge-meter.shape--default{--_meter-shape:var(--forge-meter-shape, calc(var(--forge-shape-medium, 4px) * var(--forge-shape-factor, 1)))}.forge-meter.shape--rounded{--_meter-shape:var(--forge-meter-shape, calc(var(--forge-shape-full, 9999px) * var(--forge-shape-factor, 1)))}.forge-meter.shape--squared{--_meter-shape:var(--forge-meter-shape, 0)}.forge-meter.inner-shape--inherit{--_meter-inner-shape:var(--_meter-shape)}.forge-meter.muted .track{--_meter-background:var(--forge-meter-background, var(--forge-theme-tertiary-container-minimum, #f7f8ff));--_meter-color:var(--forge-meter-color, var(--forge-theme-tertiary-container-high, #b5c0ff))}.forge-meter.muted .track.segmented{--_meter-background:var(--forge-meter-background, var(--forge-theme-warning-container-minimum, #fdf8f5));--_meter-color:var(--forge-meter-color, var(--forge-theme-warning-container-high, #eeba9e))}.forge-meter.muted .track.segmented.least-optimal{--_meter-background:var(--forge-meter-background, var(--forge-theme-error-container-minimum, #fcf5f6));--_meter-color:var(--forge-meter-color, var(--forge-theme-error-container-high, #e19eaa))}.forge-meter.muted .track.segmented.optimal{--_meter-background:var(--forge-meter-background, var(--forge-theme-success-container-minimum, #f7faf7));--_meter-color:var(--forge-meter-color, var(--forge-theme-success-container-high, #b0ceb1))}:host(:is(:state(vertical),:--vertical)){display:block}:host(:is(:state(vertical),:--vertical)) .forge-meter{display:flex;flex-direction:row-reverse;align-items:end;width:fit-content;height:100%;max-width:100%}:host(:is(:state(vertical),:--vertical)) .forge-meter .heading{flex-direction:column;align-items:start}:host(:is(:state(vertical),:--vertical)) .forge-meter .heading.not-empty{margin-bottom:0;margin-left:var(--forge-spacing-xsmall,8px)}:host(:is(:state(vertical),:--vertical)) .forge-meter .track{width:var(--_meter-height);height:100%}:host(:is(:state(vertical),:--vertical)) .forge-meter .track.tickmarks::after{margin-top:-2px;margin-left:0;background:repeating-linear-gradient(0,var(--_meter-color) 0,var(--_meter-color) 1px,var(--_meter-background) 1px,var(--_meter-background) 2px,transparent 2px,transparent calc(100% / (var(--_meter-tickmarks) + 1) + 0px));background-position-x:0;background-position-y:2px}:host(:is(:state(vertical),:--vertical)) .forge-meter .bar{left:initial;top:100%;translate:0 calc(-1 * var(--_meter-percentage))}:host(:is(:state(vertical),:--vertical)) .forge-meter.grouped{display:block;top:calc(100% - var(--_meter-percentage) - var(--_meter-inset));left:0;width:100%;height:calc(var(--_meter-percentage) + var(--_meter-group-height) * .5);max-width:initial;border-radius:var(--_meter-inner-shape);border-bottom-left-radius:0;border-bottom-right-radius:0;margin-left:0;margin-bottom:calc(-1 * var(--_meter-group-height) * .5)}.theme--primary:not(.muted) .track:not(.segmented){--_meter-background:var(--forge-meter-background, var(--forge-theme-primary-container-low, #e8eaf6));--_meter-color:var(--forge-meter-color, var(--forge-theme-primary, #3f51b5))}.theme--primary:not(.muted).grouped{--_meter-background:var(--forge-meter-background, var(--forge-theme-primary-container-low, #e8eaf6));--_meter-color:var(--forge-meter-color, var(--forge-theme-primary, #3f51b5))}.theme--primary.muted .track:not(.segmented){--_meter-background:var(--forge-meter-background, var(--forge-theme-primary-container-minimum, #f7f8fc));--_meter-color:var(--forge-meter-color, var(--forge-theme-primary-container-high, #b6bde3))}.theme--primary.muted .grouped{--_meter-background:var(--forge-meter-background, var(--forge-theme-primary-container-minimum, #f7f8fc));--_meter-color:var(--forge-meter-color, var(--forge-theme-primary-container-high, #b6bde3))}.theme--secondary:not(.muted) .track:not(.segmented){--_meter-background:var(--forge-meter-background, var(--forge-theme-secondary-container-low, #fff8e1));--_meter-color:var(--forge-meter-color, var(--forge-theme-secondary, #ffc107))}.theme--secondary:not(.muted).grouped{--_meter-background:var(--forge-meter-background, var(--forge-theme-secondary-container-low, #fff8e1));--_meter-color:var(--forge-meter-color, var(--forge-theme-secondary, #ffc107))}.theme--secondary.muted .track:not(.segmented){--_meter-background:var(--forge-meter-background, var(--forge-theme-secondary-container-minimum, #fffdf5));--_meter-color:var(--forge-meter-color, var(--forge-theme-secondary-container-high, #ffe7a1))}.theme--secondary.muted .grouped{--_meter-background:var(--forge-meter-background, var(--forge-theme-secondary-container-minimum, #fffdf5));--_meter-color:var(--forge-meter-color, var(--forge-theme-secondary-container-high, #ffe7a1))}.theme--tertiary:not(.muted) .track:not(.segmented){--_meter-background:var(--forge-meter-background, var(--forge-theme-tertiary-container-low, #e8ebff));--_meter-color:var(--forge-meter-color, var(--forge-theme-tertiary, #3d5afe))}.theme--tertiary:not(.muted).grouped{--_meter-background:var(--forge-meter-background, var(--forge-theme-tertiary-container-low, #e8ebff));--_meter-color:var(--forge-meter-color, var(--forge-theme-tertiary, #3d5afe))}.theme--tertiary.muted .track:not(.segmented){--_meter-background:var(--forge-meter-background, var(--forge-theme-tertiary-container-minimum, #f7f8ff));--_meter-color:var(--forge-meter-color, var(--forge-theme-tertiary-container-high, #b5c0ff))}.theme--tertiary.muted .grouped{--_meter-background:var(--forge-meter-background, var(--forge-theme-tertiary-container-minimum, #f7f8ff));--_meter-color:var(--forge-meter-color, var(--forge-theme-tertiary-container-high, #b5c0ff))}.theme--success:not(.muted) .track:not(.segmented){--_meter-background:var(--forge-meter-background, var(--forge-theme-success-container-low, #e6efe6));--_meter-color:var(--forge-meter-color, var(--forge-theme-success, #2e7d32))}.theme--success:not(.muted).grouped{--_meter-background:var(--forge-meter-background, var(--forge-theme-success-container-low, #e6efe6));--_meter-color:var(--forge-meter-color, var(--forge-theme-success, #2e7d32))}.theme--success.muted .track:not(.segmented){--_meter-background:var(--forge-meter-background, var(--forge-theme-success-container-minimum, #f7faf7));--_meter-color:var(--forge-meter-color, var(--forge-theme-success-container-high, #b0ceb1))}.theme--success.muted .grouped{--_meter-background:var(--forge-meter-background, var(--forge-theme-success-container-minimum, #f7faf7));--_meter-color:var(--forge-meter-color, var(--forge-theme-success-container-high, #b0ceb1))}.theme--warning:not(.muted) .track:not(.segmented){--_meter-background:var(--forge-meter-background, var(--forge-theme-warning-container-low, #f9e9e0));--_meter-color:var(--forge-meter-color, var(--forge-theme-warning, #d14900))}.theme--warning:not(.muted).grouped{--_meter-background:var(--forge-meter-background, var(--forge-theme-warning-container-low, #f9e9e0));--_meter-color:var(--forge-meter-color, var(--forge-theme-warning, #d14900))}.theme--warning.muted .track:not(.segmented){--_meter-background:var(--forge-meter-background, var(--forge-theme-warning-container-minimum, #fdf8f5));--_meter-color:var(--forge-meter-color, var(--forge-theme-warning-container-high, #eeba9e))}.theme--warning.muted .grouped{--_meter-background:var(--forge-meter-background, var(--forge-theme-warning-container-minimum, #fdf8f5));--_meter-color:var(--forge-meter-color, var(--forge-theme-warning-container-high, #eeba9e))}.theme--error:not(.muted) .track:not(.segmented){--_meter-background:var(--forge-meter-background, var(--forge-theme-error-container-low, #f6e0e4));--_meter-color:var(--forge-meter-color, var(--forge-theme-error, #b00020))}.theme--error:not(.muted).grouped{--_meter-background:var(--forge-meter-background, var(--forge-theme-error-container-low, #f6e0e4));--_meter-color:var(--forge-meter-color, var(--forge-theme-error, #b00020))}.theme--error.muted .track:not(.segmented){--_meter-background:var(--forge-meter-background, var(--forge-theme-error-container-minimum, #fcf5f6));--_meter-color:var(--forge-meter-color, var(--forge-theme-error-container-high, #e19eaa))}.theme--error.muted .grouped{--_meter-background:var(--forge-meter-background, var(--forge-theme-error-container-minimum, #fcf5f6));--_meter-color:var(--forge-meter-color, var(--forge-theme-error-container-high, #e19eaa))}.theme--info:not(.muted) .track:not(.segmented){--_meter-background:var(--forge-meter-background, var(--forge-theme-info-container-low, #e3edf7));--_meter-color:var(--forge-meter-color, var(--forge-theme-info, #1565c0))}.theme--info:not(.muted).grouped{--_meter-background:var(--forge-meter-background, var(--forge-theme-info-container-low, #e3edf7));--_meter-color:var(--forge-meter-color, var(--forge-theme-info, #1565c0))}.theme--info.muted .track:not(.segmented){--_meter-background:var(--forge-meter-background, var(--forge-theme-info-container-minimum, #f6f9fc));--_meter-color:var(--forge-meter-color, var(--forge-theme-info-container-high, #a6c4e7))}.theme--info.muted .grouped{--_meter-background:var(--forge-meter-background, var(--forge-theme-info-container-minimum, #f6f9fc));--_meter-color:var(--forge-meter-color, var(--forge-theme-info-container-high, #a6c4e7))}@media (prefers-reduced-motion:reduce){.track{--_meter-transition-duration:var(--forge-meter-transition-duration, 0)}}@media (forced-colors:active){.track{border:1px solid CanvasText}.track .bar{background:CanvasText}.grouped{border-inline-end:1px solid Canvas!important;background:CanvasText!important}:host(:is(:state(vertical),:--vertical)) .grouped{border-block-start:1px solid CanvasText!important;border-inline-end:initial!important}}';
13
+ const VALUE_STATE_MAP = new Map([
14
+ ['optimal', 'optimum-value'],
15
+ ['suboptimal', 'suboptimum-value'],
16
+ ['least-optimal', 'least-optimum-value']
17
+ ]);
18
+ /**
19
+ * @tag forge-meter
20
+ *
21
+ * @summary Meters display a scalar value within a defined range.
22
+ *
23
+ * @attribute {string} aria-valuetext - Defines a text alternative for the current value. Set this if it would be inaccurate to read the value as a percentage.
24
+ *
25
+ * @state vertical - Applied when the meter is oriented vertically.
26
+ * @state optimum-value - Applied when the value is within the optimum range.
27
+ * @state suboptimum-value - Applied when the value is within the suboptimum range.
28
+ * @state least-optimum-value - Applied when the value is within the least optimum range.
29
+ *
30
+ * @cssproperty --forge-meter-background - The background color of the meter.
31
+ * @cssproperty --forge-meter-color - The color of the meter's bar.
32
+ * @cssproperty --forge-meter-height - The block size of the meter.
33
+ * @cssproperty --forge-meter-shape - The border radius of the meter.
34
+ * @cssproperty --forge-meter-bar-inner-shape - The border radius of the meter's bar.
35
+ * @cssproperty --forge-meter-tickmarks - The number of tickmarks to display.
36
+ * @cssproperty --forge-meter-tickmark-opacity - The opacity of the tickmarks.
37
+ * @cssproperty --forge-meter-transition-duration - The duration of transitions.
38
+ * @cssproperty --forge-meter-transition-timing - The timing function of transitions.
39
+ * @cssproperty --forge-theme-success - The color of the bar when the value is optimal.
40
+ * @cssproperty --forge-theme-success-container-low - The color of the track when the value is optimal.
41
+ * @cssproperty --forge-theme-warning - The color of the bar when the value is suboptimal.
42
+ * @cssproperty --forge-theme-warning-container-low - The color of the track when the value is suboptimal.
43
+ * @cssproperty --forge-theme-error - The color of the bar when the value is least optimal.
44
+ * @cssproperty --forge-theme-error-container-low - The color of the track when the value is least optimal.
45
+ *
46
+ * @csspart root - The root container element.
47
+ * @csspart track - The element comprising the meter's background.
48
+ * @csspart bar - The bar representing the value.
49
+ *
50
+ * @slot - The default slot for the meter's label.
51
+ * @slot value - A textual representation of the meter's value.
52
+ */
53
+ let MeterComponent = class MeterComponent extends LitElement {
54
+ /**
55
+ * Gets the percentage of the meter that's filled.
56
+ * @readonly
57
+ */
58
+ get percentage() {
59
+ return this._percentage;
60
+ }
61
+ get labels() {
62
+ return this._internals.labels;
63
+ }
64
+ get form() {
65
+ return this._internals.form;
66
+ }
67
+ constructor() {
68
+ super();
69
+ /**
70
+ * The current value of the meter.
71
+ * @default 0
72
+ * @attribute
73
+ */
74
+ this.value = 0;
75
+ /**
76
+ * The minimum value of the meter.
77
+ * @default 0
78
+ * @attribute
79
+ */
80
+ this.min = 0;
81
+ /**
82
+ * The maximum value of the meter.
83
+ * @default 1
84
+ * @attribute
85
+ */
86
+ this.max = 1;
87
+ /**
88
+ * Whether to display tickmarks.
89
+ * @default false
90
+ * @attribute
91
+ */
92
+ this.tickmarks = false;
93
+ /**
94
+ * Whether the current value is displayed as a percentage or raw value. When set to `'manual'`
95
+ * the value text is not shown automatically but can still be set manually via the value slot.
96
+ * @default 'manual'
97
+ * @attribute value-mode
98
+ */
99
+ this.valueMode = 'manual';
100
+ /**
101
+ * Whether the meter is oriented horizontally or vertically.
102
+ * @default 'horizontal'
103
+ * @attribute
104
+ */
105
+ this.direction = 'horizontal';
106
+ /**
107
+ * The shape of the meter.
108
+ * @default 'default'
109
+ * @attribute
110
+ */
111
+ this.shape = 'default';
112
+ /**
113
+ * The shape of the bar.
114
+ * @default 'default'
115
+ * @attribute inner-shape
116
+ */
117
+ this.innerShape = 'default';
118
+ /**
119
+ * The density of the meter.
120
+ * @default 'medium'
121
+ * @attribute
122
+ */
123
+ this.density = 'medium';
124
+ /**
125
+ * The theme of the meter.
126
+ * @default 'default'
127
+ * @attribute
128
+ */
129
+ this.theme = 'default';
130
+ /**
131
+ * Whether the theme is muted.
132
+ * @default false
133
+ * @attribute
134
+ */
135
+ this.muted = false;
136
+ this._percentage = 0;
137
+ this._status = 'optimal';
138
+ this._segmented = false;
139
+ this._grouped = false;
140
+ this._hasSlottedContent = false;
141
+ this._internals = this.attachInternals();
142
+ }
143
+ connectedCallback() {
144
+ super.connectedCallback();
145
+ setDefaultAria(this, this._internals, {
146
+ role: 'meter',
147
+ ariaValueNow: `${this.value}`,
148
+ ariaValueMin: `${this.min}`,
149
+ ariaValueMax: `${this.max}`
150
+ });
151
+ this._getGrouped();
152
+ }
153
+ willUpdate(changedProperties) {
154
+ const keys = Array.from(changedProperties.keys());
155
+ if (keys.some(key => ['value', 'min', 'max', 'low', 'high', 'optimum'].includes(key.toString()))) {
156
+ this._getStatus();
157
+ }
158
+ if (keys.some(key => ['low', 'high'].includes(key.toString()))) {
159
+ this._getSegmented();
160
+ }
161
+ // Update default ARIA when the current, min, or max value changes. Set the state when the
162
+ // direction changes.
163
+ changedProperties.forEach((_, key) => {
164
+ switch (key) {
165
+ case 'value':
166
+ setDefaultAria(this, this._internals, { ariaValueNow: `${this.value}` });
167
+ break;
168
+ case 'min':
169
+ setDefaultAria(this, this._internals, { ariaValueMin: `${this.min}` });
170
+ break;
171
+ case 'max':
172
+ setDefaultAria(this, this._internals, { ariaValueMax: `${this.max}` });
173
+ break;
174
+ case 'direction':
175
+ toggleState(this._internals, 'vertical', this.direction === 'vertical');
176
+ break;
177
+ }
178
+ });
179
+ }
180
+ render() {
181
+ const classes = {
182
+ 'inner-shape--inherit': this.innerShape === 'inherit',
183
+ muted: this.muted,
184
+ [`density--${this.density}`]: true,
185
+ [`shape--${this.shape}`]: true,
186
+ [`theme--${this.theme}`]: true
187
+ };
188
+ return this._grouped
189
+ ? html `
190
+ <div
191
+ part="root"
192
+ class=${classMap({ 'forge-meter': true, grouped: true, ...classes })}
193
+ style=${styleMap({ '--_meter-percentage': this._percentage + '%' })}></div>
194
+ `
195
+ : html `
196
+ <div part="root" class=${classMap({ 'forge-meter': true, ...classes })}>
197
+ <div class=${classMap({ heading: true, 'not-empty': this._hasSlottedContent })} @slotchange=${this._handleSlotChange}>
198
+ <div class="label"><slot></slot></div>
199
+ <div class="value">
200
+ <slot name="value">${this.valueMode !== 'manual' ? html `${this.valueMode === 'percentage' ? `${this._percentage}%` : this.value}` : ''}</slot>
201
+ </div>
202
+ </div>
203
+ <div
204
+ part="track"
205
+ class=${classMap({
206
+ track: true,
207
+ segmented: this._segmented,
208
+ optimal: this._status === 'optimal',
209
+ suboptimal: this._status === 'suboptimal',
210
+ 'least-optimal': this._status === 'least-optimal',
211
+ lowest: this._percentage === 0,
212
+ tickmarks: this.tickmarks
213
+ })}>
214
+ <div part="bar" class="bar" style=${styleMap({ '--_meter-percentage': this._percentage + '%' })}></div>
215
+ </div>
216
+ </div>
217
+ `;
218
+ }
219
+ /**
220
+ * Determines the percentage of the meter that's filled and whether the value is optimal,
221
+ * suboptimal, or least optimal.
222
+ */
223
+ _getStatus() {
224
+ const range = this.max - this.min;
225
+ this._percentage = range ? ((this.value - this.min) / range) * 100 : 0;
226
+ // Clamp the percentage between 0 and 100. Round to 3 decimal places to avoid floating point errors.
227
+ this._percentage = +Math.max(0, Math.min(100, this._percentage)).toFixed(3);
228
+ // Fallback to 0 if the percentage is NaN.
229
+ if (isNaN(this._percentage)) {
230
+ this._percentage = 0;
231
+ }
232
+ // Dispatch an event to the parent group.
233
+ if (this._grouped) {
234
+ const event = new Event('change', { bubbles: true, composed: true });
235
+ this.dispatchEvent(event);
236
+ }
237
+ // Use working values in case the properties are not set.
238
+ const low = this.low ?? this.min;
239
+ const high = this.high ?? this.max;
240
+ const optimum = this.optimum ?? this.max;
241
+ // The region that contains the optimum value is optimal. A region is suboptimal if it
242
+ // neighbors the optimal region and least-optimal otherwise.
243
+ if (optimum < low) {
244
+ this._status = this.value < low ? 'optimal' : this.value < high ? 'suboptimal' : 'least-optimal';
245
+ }
246
+ else if (optimum > high) {
247
+ this._status = this.value > high ? 'optimal' : this.value > low ? 'suboptimal' : 'least-optimal';
248
+ }
249
+ else {
250
+ this._status = this.value < low ? 'suboptimal' : this.value > high ? 'suboptimal' : 'optimal';
251
+ }
252
+ this._setValueState();
253
+ }
254
+ /**
255
+ * Determines whether low and high ranges are set. The meter is segmented if either the low or
256
+ * high property is defined.
257
+ *
258
+ * When the meter is segmented the default or themed color scheme is replaced by semantic colors
259
+ * corresponding to optimal, suboptimal, and least optimal values.
260
+ */
261
+ _getSegmented() {
262
+ this._segmented = this.low != null || this.high != null;
263
+ }
264
+ /**
265
+ * Checks if the meter is part of a group and inherits the min and max values.
266
+ */
267
+ async _getGrouped() {
268
+ const group = this.closest('forge-meter-group');
269
+ this._grouped = !!group;
270
+ if (group) {
271
+ await group.updateComplete;
272
+ this.direction = group.direction;
273
+ this.min = group.min;
274
+ this.max = group.max;
275
+ }
276
+ }
277
+ /**
278
+ * Checks whether the meter has any slotted content.
279
+ */
280
+ _handleSlotChange() {
281
+ const nodes = [...this._defaultNodes, ...this._valueNodes].filter(node => !!node.textContent?.trim());
282
+ this._hasSlottedContent = !!nodes.length;
283
+ }
284
+ /**
285
+ * Updates the internal state of the meter based on the current status.
286
+ */
287
+ _setValueState() {
288
+ VALUE_STATE_MAP.forEach((value, status) => toggleState(this._internals, value, this._status === status));
289
+ }
290
+ };
291
+ MeterComponent.styles = unsafeCSS(styles);
292
+ MeterComponent.formAssociated = true;
293
+ __decorate([
294
+ property({ type: Number })
295
+ ], MeterComponent.prototype, "value", void 0);
296
+ __decorate([
297
+ property({ type: Number })
298
+ ], MeterComponent.prototype, "min", void 0);
299
+ __decorate([
300
+ property({ type: Number })
301
+ ], MeterComponent.prototype, "max", void 0);
302
+ __decorate([
303
+ property({ type: Number })
304
+ ], MeterComponent.prototype, "low", void 0);
305
+ __decorate([
306
+ property({ type: Number })
307
+ ], MeterComponent.prototype, "high", void 0);
308
+ __decorate([
309
+ property({ type: Number })
310
+ ], MeterComponent.prototype, "optimum", void 0);
311
+ __decorate([
312
+ property({ type: Boolean })
313
+ ], MeterComponent.prototype, "tickmarks", void 0);
314
+ __decorate([
315
+ property({ attribute: 'value-mode' })
316
+ ], MeterComponent.prototype, "valueMode", void 0);
317
+ __decorate([
318
+ property()
319
+ ], MeterComponent.prototype, "direction", void 0);
320
+ __decorate([
321
+ property()
322
+ ], MeterComponent.prototype, "shape", void 0);
323
+ __decorate([
324
+ property({ attribute: 'inner-shape' })
325
+ ], MeterComponent.prototype, "innerShape", void 0);
326
+ __decorate([
327
+ property()
328
+ ], MeterComponent.prototype, "density", void 0);
329
+ __decorate([
330
+ property()
331
+ ], MeterComponent.prototype, "theme", void 0);
332
+ __decorate([
333
+ property({ type: Boolean })
334
+ ], MeterComponent.prototype, "muted", void 0);
335
+ __decorate([
336
+ state()
337
+ ], MeterComponent.prototype, "_percentage", void 0);
338
+ __decorate([
339
+ state()
340
+ ], MeterComponent.prototype, "_status", void 0);
341
+ __decorate([
342
+ state()
343
+ ], MeterComponent.prototype, "_segmented", void 0);
344
+ __decorate([
345
+ state()
346
+ ], MeterComponent.prototype, "_grouped", void 0);
347
+ __decorate([
348
+ state()
349
+ ], MeterComponent.prototype, "_hasSlottedContent", void 0);
350
+ __decorate([
351
+ queryAssignedNodes()
352
+ ], MeterComponent.prototype, "_defaultNodes", void 0);
353
+ __decorate([
354
+ queryAssignedNodes({ slot: 'value' })
355
+ ], MeterComponent.prototype, "_valueNodes", void 0);
356
+ MeterComponent = __decorate([
357
+ customElement('forge-meter')
358
+ ], MeterComponent);
359
+ export { MeterComponent };
@@ -0,0 +1,7 @@
1
+ /**
2
+ * @license
3
+ * Copyright Tyler Technologies, Inc.
4
+ * License: Apache-2.0
5
+ */
6
+ export * from './meter-group';
7
+ export declare function defineMeterGroupComponent(): void;
@@ -0,0 +1,11 @@
1
+ /**
2
+ * @license
3
+ * Copyright Tyler Technologies, Inc.
4
+ * License: Apache-2.0
5
+ */
6
+ import { tryDefine } from '@tylertech/forge-core';
7
+ import { MeterGroupComponent } from './meter-group';
8
+ export * from './meter-group';
9
+ export function defineMeterGroupComponent() {
10
+ tryDefine('forge-meter-group', MeterGroupComponent);
11
+ }