@maggioli-design-system/mds-input-otp 1.0.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 (248) hide show
  1. package/dist/cjs/app-globals-3a1e7e63.js +5 -0
  2. package/dist/cjs/index-3ce43d21.js +1360 -0
  3. package/dist/cjs/index.cjs.js +2 -0
  4. package/dist/cjs/loader.cjs.js +15 -0
  5. package/dist/cjs/mds-input-otp.cjs.entry.js +101 -0
  6. package/dist/cjs/mds-input-otp.cjs.js +25 -0
  7. package/dist/collection/collection-manifest.json +12 -0
  8. package/dist/collection/common/aria.js +45 -0
  9. package/dist/collection/common/browser.js +7 -0
  10. package/dist/collection/common/date.js +13 -0
  11. package/dist/collection/common/device.js +6 -0
  12. package/dist/collection/common/file.js +48 -0
  13. package/dist/collection/common/floating-controller.js +201 -0
  14. package/dist/collection/common/icon.js +15 -0
  15. package/dist/collection/common/keyboard-manager.js +46 -0
  16. package/dist/collection/common/locale.js +66 -0
  17. package/dist/collection/common/slot.js +28 -0
  18. package/dist/collection/common/string.js +30 -0
  19. package/dist/collection/common/unit.js +22 -0
  20. package/dist/collection/common/yugop/core.js +16 -0
  21. package/dist/collection/common/yugop/index.js +3 -0
  22. package/dist/collection/common/yugop/random-text.js +59 -0
  23. package/dist/collection/common/yugop/utils/math.js +11 -0
  24. package/dist/collection/common/yugop/utils/noop.js +1 -0
  25. package/dist/collection/common/yugop/utils/prng.js +21 -0
  26. package/dist/collection/common/yugop/utils/string.js +2 -0
  27. package/dist/collection/components/mds-input-otp/mds-input-otp.css +16 -0
  28. package/dist/collection/components/mds-input-otp/mds-input-otp.js +159 -0
  29. package/dist/collection/components/mds-input-otp/test/mds-input-otp.stories.js +56 -0
  30. package/dist/collection/dictionary/animation.js +5 -0
  31. package/dist/collection/dictionary/autocomplete.js +59 -0
  32. package/dist/collection/dictionary/button.js +39 -0
  33. package/dist/collection/dictionary/color.js +19 -0
  34. package/dist/collection/dictionary/file-extensions.js +69 -0
  35. package/dist/collection/dictionary/floating-ui.js +19 -0
  36. package/dist/collection/dictionary/icon.js +10 -0
  37. package/dist/collection/dictionary/input.js +37 -0
  38. package/dist/collection/dictionary/keyboard.js +84 -0
  39. package/dist/collection/dictionary/loading.js +5 -0
  40. package/dist/collection/dictionary/text.js +65 -0
  41. package/dist/collection/dictionary/tree.js +13 -0
  42. package/dist/collection/dictionary/typography.js +67 -0
  43. package/dist/collection/dictionary/variant.js +116 -0
  44. package/dist/collection/fixtures/cities.js +110 -0
  45. package/dist/collection/fixtures/filenames.js +118 -0
  46. package/dist/collection/type/animation.js +1 -0
  47. package/dist/collection/type/autocomplete.js +1 -0
  48. package/dist/collection/type/button.js +1 -0
  49. package/dist/collection/type/date.js +1 -0
  50. package/dist/collection/type/file-types.js +1 -0
  51. package/dist/collection/type/floating-ui.js +1 -0
  52. package/dist/collection/type/form-rel.js +1 -0
  53. package/dist/collection/type/header-bar.js +1 -0
  54. package/dist/collection/type/input-tip.js +1 -0
  55. package/dist/collection/type/input.js +1 -0
  56. package/dist/collection/type/keyboard.js +1 -0
  57. package/dist/collection/type/loading.js +1 -0
  58. package/dist/collection/type/preference.js +1 -0
  59. package/dist/collection/type/text.js +1 -0
  60. package/dist/collection/type/tree.js +1 -0
  61. package/dist/collection/type/typography.js +1 -0
  62. package/dist/collection/type/variant-file-format.js +91 -0
  63. package/dist/collection/type/variant.js +1 -0
  64. package/dist/components/index.d.ts +33 -0
  65. package/dist/components/index.js +1 -0
  66. package/dist/components/mds-input-otp.d.ts +11 -0
  67. package/dist/components/mds-input-otp.js +113 -0
  68. package/dist/documentation.d.ts +443 -0
  69. package/dist/documentation.json +105 -0
  70. package/dist/esm/app-globals-0f993ce5.js +3 -0
  71. package/dist/esm/index-7080a0cd.js +1332 -0
  72. package/dist/esm/index.js +1 -0
  73. package/dist/esm/loader.js +11 -0
  74. package/dist/esm/mds-input-otp.entry.js +97 -0
  75. package/dist/esm/mds-input-otp.js +20 -0
  76. package/dist/esm/polyfills/core-js.js +11 -0
  77. package/dist/esm/polyfills/dom.js +79 -0
  78. package/dist/esm/polyfills/es5-html-element.js +1 -0
  79. package/dist/esm/polyfills/index.js +34 -0
  80. package/dist/esm/polyfills/system.js +6 -0
  81. package/dist/esm-es5/app-globals-0f993ce5.js +1 -0
  82. package/dist/esm-es5/index-7080a0cd.js +1 -0
  83. package/dist/esm-es5/index.js +0 -0
  84. package/dist/esm-es5/loader.js +1 -0
  85. package/dist/esm-es5/mds-input-otp.entry.js +1 -0
  86. package/dist/esm-es5/mds-input-otp.js +1 -0
  87. package/dist/index.cjs.js +1 -0
  88. package/dist/index.js +1 -0
  89. package/dist/mds-input-otp/index.esm.js +0 -0
  90. package/dist/mds-input-otp/mds-input-otp.esm.js +1 -0
  91. package/dist/mds-input-otp/mds-input-otp.js +127 -0
  92. package/dist/mds-input-otp/p-0b4b7d22.system.js +1 -0
  93. package/dist/mds-input-otp/p-50ea2036.system.js +1 -0
  94. package/dist/mds-input-otp/p-56ba5cbf.system.js +1 -0
  95. package/dist/mds-input-otp/p-6fa28cad.entry.js +1 -0
  96. package/dist/mds-input-otp/p-8d749fc9.system.entry.js +1 -0
  97. package/dist/mds-input-otp/p-9c3d33cc.system.js +2 -0
  98. package/dist/mds-input-otp/p-dea9d1b9.js +2 -0
  99. package/dist/mds-input-otp/p-e1255160.js +1 -0
  100. package/dist/stats.json +588 -0
  101. package/dist/types/common/aria.d.ts +7 -0
  102. package/dist/types/common/browser.d.ts +2 -0
  103. package/dist/types/common/date.d.ts +4 -0
  104. package/dist/types/common/device.d.ts +2 -0
  105. package/dist/types/common/file.d.ts +11 -0
  106. package/dist/types/common/floating-controller.d.ts +47 -0
  107. package/dist/types/common/icon.d.ts +5 -0
  108. package/dist/types/common/keyboard-manager.d.ts +12 -0
  109. package/dist/types/common/locale.d.ts +20 -0
  110. package/dist/types/common/slot.d.ts +4 -0
  111. package/dist/types/common/string.d.ts +4 -0
  112. package/dist/types/common/unit.d.ts +3 -0
  113. package/dist/types/common/yugop/core.d.ts +10 -0
  114. package/dist/types/common/yugop/index.d.ts +1 -0
  115. package/dist/types/common/yugop/random-text.d.ts +31 -0
  116. package/dist/types/common/yugop/utils/math.d.ts +3 -0
  117. package/dist/types/common/yugop/utils/noop.d.ts +1 -0
  118. package/dist/types/common/yugop/utils/prng.d.ts +8 -0
  119. package/dist/types/common/yugop/utils/string.d.ts +1 -0
  120. package/dist/types/components/mds-input-otp/mds-input-otp.d.ts +27 -0
  121. package/dist/types/components/mds-input-otp/test/mds-input-otp.stories.d.ts +21 -0
  122. package/dist/types/components.d.ts +61 -0
  123. package/dist/types/dictionary/animation.d.ts +2 -0
  124. package/dist/types/dictionary/autocomplete.d.ts +2 -0
  125. package/dist/types/dictionary/button.d.ts +7 -0
  126. package/dist/types/dictionary/color.d.ts +3 -0
  127. package/dist/types/dictionary/file-extensions.d.ts +12 -0
  128. package/dist/types/dictionary/floating-ui.d.ts +3 -0
  129. package/dist/types/dictionary/icon.d.ts +4 -0
  130. package/dist/types/dictionary/input.d.ts +5 -0
  131. package/dist/types/dictionary/keyboard.d.ts +2 -0
  132. package/dist/types/dictionary/loading.d.ts +2 -0
  133. package/dist/types/dictionary/text.d.ts +4 -0
  134. package/dist/types/dictionary/tree.d.ts +4 -0
  135. package/dist/types/dictionary/typography.d.ts +11 -0
  136. package/dist/types/dictionary/variant.d.ts +13 -0
  137. package/dist/types/fixtures/cities.d.ts +2 -0
  138. package/dist/types/fixtures/filenames.d.ts +63 -0
  139. package/dist/types/stencil-public-runtime.d.ts +1680 -0
  140. package/dist/types/type/animation.d.ts +1 -0
  141. package/dist/types/type/autocomplete.d.ts +2 -0
  142. package/dist/types/type/button.d.ts +5 -0
  143. package/dist/types/type/date.d.ts +5 -0
  144. package/dist/types/type/file-types.d.ts +1 -0
  145. package/dist/types/type/floating-ui.d.ts +2 -0
  146. package/dist/types/type/form-rel.d.ts +1 -0
  147. package/dist/types/type/header-bar.d.ts +2 -0
  148. package/dist/types/type/input-tip.d.ts +1 -0
  149. package/dist/types/type/input.d.ts +7 -0
  150. package/dist/types/type/keyboard.d.ts +12 -0
  151. package/dist/types/type/loading.d.ts +1 -0
  152. package/dist/types/type/preference.d.ts +2 -0
  153. package/dist/types/type/text.d.ts +3 -0
  154. package/dist/types/type/tree.d.ts +3 -0
  155. package/dist/types/type/typography.d.ts +10 -0
  156. package/dist/types/type/variant-file-format.d.ts +11 -0
  157. package/dist/types/type/variant.d.ts +13 -0
  158. package/documentation.json +703 -0
  159. package/loader/cdn.js +2 -0
  160. package/loader/index.cjs.js +2 -0
  161. package/loader/index.d.ts +24 -0
  162. package/loader/index.es2017.js +2 -0
  163. package/loader/index.js +3 -0
  164. package/loader/package.json +11 -0
  165. package/package.json +54 -0
  166. package/readme.md +41 -0
  167. package/src/common/aria.ts +59 -0
  168. package/src/common/browser.ts +10 -0
  169. package/src/common/date.ts +21 -0
  170. package/src/common/device.ts +9 -0
  171. package/src/common/file.ts +62 -0
  172. package/src/common/floating-controller.ts +286 -0
  173. package/src/common/icon.ts +25 -0
  174. package/src/common/keyboard-manager.ts +51 -0
  175. package/src/common/locale.ts +90 -0
  176. package/src/common/slot.ts +35 -0
  177. package/src/common/string.ts +42 -0
  178. package/src/common/unit.ts +33 -0
  179. package/src/common/yugop/core.ts +47 -0
  180. package/src/common/yugop/index.ts +4 -0
  181. package/src/common/yugop/random-text.ts +95 -0
  182. package/src/common/yugop/utils/math.ts +21 -0
  183. package/src/common/yugop/utils/noop.ts +1 -0
  184. package/src/common/yugop/utils/prng.ts +35 -0
  185. package/src/common/yugop/utils/string.ts +4 -0
  186. package/src/components/mds-input-otp/.gitlab-ci.yml +20 -0
  187. package/src/components/mds-input-otp/mds-input-otp.css +16 -0
  188. package/src/components/mds-input-otp/mds-input-otp.tsx +123 -0
  189. package/src/components/mds-input-otp/readme.md +19 -0
  190. package/src/components/mds-input-otp/test/mds-input-otp.e2e.ts +11 -0
  191. package/src/components/mds-input-otp/test/mds-input-otp.stories.tsx +90 -0
  192. package/src/components.d.ts +61 -0
  193. package/src/dictionary/animation.ts +8 -0
  194. package/src/dictionary/autocomplete.ts +62 -0
  195. package/src/dictionary/button.ts +52 -0
  196. package/src/dictionary/color.ts +24 -0
  197. package/src/dictionary/file-extensions.ts +88 -0
  198. package/src/dictionary/floating-ui.ts +25 -0
  199. package/src/dictionary/icon.ts +15 -0
  200. package/src/dictionary/input.ts +48 -0
  201. package/src/dictionary/keyboard.ts +87 -0
  202. package/src/dictionary/loading.ts +9 -0
  203. package/src/dictionary/text.ts +73 -0
  204. package/src/dictionary/tree.ts +21 -0
  205. package/src/dictionary/typography.ts +88 -0
  206. package/src/dictionary/variant.ts +141 -0
  207. package/src/fixtures/cities.ts +116 -0
  208. package/src/fixtures/filenames.ts +123 -0
  209. package/src/fixtures/icons.json +447 -0
  210. package/src/fixtures/iconsauce.json +306 -0
  211. package/src/meta/file-format/locale.el.json +44 -0
  212. package/src/meta/file-format/locale.en.json +44 -0
  213. package/src/meta/file-format/locale.es.json +44 -0
  214. package/src/meta/file-format/locale.it.json +44 -0
  215. package/src/meta/keyboard/keys.json +83 -0
  216. package/src/tailwind/components.css +51 -0
  217. package/src/tailwind/fouc.css +118 -0
  218. package/src/tailwind/index.css +4 -0
  219. package/src/type/animation.ts +3 -0
  220. package/src/type/autocomplete.ts +68 -0
  221. package/src/type/button.ts +32 -0
  222. package/src/type/date.ts +10 -0
  223. package/src/type/file-types.ts +61 -0
  224. package/src/type/floating-ui.ts +17 -0
  225. package/src/type/form-rel.ts +11 -0
  226. package/src/type/header-bar.ts +11 -0
  227. package/src/type/input-tip.ts +11 -0
  228. package/src/type/input.ts +33 -0
  229. package/src/type/keyboard.ts +93 -0
  230. package/src/type/loading.ts +3 -0
  231. package/src/type/preference.ts +11 -0
  232. package/src/type/text.ts +63 -0
  233. package/src/type/tree.ts +12 -0
  234. package/src/type/typography.ts +65 -0
  235. package/src/type/variant-file-format.ts +126 -0
  236. package/src/type/variant.ts +119 -0
  237. package/www/build/index.esm.js +0 -0
  238. package/www/build/mds-input-otp.esm.js +1 -0
  239. package/www/build/mds-input-otp.js +127 -0
  240. package/www/build/p-0b4b7d22.system.js +1 -0
  241. package/www/build/p-50ea2036.system.js +1 -0
  242. package/www/build/p-56ba5cbf.system.js +1 -0
  243. package/www/build/p-6fa28cad.entry.js +1 -0
  244. package/www/build/p-8d749fc9.system.entry.js +1 -0
  245. package/www/build/p-9c3d33cc.system.js +2 -0
  246. package/www/build/p-dea9d1b9.js +2 -0
  247. package/www/build/p-e1255160.js +1 -0
  248. package/www/host.config.json +15 -0
@@ -0,0 +1,90 @@
1
+ import { render } from 'mustache'
2
+
3
+ type LocaleConfig = {
4
+ el?: Record<string, string | string[]>
5
+ en: Record<string, string | string[]>
6
+ es?: Record<string, string | string[]>
7
+ it?: Record<string, string | string[]>
8
+ }
9
+
10
+ export class Locale {
11
+ rollbackLanguage: string = 'en'
12
+ language: string
13
+ config: LocaleConfig
14
+ closestElement:HTMLElement
15
+ element: HTMLElement
16
+
17
+ constructor (configData?: LocaleConfig) {
18
+ if (configData) {
19
+ this.set(configData)
20
+ }
21
+ }
22
+
23
+ set = (configData: LocaleConfig): void => {
24
+ this.config = configData
25
+ }
26
+
27
+ lang = (el: HTMLElement): string => {
28
+ this.element = el
29
+ this.closestElement = this.element.closest('[lang]') as HTMLElement
30
+
31
+ if (this.closestElement) {
32
+ if (this.closestElement.lang) {
33
+ this.language = this.closestElement.lang
34
+ return this.language
35
+ }
36
+ }
37
+
38
+ this.language = this.rollbackLanguage
39
+ return this.language
40
+ }
41
+
42
+ update = (doc?: Document | ShadowRoot): void => {
43
+ const context = doc ?? this.element.shadowRoot
44
+ context && context.querySelectorAll('*').forEach(el => {
45
+ if (el.tagName.toLowerCase().startsWith('mds-')) {
46
+ // eslint-disable-next-line no-restricted-syntax
47
+ if (el && 'updateLang' in el) {
48
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
49
+ (el as any).updateLang()
50
+ }
51
+ }
52
+ })
53
+ }
54
+
55
+ private pluralize = (tag: string | string[], context: Record<string, string | number | boolean>): string => {
56
+
57
+ const languagePhrase: string | string[] = this.config[this.language] ? this.config[this.language][tag] : this.config[this.rollbackLanguage][tag]
58
+ const phrases: string[] = []
59
+
60
+ if (Array.isArray(languagePhrase)) {
61
+ phrases.push(languagePhrase[0])
62
+ phrases.push(languagePhrase[1])
63
+ } else {
64
+ phrases.push(languagePhrase)
65
+ phrases.push(languagePhrase)
66
+ }
67
+
68
+ const [ defaultPhrase ] = phrases
69
+ let translatePhrase: string = defaultPhrase
70
+
71
+ const keys = Object.keys(context)
72
+ if (keys.length > 0) {
73
+ const [firstKey] = keys
74
+ if (typeof context[firstKey] === 'number') {
75
+ if (context[firstKey] !== 1) {
76
+ translatePhrase = phrases[1]
77
+ }
78
+ }
79
+ }
80
+
81
+ return render(translatePhrase, context)
82
+ }
83
+
84
+ get = (tag: string | string[], context?: Record<string, string | number | boolean>): string => {
85
+ if (context) {
86
+ return this.pluralize(tag, context)
87
+ }
88
+ return this.config[this.language] ? this.config[this.language][tag] : this.config[this.rollbackLanguage][tag]
89
+ }
90
+ }
@@ -0,0 +1,35 @@
1
+ const hasSlottedElements = (el: HTMLElement, name?: string): boolean => {
2
+ const query = name ? `slot[name="${name}"]` : 'slot:not([name])'
3
+
4
+ const slot: HTMLSlotElement = el.shadowRoot?.querySelector(query) as HTMLSlotElement
5
+ if (slot) {
6
+ return slot.assignedElements({ flatten: true }).length > 0
7
+ }
8
+ return false
9
+ }
10
+
11
+ const hasSlottedNodes = (el: HTMLElement, name?: string): boolean => {
12
+ const query = name ? `slot[name="${name}"]` : 'slot:not([name])'
13
+
14
+ const slot: HTMLSlotElement = el.shadowRoot?.querySelector(query) as HTMLSlotElement
15
+ if (slot) {
16
+ return slot.assignedNodes().length > 0
17
+ }
18
+ return false
19
+ }
20
+
21
+ const hasSlotted = (el: HTMLElement, name?: string): boolean => {
22
+ const query = name ? `slot[name="${name}"]` : 'slot:not([name])'
23
+
24
+ const slot: HTMLSlotElement = el.shadowRoot?.querySelector(query) as HTMLSlotElement
25
+ if (slot) {
26
+ return slot.assignedNodes().length > 0 || slot.assignedElements().length > 0
27
+ }
28
+ return false
29
+ }
30
+
31
+ export {
32
+ hasSlottedElements,
33
+ hasSlottedNodes,
34
+ hasSlotted,
35
+ }
@@ -0,0 +1,42 @@
1
+ const levenshteinDistance = (a: string, b: string): number => {
2
+ const dp: number[][] = Array.from({ length: a.length + 1 }, (_, i) =>
3
+ // eslint-disable-next-line no-nested-ternary
4
+ Array.from({ length: b.length + 1 }, (_, j) => (i === 0 ? j : j === 0 ? i : 0)),
5
+ )
6
+
7
+ for (let i = 1; i <= a.length; i++) {
8
+ for (let j = 1; j <= b.length; j++) {
9
+ if (a[i - 1] === b[j - 1]) {
10
+ dp[i][j] = dp[i - 1][j - 1]
11
+ } else {
12
+ dp[i][j] = 1 + Math.min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1])
13
+ }
14
+ }
15
+ }
16
+
17
+ return dp[a.length][b.length]
18
+ }
19
+
20
+
21
+ const closest = (input: string, validCodes: string[]): string => {
22
+ let [closest] = validCodes
23
+ let minDistance = levenshteinDistance(input, closest)
24
+
25
+ for (const code of validCodes) {
26
+ const distance = levenshteinDistance(input, code)
27
+ if (distance < minDistance) {
28
+ minDistance = distance
29
+ closest = code
30
+ }
31
+ }
32
+
33
+ return closest
34
+ }
35
+
36
+ const firstLetterUppercase = (str: string): string => str.charAt(0).toUpperCase() + str.slice(1)
37
+
38
+ export {
39
+ closest,
40
+ firstLetterUppercase,
41
+ levenshteinDistance,
42
+ }
@@ -0,0 +1,33 @@
1
+ const cssDurationToMilliseconds = (duration: string, defaultValue = 1000): number => {
2
+
3
+ if (duration.includes('ms')) {
4
+ return Number(duration.replace('ms', ''))
5
+ }
6
+
7
+ if (duration.includes('s')) {
8
+ return Number(duration.replace('s', '')) * 1000
9
+ }
10
+
11
+ return defaultValue
12
+ }
13
+
14
+ const cssSizeToNumber = (size: string, defaultValue = 0): number => {
15
+ if (size.includes('px')) {
16
+ return Number(size.replace('px', ''))
17
+ }
18
+
19
+ if (size.includes('rem')) {
20
+ return Number(size.replace('rem', '')) * 16
21
+ }
22
+
23
+ if (size.includes('em')) {
24
+ return Number(size.replace('em', '')) * 16
25
+ }
26
+
27
+ return defaultValue
28
+ }
29
+
30
+ export {
31
+ cssDurationToMilliseconds,
32
+ cssSizeToNumber,
33
+ }
@@ -0,0 +1,47 @@
1
+ import { generator } from './utils/prng'
2
+ import { strToCharCodeArray } from './utils/string'
3
+ import { randomSign, minMaxLooped } from './utils/math'
4
+ const rand = generator()
5
+
6
+ const random: (arg0: number, arg1: number) => () => number = (
7
+ base,
8
+ offset,
9
+ ) => () => (base + rand.range(0, offset)) * randomSign()
10
+
11
+ export const generateRandomCharCodeArray: (
12
+ arg0: number,
13
+ arg1: number
14
+ ) => (arg0: string) => number[] = (base, offset) => str =>
15
+ strToCharCodeArray(str).map(random(base, offset))
16
+ type Options = {
17
+ str: string
18
+ minCharCode: number
19
+ maxCharCode: number
20
+ placeholderChar: string
21
+ charStep: number
22
+ }
23
+ export const charCodeArrayToString: (
24
+ arg0: Options
25
+ ) => (arg0: number[]) => string = ({
26
+ str,
27
+ minCharCode,
28
+ maxCharCode,
29
+ placeholderChar,
30
+ charStep,
31
+ }) => charCodes =>
32
+ charCodes.reduce((acc, item, index) => {
33
+ if (item !== 0) {
34
+ if (Math.abs(item) > charStep) {
35
+ return acc + placeholderChar
36
+ }
37
+
38
+ return (
39
+ acc +
40
+ String.fromCharCode(
41
+ minMaxLooped(minCharCode, maxCharCode)(str.charCodeAt(index) + item),
42
+ )
43
+ )
44
+ }
45
+
46
+ return acc + str.charAt(index)
47
+ }, '')
@@ -0,0 +1,4 @@
1
+ // taken from https://github.com/zenoplex/random-text
2
+
3
+ // @flow
4
+ export { default } from './random-text'
@@ -0,0 +1,95 @@
1
+ import { generateRandomCharCodeArray, charCodeArrayToString } from './core'
2
+ import { noop } from './utils/noop'
3
+
4
+ type Options = {
5
+ str: string
6
+ speed?: number
7
+ placeholderChar?: string
8
+ frameOffset?: number
9
+ charOffset?: number
10
+ charStep?: number
11
+ minCharCode?: number
12
+ maxCharCode?: number
13
+ onProgress?: (arg0: string) => void
14
+ onComplete?: (arg0: string) => void
15
+ }
16
+
17
+ class RandomText {
18
+ static defaults: Options = {
19
+ str: '',
20
+ speed: 2,
21
+ placeholderChar: '_',
22
+ frameOffset: 30,
23
+ charOffset: 20,
24
+ charStep: 10,
25
+ minCharCode: 32,
26
+ maxCharCode: 122,
27
+ onProgress: noop,
28
+ onComplete: noop,
29
+ }
30
+ str: string
31
+ speed: number
32
+ placeholderChar: string
33
+ frameOffset: number
34
+ charOffset: number
35
+ charStep: number
36
+ minCharCode: number
37
+ maxCharCode: number
38
+ onProgress: (...args: Array<string>) => string
39
+ onComplete: (...args: Array<string>) => string
40
+ rafId: number // TODO: should be #rafId for private
41
+
42
+ constructor (options: Options) {
43
+ Object.assign(this, { ...RandomText.defaults, ...options })
44
+ }
45
+
46
+ start = (): void => {
47
+ const { frameOffset, charOffset, str, speed } = this
48
+ const randoms = generateRandomCharCodeArray(frameOffset, charOffset)(str)
49
+ this.stop()
50
+ this.rafId = requestAnimationFrame(() => {
51
+ this.step(randoms, speed, speed)
52
+ })
53
+ }
54
+
55
+ stop (): void {
56
+ cancelAnimationFrame(this.rafId)
57
+ }
58
+
59
+ step (randoms: number[], stepCount: number, speed: number): void {
60
+ const {
61
+ str,
62
+ charStep,
63
+ minCharCode,
64
+ maxCharCode,
65
+ placeholderChar,
66
+ onProgress,
67
+ onComplete,
68
+ } = this
69
+ const stepArray = randoms.slice(0, stepCount)
70
+ const steppedArray = stepArray.map(item => {
71
+ if (item > 0) return item - 1
72
+ if (item < 0) return item + 1
73
+ return 0
74
+ })
75
+ const output = charCodeArrayToString({
76
+ str,
77
+ minCharCode,
78
+ maxCharCode,
79
+ placeholderChar,
80
+ charStep,
81
+ })(steppedArray)
82
+ const updatedRandoms = [...steppedArray, ...randoms.slice(stepCount)]
83
+ onProgress(output)
84
+
85
+ if (output !== str) {
86
+ this.rafId = requestAnimationFrame(() => {
87
+ this.step(updatedRandoms, stepCount + speed, speed)
88
+ })
89
+ } else {
90
+ onComplete(output)
91
+ }
92
+ }
93
+ }
94
+
95
+ export default RandomText
@@ -0,0 +1,21 @@
1
+ import { generator } from './prng'
2
+
3
+ const rand = generator()
4
+ export const randomSign: () => number = () =>
5
+ (Math.round(Math.random()) - 0.5) * 2
6
+ export const generateRandomNumbers: (
7
+ arg0: number
8
+ ) => (
9
+ arg0: number
10
+ ) => (arg0: number) => number[] = base => charOffset => length =>
11
+ [...Array(length)].map(
12
+ () => (base + rand.range(0, charOffset)) * randomSign(),
13
+ )
14
+ export const minMaxLooped: (
15
+ arg0: number,
16
+ arg1: number
17
+ ) => (arg0: number) => number = (min, max) => value => {
18
+ if (value > max) return min + (value - max)
19
+ if (value < min) return max + (value - min)
20
+ return value
21
+ }
@@ -0,0 +1 @@
1
+ export const noop: (...rest: unknown[]) => unknown = () => {}
@@ -0,0 +1,35 @@
1
+ const int32 = 2147483647
2
+
3
+ const gen: (arg0: number) => number = v => (v * 16807) % int32
4
+
5
+ const randomFloat: (arg0: number) => number = v => gen(v) / int32
6
+
7
+ const randomInt: (arg0: number) => number = v => gen(v)
8
+
9
+ type Generator = (
10
+ _?: number
11
+ ) => {
12
+ random: () => number
13
+ randomFloat: () => number
14
+ range: (min: number, max: number) => number
15
+ rangeFloat: (min: number, max: number) => number
16
+ }
17
+ export const generator: Generator = (seed = 1) => {
18
+ let value = seed < 1 ? 1 : seed
19
+
20
+ const next: () => number = () => {
21
+ value = randomInt(value)
22
+ return value
23
+ }
24
+
25
+ return {
26
+ random: () => next(),
27
+ randomFloat: () => randomFloat(next()),
28
+ range: (min, max) => {
29
+ const minimum = min - 0.4999
30
+ const maximum = max + 0.4999
31
+ return Math.round(minimum + (maximum - minimum) * randomFloat(next()))
32
+ },
33
+ rangeFloat: (min, max) => min + (max - min) * randomFloat(next()),
34
+ }
35
+ }
@@ -0,0 +1,4 @@
1
+ // export const strToCharCodeArray: string => number[] = str => str.split('').map(item => item.charCodeAt(0));
2
+
3
+ export const strToCharCodeArray: (arg0: string) => number[] = str =>
4
+ str.split('').map(item => item.charCodeAt(0))
@@ -0,0 +1,20 @@
1
+ .base-input-otp:
2
+ variables:
3
+ COMPONENT: mds-input-otp
4
+
5
+ # TEST
6
+ input-otp-publish-test:
7
+ extends: [.base-stencil-publish-test, .base-input-otp]
8
+ dependencies: [base-stencil-build, base-isolate]
9
+
10
+ # PUBLISH
11
+ input-otp-publish:
12
+ extends: [.base-stencil-publish, .base-input-otp]
13
+ dependencies: [base-stencil-build, base-isolate]
14
+ needs: [base-stencil-build, base-isolate, input-otp-publish-test]
15
+
16
+ # INSTALL TEST
17
+ input-otp-install-test:
18
+ extends: [.base-stencil-install-test, .base-input-otp]
19
+ dependencies: [base-stencil-build, base-isolate]
20
+ needs: [base-stencil-build, base-isolate, input-otp-publish]
@@ -0,0 +1,16 @@
1
+ :host {
2
+ display: inline-flex;
3
+ gap: theme('spacing.400');
4
+ }
5
+
6
+ .input {
7
+ width: theme('size.1200');
8
+ }
9
+
10
+ .input::part(field) {
11
+ text-align: center;
12
+ }
13
+
14
+ .input::part(tip-count) {
15
+ display: none;
16
+ }
@@ -0,0 +1,123 @@
1
+ import { Component, Element, AttachInternals, Host, h, Prop } from '@stencil/core'
2
+
3
+ export interface MdsInputOtpInterface {
4
+ length?: number
5
+ autosubmit?: boolean
6
+ value?: string
7
+ }
8
+
9
+ @Component({
10
+ tag: 'mds-input-otp',
11
+ styleUrl: 'mds-input-otp.css',
12
+ formAssociated: true,
13
+ shadow: true,
14
+ })
15
+ export class MdsInputOtp {
16
+
17
+ @Element() private element: HTMLMdsInputOtpElement
18
+ @AttachInternals() internals: ElementInternals
19
+
20
+ /**
21
+ * Number of digits in the OTP code
22
+ */
23
+ @Prop() readonly length: number = 6
24
+
25
+ /**
26
+ * Automatically submits the form when the OTP code is complete
27
+ */
28
+ @Prop({ reflect: true }) readonly autosubmit: boolean = false
29
+
30
+ /**
31
+ * The current value of the OTP code
32
+ */
33
+ @Prop({ mutable: true, reflect: true }) value?: string = ''
34
+
35
+ private getOtpCode = (): string => {
36
+ const inputs = Array.from(this.element.shadowRoot!.querySelectorAll('mds-input'))
37
+ const otpCode = inputs.map(input => input.value).join('')
38
+
39
+ return otpCode
40
+ }
41
+
42
+ private setOtpDigit = (currentInput: HTMLMdsInputElement, digit: string): void => {
43
+ currentInput.value = digit
44
+
45
+ const otpCode = this.getOtpCode()
46
+ this.value = otpCode
47
+ this.internals.setFormValue(otpCode)
48
+ }
49
+
50
+ private submit = (currentInput: HTMLMdsInputElement): void => {
51
+ const isOtpCompleted = this.getOtpCode().length === this.length
52
+ currentInput.blur()
53
+
54
+ if (this.autosubmit && isOtpCompleted) {
55
+ this.internals.form?.requestSubmit()
56
+ }
57
+ }
58
+
59
+ private handleKeyDown = (e: KeyboardEvent): void => {
60
+ if (e.ctrlKey) {
61
+ return
62
+ }
63
+
64
+ // e.preventDefault() must be called *outside* the ctrlKey check,
65
+ // otherwise the onPaste event won't be triggered correctly
66
+ e.preventDefault()
67
+
68
+ if (isNaN(Number(e.key))) {
69
+ return
70
+ }
71
+
72
+ const currentInput = e.target as HTMLMdsInputElement
73
+ this.setOtpDigit(currentInput, e.key)
74
+
75
+ const nextInput = currentInput.nextElementSibling as HTMLMdsInputElement
76
+
77
+ if (nextInput) {
78
+ nextInput.setFocus()
79
+ } else {
80
+ this.submit(currentInput)
81
+ }
82
+ }
83
+
84
+ private handlePaste = (e: ClipboardEvent) => {
85
+ e.preventDefault()
86
+
87
+ const pastedText = e.clipboardData?.getData('text')
88
+
89
+ if (isNaN(Number(pastedText))) {
90
+ return
91
+ }
92
+
93
+ const digits = pastedText?.split('') ?? []
94
+ let currentInput = e.target as HTMLMdsInputElement
95
+ for (const currentDigit of digits) {
96
+ this.setOtpDigit(currentInput, currentDigit)
97
+
98
+ currentInput = currentInput.nextElementSibling as HTMLMdsInputElement
99
+
100
+ if (currentInput) {
101
+ currentInput.setFocus()
102
+ } else {
103
+ this.submit(currentInput)
104
+ return
105
+ }
106
+ }
107
+ }
108
+
109
+ render () {
110
+ return (
111
+ <Host>
112
+ {Array.from({ length: this.length }).map(() => (
113
+ <mds-input
114
+ class="input"
115
+ maxlength={1}
116
+ onKeyDown={this.handleKeyDown}
117
+ onPaste={this.handlePaste}
118
+ ></mds-input>
119
+ ))}
120
+ </Host>
121
+ )
122
+ }
123
+ }
@@ -0,0 +1,19 @@
1
+ # mds-input-otp
2
+
3
+
4
+
5
+ <!-- Auto Generated Below -->
6
+
7
+
8
+ ## Properties
9
+
10
+ | Property | Attribute | Description | Type | Default |
11
+ | ------------ | ------------ | ------------------------------------------------------------ | --------------------- | ------- |
12
+ | `autosubmit` | `autosubmit` | Automatically submits the form when the OTP code is complete | `boolean` | `false` |
13
+ | `length` | `length` | Number of digits in the OTP code | `number` | `6` |
14
+ | `value` | `value` | The current value of the OTP code | `string \| undefined` | `''` |
15
+
16
+
17
+ ----------------------------------------------
18
+
19
+ Built with love @ [Gruppo Maggioli](https://www.maggioli.com) from [R&D Department](https://www.maggioli.com/it-it/chi-siamo/ricerca-sviluppo)
@@ -0,0 +1,11 @@
1
+ import { newE2EPage } from '@stencil/core/testing'
2
+
3
+ describe('mds-input-otp', () => {
4
+ it('renders', async () => {
5
+ const page = await newE2EPage()
6
+ await page.setContent('<mds-input-otp></mds-input-otp>')
7
+
8
+ const element = await page.find('mds-input-otp')
9
+ expect(element).toHaveAttribute('hydrated')
10
+ })
11
+ })