@vonage/vivid 3.49.0 → 3.50.1

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 (195) hide show
  1. package/accordion/index.cjs +0 -2
  2. package/accordion/index.js +0 -2
  3. package/accordion-item/index.cjs +0 -2
  4. package/accordion-item/index.js +0 -2
  5. package/alert/index.cjs +0 -2
  6. package/alert/index.js +0 -2
  7. package/audio-player/index.cjs +0 -2
  8. package/audio-player/index.js +0 -2
  9. package/banner/index.cjs +0 -2
  10. package/banner/index.js +0 -2
  11. package/breadcrumb-item/index.cjs +0 -2
  12. package/breadcrumb-item/index.js +0 -2
  13. package/button/index.cjs +0 -2
  14. package/button/index.js +0 -2
  15. package/checkbox/index.cjs +0 -3
  16. package/checkbox/index.js +0 -3
  17. package/combobox/index.cjs +4 -4
  18. package/combobox/index.js +4 -4
  19. package/custom-elements.json +749 -230
  20. package/data-grid/index.cjs +0 -2
  21. package/data-grid/index.js +0 -2
  22. package/date-picker/index.cjs +3 -2
  23. package/date-picker/index.js +3 -2
  24. package/date-range-picker/index.cjs +3 -2
  25. package/date-range-picker/index.js +3 -2
  26. package/dialog/index.cjs +0 -3
  27. package/dialog/index.js +0 -3
  28. package/fab/index.cjs +0 -2
  29. package/fab/index.js +0 -2
  30. package/file-picker/index.cjs +1 -2
  31. package/file-picker/index.js +1 -2
  32. package/focus/index.cjs +1 -1
  33. package/focus/index.js +1 -1
  34. package/index.cjs +20 -15
  35. package/index.js +9 -7
  36. package/lib/components.d.ts +1 -0
  37. package/lib/file-picker/file-picker.d.ts +2 -2
  38. package/lib/menu/definition.d.ts +2 -2
  39. package/lib/radio-group/definition.d.ts +2 -2
  40. package/lib/switch/switch.d.ts +2 -2
  41. package/lib/time-picker/definition.d.ts +3 -0
  42. package/lib/time-picker/locale.d.ts +12 -0
  43. package/lib/time-picker/time/picker.d.ts +9 -0
  44. package/lib/time-picker/time/presentationTime.d.ts +5 -0
  45. package/lib/time-picker/time/time.d.ts +15 -0
  46. package/lib/time-picker/time-picker.d.ts +16 -0
  47. package/lib/time-picker/time-picker.form-associated.d.ts +10 -0
  48. package/lib/time-picker/time-picker.template.d.ts +4 -0
  49. package/listbox/index.cjs +4 -12
  50. package/listbox/index.js +4 -12
  51. package/locales/en-GB.cjs +15 -0
  52. package/locales/en-GB.js +15 -0
  53. package/locales/en-US.cjs +15 -0
  54. package/locales/en-US.js +15 -0
  55. package/locales/ja-JP.cjs +15 -0
  56. package/locales/ja-JP.js +15 -0
  57. package/locales/zh-CN.cjs +15 -0
  58. package/locales/zh-CN.js +15 -0
  59. package/menu/index.cjs +0 -2
  60. package/menu/index.js +0 -2
  61. package/menu-item/index.cjs +0 -2
  62. package/menu-item/index.js +0 -2
  63. package/nav-disclosure/index.cjs +0 -2
  64. package/nav-disclosure/index.js +0 -2
  65. package/nav-item/index.cjs +0 -2
  66. package/nav-item/index.js +0 -2
  67. package/number-field/index.cjs +1 -2
  68. package/number-field/index.js +1 -2
  69. package/option/index.cjs +0 -5
  70. package/option/index.js +0 -5
  71. package/package.json +1 -1
  72. package/pagination/index.cjs +0 -2
  73. package/pagination/index.js +0 -2
  74. package/popup/index.cjs +0 -2
  75. package/popup/index.js +0 -2
  76. package/radio/index.cjs +0 -3
  77. package/radio/index.js +0 -3
  78. package/select/index.cjs +0 -3
  79. package/select/index.js +0 -3
  80. package/selectable-box/index.cjs +0 -3
  81. package/selectable-box/index.js +0 -3
  82. package/shared/date-picker/date-picker-base.d.ts +2 -2
  83. package/shared/definition.cjs +2 -6
  84. package/shared/definition.js +2 -6
  85. package/shared/definition11.cjs +1 -2
  86. package/shared/definition11.js +1 -2
  87. package/shared/definition15.cjs +2 -6
  88. package/shared/definition15.js +2 -6
  89. package/shared/definition16.cjs +1 -1
  90. package/shared/definition16.js +1 -1
  91. package/shared/definition17.cjs +1 -4
  92. package/shared/definition17.js +1 -4
  93. package/shared/definition18.cjs +2 -4
  94. package/shared/definition18.js +0 -2
  95. package/shared/definition19.cjs +2 -4
  96. package/shared/definition19.js +0 -2
  97. package/shared/definition20.cjs +1 -4
  98. package/shared/definition20.js +1 -4
  99. package/shared/definition23.cjs +1 -2
  100. package/shared/definition23.js +1 -2
  101. package/shared/definition24.cjs +2 -5
  102. package/shared/definition24.js +2 -5
  103. package/shared/definition28.cjs +2 -3
  104. package/shared/definition28.js +2 -3
  105. package/shared/definition30.cjs +2 -3
  106. package/shared/definition30.js +2 -3
  107. package/shared/definition31.cjs +2 -3
  108. package/shared/definition31.js +2 -3
  109. package/shared/definition34.cjs +1 -1
  110. package/shared/definition34.js +1 -1
  111. package/shared/definition35.cjs +2 -7
  112. package/shared/definition35.js +2 -7
  113. package/shared/definition4.cjs +3 -3
  114. package/shared/definition4.js +4 -4
  115. package/shared/definition40.cjs +3 -7
  116. package/shared/definition40.js +3 -7
  117. package/shared/definition41.cjs +5 -6
  118. package/shared/definition41.js +4 -5
  119. package/shared/definition42.cjs +5 -10
  120. package/shared/definition42.js +3 -8
  121. package/shared/definition44.cjs +1 -2
  122. package/shared/definition44.js +1 -2
  123. package/shared/definition45.cjs +1 -2
  124. package/shared/definition45.js +1 -2
  125. package/shared/definition46.cjs +1 -2
  126. package/shared/definition46.js +1 -2
  127. package/shared/definition48.cjs +2 -6
  128. package/shared/definition48.js +2 -6
  129. package/shared/definition5.cjs +1 -2
  130. package/shared/definition5.js +1 -2
  131. package/shared/definition51.cjs +2 -6
  132. package/shared/definition51.js +2 -6
  133. package/shared/definition52.cjs +2 -3
  134. package/shared/definition52.js +2 -3
  135. package/shared/definition53.cjs +1 -1
  136. package/shared/definition53.js +1 -1
  137. package/shared/definition54.cjs +768 -90
  138. package/shared/definition54.js +767 -89
  139. package/shared/definition55.cjs +75 -57
  140. package/shared/definition55.js +74 -56
  141. package/shared/definition56.cjs +100 -71
  142. package/shared/definition56.js +99 -70
  143. package/shared/definition57.cjs +76 -291
  144. package/shared/definition57.js +77 -292
  145. package/shared/definition58.cjs +303 -13
  146. package/shared/definition58.js +302 -13
  147. package/shared/definition61.cjs +20 -0
  148. package/shared/definition61.js +17 -0
  149. package/shared/definition9.cjs +1 -2
  150. package/shared/definition9.js +1 -2
  151. package/shared/icon.cjs +1 -1
  152. package/shared/icon.js +1 -1
  153. package/shared/localization/Locale.d.ts +2 -0
  154. package/shared/patterns/index.d.ts +1 -0
  155. package/shared/patterns/trapped-focus.d.ts +4 -0
  156. package/shared/presentationDate.cjs +15 -34
  157. package/shared/presentationDate.js +15 -34
  158. package/shared/text-field.cjs +1 -1
  159. package/shared/text-field.js +1 -1
  160. package/shared/trapped-focus.cjs +29 -0
  161. package/shared/trapped-focus.js +27 -0
  162. package/slider/index.cjs +0 -2
  163. package/slider/index.js +0 -2
  164. package/split-button/index.cjs +0 -2
  165. package/split-button/index.js +0 -2
  166. package/styles/core/all.css +1 -1
  167. package/styles/core/theme.css +1 -1
  168. package/styles/core/typography.css +1 -1
  169. package/styles/tokens/theme-dark.css +4 -4
  170. package/styles/tokens/theme-light.css +4 -4
  171. package/styles/tokens/vivid-2-compat.css +1 -1
  172. package/switch/index.cjs +0 -2
  173. package/switch/index.js +0 -2
  174. package/tab/index.cjs +0 -3
  175. package/tab/index.js +0 -3
  176. package/tabs/index.cjs +0 -3
  177. package/tabs/index.js +0 -3
  178. package/tag/index.cjs +0 -3
  179. package/tag/index.js +0 -3
  180. package/text-area/index.cjs +0 -2
  181. package/text-area/index.js +0 -2
  182. package/text-field/index.cjs +1 -1
  183. package/text-field/index.js +1 -1
  184. package/time-picker/index.cjs +38 -0
  185. package/time-picker/index.js +36 -0
  186. package/toggletip/index.cjs +1 -3
  187. package/toggletip/index.js +1 -3
  188. package/tooltip/index.cjs +1 -3
  189. package/tooltip/index.js +1 -3
  190. package/tree-item/index.cjs +1 -4
  191. package/tree-item/index.js +1 -4
  192. package/tree-view/index.cjs +1 -1
  193. package/tree-view/index.js +1 -1
  194. package/vivid.api.json +111 -42
  195. package/style.css +0 -1
@@ -1,12 +1,217 @@
1
1
  'use strict';
2
2
 
3
3
  const index = require('./index.cjs');
4
+ const definition$1 = require('./definition53.cjs');
4
5
  const definition = require('./definition60.cjs');
5
- const anchored = require('./anchored.cjs');
6
+ const definition$2 = require('./definition11.cjs');
7
+ require('./affix.cjs');
8
+ const index$1 = require('./index2.cjs');
9
+ const localized = require('./localized.cjs');
10
+ const trappedFocus = require('./trapped-focus.cjs');
11
+ const formAssociated = require('./form-associated.cjs');
12
+ const applyMixins = require('./apply-mixins.cjs');
13
+ const ref = require('./ref.cjs');
6
14
  const when = require('./when.cjs');
15
+ const repeat = require('./repeat.cjs');
7
16
  const classNames = require('./class-names.cjs');
8
17
 
9
- const styles = ".control{display:inline-block}.content-wrapper{width:var(--toggletip-inline-size, auto);padding:16px}.headline{font:var(--vvd-typography-base-bold)}.action-items{display:flex;justify-content:flex-end;gap:10px}::slotted([slot=action-items]){margin-block-start:16px}\n";
18
+ const styles = ":host{display:inline-block}.base,.control{inline-size:100%}.dialog{display:inline-flex;flex-direction:column}.dialog .footer{display:flex;align-items:center;justify-content:flex-end;padding:8px;border-top:1px solid var(--vvd-color-neutral-200);gap:8px}.time-pickers{display:flex;overflow:hidden;padding:4px;block-size:188px;gap:4px}.time-pickers .picker{position:relative;display:flex;flex-direction:column;padding:0;margin:0;border-radius:4px;gap:4px;inline-size:50px;list-style:none;overflow-x:hidden;overflow-y:hidden;scrollbar-width:thin}.time-pickers .picker:hover{overflow-y:auto}.time-pickers .picker:after{display:block;flex-shrink:0;block-size:156px;content:\"\"}.time-pickers .picker:focus-visible{--focus-stroke-gap-color: transparent;--focus-inset: -2px;box-shadow:inset 0 0 0 3px var(--focus-stroke-gap-color, currentColor);outline:2px solid var(--focus-stroke-color, var(--vvd-color-canvas-text));outline-offset:calc(-2px - var(--focus-inset, 0px))}.time-pickers .item{display:flex;flex-shrink:0;align-items:center;justify-content:center;background-color:var(--_appearance-color-fill);block-size:28px;border-radius:4px;color:var(--_appearance-color-text);cursor:pointer;font:var(--vvd-typography-base);inline-size:50px}.time-pickers .item{--_connotation-color-primary: var(--vvd-time-picker-accent-primary, var(--vvd-color-canvas-text));--_connotation-color-faint: var(--vvd-time-picker-accent-faint, var(--vvd-color-neutral-50));--_connotation-color-soft: var(--vvd-time-picker-accent-soft, var(--vvd-color-neutral-100));--_connotation-color-dim: var(--vvd-time-picker-accent-dim, var(--vvd-color-neutral-200));--_connotation-color-pale: var(--vvd-time-picker-accent-pale, var(--vvd-color-neutral-300))}.time-pickers .item{--_appearance-color-text: var(--_connotation-color-primary);--_appearance-color-fill: transparent;--_appearance-color-outline: transparent}.time-pickers .item:where(:hover,.hover):where(:not(:disabled,.disabled,.readonly)){--_appearance-color-text: var(--_connotation-color-primary);--_appearance-color-fill: var(--_connotation-color-faint);--_appearance-color-outline: transparent}.time-pickers .item:where(:active,.active):where(:not(:disabled,.disabled)){--_appearance-color-text: var(--_connotation-color-primary);--_appearance-color-fill: var(--_connotation-color-soft);--_appearance-color-outline: transparent}.time-pickers .item:where(.selected,[aria-current]):where(:not(:disabled,.disabled)){--_appearance-color-text: var(--_connotation-color-primary);--_appearance-color-fill: var(--_connotation-color-dim);--_appearance-color-outline: transparent}.time-pickers .item:where(.selected,[aria-current]):where(:hover,.hover):where(:not(:disabled,.disabled,.readonly)){--_appearance-color-text: var(--_connotation-color-primary);--_appearance-color-fill: var(--_connotation-color-pale);--_appearance-color-outline: transparent}.time-pickers .item:where(.selected,[aria-current]):where(:disabled,.disabled){--_appearance-color-text: var(--vvd-color-neutral-300);--_appearance-color-fill: var(--vvd-color-neutral-200);--_appearance-color-outline: transparent}\n";
19
+
20
+ class _TimePicker extends index.FoundationElement {
21
+ }
22
+ class FormAssociatedTimePicker extends formAssociated.FormAssociated(_TimePicker) {
23
+ constructor() {
24
+ super(...arguments);
25
+ this.proxy = document.createElement("input");
26
+ }
27
+ }
28
+
29
+ const isValidTimeStr = (timeStr) => {
30
+ const parts = timeStr.split(":");
31
+ if (parts.length !== 3) {
32
+ return false;
33
+ }
34
+ const [hours, minutes, seconds] = parts;
35
+ if (hours.length !== 2 || minutes.length !== 2 || seconds.length !== 2) {
36
+ return false;
37
+ }
38
+ const hoursNum = parseInt(hours, 10);
39
+ const minutesNum = parseInt(minutes, 10);
40
+ const secondsNum = parseInt(seconds, 10);
41
+ if (isNaN(hoursNum) || isNaN(minutesNum) || isNaN(secondsNum)) {
42
+ return false;
43
+ }
44
+ if (hoursNum < 0 || hoursNum > 23) {
45
+ return false;
46
+ }
47
+ if (minutesNum < 0 || minutesNum > 59) {
48
+ return false;
49
+ }
50
+ if (secondsNum < 0 || secondsNum > 59) {
51
+ return false;
52
+ }
53
+ return true;
54
+ };
55
+ const parseTimePart = (partStr) => Number.parseInt(partStr, 10);
56
+ const formatTimePart = (part) => part.toString().padStart(2, "0");
57
+ const parseTimeStr = (timeStr) => {
58
+ const [hoursStr, minutesStr, secondsStr] = timeStr.split(":");
59
+ const hours = parseTimePart(hoursStr);
60
+ const minutes = parseTimePart(minutesStr);
61
+ const seconds = parseTimePart(secondsStr);
62
+ return {
63
+ hourStr: hoursStr,
64
+ hours,
65
+ minuteStr: minutesStr,
66
+ minutes,
67
+ secondStr: secondsStr,
68
+ seconds,
69
+ meridiem: hours < 12 ? "AM" : "PM"
70
+ };
71
+ };
72
+ const hoursAs12hClock = (hour) => hour % 12 || 12;
73
+
74
+ const formatPresentationTime = (timeStr, includeSeconds, use12HourClock) => {
75
+ const time = parseTimeStr(timeStr);
76
+ const hoursStr = formatTimePart(use12HourClock ? hoursAs12hClock(time.hours) : time.hours);
77
+ let result = `${hoursStr}:${time.minuteStr}`;
78
+ if (includeSeconds) {
79
+ result += `:${time.secondStr}`;
80
+ }
81
+ if (use12HourClock) {
82
+ result += ` ${time.meridiem}`;
83
+ }
84
+ return result;
85
+ };
86
+ const isDigit = (char) => char >= "0" && char <= "9";
87
+ const parsePresentationTime = (input, use12HourClock) => {
88
+ const cleanedInput = input.toLowerCase();
89
+ const numerals = [];
90
+ let meridiem;
91
+ for (let i = 0; i < cleanedInput.length; i++) {
92
+ const char = cleanedInput[i];
93
+ if (char === "a" && cleanedInput[i + 1] === "m") {
94
+ i++;
95
+ meridiem = "AM";
96
+ }
97
+ if (char === "p" && cleanedInput[i + 1] === "m") {
98
+ i++;
99
+ meridiem = "PM";
100
+ }
101
+ if (isDigit(char)) {
102
+ let numeral = char;
103
+ while (isDigit(cleanedInput[i + 1])) {
104
+ i++;
105
+ numeral += cleanedInput[i];
106
+ }
107
+ numerals.push(Number.parseInt(numeral, 10));
108
+ }
109
+ }
110
+ if (numerals.length === 0 || numerals.length > 3) {
111
+ throw new Error("Invalid time format");
112
+ }
113
+ if (meridiem && (numerals[0] < 1 || numerals[0] > 12)) {
114
+ throw new Error("Invalid time format");
115
+ }
116
+ if (meridiem || use12HourClock) {
117
+ if (numerals[0] === 12) {
118
+ numerals[0] = 0;
119
+ }
120
+ }
121
+ if (meridiem === "PM") {
122
+ numerals[0] = numerals[0] + 12;
123
+ }
124
+ const [hours, minutes = 0, seconds = 0] = numerals;
125
+ if (hours > 23 || minutes > 59 || seconds > 59) {
126
+ throw new Error("Invalid value");
127
+ }
128
+ return [hours, minutes, seconds].map(formatTimePart).join(":");
129
+ };
130
+
131
+ const fallsIntoMeridiem = (meridiem, hour) => meridiem === "AM" && hour < 12 || meridiem === "PM" && hour >= 12;
132
+ const getHoursOptions = (min, max, forMeridiem) => {
133
+ const result = [];
134
+ const minHour = min ? parseTimeStr(min).hours : 0;
135
+ const maxHour = max ? parseTimeStr(max).hours : 23;
136
+ for (let i = minHour; i <= maxHour; i++) {
137
+ if (forMeridiem && !fallsIntoMeridiem(forMeridiem, i)) {
138
+ continue;
139
+ }
140
+ result.push({
141
+ value: formatTimePart(i),
142
+ label: formatTimePart(forMeridiem ? hoursAs12hClock(i) : i)
143
+ });
144
+ }
145
+ return result;
146
+ };
147
+ const getMinutesOptions = (step, value, min, max) => {
148
+ const result = [];
149
+ let minMinute = 0;
150
+ let maxMinute = 59;
151
+ if (min) {
152
+ const { hourStr: minHourStr, minutes: minMinutes } = parseTimeStr(min);
153
+ if (value && parseTimeStr(value).hourStr === minHourStr) {
154
+ minMinute = minMinutes;
155
+ }
156
+ }
157
+ if (max) {
158
+ const { hourStr: maxHourStr, minutes: maxMinutes } = parseTimeStr(max);
159
+ if (value && parseTimeStr(value).hourStr === maxHourStr) {
160
+ maxMinute = maxMinutes;
161
+ }
162
+ }
163
+ for (let i = minMinute; i <= maxMinute; i += Math.max(1, step ?? 1)) {
164
+ const minutes = formatTimePart(i);
165
+ result.push({
166
+ value: minutes,
167
+ label: minutes
168
+ });
169
+ }
170
+ return result;
171
+ };
172
+ const getSecondsOptions = (step, value, min, max) => {
173
+ const result = [];
174
+ let minSecond = 0;
175
+ let maxSecond = 59;
176
+ if (min) {
177
+ const minTime = parseTimeStr(min);
178
+ if (value && (parseTimeStr(value).hourStr === minTime.hourStr && parseTimeStr(value).minuteStr) === minTime.minuteStr) {
179
+ minSecond = minTime.seconds;
180
+ }
181
+ }
182
+ if (max) {
183
+ const maxTime = parseTimeStr(max);
184
+ if (value && (parseTimeStr(value).hourStr === maxTime.hourStr && parseTimeStr(value).minuteStr) === maxTime.minuteStr) {
185
+ maxSecond = maxTime.seconds;
186
+ }
187
+ }
188
+ for (let i = minSecond; i <= maxSecond; i += Math.max(1, step)) {
189
+ const seconds = formatTimePart(i);
190
+ result.push({
191
+ value: seconds,
192
+ label: seconds
193
+ });
194
+ }
195
+ return result;
196
+ };
197
+ const getMeridiesOptions = (min, max) => {
198
+ const result = [];
199
+ const hideAM = min ? parseTimeStr(min).meridiem === "PM" : false;
200
+ if (!hideAM) {
201
+ result.push({
202
+ value: "AM",
203
+ label: "AM"
204
+ });
205
+ }
206
+ const hidePM = max ? parseTimeStr(max).meridiem === "AM" : false;
207
+ if (!hidePM) {
208
+ result.push({
209
+ value: "PM",
210
+ label: "PM"
211
+ });
212
+ }
213
+ return result;
214
+ };
10
215
 
11
216
  var __defProp = Object.defineProperty;
12
217
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
@@ -19,128 +224,601 @@ var __decorateClass = (decorators, target, key, kind) => {
19
224
  __defProp(target, key, result);
20
225
  return result;
21
226
  };
22
- let Toggletip = class extends index.FoundationElement {
227
+ const ValidTimeFilter = {
228
+ fromView: (value) => {
229
+ if (value && isValidTimeStr(value)) {
230
+ return value;
231
+ }
232
+ return "";
233
+ },
234
+ toView(value) {
235
+ return value;
236
+ }
237
+ };
238
+ let TimePicker = class extends FormAssociatedTimePicker {
23
239
  constructor() {
24
- super(...arguments);
25
- this.#ANCHOR_ARIA_LABEL_SUFFIX = " ; Show more information";
26
- this.alternate = false;
27
- this.placement = "right";
28
- this.open = false;
29
- this.#openIfClosed = () => {
30
- if (!this.open)
31
- index.DOM.queueUpdate(() => this.open = true);
240
+ super();
241
+ this.readOnly = false;
242
+ this.minutesStep = null;
243
+ this.secondsStep = null;
244
+ this.#getFocusableEls = () => this.shadowRoot.querySelectorAll(`
245
+ .dialog [tabindex="0"],
246
+ .dialog .vwc-button:not(:disabled)
247
+ `);
248
+ this.#onFocusIn = () => {
249
+ this.$emit("focus", void 0, { bubbles: false });
32
250
  };
33
- this.#closeOnClickOutside = (e) => {
34
- if (!this.contains(e.target))
35
- this.open = false;
251
+ this.#onFocusOut = () => {
252
+ this.$emit("blur", void 0, { bubbles: false });
36
253
  };
37
- this.#closeOnEscape = (e) => {
38
- if (e.key === "Escape")
39
- this.open = false;
254
+ this._popupOpen = false;
255
+ this.#dismissOnClickOutside = (event) => {
256
+ if (!this._popupOpen) {
257
+ return;
258
+ }
259
+ const path = event.composedPath();
260
+ const elementsToIgnoreClicksOn = [this._dialogEl, this._clockButtonEl];
261
+ if (!elementsToIgnoreClicksOn.some((element) => path.includes(element))) {
262
+ this._closePopup(false);
263
+ }
40
264
  };
265
+ this._presentationValue = "";
266
+ this.value = "";
267
+ this.min = "";
268
+ this.max = "";
269
+ this.proxy.type = "time";
270
+ this.proxy.step = "1";
41
271
  }
42
- #ANCHOR_ARIA_LABEL_SUFFIX;
43
- openChanged(oldValue, newValue) {
44
- if (oldValue === void 0)
45
- return;
46
- if (newValue) {
47
- this.setAttribute("role", "status");
48
- } else {
49
- this.removeAttribute("role");
272
+ /**
273
+ * @internal
274
+ */
275
+ readOnlyChanged() {
276
+ if (this.proxy instanceof HTMLInputElement) {
277
+ this.proxy.readOnly = this.readOnly;
278
+ this.validate();
279
+ }
280
+ }
281
+ /**
282
+ * @internal
283
+ */
284
+ minChanged(_, newMin) {
285
+ if (this.proxy instanceof HTMLInputElement) {
286
+ this.proxy.min = newMin;
287
+ this.validate();
288
+ }
289
+ }
290
+ /**
291
+ * @internal
292
+ */
293
+ maxChanged(_, newMax) {
294
+ if (this.proxy instanceof HTMLInputElement) {
295
+ this.proxy.max = newMax;
296
+ this.validate();
50
297
  }
51
- this.#updateListeners();
52
- if (this._anchorEl) {
53
- this.#updateAnchor(this._anchorEl);
298
+ }
299
+ // --- Core ---
300
+ /**
301
+ * @internal
302
+ */
303
+ get _displaySeconds() {
304
+ return this.secondsStep !== null;
305
+ }
306
+ /**
307
+ * @internal
308
+ */
309
+ get _use12hClock() {
310
+ return this.clock ? this.clock === "12h" : this.locale.timePicker.defaultTo12HourClock;
311
+ }
312
+ #getFocusableEls;
313
+ /**
314
+ * @internal
315
+ */
316
+ valueChanged(previous, next) {
317
+ super.valueChanged(previous, next);
318
+ if (this.value) {
319
+ if (!isValidTimeStr(this.value)) {
320
+ this.value = "";
321
+ return;
322
+ }
323
+ this._presentationValue = formatPresentationTime(
324
+ this.value,
325
+ this._displaySeconds,
326
+ this._use12hClock
327
+ );
328
+ } else {
329
+ this._presentationValue = "";
54
330
  }
55
331
  }
332
+ #updateValueDueToUserInteraction(newValue) {
333
+ this.value = newValue;
334
+ this.$emit("change");
335
+ this.$emit("input");
336
+ }
56
337
  connectedCallback() {
57
338
  super.connectedCallback();
58
- this.#updateListeners();
339
+ document.addEventListener("click", this.#dismissOnClickOutside);
340
+ this.addEventListener("focusin", this.#onFocusIn);
341
+ this.addEventListener("focusout", this.#onFocusOut);
59
342
  }
60
343
  disconnectedCallback() {
61
344
  super.disconnectedCallback();
62
- this.#updateListeners();
345
+ document.removeEventListener("click", this.#dismissOnClickOutside);
346
+ this.removeEventListener("focusin", this.#onFocusIn);
347
+ this.removeEventListener("focusout", this.#onFocusOut);
348
+ }
349
+ #onFocusIn;
350
+ #onFocusOut;
351
+ #dismissOnClickOutside;
352
+ #openPopupIfPossible() {
353
+ if (!this.readOnly) {
354
+ this._popupOpen = true;
355
+ }
356
+ }
357
+ /**
358
+ * @internal
359
+ */
360
+ _closePopup(restoreFocusToTextField = true) {
361
+ this._popupOpen = false;
362
+ if (restoreFocusToTextField) {
363
+ this._textFieldEl.focus();
364
+ }
365
+ }
366
+ /**
367
+ * On keydown anywhere in the time picker.
368
+ * @internal
369
+ */
370
+ _onBaseKeyDown(event) {
371
+ if (event.key === "Escape") {
372
+ this._closePopup();
373
+ return false;
374
+ }
375
+ if (this._trappedFocus(event, this.#getFocusableEls)) {
376
+ return false;
377
+ }
378
+ return true;
379
+ }
380
+ /**
381
+ * @internal
382
+ */
383
+ _presentationValueChanged() {
384
+ this.dirtyValue = true;
385
+ this.validate();
386
+ }
387
+ /**
388
+ * @internal
389
+ */
390
+ get _textFieldPlaceholder() {
391
+ let format = "hh:mm";
392
+ if (this._displaySeconds) {
393
+ format += ":ss";
394
+ }
395
+ if (this._use12hClock) {
396
+ format += " aa";
397
+ }
398
+ return format;
399
+ }
400
+ /**
401
+ * @internal
402
+ */
403
+ _onTextFieldInput(event) {
404
+ const textField = event.currentTarget;
405
+ this._presentationValue = textField.value;
406
+ }
407
+ /**
408
+ * @internal
409
+ */
410
+ _onTextFieldChange() {
411
+ if (this._presentationValue === "") {
412
+ this.#updateValueDueToUserInteraction("");
413
+ return;
414
+ }
415
+ try {
416
+ this.#updateValueDueToUserInteraction(
417
+ parsePresentationTime(this._presentationValue, this._use12hClock)
418
+ );
419
+ } catch (_) {
420
+ return;
421
+ }
63
422
  }
423
+ // --- Clock button ---
64
424
  /**
65
425
  * @internal
66
426
  */
67
- _anchorElChanged(oldValue, newValue) {
68
- if (oldValue)
69
- this.#cleanupAnchor(oldValue);
70
- if (newValue)
71
- this.#setupAnchor(newValue);
427
+ get _clockButtonLabel() {
428
+ if (this.value) {
429
+ return this.locale.timePicker.changeTimeLabel(formatPresentationTime(this.value, this._displaySeconds, this._use12hClock));
430
+ }
431
+ return this.locale.timePicker.chooseTimeLabel;
72
432
  }
73
- #setupAnchor(a) {
74
- a.addEventListener("click", this.#openIfClosed, true);
75
- a.ariaLabel = (a.ariaLabel ?? "") + this.#ANCHOR_ARIA_LABEL_SUFFIX;
76
- this.#updateAnchor(a);
433
+ /**
434
+ * @internal
435
+ */
436
+ _onClockButtonClick() {
437
+ if (this._popupOpen) {
438
+ this._closePopup();
439
+ } else {
440
+ this.#openPopupIfPossible();
441
+ index.DOM.processUpdates();
442
+ if (this._selectedHour) {
443
+ this.#scrollToItem("hours", this._selectedHour, "start");
444
+ }
445
+ if (this._selectedMinute) {
446
+ this.#scrollToItem("minutes", this._selectedMinute, "start");
447
+ }
448
+ if (this._displaySeconds && this._selectedSecond) {
449
+ this.#scrollToItem("seconds", this._selectedSecond, "start");
450
+ }
451
+ if (this._use12hClock && this._selectedMeridiem) {
452
+ this.#scrollToItem("meridies", this._selectedMeridiem, "start");
453
+ }
454
+ this.#getFocusableEls()[0].focus();
455
+ }
77
456
  }
78
- #updateAnchor(a) {
79
- a.setAttribute("aria-expanded", this.open.toString());
457
+ // --- Pickers ---
458
+ /**
459
+ * @internal
460
+ */
461
+ get _hours() {
462
+ return getHoursOptions(this.min, this.max, this._use12hClock ? this._selectedMeridiem ?? this._meridies[0].value : void 0);
80
463
  }
81
- #cleanupAnchor(a) {
82
- a.removeEventListener("click", this.#openIfClosed, true);
83
- if (a.ariaLabel)
84
- a.ariaLabel = a.ariaLabel.replace(this.#ANCHOR_ARIA_LABEL_SUFFIX, "");
464
+ /**
465
+ * @internal
466
+ */
467
+ get _selectedHour() {
468
+ return this.value ? parseTimeStr(this.value).hourStr : void 0;
85
469
  }
86
- #openIfClosed;
87
- #updateListeners() {
88
- document.removeEventListener("click", this.#closeOnClickOutside);
89
- document.removeEventListener("keydown", this.#closeOnEscape);
90
- if (this.open && this.isConnected) {
91
- document.addEventListener("click", this.#closeOnClickOutside);
92
- document.addEventListener("keydown", this.#closeOnEscape);
470
+ /**
471
+ * @internal
472
+ */
473
+ set _selectedHour(value) {
474
+ if (this.value) {
475
+ const { minuteStr, secondStr } = parseTimeStr(this.value);
476
+ this.value = `${value}:${minuteStr}:${secondStr}`;
477
+ } else {
478
+ this.value = `${value}:00:00`;
479
+ }
480
+ }
481
+ /**
482
+ * @internal
483
+ */
484
+ get _minutes() {
485
+ return getMinutesOptions(this.minutesStep, this.value, this.min, this.max);
486
+ }
487
+ /**
488
+ * @internal
489
+ */
490
+ get _selectedMinute() {
491
+ return this.value ? parseTimeStr(this.value).minuteStr : void 0;
492
+ }
493
+ /**
494
+ * @internal
495
+ */
496
+ set _selectedMinute(value) {
497
+ if (this.value) {
498
+ const { hourStr, secondStr } = parseTimeStr(this.value);
499
+ this.value = `${hourStr}:${value}:${secondStr}`;
500
+ } else {
501
+ this.value = `00:${value}:00`;
502
+ }
503
+ }
504
+ /**
505
+ * @internal
506
+ */
507
+ get _seconds() {
508
+ return getSecondsOptions(this.secondsStep, this.value, this.min, this.max);
509
+ }
510
+ /**
511
+ * @internal
512
+ */
513
+ get _selectedSecond() {
514
+ return this.value ? parseTimeStr(this.value).secondStr : void 0;
515
+ }
516
+ /**
517
+ * @internal
518
+ */
519
+ set _selectedSecond(value) {
520
+ if (this.value) {
521
+ const { hourStr, minuteStr } = parseTimeStr(this.value);
522
+ this.value = `${hourStr}:${minuteStr}:${value}`;
523
+ } else {
524
+ this.value = `00:00:${value}`;
525
+ }
526
+ }
527
+ /**
528
+ * @internal
529
+ */
530
+ get _meridies() {
531
+ return getMeridiesOptions(this.min, this.max);
532
+ }
533
+ /**
534
+ * @internal
535
+ */
536
+ get _selectedMeridiem() {
537
+ return this.value ? parseTimeStr(this.value).meridiem : void 0;
538
+ }
539
+ /**
540
+ * @internal
541
+ */
542
+ set _selectedMeridiem(value) {
543
+ if (this.value) {
544
+ const { hours, minuteStr, secondStr } = parseTimeStr(this.value);
545
+ let adjustedHours = hours;
546
+ if (value === "AM" && hours >= 12) {
547
+ adjustedHours -= 12;
548
+ } else if (value === "PM" && hours < 12) {
549
+ adjustedHours += 12;
550
+ }
551
+ this.value = `${formatTimePart(adjustedHours)}:${minuteStr}:${secondStr}`;
552
+ } else {
553
+ if (value === "AM") {
554
+ this.value = "00:00:00";
555
+ } else {
556
+ this.value = "12:00:00";
557
+ }
558
+ }
559
+ }
560
+ /**
561
+ * @internal
562
+ */
563
+ _onPickerKeyDown(picker, options, selectedValue, setSelectedValue, event) {
564
+ const offset = {
565
+ ArrowUp: -1,
566
+ ArrowDown: 1
567
+ }[event.key];
568
+ if (offset) {
569
+ event.preventDefault();
570
+ const index = options.findIndex((h) => h.value === selectedValue);
571
+ const newRawIndex = index === -1 ? 0 : index + offset;
572
+ const newIndex = (newRawIndex + options.length) % options.length;
573
+ const newValue = options[newIndex].value;
574
+ setSelectedValue(newValue);
575
+ this.#scrollToItem(picker, newValue, "nearest");
576
+ this.#updateValueDueToUserInteraction(this.value);
577
+ }
578
+ return true;
579
+ }
580
+ #scrollToItem(picker, selectedValue, position) {
581
+ const element = this.shadowRoot.querySelector(`#${picker}-${selectedValue}`);
582
+ if (!element) {
583
+ return;
584
+ }
585
+ const parent = element.parentElement;
586
+ switch (position) {
587
+ case "start":
588
+ parent.scrollTop = element.offsetTop;
589
+ break;
590
+ case "nearest":
591
+ if (element.offsetTop < parent.scrollTop) {
592
+ parent.scrollTop = element.offsetTop;
593
+ }
594
+ if (element.offsetTop + element.offsetHeight > parent.scrollTop + parent.offsetHeight) {
595
+ parent.scrollTop = element.offsetTop + element.offsetHeight - parent.offsetHeight;
596
+ }
597
+ break;
598
+ }
599
+ }
600
+ /**
601
+ * @internal
602
+ */
603
+ _onPickerItemClick(picker, setSelectedValue, value) {
604
+ setSelectedValue(value);
605
+ this.#scrollToItem(picker, value, "start");
606
+ this.#updateValueDueToUserInteraction(this.value);
607
+ const nextPickerEl = this.shadowRoot.querySelector(`#${picker} + .picker`);
608
+ if (nextPickerEl) {
609
+ nextPickerEl.focus();
610
+ } else {
611
+ this._closePopup();
612
+ }
613
+ }
614
+ // --- Dialog footer ---
615
+ /**
616
+ * @internal
617
+ */
618
+ _onOkClick() {
619
+ this._closePopup();
620
+ }
621
+ /**
622
+ * @internal
623
+ */
624
+ _onClearClick() {
625
+ this.#updateValueDueToUserInteraction("");
626
+ this._closePopup();
627
+ }
628
+ // --- Validation ---
629
+ /**
630
+ * @internal
631
+ */
632
+ validate() {
633
+ if (this.proxy) {
634
+ this.proxy.setCustomValidity(this._getCustomValidationError() ?? "");
635
+ }
636
+ super.validate(this._textFieldEl?.querySelector("input") ?? void 0);
637
+ }
638
+ /**
639
+ * @internal
640
+ */
641
+ _getCustomValidationError() {
642
+ if (this._isPresentationValueInvalid()) {
643
+ return this.locale.timePicker.invalidTimeError;
644
+ }
645
+ return null;
646
+ }
647
+ /**
648
+ * @internal
649
+ */
650
+ _isPresentationValueInvalid() {
651
+ if (this._presentationValue === "") {
652
+ return false;
653
+ }
654
+ try {
655
+ parsePresentationTime(this._presentationValue, this._use12hClock);
656
+ return false;
657
+ } catch (_) {
658
+ return true;
93
659
  }
94
660
  }
95
- #closeOnClickOutside;
96
- #closeOnEscape;
97
661
  };
662
+ __decorateClass([
663
+ index.attr({ attribute: "readonly", mode: "boolean" })
664
+ ], TimePicker.prototype, "readOnly", 2);
665
+ __decorateClass([
666
+ index.attr({ attribute: "minutes-step", converter: index.nullableNumberConverter })
667
+ ], TimePicker.prototype, "minutesStep", 2);
668
+ __decorateClass([
669
+ index.attr({ attribute: "seconds-step", converter: index.nullableNumberConverter })
670
+ ], TimePicker.prototype, "secondsStep", 2);
98
671
  __decorateClass([
99
672
  index.attr
100
- ], Toggletip.prototype, "headline", 2);
673
+ ], TimePicker.prototype, "clock", 2);
674
+ __decorateClass([
675
+ index.attr({ converter: ValidTimeFilter })
676
+ ], TimePicker.prototype, "min", 2);
101
677
  __decorateClass([
102
- index.attr({ mode: "boolean" })
103
- ], Toggletip.prototype, "alternate", 2);
678
+ index.attr({ converter: ValidTimeFilter })
679
+ ], TimePicker.prototype, "max", 2);
104
680
  __decorateClass([
105
- index.attr({ mode: "fromView" })
106
- ], Toggletip.prototype, "placement", 2);
681
+ index.observable
682
+ ], TimePicker.prototype, "_popupOpen", 2);
107
683
  __decorateClass([
108
- index.attr({ mode: "boolean" })
109
- ], Toggletip.prototype, "open", 2);
110
- Toggletip = __decorateClass([
111
- anchored.anchored
112
- ], Toggletip);
684
+ index.observable
685
+ ], TimePicker.prototype, "_presentationValue", 2);
686
+ TimePicker = __decorateClass([
687
+ index$1.errorText,
688
+ index$1.formElements
689
+ ], TimePicker);
690
+ applyMixins.applyMixins(TimePicker, localized.Localized, index$1.FormElementHelperText, trappedFocus.TrappedFocus);
113
691
 
114
- const getClasses = (_) => classNames.classNames("control");
115
- const ToggletipTemplate = (context) => {
116
- const popup = context.tagFor(definition.Popup);
692
+ const renderPicker = (id, getLabel, getSelected, setSelected, getOptions) => {
117
693
  return index.html`
118
- <${popup}
119
- class="${getClasses}"
120
- arrow
121
- :anchor="${(x) => x._anchorEl}"
122
- :open="${(x) => x.open}"
123
- ?alternate="${(x) => !x.alternate}"
124
- placement="${(x) => x.placement}"
125
- exportparts="vvd-theme-alternate"
694
+ <ul
695
+ id="${id}"
696
+ class="picker"
697
+ role="listbox"
698
+ tabindex="0"
699
+ aria-label="${getLabel}"
700
+ aria-activedescendant="${(x) => getSelected(x) ? `${id}-${getSelected(x)}` : void 0}"
701
+ @keydown="${(x, c) => x._onPickerKeyDown(id, getOptions(x), getSelected(x), setSelected(x), c.event)}"
126
702
  >
127
- <div class="content-wrapper">
128
- ${when.when((x) => x.headline, index.html`<header class="headline">${(x) => x.headline}</header>`)}
129
- <slot></slot>
130
- <footer class="action-items"><slot name="action-items"></slot></footer>
131
- </div>
132
- </${popup}>
703
+ ${repeat.repeat(
704
+ getOptions,
705
+ index.html`
706
+ <li
707
+ id="${(x) => `${id}-${x.value}`}"
708
+ class="${(x, c) => classNames.classNames("item", [
709
+ "selected",
710
+ getSelected(c.parent) === x.value
711
+ ])}"
712
+ role="option"
713
+ aria-selected="${(x, c) => getSelected(c.parent) === x.value}"
714
+ @click="${(x, c) => c.parent._onPickerItemClick(id, setSelected(c.parent), x.value)}"
715
+ >
716
+ ${(x) => x.label}
717
+ </li>
718
+ `
719
+ )}
720
+ </ul>
133
721
  `;
134
722
  };
723
+ const TimePickerTemplate = (context, _) => {
724
+ const popupTag = context.tagFor(definition.Popup);
725
+ const textFieldTag = context.tagFor(definition$1.TextField);
726
+ const buttonTag = context.tagFor(definition$2.Button);
727
+ return index.html`<div class="base" @keydown="${(x, { event }) => x._onBaseKeyDown(event)}">
728
+ <${textFieldTag} id="text-field"
729
+ ${ref.ref("_textFieldEl")}
730
+ class="control"
731
+ label="${(x) => x.label}"
732
+ helper-text="${(x) => x.helperText}"
733
+ error-text="${(x) => x.errorValidationMessage}"
734
+ placeholder="${(x) => x._textFieldPlaceholder}"
735
+ current-value="${(x) => x._presentationValue}"
736
+ ?disabled="${(x) => x.disabled}"
737
+ ?readonly="${(x) => x.readOnly}"
738
+ @input="${(x, c) => x._onTextFieldInput(c.event)}"
739
+ @change="${(x) => x._onTextFieldChange()}"
740
+ >
741
+ <${buttonTag}
742
+ id="clock-button"
743
+ ${ref.ref("_clockButtonEl")}
744
+ slot="action-items"
745
+ size="condensed"
746
+ icon="clock-line"
747
+ appearance="ghost"
748
+ ?disabled="${(x) => x.disabled || x.readOnly}"
749
+ aria-label="${(x) => x._clockButtonLabel}"
750
+ @click="${(x) => x._onClockButtonClick()}"
751
+ ></${buttonTag}>
752
+ </${textFieldTag}>
753
+ <${popupTag}
754
+ ?open="${(x) => x._popupOpen}"
755
+ :anchor="${(x) => x._textFieldEl}"
756
+ placement="bottom-start"
757
+ class="popup">
758
+ <div class="dialog" role="dialog" ${ref.ref(
759
+ "_dialogEl"
760
+ )} aria-modal="true" aria-label="${(x) => x.locale.timePicker.chooseTimeLabel}">
761
+ <div class="time-pickers">
762
+ ${renderPicker(
763
+ "hours",
764
+ (x) => x.locale.timePicker.hoursLabel,
765
+ (x) => x._selectedHour,
766
+ (x) => (v) => x._selectedHour = v,
767
+ (x) => x._hours
768
+ )}
769
+ ${renderPicker(
770
+ "minutes",
771
+ (x) => x.locale.timePicker.minutesLabel,
772
+ (x) => x._selectedMinute,
773
+ (x) => (v) => x._selectedMinute = v,
774
+ (x) => x._minutes
775
+ )}
776
+ ${when.when((x) => x._displaySeconds, renderPicker(
777
+ "seconds",
778
+ (x) => x.locale.timePicker.secondsLabel,
779
+ (x) => x._selectedSecond,
780
+ (x) => (v) => x._selectedSecond = v,
781
+ (x) => x._seconds
782
+ ))}
783
+ ${when.when((x) => x._use12hClock, renderPicker(
784
+ "meridies",
785
+ (x) => x.locale.timePicker.meridiesLabel,
786
+ (x) => x._selectedMeridiem,
787
+ (x) => (v) => x._selectedMeridiem = v,
788
+ (x) => x._meridies
789
+ ))}
790
+ </div>
791
+ <div class="footer">
792
+ <${buttonTag}
793
+ class="vwc-button"
794
+ size="condensed"
795
+ label="${(x) => x.locale.timePicker.clearLabel}"
796
+ @click="${(x) => x._onClearClick()}"
797
+ ></${buttonTag}>
798
+ <${buttonTag}
799
+ class="vwc-button"
800
+ size="condensed"
801
+ appearance="filled"
802
+ label="${(x) => x.locale.timePicker.okLabel}"
803
+ @click="${(x) => x._onOkClick()}"
804
+ ></${buttonTag}>
805
+ </div>
806
+ </div>
807
+ </${popupTag}>
808
+ </div>`;
809
+ };
135
810
 
136
- const toggletipDefinition = Toggletip.compose({
137
- baseName: "toggletip",
138
- template: ToggletipTemplate,
139
- styles
811
+ const timePickerDefinition = TimePicker.compose({
812
+ baseName: "time-picker",
813
+ template: TimePickerTemplate,
814
+ styles,
815
+ shadowOptions: {
816
+ delegatesFocus: true
817
+ }
140
818
  });
141
- const toggletipRegistries = [toggletipDefinition(), ...definition.popupRegistries];
142
- const registerToggletip = index.registerFactory(toggletipRegistries);
819
+ const timePickerRegistries = [timePickerDefinition(), ...definition$1.textFieldRegistries, ...definition.popupRegistries, ...definition$2.buttonRegistries];
820
+ const registerTimePicker = index.registerFactory(timePickerRegistries);
143
821
 
144
- exports.registerToggletip = registerToggletip;
145
- exports.toggletipDefinition = toggletipDefinition;
146
- exports.toggletipRegistries = toggletipRegistries;
822
+ exports.registerTimePicker = registerTimePicker;
823
+ exports.timePickerDefinition = timePickerDefinition;
824
+ exports.timePickerRegistries = timePickerRegistries;