@natachah/vanilla-frontend 0.0.2

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 (104) hide show
  1. package/.gitlab-ci.yml +40 -0
  2. package/LICENSE.md +7 -0
  3. package/README.md +11 -0
  4. package/docs/index.html +36 -0
  5. package/docs/main.js +32 -0
  6. package/docs/pages/components/badge.html +154 -0
  7. package/docs/pages/components/button.html +186 -0
  8. package/docs/pages/components/card.html +184 -0
  9. package/docs/pages/components/dialog.html +334 -0
  10. package/docs/pages/components/disclosure.html +310 -0
  11. package/docs/pages/components/dropdown.html +255 -0
  12. package/docs/pages/components/form.html +331 -0
  13. package/docs/pages/components/list.html +140 -0
  14. package/docs/pages/components/loading.html +58 -0
  15. package/docs/pages/components/media.html +130 -0
  16. package/docs/pages/components/nav.html +119 -0
  17. package/docs/pages/components/progress.html +47 -0
  18. package/docs/pages/components/slider.html +311 -0
  19. package/docs/pages/components/table.html +168 -0
  20. package/docs/pages/javascript/autofill.html +170 -0
  21. package/docs/pages/javascript/checkall.html +59 -0
  22. package/docs/pages/javascript/comfort.html +134 -0
  23. package/docs/pages/javascript/consent.html +112 -0
  24. package/docs/pages/javascript/cookie.html +81 -0
  25. package/docs/pages/javascript/form.html +199 -0
  26. package/docs/pages/javascript/scroll.html +209 -0
  27. package/docs/pages/javascript/sidebar.html +53 -0
  28. package/docs/pages/javascript/sortable.html +148 -0
  29. package/docs/pages/javascript/toggle.html +191 -0
  30. package/docs/pages/javascript/tree.html +221 -0
  31. package/docs/pages/layout/grid.html +201 -0
  32. package/docs/pages/layout/reset.html +53 -0
  33. package/docs/pages/layout/typography.html +324 -0
  34. package/docs/pages/quick-start/conventions.html +112 -0
  35. package/docs/pages/quick-start/customization.html +187 -0
  36. package/docs/pages/quick-start/installation.html +95 -0
  37. package/docs/pages/quick-start/mixins.html +228 -0
  38. package/docs/pages/test.html +15 -0
  39. package/docs/src/js/demo.js +98 -0
  40. package/docs/src/js/doc-code.js +102 -0
  41. package/docs/src/js/doc-demo.js +14 -0
  42. package/docs/src/js/doc-layout.js +108 -0
  43. package/docs/src/scss/demo.scss +77 -0
  44. package/docs/src/scss/layout.scss +160 -0
  45. package/docs/src/scss/style.scss +278 -0
  46. package/docs/vite.config.mjs +23 -0
  47. package/esbuild.mjs +25 -0
  48. package/js/_autofill.js +131 -0
  49. package/js/_check-all.js +77 -0
  50. package/js/_comfort.js +174 -0
  51. package/js/_consent.js +84 -0
  52. package/js/_dialog.js +164 -0
  53. package/js/_dropdown.js +101 -0
  54. package/js/_scroll.js +184 -0
  55. package/js/_sidebar.js +97 -0
  56. package/js/_slider.js +249 -0
  57. package/js/_sortable.js +143 -0
  58. package/js/_tabpanel.js +88 -0
  59. package/js/_toggle.js +123 -0
  60. package/js/_tree.js +85 -0
  61. package/js/tests/autofill.test.js +157 -0
  62. package/js/tests/base-component.test.js +108 -0
  63. package/js/tests/check-all.test.js +88 -0
  64. package/js/tests/comfort.test.js +219 -0
  65. package/js/tests/consent.test.js +84 -0
  66. package/js/tests/cookie.test.js +102 -0
  67. package/js/tests/dialog.test.js +189 -0
  68. package/js/tests/dropdown.test.js +115 -0
  69. package/js/tests/form-helper.test.js +155 -0
  70. package/js/tests/scroll.test.js +203 -0
  71. package/js/tests/sidebar.test.js +99 -0
  72. package/js/tests/slider.test.js +307 -0
  73. package/js/tests/sortable.test.js +124 -0
  74. package/js/tests/tabpanel.test.js +114 -0
  75. package/js/tests/toggle.test.js +190 -0
  76. package/js/tests/tree.test.js +165 -0
  77. package/js/utilities/_base-component.js +101 -0
  78. package/js/utilities/_cookie.js +98 -0
  79. package/js/utilities/_error.js +80 -0
  80. package/js/utilities/_form-helper.js +101 -0
  81. package/package.json +42 -0
  82. package/scss/_badge.scss +37 -0
  83. package/scss/_button.scss +34 -0
  84. package/scss/_card.scss +122 -0
  85. package/scss/_dialog.scss +116 -0
  86. package/scss/_disclosure.scss +101 -0
  87. package/scss/_dropdown.scss +68 -0
  88. package/scss/_form.scss +197 -0
  89. package/scss/_grid.scss +40 -0
  90. package/scss/_group.scss +57 -0
  91. package/scss/_list.scss +18 -0
  92. package/scss/_loading.scss +49 -0
  93. package/scss/_media.scss +37 -0
  94. package/scss/_nav.scss +72 -0
  95. package/scss/_progress.scss +40 -0
  96. package/scss/_slider.scss +35 -0
  97. package/scss/_table.scss +36 -0
  98. package/scss/utilities/_mixin.scss +322 -0
  99. package/scss/utilities/_reset.scss +145 -0
  100. package/scss/utilities/_typography.scss +107 -0
  101. package/scss/vanilla-frontend.scss +23 -0
  102. package/scss/variables/_root.scss +70 -0
  103. package/scss/variables/_setting.scss +63 -0
  104. package/vitest.config.js +7 -0
@@ -0,0 +1,143 @@
1
+ /**
2
+ * ------------------------------------------------------------------
3
+ * Sortable
4
+ * ------------------------------------------------------------------
5
+ * This class enable the functionality to sort a list or a table
6
+ *
7
+ * @author Natacha Herth
8
+ * @version 0.0.1
9
+ * @copyright Natacha Herth, design & web development
10
+ */
11
+
12
+ import BaseComponent from './utilities/_base-component'
13
+ import ErrorMessage from './utilities/_error'
14
+
15
+ export default class Sortable extends BaseComponent {
16
+
17
+ /**
18
+ * Creates an instance
19
+ *
20
+ * @param {HTMLElement} el - The HTML element
21
+ * @param {object} options - The custom options
22
+ * @constructor
23
+ */
24
+ constructor(el, options = {}) {
25
+
26
+ // Run the SUPER constructor from BaseComponent
27
+ super(el, options)
28
+
29
+ // Define the properties
30
+ this._withHandle = this._element.querySelector('[data-handle]') ? true : false
31
+ this._current = null
32
+
33
+ // Init the event listener
34
+ this.#init()
35
+
36
+ }
37
+
38
+ /**
39
+ * Init the event listener
40
+ *
41
+ * @private
42
+ */
43
+ #init() {
44
+
45
+ // Prevent default animation at the drop
46
+ this._element.addEventListener('dragover', (e) => e.preventDefault())
47
+
48
+ // Events directly on the items
49
+ this.items.forEach((item) => {
50
+
51
+ // Toggle the [dragable] attribute
52
+ item.addEventListener('mousedown', (e) => { if (!this._withHandle || e.target.hasAttribute('data-handle')) item.draggable = true })
53
+ item.addEventListener('mouseup', () => item.draggable = false)
54
+
55
+ // Drag and drop events
56
+ item.addEventListener('dragstart', () => this.#drag(item))
57
+ item.addEventListener('dragenter', () => this.#move(item))
58
+ item.addEventListener('dragend', () => this.#drop(item))
59
+
60
+ })
61
+
62
+ }
63
+
64
+ /**
65
+ * Get the list of the items
66
+ *
67
+ * @return {object}
68
+ */
69
+ get items() {
70
+ return this._element.querySelectorAll('[draggable]')
71
+ }
72
+
73
+ /**
74
+ * Drag an item
75
+ *
76
+ * @param {HTMLElement} item - The current item
77
+ * @private
78
+ */
79
+ #drag(item) {
80
+
81
+ // Check for errors
82
+ if (!(item instanceof HTMLElement)) throw new Error(ErrorMessage.instanceOf('item', 'HTMLElement'))
83
+
84
+ // Prevent drag on text selection
85
+ if (!item.draggable) return
86
+
87
+ // Set the current property
88
+ this._current = item
89
+
90
+ // Add the attribute on the current
91
+ item.setAttribute('aria-grabbed', true)
92
+
93
+ // Run custom event
94
+ this.emmitEvent('drag', { items: this.items, current: item })
95
+
96
+ }
97
+
98
+ /**
99
+ * When dragging an item, move it before or after an element
100
+ *
101
+ * @param {HTMLElement} item - The current item
102
+ * @private
103
+ */
104
+ #move(item) {
105
+
106
+ // Check for errors
107
+ if (!(item instanceof HTMLElement)) throw new Error(ErrorMessage.instanceOf('item', 'HTMLElement'))
108
+
109
+ // Do nothing if there is NO current
110
+ if (!this._current) return
111
+
112
+ // Move the item
113
+ const position = item === this._element.firstElementChild ? 'beforebegin' : 'afterend'
114
+ item.insertAdjacentElement(position, this._current)
115
+
116
+ }
117
+
118
+ /**
119
+ * Drop an item
120
+ *
121
+ * @param {HTMLElement} item - The current item
122
+ * @private
123
+ */
124
+ #drop(item) {
125
+
126
+ // Check for errors
127
+ if (!(item instanceof HTMLElement)) throw new Error(ErrorMessage.instanceOf('item', 'HTMLElement'))
128
+
129
+ // Reset the current property
130
+ this._current = null
131
+
132
+ // Remove the attribute on the current
133
+ item.removeAttribute('aria-grabbed', true)
134
+
135
+ // Reset draggable attribute
136
+ item.draggable = false
137
+
138
+ // Run custom event
139
+ this.emmitEvent('drop', { items: this.items, current: item })
140
+
141
+ }
142
+
143
+ }
@@ -0,0 +1,88 @@
1
+ /**
2
+ * ------------------------------------------------------------------
3
+ * Tabpanel
4
+ * ------------------------------------------------------------------
5
+ * This class enable the functionality to toggles multiple tabpanel
6
+ *
7
+ * @author Natacha Herth
8
+ * @version 0.0.1
9
+ * @copyright Natacha Herth, design & web development
10
+ *
11
+ */
12
+
13
+ import BaseComponent from './utilities/_base-component'
14
+ import ErrorMessage from "./utilities/_error"
15
+
16
+ export default class Tabpanel extends BaseComponent {
17
+
18
+ /**
19
+ * Creates an instance
20
+ *
21
+ * @param {HTMLElement} el - The HTML element
22
+ * @param {object} options - The custom options
23
+ * @constructor
24
+ */
25
+ constructor(el, options = {}) {
26
+
27
+ // Run the SUPER constructor from BaseComponent
28
+ super(el, options)
29
+
30
+ // Check for errors
31
+ if (!el.querySelector('[role="tab"]')) throw new Error(ErrorMessage.exist('button [role="tab"]'))
32
+ if (!el.querySelector('[role="tabpanel"]')) throw new Error(ErrorMessage.exist('div [role="tabpanel"]'))
33
+
34
+ // Define the properties
35
+ this._tabs = this._element.querySelectorAll('[role="tab"]')
36
+ this._panels = this._element.querySelectorAll('[role="tabpanel"]')
37
+ this._current = null
38
+
39
+ // Init the event listener
40
+ this.#init()
41
+
42
+ }
43
+
44
+ /**
45
+ * Init the event listener
46
+ *
47
+ * @private
48
+ */
49
+ #init() {
50
+
51
+ // Init first
52
+ if (!this._current) this.#change(this._element.querySelector('[role="tab"][aria-selected="true"]') ?? this._tabs[0])
53
+
54
+ // CLICK tabs
55
+ this._tabs.forEach(tab => tab.addEventListener('click', () => this.#change(tab)))
56
+
57
+ }
58
+
59
+ /**
60
+ * Change the tabpanel
61
+ * @param {HTMLElement} button - A <button> element
62
+ *
63
+ * @private
64
+ */
65
+ #change(button) {
66
+
67
+ // Stop here if the tab is already the current one
68
+ if (button === this._current) return
69
+
70
+ // Get the [aria-controls] atribute
71
+ const arialist = button.hasAttribute('aria-controls') ? button.getAttribute('aria-controls') : null
72
+ if (!arialist) return
73
+
74
+ // Change the current current
75
+ this._current = button
76
+
77
+ // Change the [aria-selected] attribute on tabs
78
+ this._tabs.forEach((tab) => tab.setAttribute('aria-selected', tab === this._current))
79
+
80
+ // Change the [hidden] attribute on tabpanels
81
+ this._panels.forEach((panel) => panel.hidden = panel.id !== arialist)
82
+
83
+ // Run event after changed
84
+ this.emmitEvent('changed', { current: this._current })
85
+
86
+ }
87
+
88
+ }
package/js/_toggle.js ADDED
@@ -0,0 +1,123 @@
1
+ /**
2
+ * ------------------------------------------------------------------
3
+ * Toggle
4
+ * ------------------------------------------------------------------
5
+ * This class enable the functionality to un/collapse some element by another
6
+ *
7
+ * @author Natacha Herth
8
+ * @version 0.0.1
9
+ * @copyright Natacha Herth, design & web development
10
+ *
11
+ * * NOTE: Check availability of the ariaControlsElements to select the #ids
12
+ */
13
+
14
+ import BaseComponent from './utilities/_base-component'
15
+
16
+ export default class Toggle extends BaseComponent {
17
+
18
+ /**
19
+ * Creates an instance
20
+ *
21
+ * @param {HTMLElement} el - The HTML element
22
+ * @param {object} options - The custom options
23
+ * @constructor
24
+ */
25
+ constructor(el, options = {}) {
26
+
27
+ // Run the SUPER constructor from BaseComponent
28
+ super(el, options)
29
+
30
+ // Define the properties
31
+ this._type = this._element.tagName == 'SELECT' ? 'select' : this._element.getAttribute('type') ?? 'button'
32
+
33
+ const arialist = this._element.hasAttribute('aria-controls') ? this._element.getAttribute('aria-controls').split(' ').filter(id => document.getElementById(id)) : []
34
+ this._toggables = arialist.map(id => document.getElementById(id))
35
+
36
+ // Init the event listener
37
+ this.#init()
38
+
39
+ }
40
+
41
+ /**
42
+ * Init the event listener
43
+ *
44
+ * @private
45
+ */
46
+ #init() {
47
+
48
+ // On first load run method #toggle()
49
+ this.#toggle()
50
+
51
+ if (this._type === 'button') {
52
+
53
+ // CLICK for <button> and change the [aria-pressed] attribute
54
+ this._element.addEventListener('click', () => {
55
+ this._element.setAttribute('aria-pressed', this.value === 'false')
56
+ this.#toggle()
57
+ })
58
+
59
+ } else {
60
+
61
+ // CHANGE for <checkbox> <radio> <select>
62
+ this._element.addEventListener('change', () => this.#toggle())
63
+
64
+ }
65
+
66
+ }
67
+
68
+ /**
69
+ * Define the value: <checkbox> and <radio> = :checked, <button> = [aria-pressed], <else> = value
70
+ *
71
+ * @return {string}
72
+ * @private
73
+ */
74
+ get value() {
75
+
76
+ switch (this._type) {
77
+ case 'button':
78
+ return (this._element.getAttribute('aria-pressed') === 'true').toString()
79
+
80
+ case 'checkbox':
81
+ case 'radio':
82
+ return this._element.checked.toString()
83
+
84
+ default:
85
+ return this._element.value
86
+ }
87
+
88
+ }
89
+
90
+ /**
91
+ * Toggle the [hidden] and [aria-expanded] attributes
92
+ *
93
+ * @private
94
+ */
95
+ #toggle() {
96
+
97
+ // Define the group value for <select>
98
+ const groupValue = this._type === 'select' && this._element.querySelector('option:checked') ? this._element.querySelector('option:checked').parentElement.label ?? null : null
99
+
100
+ // Check for each toggables elements
101
+ this._toggables.forEach(toggable => {
102
+
103
+ // Define if there is a [data-toggle-when] attribute, otherwise check on the true value
104
+ const toggleValue = toggable.getAttribute('data-toggle-when') ?? 'true'
105
+
106
+ // Toggle the [hidden] attribute
107
+ toggable.hidden = this.value !== toggleValue && groupValue !== toggleValue
108
+
109
+ })
110
+
111
+ // Update the [aria-expanded] attribute if there is any toggables visible
112
+ const areAllHidden = this._toggables.every(el => el.hidden)
113
+ this._element.setAttribute('aria-expanded', !areAllHidden)
114
+
115
+ // If the _element is <radio>, emmit event 'change' on <radio> with same [name]
116
+ if (this._type === 'radio' && this._element.checked) document.querySelectorAll(`input[name="${this._element.name}"]:not(:checked)`).forEach(radio => radio.dispatchEvent(new Event('change')))
117
+
118
+ // Emmit event
119
+ this.emmitEvent('changed')
120
+
121
+ }
122
+
123
+ }
package/js/_tree.js ADDED
@@ -0,0 +1,85 @@
1
+ /**
2
+ * ------------------------------------------------------------------
3
+ * Tree
4
+ * ------------------------------------------------------------------
5
+ * This class enable the functionality to expand/contract element as a tree
6
+ *
7
+ * @author Natacha Herth
8
+ * @version 0.0.1
9
+ * @copyright Natacha Herth, design & web development
10
+ */
11
+
12
+ import BaseComponent from './utilities/_base-component'
13
+
14
+ export default class Tree extends BaseComponent {
15
+
16
+ /**
17
+ * Creates an instance
18
+ *
19
+ * @param {HTMLElement} el - The HTML element
20
+ * @param {object} options - The custom options
21
+ * @constructor
22
+ */
23
+ constructor(el, options = {}) {
24
+
25
+ // Run the SUPER constructor from BaseComponent
26
+ super(el, options)
27
+
28
+ // Define the properties
29
+ this._type = this._element.role == 'tree' ? 'list' : 'grid'
30
+
31
+ this._withHandle = this._element.querySelector('[data-handle]') ? true : false
32
+
33
+ this._items = this._element.querySelectorAll('[aria-expanded]')
34
+
35
+ // Init the event listener
36
+ this.#init()
37
+
38
+ }
39
+
40
+ /**
41
+ * Init the event listener
42
+ *
43
+ * @private
44
+ */
45
+ #init() {
46
+
47
+ this._items.forEach(item => item.addEventListener('click', (e) => {
48
+ if (!this._withHandle || e.target.hasAttribute('data-handle')) {
49
+ e.stopPropagation()
50
+ this.#toggle(item)
51
+ }
52
+ }))
53
+
54
+ }
55
+
56
+ /**
57
+ * Toggle the [hidden] and [aria-expanded] attributes
58
+ *
59
+ * @param {HTMLElement} item - The current item
60
+ * @private
61
+ */
62
+ #toggle(item) {
63
+
64
+ // Check for errors
65
+ if (!(item instanceof HTMLElement)) throw new Error(ErrorMessage.instanceOf('item', 'HTMLElement'))
66
+
67
+ // Update the [aria-expanded]
68
+ const isExpanded = item.getAttribute('aria-expanded') === 'true'
69
+ item.setAttribute('aria-expanded', !isExpanded)
70
+
71
+ // Get children to toggle
72
+ const children = item.hasAttribute('aria-owns') ? item.getAttribute('aria-owns').split(' ').filter(id => document.getElementById(id)).map(id => document.getElementById(id)) : []
73
+
74
+ // Toggle the [hidden] attribute on the children
75
+ children.forEach(child => child.hidden = isExpanded)
76
+
77
+ // If type grid, collapse the subchildren
78
+ if (this._type === 'grid' && isExpanded) children.filter(child => child.hasAttribute('aria-expanded') && child.getAttribute('aria-expanded') === 'true').forEach(child => this.#toggle(child))
79
+
80
+ // Emmit event
81
+ this.emmitEvent('changed', { isOpen: !isExpanded })
82
+
83
+ }
84
+
85
+ }
@@ -0,0 +1,157 @@
1
+ /**
2
+ * ------------------------------------------------------------------
3
+ * TEST for the _autofill.js
4
+ * ------------------------------------------------------------------
5
+ * The test will take care of:
6
+ * - Constructor: Passing the correct parameters
7
+ * - Constructor: Return the correct properties
8
+ * - #Init(): Change <select> will set a value in another input
9
+ * - #Init(): Change <input> will set a value in another input
10
+ * - #Init(): Change <input type="file"> will set a value in another input
11
+ * - #ByOption(): Emmit the autofill:changed event
12
+ * - #byFile(): Emmit the autofill:changed event
13
+ */
14
+
15
+ import { describe, test, expect, beforeAll, vi } from "vitest"
16
+ import { fireEvent } from "@testing-library/dom"
17
+ import Autofill from "../_autofill"
18
+ import ErrorMessage from "../utilities/_error"
19
+
20
+ let fakeSelect, fakeList, fakeFile, fakeAutofillSelect, fakeAutofillList, fakeAutofillFile
21
+ /**
22
+ * Before all tests
23
+ *
24
+ */
25
+
26
+ beforeAll(() => {
27
+
28
+ document.body.innerHTML =
29
+ '<select id="fakeSelect" aria-controls="fakeSelectInput">' +
30
+ '<option value="null">--</option>' +
31
+ '<option value="cat" data-id="1">Cat</option>' +
32
+ '</select>' +
33
+ '<input id="fakeSelectInput" type="text" data-autofill="id">' +
34
+
35
+ '<input id="fakeList" list="fakeDataList" aria-controls="fakeListInput">' +
36
+ '<datalist id="fakeDataList">' +
37
+ '<option data-id="1" value="cat">' +
38
+ '<option data-id="2" value="dog">' +
39
+ '</datalist>' +
40
+ '<input id="fakeListInput" type="text" data-autofill="id">' +
41
+
42
+ '<input id="fakeFile" type="file" aria-controls="fakeFileInput fakeFileName fakeFileExt">' +
43
+ '<input id="fakeFileInput" type="text" data-autofill="name" >' +
44
+ '<input id="fakeFileName" type="text" data-autofill="filename">' +
45
+ '<input id="fakeFileExt" type="text" data-autofill="extension">'
46
+
47
+ fakeSelect = document.getElementById('fakeSelect')
48
+ fakeList = document.getElementById('fakeList')
49
+ fakeFile = document.getElementById('fakeFile')
50
+
51
+ fakeAutofillSelect = new Autofill(fakeSelect)
52
+ fakeAutofillList = new Autofill(fakeList)
53
+ fakeAutofillFile = new Autofill(fakeFile)
54
+
55
+ })
56
+
57
+ describe('Structure of the class', () => {
58
+
59
+ test('Constructor: Passing the correct parameters', () => {
60
+ expect(() => new Autofill('make-error')).toThrowError(ErrorMessage.instanceOf('el', 'HTMLElement'))
61
+ expect(() => new Autofill(document.createElement('button'))).toThrowError(ErrorMessage.typeOf('el', 'input|select'))
62
+ expect(() => new Autofill(document.createElement('select'))).toThrowError(ErrorMessage.withAttribute('el', 'aria-controls'))
63
+ const fakeWrongInput = document.createElement('input')
64
+ fakeWrongInput.setAttribute('aria-controls', 'something')
65
+ fakeWrongInput.type = 'checkbox'
66
+ expect(() => new Autofill(fakeWrongInput)).toThrowError(ErrorMessage.typeOf('type', 'text|file'))
67
+ fakeWrongInput.type = 'text'
68
+ expect(() => new Autofill(fakeWrongInput)).toThrowError(ErrorMessage.withAttribute('input', 'list'))
69
+ })
70
+
71
+ test('Constructor: Return the correct properties', () => {
72
+ expect(fakeAutofillSelect).toHaveProperty('_fields')
73
+ expect(fakeAutofillSelect).toHaveProperty('_type')
74
+ expect(fakeAutofillSelect._fields).toBeTypeOf('object')
75
+ expect(fakeAutofillSelect._fields).toStrictEqual([...document.querySelectorAll('#fakeSelectInput')])
76
+ expect(fakeAutofillSelect._type).toBe('select')
77
+ expect(fakeAutofillList._fields).toBeTypeOf('object')
78
+ expect(fakeAutofillList._fields).toStrictEqual([...document.querySelectorAll('#fakeListInput')])
79
+ expect(fakeAutofillList._type).toBe('datalist')
80
+ expect(fakeAutofillFile._fields).toBeTypeOf('object')
81
+ expect(fakeAutofillFile._fields).toStrictEqual([...document.querySelectorAll('#fakeFileInput,#fakeFileName,#fakeFileExt')])
82
+ expect(fakeAutofillFile._type).toBe('file')
83
+ })
84
+
85
+ })
86
+
87
+ describe('#Init()', () => {
88
+
89
+ test('Change <select> will set a value in another input', () => {
90
+ const fakeInput = document.getElementById('fakeSelectInput')
91
+ expect(fakeSelect.value).toBe('null')
92
+ expect(fakeInput.value).toBe('')
93
+ fireEvent.change(fakeSelect, { target: { value: 'cat' } })
94
+ expect(fakeSelect.value).toBe('cat')
95
+ expect(fakeInput.value).toBe('1')
96
+ fireEvent.change(fakeSelect, { target: { value: 'null' } })
97
+ expect(fakeSelect.value).toBe('null')
98
+ expect(fakeInput.value).toBe('')
99
+ })
100
+
101
+ test('Change <input> will set a value in another input', () => {
102
+ const fakeInput = document.getElementById('fakeListInput')
103
+ expect(fakeList.value).toBe('')
104
+ expect(fakeInput.value).toBe('')
105
+ fireEvent.change(fakeList, { target: { value: 'dog' } })
106
+ expect(fakeList.value).toBe('dog')
107
+ expect(fakeInput.value).toBe('2')
108
+ fireEvent.change(fakeList, { target: { value: 'cat' } })
109
+ expect(fakeList.value).toBe('cat')
110
+ expect(fakeInput.value).toBe('1')
111
+ fireEvent.change(fakeList, { target: { value: '' } })
112
+ expect(fakeList.value).toBe('')
113
+ expect(fakeInput.value).toBe('')
114
+ })
115
+
116
+ test('Change <input type="file"> will set a value in another input', () => {
117
+ const fakeFileInput = document.getElementById('fakeFileInput')
118
+ const fakeFileName = document.getElementById('fakeFileName')
119
+ const fakeFileExt = document.getElementById('fakeFileExt')
120
+ const fakeImage = new File(["my testing file"], "my-file.jpg", {
121
+ type: "image/jpeg",
122
+ })
123
+ expect(fakeFileInput.value).toBe('')
124
+ expect(fakeFileName.value).toBe('')
125
+ expect(fakeFileExt.value).toBe('')
126
+ fireEvent.change(fakeFile, { target: { files: [fakeImage] } })
127
+ expect(fakeFileInput.value).toBe('my-file.jpg')
128
+ expect(fakeFileName.value).toBe('my-file')
129
+ expect(fakeFileExt.value).toBe('jpg')
130
+ })
131
+
132
+ })
133
+
134
+ describe('#ByOption()', () => {
135
+
136
+ test('Emmit the autofill:changed event', () => {
137
+ const eventSpy = vi.spyOn(fakeAutofillSelect, 'emmitEvent')
138
+ expect(eventSpy).not.toHaveBeenCalled()
139
+ fireEvent.change(fakeSelect, { target: { value: 'cat' } })
140
+ expect(eventSpy).toHaveBeenCalledWith('changed', { current: document.querySelector('option[value="cat"]') })
141
+ })
142
+
143
+ })
144
+
145
+ describe('#ByFile()', () => {
146
+
147
+ test('Emmit the autofill:changed event', () => {
148
+ const fakeImage = new File(["my testing file"], "my-file.jpg", {
149
+ type: "image/jpeg",
150
+ })
151
+ const eventSpy = vi.spyOn(fakeAutofillFile, 'emmitEvent')
152
+ expect(eventSpy).not.toHaveBeenCalled()
153
+ fireEvent.change(fakeFile, { target: { files: [fakeImage] } })
154
+ expect(eventSpy).toHaveBeenCalledWith('changed', { current: fakeImage })
155
+ })
156
+
157
+ })