@swiftwc/ui 0.0.0-dev.6 → 0.0.0-dev.8

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 (263) hide show
  1. package/README.md +15 -0
  2. package/generated/client/index.d.ts +13 -3
  3. package/generated/client/index.js +228 -158
  4. package/generated/components/bordered-button.d.ts +7 -0
  5. package/generated/components/bordered-button.js +20 -0
  6. package/generated/components/bordered-prominent-button.d.ts +7 -0
  7. package/generated/components/bordered-prominent-button.js +20 -0
  8. package/generated/components/borderless-button.d.ts +4 -4
  9. package/generated/components/borderless-button.js +26 -16
  10. package/generated/components/confirmation-dialog.d.ts +9 -0
  11. package/generated/components/confirmation-dialog.js +102 -0
  12. package/generated/components/date-picker.d.ts +46 -0
  13. package/generated/components/date-picker.js +430 -0
  14. package/generated/components/disclosure-group.d.ts +4 -7
  15. package/generated/components/disclosure-group.js +41 -66
  16. package/generated/components/form-view.d.ts +6 -0
  17. package/generated/components/form-view.js +58 -0
  18. package/generated/components/glass-button.d.ts +6 -0
  19. package/generated/components/glass-button.js +17 -0
  20. package/generated/components/glass-prominent-button.d.ts +6 -0
  21. package/generated/components/glass-prominent-button.js +17 -0
  22. package/generated/components/index.d.ts +34 -10
  23. package/generated/components/index.js +33 -14
  24. package/generated/components/label-view.d.ts +9 -0
  25. package/generated/components/label-view.js +83 -0
  26. package/generated/components/list-view.d.ts +5 -0
  27. package/generated/components/list-view.js +29 -0
  28. package/generated/components/menu-view.d.ts +9 -0
  29. package/generated/components/menu-view.js +133 -0
  30. package/generated/components/navigation-large-title.d.ts +6 -0
  31. package/generated/components/navigation-large-title.js +177 -0
  32. package/generated/components/navigation-split-view.d.ts +4 -2
  33. package/generated/components/navigation-split-view.js +11 -2
  34. package/generated/components/navigation-stack.d.ts +3 -2
  35. package/generated/components/navigation-stack.js +15 -58
  36. package/generated/components/navigation-title.d.ts +8 -0
  37. package/generated/components/navigation-title.js +66 -0
  38. package/generated/components/picker-view.d.ts +27 -0
  39. package/generated/components/picker-view.js +442 -0
  40. package/generated/components/plain-button.d.ts +7 -0
  41. package/generated/components/plain-button.js +20 -0
  42. package/generated/components/screen-view.d.ts +1 -1
  43. package/generated/components/screen-view.js +1 -1
  44. package/generated/components/scroll-view.d.ts +4 -2
  45. package/generated/components/scroll-view.js +169 -62
  46. package/generated/components/section-view.d.ts +9 -0
  47. package/generated/components/section-view.js +81 -0
  48. package/generated/components/sheet-view.d.ts +4 -4
  49. package/generated/components/sheet-view.js +59 -16
  50. package/generated/components/sidebar-toggle.d.ts +1 -1
  51. package/generated/components/sidebar-toggle.js +89 -63
  52. package/generated/components/sidebar-view.d.ts +2 -4
  53. package/generated/components/sidebar-view.js +20 -17
  54. package/generated/components/sticky-container.d.ts +6 -0
  55. package/generated/components/sticky-container.js +22 -0
  56. package/generated/components/tab-bar.d.ts +2 -4
  57. package/generated/components/tab-bar.js +24 -17
  58. package/generated/components/tab-item.d.ts +4 -3
  59. package/generated/components/tab-item.js +114 -29
  60. package/generated/components/tab-view.d.ts +17 -2
  61. package/generated/components/tab-view.js +244 -17
  62. package/generated/components/table-view.d.ts +7 -0
  63. package/generated/components/table-view.js +175 -0
  64. package/generated/components/text-field.d.ts +29 -0
  65. package/generated/components/text-field.js +489 -0
  66. package/generated/components/tool-bar-item-group.d.ts +5 -0
  67. package/generated/components/tool-bar-item-group.js +11 -0
  68. package/generated/components/tool-bar-item.d.ts +5 -0
  69. package/generated/components/tool-bar-item.js +19 -0
  70. package/generated/components/tool-bar.d.ts +7 -0
  71. package/generated/components/tool-bar.js +77 -0
  72. package/generated/components/v-keyboard.d.ts +2 -0
  73. package/generated/components/v-keyboard.js +64 -68
  74. package/generated/components/v-stack.d.ts +5 -0
  75. package/generated/components/v-stack.js +11 -0
  76. package/generated/confirmation-dialog/index.d.ts +1 -0
  77. package/generated/confirmation-dialog/index.js +1 -0
  78. package/generated/css/index.css +7463 -0
  79. package/generated/events/confirmation-dialog.d.ts +9 -0
  80. package/generated/events/date-picker.d.ts +8 -0
  81. package/generated/events/date-picker.js +1 -0
  82. package/generated/events/index.d.ts +7 -0
  83. package/generated/events/index.js +7 -0
  84. package/generated/events/lifecycle-observer.d.ts +10 -0
  85. package/generated/events/lifecycle-observer.js +1 -0
  86. package/generated/events/picker-view.d.ts +8 -0
  87. package/generated/events/picker-view.js +1 -0
  88. package/generated/events/scroll-view.d.ts +10 -0
  89. package/generated/events/scroll-view.js +1 -0
  90. package/generated/events/tab-view.d.ts +24 -0
  91. package/generated/events/tab-view.js +1 -0
  92. package/generated/events/text-field.d.ts +8 -0
  93. package/generated/events/text-field.js +1 -0
  94. package/generated/i18n/index.d.ts +24 -0
  95. package/generated/i18n/index.js +139 -0
  96. package/generated/internal/class/cleanup-registry.d.ts +5 -0
  97. package/generated/internal/class/cleanup-registry.js +38 -0
  98. package/generated/internal/class/css-style-observer.d.ts +8 -0
  99. package/generated/internal/class/css-style-observer.js +25 -0
  100. package/generated/internal/class/form-associated-base.d.ts +20 -0
  101. package/generated/internal/class/form-associated-base.js +93 -0
  102. package/generated/internal/class/mutation-observer-singleton.d.ts +10 -0
  103. package/generated/internal/class/mutation-observer-singleton.js +46 -0
  104. package/generated/internal/class/navigation-path.d.ts +15 -0
  105. package/generated/internal/class/navigation-path.js +84 -0
  106. package/generated/internal/class/navigation-view.d.ts +8 -0
  107. package/generated/internal/class/navigation-view.js +77 -0
  108. package/generated/internal/class/resize-observer-singleton.d.ts +7 -0
  109. package/generated/internal/class/resize-observer-singleton.js +22 -0
  110. package/generated/internal/decorators/custom-element.d.ts +5 -0
  111. package/generated/internal/decorators/custom-element.js +4 -0
  112. package/generated/internal/privateNamespace.d.ts +4 -0
  113. package/generated/internal/privateNamespace.js +1 -0
  114. package/generated/internal/utils/add.d.ts +1 -0
  115. package/generated/internal/utils/add.js +7 -0
  116. package/generated/internal/utils/cash/ancestors.d.ts +1 -0
  117. package/generated/internal/utils/cash/ancestors.js +27 -0
  118. package/generated/internal/utils/cash/index.d.ts +22 -0
  119. package/generated/internal/utils/cash/index.js +23 -0
  120. package/generated/internal/utils/cash/next-all.d.ts +1 -0
  121. package/generated/internal/utils/cash/next-all.js +10 -0
  122. package/generated/internal/utils/cash/next.d.ts +1 -0
  123. package/generated/internal/utils/cash/next.js +9 -0
  124. package/generated/internal/utils/cash/prev-all.d.ts +1 -0
  125. package/generated/internal/utils/cash/prev-all.js +10 -0
  126. package/generated/internal/utils/cash/prev.d.ts +1 -0
  127. package/generated/internal/utils/cash/prev.js +9 -0
  128. package/generated/internal/utils/cash/prop.d.ts +18 -0
  129. package/generated/internal/utils/cash/prop.js +30 -0
  130. package/generated/internal/utils/cash/siblings.d.ts +1 -0
  131. package/generated/internal/utils/cash/siblings.js +10 -0
  132. package/generated/internal/utils/clamp.d.ts +1 -0
  133. package/generated/internal/utils/clamp.js +4 -0
  134. package/generated/internal/utils/compare-big-decimals.d.ts +1 -0
  135. package/generated/internal/utils/compare-big-decimals.js +90 -0
  136. package/generated/internal/utils/debounce.d.ts +1 -0
  137. package/generated/internal/utils/debounce.js +13 -0
  138. package/generated/internal/utils/frame.d.ts +1 -0
  139. package/generated/internal/utils/frame.js +6 -0
  140. package/generated/internal/utils/index.d.ts +16 -1
  141. package/generated/internal/utils/index.js +17 -1
  142. package/generated/internal/utils/kebab-case.d.ts +1 -1
  143. package/generated/internal/utils/list-active.d.ts +7 -0
  144. package/generated/internal/utils/list-active.js +28 -0
  145. package/generated/internal/utils/microtask.d.ts +1 -0
  146. package/generated/internal/utils/microtask.js +3 -0
  147. package/generated/internal/utils/onoff.d.ts +45 -0
  148. package/generated/internal/utils/onoff.js +31 -0
  149. package/generated/internal/utils/set.d.ts +1 -0
  150. package/generated/internal/utils/set.js +7 -0
  151. package/generated/internal/utils/sleep.d.ts +1 -0
  152. package/generated/internal/utils/sleep.js +3 -0
  153. package/generated/internal/utils/slow-hide-show.d.ts +1 -0
  154. package/generated/internal/utils/slow-hide-show.js +16 -0
  155. package/generated/internal/utils/timeout.d.ts +5 -0
  156. package/generated/internal/utils/timeout.js +16 -0
  157. package/generated/internal/utils/touch-glass.d.ts +7 -0
  158. package/generated/internal/utils/touch-glass.js +19 -0
  159. package/generated/lifecycle-observer/index.d.ts +1 -0
  160. package/generated/lifecycle-observer/index.js +1 -0
  161. package/generated/namespace-browser/base.d.ts +36 -0
  162. package/generated/namespace-browser/base.js +92 -0
  163. package/generated/namespace-browser/index.d.ts +7 -0
  164. package/generated/namespace-browser/index.js +1 -0
  165. package/generated/snapshot/index.d.ts +2 -11
  166. package/generated/snapshot/index.js +31 -144
  167. package/package.json +19 -8
  168. package/scss/_components.scss +52 -16
  169. package/scss/_final.scss +1 -0
  170. package/scss/_mixins.scss +2 -171
  171. package/scss/_placeholders.scss +3 -0
  172. package/scss/_transitions.scss +16 -0
  173. package/scss/_utils.scss +9 -0
  174. package/scss/_vars.scss +137 -23
  175. package/scss/base/_layout.scss +31 -15
  176. package/scss/base/_reboot.scss +118 -15
  177. package/scss/base/_root.scss +355 -25
  178. package/scss/colors/_index.scss +624 -70
  179. package/scss/components/_body-view.scss +12 -3
  180. package/scss/components/_bordered-button.scss +22 -0
  181. package/scss/components/_bordered-prominent-button.scss +19 -0
  182. package/scss/components/_borderless-button.scss +11 -6
  183. package/scss/components/_confirmation-dialog.scss +110 -0
  184. package/scss/components/_date-picker.scss +30 -0
  185. package/scss/components/_detail-placeholder.scss +155 -0
  186. package/scss/components/_disclosure-group.scss +100 -52
  187. package/scss/components/_form-view.scss +195 -0
  188. package/scss/components/_full-screen.scss +7 -5
  189. package/scss/components/_glass-button.scss +24 -0
  190. package/scss/components/_glass-prominent-button.scss +24 -0
  191. package/scss/components/_h-divider.scss +13 -0
  192. package/scss/components/_h-stack.scss +39 -0
  193. package/scss/components/_index.scss +224 -7
  194. package/scss/components/_label-view.scss +386 -0
  195. package/scss/components/_labeled-content.scss +9 -0
  196. package/scss/components/_list-view.scss +229 -0
  197. package/scss/components/_menu-view.scss +188 -0
  198. package/scss/components/_navigation-large-title.scss +27 -0
  199. package/scss/components/_navigation-split-view.scss +329 -269
  200. package/scss/components/_navigation-stack.scss +6 -6
  201. package/scss/components/_navigation-title.scss +10 -0
  202. package/scss/components/_picker-view.scss +122 -0
  203. package/scss/components/_plain-button.scss +11 -0
  204. package/scss/components/_scroll-view-proxy.scss +79 -0
  205. package/scss/components/_scroll-view-toolbars.scss +126 -0
  206. package/scss/components/_scroll-view.scss +110 -66
  207. package/scss/components/_section-view.scss +119 -0
  208. package/scss/components/_sheet-view.scss +68 -35
  209. package/scss/components/_sidebar-toggle.scss +90 -27
  210. package/scss/components/_sidebar-view.scss +30 -40
  211. package/scss/components/_sticky-container.scss +42 -0
  212. package/scss/components/_tab-bar.scss +201 -84
  213. package/scss/components/_tab-item.scss +25 -0
  214. package/scss/components/_tab-view.scss +268 -126
  215. package/scss/components/_table-column.scss +52 -0
  216. package/scss/components/_table-row.scss +172 -0
  217. package/scss/components/_table-view.scss +223 -0
  218. package/scss/components/_text-field.scss +37 -0
  219. package/scss/components/_tool-bar-item-group.scss +30 -19
  220. package/scss/components/_tool-bar-item.scss +128 -70
  221. package/scss/components/_tool-bar.scss +107 -64
  222. package/scss/components/_v-divider.scss +13 -0
  223. package/scss/components/_v-flex-stack.scss +29 -0
  224. package/scss/components/_v-keyboard.scss +6 -4
  225. package/scss/components/_v-stack.scss +8 -9
  226. package/scss/final/_touch-glass.scss +67 -0
  227. package/scss/index.scss +6 -2
  228. package/scss/mixins/_dialog.scss +88 -0
  229. package/scss/mixins/_index.scss +405 -0
  230. package/scss/placeholders/_buttons.scss +83 -0
  231. package/scss/placeholders/_lists.scss +589 -0
  232. package/scss/transitions/_bwd.navbar.scss +3 -13
  233. package/scss/transitions/_bwd.scss +4 -20
  234. package/scss/transitions/_confirmation-dialog.scss +19 -0
  235. package/scss/transitions/_dialog.scss +7 -11
  236. package/scss/transitions/_disclosure-group.scss +35 -0
  237. package/scss/transitions/_fwd.navbar.scss +4 -9
  238. package/scss/transitions/_fwd.scss +4 -34
  239. package/scss/transitions/_glass-button.scss +12 -0
  240. package/scss/transitions/_glass-prominent-button.scss +12 -0
  241. package/scss/transitions/_index.scss +35 -143
  242. package/scss/transitions/_menu-view.scss +26 -0
  243. package/scss/transitions/_navigation-split-view.scss +23 -0
  244. package/scss/transitions/_sidebar-view.scss +36 -0
  245. package/scss/transitions/_tab-bar.scss +19 -0
  246. package/scss/utils/_frame.scss +84 -0
  247. package/scss/utils/_index.scss +68 -0
  248. package/scss/utils/_scroll-view.scss +14 -0
  249. package/scss/utils/_spacing.scss +25 -0
  250. package/scss/utils/_stacks.scss +242 -0
  251. package/web-components.html-data/en.json +330 -0
  252. package/generated/components/bottom-bar.d.ts +0 -10
  253. package/generated/components/bottom-bar.js +0 -73
  254. package/generated/components/navigation-bar.d.ts +0 -10
  255. package/generated/components/navigation-bar.js +0 -80
  256. package/generated/internal/class.d.ts +0 -18
  257. package/generated/internal/class.js +0 -18
  258. package/generated/namespace/index.d.ts +0 -6
  259. package/generated/styles.css +0 -1305
  260. package/scss/_dev.scss +0 -68
  261. package/scss/components/_tab-bar-stack.scss +0 -101
  262. package/scss/components/_toolbars.scss +0 -100
  263. /package/generated/{namespace/index.js → events/confirmation-dialog.js} +0 -0
@@ -0,0 +1,489 @@
1
+ var _a;
2
+ import { I18n } from '../i18n';
3
+ import { CleanupRegistry } from '../internal/class/cleanup-registry';
4
+ import { FormAssociatedBase, getInternals, makeSlotchangeHandler } from '../internal/class/form-associated-base';
5
+ import { $, compareBigDecimals, kebabCase, onoff, set } from '../internal/utils';
6
+ const keyboardTypes = ['decimal-pad', 'number-pad', 'default'];
7
+ /**
8
+ * @slot label
9
+ * @slot validity-options
10
+ */
11
+ export class TextField extends FormAssociatedBase {
12
+ static get observedAttributes() {
13
+ return [
14
+ 'prompt',
15
+ 'minimum',
16
+ 'maximum',
17
+ 'min-length',
18
+ 'max-length',
19
+ 'label',
20
+ 'name',
21
+ 'text',
22
+ 'text-input-autocapitalization',
23
+ 'disable-autocorrection',
24
+ 'keyboard-type',
25
+ 'required',
26
+ 'disabled',
27
+ ];
28
+ }
29
+ static #template;
30
+ static get template() {
31
+ return (this.#template ??= $(String.raw `
32
+ <label part="root text-field-stack">
33
+ <div part="root text-field-label-stack">
34
+ <slot name="label"></slot>
35
+ </div>
36
+ <div part="root text-field-input-stack">
37
+ <input type="text" part="root input text-field-form-input">
38
+ </div>
39
+ <slot name="validity-options" hidden></slot>
40
+ </label>`, ''));
41
+ }
42
+ #shadowRoot;
43
+ // #internals: ElementInternals
44
+ #customValidity = '';
45
+ #validitiesSlot;
46
+ #input;
47
+ get #internals() {
48
+ return getInternals(this);
49
+ }
50
+ constructor() {
51
+ super();
52
+ this.#shadowRoot = this.attachShadow({ mode: 'closed' });
53
+ this.#shadowRoot.appendChild(document.importNode(this.constructor.template, true));
54
+ this.#validitiesSlot = this.#shadowRoot.querySelector('slot[name=validity-options]') ?? undefined;
55
+ CleanupRegistry.unregister(this, 'validities');
56
+ CleanupRegistry.register(this, onoff(makeSlotchangeHandler(this), this.#validitiesSlot).on(), 'validities');
57
+ this.#input = this.#shadowRoot.querySelector('input') ?? undefined;
58
+ CleanupRegistry.register(this, onoff([{ types: 'focusin', listener: this.#handleFocusin }], this).on());
59
+ CleanupRegistry.register(this, onoff([
60
+ { types: 'blur', listener: this.#handleInputBlur },
61
+ { types: 'input', listener: this.#handleInputInput },
62
+ { types: 'beforeinput', listener: this.#handleInputBeforeinput },
63
+ { types: 'paste', listener: this.#handleInputPaste },
64
+ ], this.#input).on());
65
+ CleanupRegistry.register(this, onoff('change', () => {
66
+ this.text = this.text;
67
+ }, I18n.on).on());
68
+ }
69
+ connectedCallback() {
70
+ super.connectedCallback();
71
+ // finally
72
+ if (!this.hasAttribute('text'))
73
+ return;
74
+ this.text = this.getAttribute('text') ?? ''; // this.#input.value = this.getAttribute('text') ?? ''
75
+ this.#sendValueToForm(false);
76
+ }
77
+ disconnectedCallback() {
78
+ super.disconnectedCallback();
79
+ }
80
+ attributeChangedCallback(name, oldValue, newValue) {
81
+ console.debug(`${_a.name} ⚡️ attr-change [${name}] ("${oldValue}" → "${newValue}")`);
82
+ switch (name) {
83
+ case 'keyboard-type':
84
+ switch (newValue) {
85
+ case 'decimal-pad':
86
+ this.#input?.setAttribute('inputmode', 'decimal');
87
+ break;
88
+ case 'number-pad':
89
+ this.#input?.setAttribute('inputmode', 'numeric');
90
+ break;
91
+ case 'default':
92
+ default:
93
+ this.#input?.removeAttribute('inputmode');
94
+ break;
95
+ }
96
+ this.#sendValueToForm();
97
+ break;
98
+ case 'text-input-autocapitalization':
99
+ switch (newValue) {
100
+ case 'never':
101
+ this.#input?.setAttribute('autocapitalize', 'off');
102
+ break;
103
+ case 'characters':
104
+ this.#input?.setAttribute('autocapitalize', newValue);
105
+ break;
106
+ case 'words':
107
+ this.#input?.setAttribute('autocapitalize', newValue);
108
+ break;
109
+ default:
110
+ case 'sentences':
111
+ this.#input?.setAttribute('autocapitalize', 'on');
112
+ break;
113
+ }
114
+ break;
115
+ case 'disable-autocorrection':
116
+ if ('' === newValue)
117
+ for (const [k, v] of [
118
+ ['autocomplete', 'off'],
119
+ ['autocorrect', 'off'],
120
+ ['spellcheck', 'false'],
121
+ ])
122
+ this.#input?.setAttribute(k, v);
123
+ else
124
+ for (const k of ['autocomplete', 'autocorrect', 'spellcheck'])
125
+ this.#input?.removeAttribute(k);
126
+ break;
127
+ case 'text':
128
+ // if (this.#input) this.#input.value = newValue ?? ''
129
+ this.text = newValue ?? '';
130
+ break;
131
+ case 'required':
132
+ this.#input?.setAttribute(name, newValue ?? ''); // else this.#input?.removeAttribute(name)
133
+ this.#sendValueToForm();
134
+ break;
135
+ case 'name':
136
+ case 'minimum':
137
+ case 'maximum':
138
+ this.#sendValueToForm();
139
+ break;
140
+ case 'prompt':
141
+ this.#input?.setAttribute('placeholder', newValue ?? ''); // else this.#input?.removeAttribute(name)
142
+ break;
143
+ case 'min-length':
144
+ this.#input?.setAttribute('minlength', newValue ?? '');
145
+ this.#sendValueToForm();
146
+ break;
147
+ case 'max-length':
148
+ this.#input?.setAttribute('maxlength', newValue ?? '');
149
+ this.#sendValueToForm();
150
+ break;
151
+ case 'label':
152
+ let label = this.querySelector(':scope>[slot=label]');
153
+ if (newValue) {
154
+ label ??= this.appendChild($(`<span slot="label" foreground="secondary"></span>`));
155
+ label.textContent = newValue;
156
+ }
157
+ else
158
+ label?.remove();
159
+ this.#sendValueToForm();
160
+ break;
161
+ case 'disabled':
162
+ for (const el of this.#shadowRoot.querySelectorAll('input'))
163
+ el.toggleAttribute('disabled', !newValue);
164
+ break;
165
+ }
166
+ // render pattern
167
+ switch (this.keyboardType) {
168
+ case 'decimal-pad':
169
+ const allowedSignsRegex2 = String.raw `[+\-]?|[+\-]?(\d+([.,]\d*)?|[.,]\d*)`, // allow single '+' or '-', then allow only one ',' or '.' and finally only digits
170
+ digitsDecimalsOnlyRegex = String.raw `(\d+([.,]\d*)?|[.,]\d*)?`; // allow only one ',' or '.' and finally only digits
171
+ this.#input?.setAttribute('pattern', this.negativeNumbersAllowed ? allowedSignsRegex2 : digitsDecimalsOnlyRegex);
172
+ break;
173
+ case 'number-pad':
174
+ const allowedSignsRegex = String.raw `([+\-]|\d+|[+\-]\d+)?`, // allow single '+' or '-', then allow only digits
175
+ digitsOnlyRegex = String.raw `\d*`; // allow only digits
176
+ this.#input?.setAttribute('pattern', this.negativeNumbersAllowed ? allowedSignsRegex : digitsOnlyRegex);
177
+ break;
178
+ default:
179
+ this.#input?.removeAttribute('pattern');
180
+ break;
181
+ }
182
+ }
183
+ get keyboardType() {
184
+ return keyboardTypes.includes(this.getAttribute('keyboard-type') ?? '')
185
+ ? this.getAttribute('keyboard-type')
186
+ : 'default';
187
+ }
188
+ get text() {
189
+ return this.#input?.value ?? '';
190
+ }
191
+ set text(v) {
192
+ if (!this.#input)
193
+ return;
194
+ const nv = this.#patternTest(v) ? v : '';
195
+ set(this.#input, 'value', nv);
196
+ // this.text AND this.value have NOW been updated to new values
197
+ // if user is NOT interacting replace new-text/input.value with the formatted version of the new-text/input.value!
198
+ if (document.activeElement !== this && 0 < this.#input.value.length) {
199
+ const finalText = this.value.replace(/[.,]/g, I18n.decimalSeparator);
200
+ set(this.#input, 'value', finalText); // if (this.text !== finalText) this.#input.value = finalText
201
+ }
202
+ }
203
+ #handleFocusin = (evt) => {
204
+ console.debug(`${_a.name} ⚡️ ${evt?.type}`);
205
+ if (evt.target === this)
206
+ this.#input?.focus();
207
+ };
208
+ #sendValueToForm = (dispatchEvent = true) => {
209
+ // input.value has already been updated/synced !!
210
+ if (this.matches(':disabled'))
211
+ return this.setValidity({});
212
+ // if (this.hasAttribute('required')) {
213
+ if (this.#input?.matches(':invalid')) {
214
+ this.setValidity(this.#input?.validity, this.#input?.validationMessage);
215
+ }
216
+ else if (['number-pad', 'decimal-pad'].includes(this.keyboardType) && (this.hasAttribute('minimum') || this.hasAttribute('maximum'))) {
217
+ const underflow = compareBigDecimals(this.value, this.getAttribute('minimum') ?? '-Infinity'), overflow = compareBigDecimals(this.value, this.getAttribute('maximum') ?? 'Infinity');
218
+ if (0 > underflow)
219
+ this.setValidity({ rangeUnderflow: true });
220
+ else if (0 < overflow)
221
+ this.setValidity({ rangeOverflow: true });
222
+ else
223
+ this.setValidity({});
224
+ }
225
+ else {
226
+ this.setValidity({});
227
+ }
228
+ const entries = new FormData();
229
+ entries.append(this.name, this.text);
230
+ this.#internals.setFormValue(entries);
231
+ if (dispatchEvent)
232
+ this.dispatchEvent(new CustomEvent('commit', { detail: { text: this.text }, bubbles: true, composed: true }));
233
+ };
234
+ #handleInputPaste = (evt) => {
235
+ console.debug(`${_a.name} ⚡️ ${evt?.type}`);
236
+ const input = evt.target;
237
+ if (!input)
238
+ return;
239
+ evt.preventDefault();
240
+ const data = this.#identity(evt.clipboardData?.getData('text') ?? ''); // number is now sanitized but contains edge cases like '+' and also global one separator that could be wither dot or decimal.
241
+ if (0 === data.length)
242
+ return this.shake(); //.then(this.reportValidity) // nothing to paste
243
+ const start = input.selectionStart ?? 0, end = input.selectionEnd ?? 0, before = input.value.slice(0, start), after = input.value.slice(end), newText = `${before}${data}${after}`;
244
+ if (-1 < input.maxLength && input.maxLength < newText.length)
245
+ return this.shake(); //.then(this.reportValidity) // exceeding maxlength
246
+ input.value = newText;
247
+ const newCaret = start + data.length;
248
+ input.setSelectionRange(newCaret, newCaret); // move caret after inserted char
249
+ this.#sendValueToForm(); // input.dispatchEvent(new InputEvent('input', { bubbles: true })) // Manually trigger input event so listeners react
250
+ };
251
+ // NOTE: identity MUST always pass beforeinput checks
252
+ #identity = (str) => {
253
+ // 'ab-1.2.3.4x yz ' // "-1.234"
254
+ // '++12..34 ' // "+12.34"
255
+ // '-+5.6.7.8 ' // "-5.678"
256
+ // ' -+5.6,7.8 ' // "-5.678"
257
+ // 'foo123bar ' // "123"
258
+ // '.12.3 ' // ".123"
259
+ // ' http://localhost:5173/input.html' // "5173."
260
+ // ' http://localhost:51,73/input.html' // "51,73"
261
+ // ' +- 0000.' // "+0000."
262
+ // ' +' // "+"
263
+ // ' +0000234' // "+0000234"
264
+ // ' +-1.2.3.4x yz ' // "+1.234"
265
+ let seenSign = false;
266
+ switch (this.keyboardType) {
267
+ case 'decimal-pad': // allow only ^+- and then only one instance of ., finally remove all non digit rest appearances
268
+ let seenDot = false;
269
+ return [...`${str.trim()}`].reduce((acc, ch, i) => {
270
+ // +- signs are allowed
271
+ if (this.negativeNumbersAllowed)
272
+ if (!seenSign && (ch === '+' || ch === '-')) {
273
+ seenSign = true;
274
+ return `${acc}${ch}`;
275
+ }
276
+ if ((ch === '.' || ch === ',') && !seenDot) {
277
+ seenDot = true;
278
+ return `${acc}${ch}`;
279
+ }
280
+ if (/\d/.test(ch))
281
+ return `${acc}${ch}`;
282
+ return acc; // skip everything else
283
+ }, '');
284
+ case 'number-pad': // allow only ^+- finally remove all non digit rest appearances
285
+ return [...`${str.trim()}`].reduce((acc, ch, i) => {
286
+ // +- signs are allowed
287
+ if (this.negativeNumbersAllowed)
288
+ if (!seenSign && (ch === '+' || ch === '-')) {
289
+ seenSign = true;
290
+ return `${acc}${ch}`;
291
+ }
292
+ if (/\d/.test(ch))
293
+ return `${acc}${ch}`;
294
+ return acc; // skip everything else
295
+ }, '');
296
+ default:
297
+ return `${str}`;
298
+ }
299
+ };
300
+ #patternTest = (str) => {
301
+ switch (this.keyboardType) {
302
+ case 'decimal-pad':
303
+ const allowedSignsRegex2 = /^[+-]?$|^[+-]?(\d+([.,]\d*)?|[.,]\d*)$/, // allow single '+' or '-', then allow only one ',' or '.' and finally only digits
304
+ digitsDecimalsOnlyRegex = /^(\d+([.,]\d*)?|[.,]\d*)?$/; // allow only one ',' or '.' and finally only digits
305
+ return (this.negativeNumbersAllowed ? allowedSignsRegex2 : digitsDecimalsOnlyRegex).test(str);
306
+ // // console.log(isValidDecimal("")); // true
307
+ // // console.log(isValidDecimal("+")); // true
308
+ // // console.log(isValidDecimal("-")); // true
309
+ // // console.log(isValidDecimal("123")); // true
310
+ // // console.log(isValidDecimal("+123")); // true
311
+ // // console.log(isValidDecimal("-456")); // true
312
+ // // console.log(isValidDecimal("12.34")); // true
313
+ // // console.log(isValidDecimal("-0,56")); // true
314
+ // // console.log(isValidDecimal(".78")); // true
315
+ // // console.log(isValidDecimal(",9")); // true
316
+ // // console.log(isValidDecimal("12.3.4")); // false
317
+ // // console.log(isValidDecimal("12,3,4")); // false
318
+ // // console.log(isValidDecimal("12-3")); // false
319
+ // // console.log(isValidDecimal("12a")); // false
320
+ case 'number-pad':
321
+ const allowedSignsRegex = /^([+-]|\d+|[+-]\d+)?$/, // allow single '+' or '-', then allow only digits
322
+ digitsOnlyRegex = /^(\d+)?$/; // allow only digits
323
+ return (this.negativeNumbersAllowed ? allowedSignsRegex : digitsOnlyRegex).test(str);
324
+ // // console.log(isValidInteger("")); // true
325
+ // // console.log(isValidInteger("+")); // true
326
+ // // console.log(isValidInteger("-")); // true
327
+ // // console.log(isValidInteger("123")); // true
328
+ // // console.log(isValidInteger("+123")); // true
329
+ // // console.log(isValidInteger("-456")); // true
330
+ // // console.log(isValidInteger("12-3")); // false
331
+ // // console.log(isValidInteger("++123")); // false
332
+ // // console.log(isValidInteger("123a")); // false
333
+ default:
334
+ return true;
335
+ }
336
+ };
337
+ #handleInputBeforeinput = (evt) => {
338
+ console.debug(`${_a.name} ⚡️ ${evt?.type}`);
339
+ const input = evt.target;
340
+ if (!input)
341
+ return;
342
+ if ('insertText' !== evt.inputType)
343
+ return;
344
+ const data = evt.data ?? '';
345
+ if (-1 < input.maxLength && 0 === data.length) {
346
+ evt.preventDefault();
347
+ return this.shake(); //.then(this.reportValidity)
348
+ } // nothing to add
349
+ const start = input.selectionStart ?? 0, end = input.selectionEnd ?? 0, before = this.text.slice(0, start), after = this.text.slice(end), newText = `${before}${data}${after}`;
350
+ if (0 === newText.length)
351
+ return;
352
+ switch (input.getAttribute('inputmode')) {
353
+ case 'decimal':
354
+ // const allowedSignsRegex2 = /^[+-]?$|^[+-]?(\d+([.,]\d*)?|[.,]\d*)$/, // allow single '+' or '-', then allow only one ',' or '.' and finally only digits
355
+ // digitsDecimalsOnlyRegex = /^(\d+([.,]\d*)?|[.,]\d*)?$/ // allow only one ',' or '.' and finally only digits
356
+ // if ((this.min < 0 ? allowedSignsRegex2 : digitsDecimalsOnlyRegex).test(newText)) break
357
+ if (this.#patternTest(newText))
358
+ break;
359
+ evt.preventDefault();
360
+ return this.shake(); //.then(this.reportValidity)
361
+ case 'numeric':
362
+ // const allowedSignsRegex = /^([+-]|\d+|[+-]\d+)?$/, // allow single '+' or '-', then allow only digits
363
+ // digitsOnlyRegex = /^(\d+)?$/ // allow only digits
364
+ // if ((this.min < 0 ? allowedSignsRegex : digitsOnlyRegex).test(newText)) break
365
+ if (this.#patternTest(newText))
366
+ break;
367
+ evt.preventDefault();
368
+ return this.shake(); //.then(this.reportValidity)
369
+ // this.setValidity(prevValidity, prevValiditationMessage) // restore
370
+ }
371
+ };
372
+ #handleInputBlur = (evt) => {
373
+ console.debug(`${_a.name} ⚡️ ${evt?.type}`);
374
+ const input = evt.target;
375
+ if (!input)
376
+ return;
377
+ if (0 === input.value.length)
378
+ return;
379
+ const finalText = this.value.replace(/[.,]/g, I18n.decimalSeparator);
380
+ if (!set(input, 'value', finalText))
381
+ return;
382
+ this.#sendValueToForm();
383
+ };
384
+ #handleInputInput = (evt) => {
385
+ console.debug(`${_a.name} ⚡️ ${evt?.type}`);
386
+ this.#sendValueToForm();
387
+ };
388
+ // Optional: form participation properties
389
+ get name() {
390
+ return this.getAttribute('name') ?? this.getAttribute('label') ?? this.querySelector(':scope>[slot=label]')?.textContent ?? '';
391
+ }
392
+ get value() {
393
+ // text allows special edge cases, like '-.' or '+' and generally might be invalid number. It might also be localized and not US based.
394
+ // here we make sure it is number-like, to be used in number operations.
395
+ switch (this.keyboardType) {
396
+ case 'decimal-pad':
397
+ case 'number-pad':
398
+ if ('string' !== typeof this.text)
399
+ return '0';
400
+ const value = this.text.replace(/[.,]/g, '.');
401
+ // Capture optional leading sign
402
+ const sign = value.startsWith('-') ? '-' : '';
403
+ // Strip sign for processing
404
+ let s = value.replace(/^[+-]/, '');
405
+ // Split on dot (take only first two parts in case of multiple dots — though
406
+ // your input guarantees one, this is defensive)
407
+ const [intPart = '', fracPart = ''] = s.split('.'), hasDot = s.includes('.');
408
+ // Remove leading zeros from integer part, keep at least '0'
409
+ const cleanInt = intPart.replace(/^0+/, '') || '0';
410
+ // Remove trailing zeros from fractional part
411
+ const cleanFrac = fracPart.replace(/0+$/, '');
412
+ // Build result
413
+ const result = hasDot && cleanFrac.length > 0 ? `${sign}${cleanInt}.${cleanFrac}` : `${sign}${cleanInt}`;
414
+ return result.replace(/^-0(\.0+)?$/, '0');
415
+ default:
416
+ return this.text;
417
+ }
418
+ }
419
+ get valueAsNumber() {
420
+ switch (this.keyboardType) {
421
+ case 'decimal-pad':
422
+ case 'number-pad':
423
+ return Number(this.value);
424
+ default:
425
+ return '';
426
+ }
427
+ }
428
+ get negativeNumbersAllowed() {
429
+ // switch (this.keyboardType) {
430
+ // case 'decimal-pad':
431
+ // case 'number-pad':
432
+ const min = this.getAttribute('minimum') ?? '-Infinity', max = this.getAttribute('maximum') ?? 'Infinity';
433
+ return compareBigDecimals('0', min) >= 0 && compareBigDecimals('0', max) <= 0;
434
+ // default:
435
+ // return false
436
+ // }
437
+ }
438
+ setValidity = (flags, message, anchor) => {
439
+ // let msg
440
+ // if (message)
441
+ for (const k in flags) {
442
+ const key = k; // ✅ type-safe cast
443
+ if (true !== flags[key])
444
+ continue;
445
+ for (const el of this.#validitiesSlot?.assignedElements({ flatten: true }) ?? []) {
446
+ if (!el.matches('option'))
447
+ continue;
448
+ const option = el;
449
+ if (`${kebabCase(key)}` === option.value) {
450
+ message = option.label;
451
+ break;
452
+ }
453
+ else if (`${kebabCase(key)}:${message}` === option.value) {
454
+ message = option.label;
455
+ break;
456
+ }
457
+ }
458
+ }
459
+ if (!message)
460
+ for (const k in flags) {
461
+ const key = k; // ✅ type-safe cast
462
+ if (true !== flags[key])
463
+ continue;
464
+ message = kebabCase(key);
465
+ break;
466
+ }
467
+ console.debug(`${_a.name} ⚡️ validity-change`);
468
+ return this.#internals.setValidity(flags, this.#customValidity || message, anchor ?? this.#input);
469
+ };
470
+ setCustomValidity = (message) => {
471
+ this.#customValidity = message;
472
+ if (this.#customValidity)
473
+ this.#internals.setValidity({ ...this.#internals.validity, customError: true }, message);
474
+ else
475
+ this.#sendValueToForm(false);
476
+ };
477
+ formAssociatedCallback = (form) => {
478
+ this.#sendValueToForm();
479
+ };
480
+ formDisabledCallback = (disabled) => {
481
+ for (const el of this.#shadowRoot.querySelectorAll('input'))
482
+ el.toggleAttribute('disabled', !disabled);
483
+ };
484
+ formResetCallback = () => {
485
+ this.text = '';
486
+ this.#sendValueToForm();
487
+ };
488
+ }
489
+ _a = TextField;
@@ -0,0 +1,5 @@
1
+ export declare class ToolBarItemGroup extends HTMLElement {
2
+ constructor();
3
+ connectedCallback(): void;
4
+ disconnectedCallback(): void;
5
+ }
@@ -0,0 +1,11 @@
1
+ export class ToolBarItemGroup extends HTMLElement {
2
+ constructor() {
3
+ super();
4
+ }
5
+ connectedCallback() {
6
+ console.debug(`${ToolBarItemGroup.name} ⚡️ connect`);
7
+ }
8
+ disconnectedCallback() {
9
+ console.debug(`${ToolBarItemGroup.name} ⚡️ disconnect`);
10
+ }
11
+ }
@@ -0,0 +1,5 @@
1
+ export declare class ToolBarItem extends HTMLElement {
2
+ constructor();
3
+ connectedCallback(): void;
4
+ disconnectedCallback(): void;
5
+ }
@@ -0,0 +1,19 @@
1
+ import { CleanupRegistry } from '../internal/class/cleanup-registry';
2
+ import { onoff, touchGlass } from '../internal/utils';
3
+ export class ToolBarItem extends HTMLElement {
4
+ constructor() {
5
+ super();
6
+ }
7
+ connectedCallback() {
8
+ console.debug(`${ToolBarItem.name} ⚡️ connect`);
9
+ CleanupRegistry.register(this, onoff(touchGlass(this, (t) => t.closest('tool-bar-item-group') ?? t, (event) => {
10
+ if (event.target.closest('menu-view[open]'))
11
+ return false;
12
+ return true;
13
+ }), this).on());
14
+ }
15
+ disconnectedCallback() {
16
+ console.debug(`${ToolBarItem.name} ⚡️ disconnect`);
17
+ CleanupRegistry.unregister(this);
18
+ }
19
+ }
@@ -0,0 +1,7 @@
1
+ export declare class ToolBar extends HTMLElement {
2
+ #private;
3
+ static get template(): DocumentFragment;
4
+ constructor();
5
+ connectedCallback(): void;
6
+ disconnectedCallback(): void;
7
+ }
@@ -0,0 +1,77 @@
1
+ var _a;
2
+ import { ResizeObserverSingleton } from '../internal/class/resize-observer-singleton';
3
+ import { $ } from '../internal/utils';
4
+ const observers = new ResizeObserverSingleton();
5
+ export class ToolBar extends HTMLElement {
6
+ static #template;
7
+ static get template() {
8
+ // <!--exportparts="toolbar-leading-stack,toolbar-principal-stack,toolbar-trailing-stack"-->
9
+ return (this.#template ??= $(String.raw `
10
+ <div part="root top-bar">
11
+ <div part="root toolbar-leading-stack">
12
+ <slot name="top-bar-leading"></slot>
13
+ </div>
14
+ <div part="root toolbar-principal-stack">
15
+ <slot name="top-bar-principal"></slot>
16
+ </div>
17
+ <div part="root toolbar-trailing-stack">
18
+ <slot name="top-bar-trailing"></slot>
19
+ </div>
20
+ </div>
21
+ <div part="root bottom-bar">
22
+ <div part="root toolbar-leading-stack">
23
+ <slot name="bottom-bar-leading"></slot>
24
+ </div>
25
+ <div part="root toolbar-principal-stack">
26
+ <slot name="bottom-bar-principal"></slot>
27
+ </div>
28
+ <div part="root toolbar-trailing-stack">
29
+ <slot name="bottom-bar-trailing"></slot>
30
+ </div>
31
+ </div>`, ''));
32
+ }
33
+ #shadowRoot;
34
+ get #scrollView() {
35
+ return this.parentElement?.querySelector(':scope > scroll-view') ?? undefined; //this.previousElementSibling ?? undefined
36
+ }
37
+ constructor() {
38
+ super();
39
+ this.#shadowRoot = this.attachShadow({ mode: 'closed' });
40
+ // NOTE: wait for config
41
+ // Snapshot.waitReady.then(() => {
42
+ this.#shadowRoot.appendChild(document.importNode(this.constructor.template, true));
43
+ // })
44
+ }
45
+ connectedCallback() {
46
+ console.debug(`${_a.name} ⚡️ connect`);
47
+ // NOTE: wait for config
48
+ // Snapshot.waitReady.then(() => {
49
+ for (const el of this.#shadowRoot.querySelectorAll(`[part*="toolbar-leading-stack"],[part*="toolbar-trailing-stack"]`))
50
+ observers.observe(el, this.#measureStacks.bind(this));
51
+ // })
52
+ }
53
+ disconnectedCallback() {
54
+ console.debug(`${_a.name} ⚡️ disconnect`);
55
+ observers.unobserve(this);
56
+ }
57
+ #measureStacks(entry) {
58
+ console.debug(`${_a.name} ⚡️ measure`);
59
+ if (this.closest('[hidden]'))
60
+ return;
61
+ const leading = 'toolbar-leading-stack', trailing = 'toolbar-trailing-stack';
62
+ const parentMap = {
63
+ 'top-bar': 'navbar',
64
+ 'bottom-bar': 'toolbar', //'bottombar',
65
+ };
66
+ const { contentRect, target } = entry;
67
+ const parentPart = target.parentElement?.part.contains('top-bar') ? 'top-bar' : target.parentElement?.part.contains('bottom-bar') ? 'bottom-bar' : null;
68
+ if (!parentPart)
69
+ return;
70
+ const side = target.part.contains(leading) ? 'inline-start' : target.part.contains(trailing) ? 'inline-end' : null;
71
+ if (!side)
72
+ return;
73
+ const prop = `--${parentMap[parentPart]}-padding-${side}`;
74
+ $.prop(prop, `${Math.round(contentRect.width)}px`, this.#scrollView); //;(this.#scrollView as HTMLElement)?.style?.setProperty(prop, `${Math.round(contentRect.width)}px`)
75
+ }
76
+ }
77
+ _a = ToolBar;
@@ -1,6 +1,8 @@
1
1
  /**
2
2
  * BUG: Safari on IOS reports inaccurate innerHeight (which is what we really want) on orientationchange.
3
3
  * So we live with a pescy body-scrollbar that shows up on resize on desktops.
4
+ *
5
+ * @summary Required component, must be BODY tag
4
6
  */
5
7
  export declare class VKeyboard extends HTMLElement {
6
8
  #private;