@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,190 @@
1
+ /**
2
+ * ------------------------------------------------------------------
3
+ * TEST for the _toggle.js
4
+ * ------------------------------------------------------------------
5
+ * The test will take care of:
6
+ * ! herit from BaseComponent - Constructor: Passing the correct parameters
7
+ * - Constructor: Return the correct properties
8
+ * - #Toggle(): Button : Toggle the [aria-pressed] and [aria-expanded] attribute on the <button>
9
+ * - #Toggle(): Button : Toggle the [hidden] attribute on the <div>
10
+ * - #Toggle(): Checkbox : Toggle the [aria-expanded] attribute on the <checkbox>
11
+ * - #Toggle(): Checkbox : Toggle the [hidden] attribute on the <div>
12
+ * - #Toggle(): Radio : Toggle the [aria-expanded] attribute on the <radio>
13
+ * - #Toggle(): Radio : Toggle the [hidden] attribute on the <div>
14
+ * - #Toggle(): Select : Toggle the [aria-expanded] attribute on the <select>
15
+ * - #Toggle(): Select : Toggle the [hidden] attribute on the <div>
16
+ * - #Toggle(): Emmit the toggle:changed event
17
+ */
18
+
19
+ import { describe, test, expect, beforeAll, vi } from "vitest"
20
+ import { fireEvent } from "@testing-library/dom"
21
+ import Toggle from "../_toggle"
22
+
23
+ let fakeToggleButton, fakeToggleCheckbox, fakeToggleRadioA, fakeToggleRadioB, fakeToggleSelect
24
+
25
+ /**
26
+ * Before all tests
27
+ *
28
+ */
29
+
30
+ beforeAll(() => {
31
+
32
+ document.body.innerHTML =
33
+ '<button id="fakeButton" aria-controls="fakeCollapse" aria-expanded="false" aria-pressed="false"></button>' +
34
+ '<div id="fakeCollapse" hidden></div>' +
35
+ '<input id="fakeCheckbox" type="checkbox" aria-controls="fakeCollapseCheckbox" aria-expanded="false">' +
36
+ '<div id="fakeCollapseCheckbox" hidden></div>' +
37
+ '<input id="fakeRadioA" type="radio" name="fake-radio" aria-controls="fakeCollapseRadioA" aria-expanded="false">' +
38
+ '<input id="fakeRadioB" type="radio" name="fake-radio" aria-controls="fakeCollapseRadioB" aria-expanded="false">' +
39
+ '<div id="fakeCollapseRadioA" hidden></div>' +
40
+ '<div id="fakeCollapseRadioB" hidden></div>' +
41
+ '<select id="fakeSelect" aria-controls="fakeCollapseSelectA fakeCollapseSelectB fakeCollapseSelectC" aria-expanded="false">' +
42
+ '<option value="null"></option>' +
43
+ '<option value="A"></option>' +
44
+ '<optgroup label="G">' +
45
+ '<option value="B"></option>' +
46
+ '</optgroup>' +
47
+ '</select>' +
48
+ '<div id="fakeCollapseSelectA" data-toggle-when="A" hidden></div>' +
49
+ '<div id="fakeCollapseSelectB" data-toggle-when="B" hidden></div>' +
50
+ '<div id="fakeCollapseSelectG" data-toggle-when="G" hidden></div>'
51
+
52
+ fakeToggleButton = new Toggle(document.getElementById('fakeButton'))
53
+ fakeToggleCheckbox = new Toggle(document.getElementById('fakeCheckbox'))
54
+ fakeToggleRadioA = new Toggle(document.getElementById('fakeRadioA'))
55
+ fakeToggleRadioB = new Toggle(document.getElementById('fakeRadioB'))
56
+ fakeToggleSelect = new Toggle(document.getElementById('fakeSelect'))
57
+
58
+ })
59
+
60
+ describe('Structure of the class', () => {
61
+
62
+ test('Constructor: Return the correct properties', () => {
63
+ expect(fakeToggleButton).toHaveProperty('_type')
64
+ expect(fakeToggleButton).toHaveProperty('_toggables')
65
+ expect(fakeToggleButton._type).toBe('button')
66
+ expect(fakeToggleCheckbox._type).toBe('checkbox')
67
+ expect(fakeToggleRadioA._type).toBe('radio')
68
+ expect(fakeToggleSelect._type).toBe('select')
69
+ expect(fakeToggleButton._toggables).toStrictEqual([...document.querySelectorAll('#fakeCollapse')])
70
+ expect(fakeToggleSelect._toggables).toStrictEqual([...document.querySelectorAll('#fakeCollapseSelectA, #fakeCollapseSelectB, #fakeCollapseSelectC')])
71
+ })
72
+
73
+ })
74
+
75
+ describe('#Toggle()', () => {
76
+
77
+ describe('Button', () => {
78
+
79
+ test('Toggle the [aria-pressed] and [aria-expanded] attribute on the <button>', () => {
80
+ expect(fakeToggleButton._element.getAttribute('aria-pressed')).toBe('false')
81
+ expect(fakeToggleButton._element.getAttribute('aria-expanded')).toBe('false')
82
+ fireEvent(fakeToggleButton._element, new MouseEvent('click'))
83
+ expect(fakeToggleButton._element.getAttribute('aria-pressed')).toBe('true')
84
+ expect(fakeToggleButton._element.getAttribute('aria-expanded')).toBe('true')
85
+ fireEvent(fakeToggleButton._element, new MouseEvent('click'))
86
+ expect(fakeToggleButton._element.getAttribute('aria-pressed')).toBe('false')
87
+ expect(fakeToggleButton._element.getAttribute('aria-expanded')).toBe('false')
88
+ })
89
+
90
+ test('Toggle the [hidden] attribute on the <div>', () => {
91
+ const div = document.getElementById('fakeCollapse')
92
+ expect(div.hidden).toBeTruthy()
93
+ fireEvent(fakeToggleButton._element, new MouseEvent('click'))
94
+ expect(div.hidden).toBeFalsy()
95
+ fireEvent(fakeToggleButton._element, new MouseEvent('click'))
96
+ expect(div.hidden).toBeTruthy()
97
+ })
98
+
99
+ })
100
+
101
+ describe('Checkbox', () => {
102
+
103
+ test('Toggle the [aria-expanded] attribute on the <checkbox>', () => {
104
+ expect(fakeToggleCheckbox._element.getAttribute('aria-expanded')).toBe('false')
105
+ fireEvent.change(fakeToggleCheckbox._element, { target: { checked: true } })
106
+ expect(fakeToggleCheckbox._element.getAttribute('aria-expanded')).toBe('true')
107
+ fireEvent.change(fakeToggleCheckbox._element, { target: { checked: false } })
108
+ expect(fakeToggleCheckbox._element.getAttribute('aria-expanded')).toBe('false')
109
+ })
110
+
111
+ test('Toggle the [hidden] attribute on the <div>', () => {
112
+ const div = document.getElementById('fakeCollapseCheckbox')
113
+ expect(div.hidden).toBeTruthy()
114
+ fireEvent.change(fakeToggleCheckbox._element, { target: { checked: true } })
115
+ expect(div.hidden).toBeFalsy()
116
+ fireEvent.change(fakeToggleCheckbox._element, { target: { checked: false } })
117
+ expect(div.hidden).toBeTruthy()
118
+ })
119
+
120
+ })
121
+
122
+ describe('Radio', () => {
123
+
124
+ test('Toggle the [aria-expanded] attribute on the <radio>', () => {
125
+ expect(fakeToggleRadioA._element.getAttribute('aria-expanded')).toBe('false')
126
+ expect(fakeToggleRadioB._element.getAttribute('aria-expanded')).toBe('false')
127
+ fireEvent.change(fakeToggleRadioA._element, { target: { checked: true } })
128
+ expect(fakeToggleRadioA._element.getAttribute('aria-expanded')).toBe('true')
129
+ expect(fakeToggleRadioB._element.getAttribute('aria-expanded')).toBe('false')
130
+ fireEvent.change(fakeToggleRadioB._element, { target: { checked: true } })
131
+ expect(fakeToggleRadioA._element.getAttribute('aria-expanded')).toBe('false')
132
+ expect(fakeToggleRadioB._element.getAttribute('aria-expanded')).toBe('true')
133
+ })
134
+
135
+ test('Toggle the [hidden] attribute on the <div>', () => {
136
+ const divA = document.getElementById('fakeCollapseRadioA')
137
+ const divB = document.getElementById('fakeCollapseRadioB')
138
+ expect(divA.hidden).toBeTruthy()
139
+ expect(divB.hidden).toBeFalsy()
140
+ fireEvent.change(fakeToggleRadioA._element, { target: { checked: true } })
141
+ expect(divA.hidden).toBeFalsy()
142
+ expect(divB.hidden).toBeTruthy()
143
+ fireEvent.change(fakeToggleRadioB._element, { target: { checked: true } })
144
+ expect(divA.hidden).toBeTruthy()
145
+ expect(divB.hidden).toBeFalsy()
146
+ })
147
+
148
+ })
149
+
150
+ describe('Select', () => {
151
+
152
+ test('Toggle the [aria-expanded] attribute on the <select>', () => {
153
+ expect(fakeToggleSelect._element.getAttribute('aria-expanded')).toBe('false')
154
+ fireEvent.change(fakeToggleSelect._element, { target: { value: 'A' } })
155
+ expect(fakeToggleSelect._element.getAttribute('aria-expanded')).toBe('true')
156
+ fireEvent.change(fakeToggleSelect._element, { target: { value: 'null' } })
157
+ expect(fakeToggleSelect._element.getAttribute('aria-expanded')).toBe('false')
158
+ })
159
+
160
+ test('Toggle the [hidden] attribute on the <div>', () => {
161
+ const divA = document.getElementById('fakeCollapseSelectA')
162
+ const divB = document.getElementById('fakeCollapseSelectB')
163
+ const divC = document.getElementById('fakeCollapseSelectB')
164
+ expect(divA.hidden).toBeTruthy()
165
+ expect(divB.hidden).toBeTruthy()
166
+ expect(divC.hidden).toBeTruthy()
167
+ fireEvent.change(fakeToggleSelect._element, { target: { value: 'A' } })
168
+ expect(divA.hidden).toBeFalsy()
169
+ expect(divB.hidden).toBeTruthy()
170
+ expect(divC.hidden).toBeTruthy()
171
+ fireEvent.change(fakeToggleSelect._element, { target: { value: 'B' } })
172
+ expect(divA.hidden).toBeTruthy()
173
+ expect(divB.hidden).toBeFalsy()
174
+ expect(divC.hidden).toBeFalsy()
175
+ fireEvent.change(fakeToggleSelect._element, { target: { value: 'null' } })
176
+ expect(divA.hidden).toBeTruthy()
177
+ expect(divB.hidden).toBeTruthy()
178
+ expect(divC.hidden).toBeTruthy()
179
+ })
180
+
181
+ })
182
+
183
+ test('Emmit the toggle:changed event', () => {
184
+ const eventSpy = vi.spyOn(fakeToggleButton, 'emmitEvent')
185
+ expect(eventSpy).not.toHaveBeenCalled()
186
+ fireEvent(fakeToggleButton._element, new MouseEvent('click'))
187
+ expect(eventSpy).toHaveBeenCalledWith('changed')
188
+ })
189
+
190
+ })
@@ -0,0 +1,165 @@
1
+ /**
2
+ * ------------------------------------------------------------------
3
+ * TEST for the _tree.js
4
+ * ------------------------------------------------------------------
5
+ * The test will take care of:
6
+ * ! herit from BaseComponent - Constructor: Passing the correct parameters
7
+ * - Constructor: Return the correct properties
8
+ * - #Init() : Do nothing if click outside the handle
9
+ * - #Toggle(): Passing the correct parameter
10
+ * - #Toggle(): List: Update the [aria-expanded] attribute
11
+ * - #Toggle(): List: Update the [hidden] attribute on children
12
+ * - #Toggle(): Grid: Update the [aria-expanded] attribute
13
+ * - #Toggle(): Grid: Update the [hidden] attribute on children
14
+ * - #Toggle(): Grid: Collapse the sub-children
15
+ * - #Toggle(): Emmit the tree:changed event
16
+ */
17
+
18
+ import { describe, test, expect, beforeAll, vi } from "vitest"
19
+ import { fireEvent } from "@testing-library/dom"
20
+ import Tree from "../_tree"
21
+
22
+
23
+ let fakeListTree, fakeGridTree, fakeLi, fakeRow, customClick
24
+
25
+ /**
26
+ * Before all tests
27
+ *
28
+ */
29
+
30
+ beforeAll(() => {
31
+
32
+ document.body.innerHTML =
33
+ '<ul id="fakeListTree" role="tree">' +
34
+ '<li role="treeitem"></li>' +
35
+ '<li role="treeitem" aria-expanded="false" aria-owns="child">' +
36
+ '<ul id="child" role="group" hidden>' +
37
+ '<li role="treeitem"></li>' +
38
+ '</ul>' +
39
+ '</li>' +
40
+ '<li role="treeitem"></li>' +
41
+ '</ul>' +
42
+ '<table id="fakeGridTree" role="treegrid">' +
43
+ '<tr aria-level="1"><td></td></tr>' +
44
+ '<tr aria-level="1" aria-expanded="false" aria-owns="lvl2"><td data-handle></td></tr>' +
45
+ '<tr id="lvl2" aria-level="2" aria-expanded="false" aria-owns="lvl3" hidden><td data-handle></td></tr>' +
46
+ '<tr id="lvl3" aria-level="3" hidden><td></td></tr>' +
47
+ '<tr aria-level="1"><td></td></tr>' +
48
+ '</table>'
49
+
50
+ fakeListTree = new Tree(document.getElementById('fakeListTree'))
51
+ fakeGridTree = new Tree(document.getElementById('fakeGridTree'))
52
+ fakeLi = fakeListTree._element.querySelector('li[aria-expanded]')
53
+ fakeRow = fakeGridTree._element.querySelector('tr[aria-level="1"][aria-expanded]')
54
+
55
+ customClick = new MouseEvent('click')
56
+ Object.defineProperty(customClick, 'target', { value: fakeRow.querySelector('[data-handle]') }) // Define the click event with custom target
57
+
58
+ })
59
+
60
+ describe('Structure of the class', () => {
61
+
62
+ test('Constructor: Return the correct properties', () => {
63
+ expect(fakeListTree).toHaveProperty('_type')
64
+ expect(fakeListTree).toHaveProperty('_withHandle')
65
+ expect(fakeListTree).toHaveProperty('_items')
66
+ expect(fakeListTree._type).toBe('list')
67
+ expect(fakeGridTree._type).toBe('grid')
68
+ expect(fakeListTree._withHandle).toBeFalsy()
69
+ expect(fakeGridTree._withHandle).toBeTruthy()
70
+ expect(fakeListTree._items).toBeTypeOf('object')
71
+ expect(fakeListTree._items).toStrictEqual(document.querySelectorAll('#fakeListTree [aria-expanded]'))
72
+ })
73
+
74
+ })
75
+
76
+ describe('#Init()', () => {
77
+
78
+ test('Do nothing if click outside the handle', () => {
79
+ expect(fakeRow.getAttribute('aria-expanded')).toBe('false')
80
+ fireEvent(fakeRow, new MouseEvent('click'))
81
+ expect(fakeRow.getAttribute('aria-expanded')).toBe('false')
82
+ })
83
+
84
+ })
85
+
86
+ describe('#Toggle()', () => {
87
+
88
+ describe('List', () => {
89
+
90
+ test('Update the [aria-expanded] attribute', () => {
91
+ expect(fakeLi.getAttribute('aria-expanded')).toBe('false')
92
+ fireEvent(fakeLi, new MouseEvent('click'))
93
+ expect(fakeLi.getAttribute('aria-expanded')).toBe('true')
94
+ fireEvent(fakeLi, new MouseEvent('click'))
95
+ expect(fakeLi.getAttribute('aria-expanded')).toBe('false')
96
+ })
97
+
98
+ test('Update the [hidden] attribute on children', () => {
99
+ const child = document.getElementById('child')
100
+ expect(child.hidden).toBeTruthy()
101
+ fireEvent(fakeLi, new MouseEvent('click'))
102
+ expect(child.hidden).toBeFalsy()
103
+ fireEvent(fakeLi, new MouseEvent('click'))
104
+ expect(child.hidden).toBeTruthy()
105
+ })
106
+
107
+ })
108
+
109
+ describe('Grid', () => {
110
+
111
+ test('Update the [aria-expanded] attribute', () => {
112
+ expect(fakeRow.getAttribute('aria-expanded')).toBe('false')
113
+ fireEvent(fakeRow, customClick)
114
+ expect(fakeRow.getAttribute('aria-expanded')).toBe('true')
115
+ fireEvent(fakeRow, customClick)
116
+ expect(fakeRow.getAttribute('aria-expanded')).toBe('false')
117
+ })
118
+
119
+ test('Update the [hidden] attribute on children', () => {
120
+ const child = document.getElementById('lvl2')
121
+ expect(child.hidden).toBeTruthy()
122
+ fireEvent(fakeRow, customClick)
123
+ expect(child.hidden).toBeFalsy()
124
+ fireEvent(fakeRow, customClick)
125
+ expect(child.hidden).toBeTruthy()
126
+ })
127
+
128
+ test('Collapse the sub-children', () => {
129
+ const lvl2 = document.getElementById('lvl2')
130
+ const lvl3 = document.getElementById('lvl3')
131
+
132
+ const customClickLvl2 = new MouseEvent('click')
133
+ Object.defineProperty(customClickLvl2, 'target', { value: lvl2.querySelector('[data-handle]') }) // Define the click event with custom target
134
+
135
+ const customClickLvl3 = new MouseEvent('click')
136
+ Object.defineProperty(customClickLvl3, 'target', { value: lvl3.querySelector('[data-handle]') }) // Define the click event with custom target
137
+
138
+ fireEvent(fakeRow, customClick)
139
+ fireEvent(lvl2, customClickLvl2)
140
+ fireEvent(lvl3, customClickLvl3)
141
+
142
+ expect(fakeRow.getAttribute('aria-expanded')).toBe('true')
143
+ expect(lvl2.hidden).toBeFalsy()
144
+ expect(lvl2.getAttribute('aria-expanded')).toBe('true')
145
+ expect(lvl3.hidden).toBeFalsy()
146
+
147
+ fireEvent(fakeRow, customClick)
148
+
149
+ expect(fakeRow.getAttribute('aria-expanded')).toBe('false')
150
+ expect(lvl2.hidden).toBeTruthy()
151
+ expect(lvl2.getAttribute('aria-expanded')).toBe('false')
152
+ expect(lvl3.hidden).toBeTruthy()
153
+
154
+ })
155
+
156
+ })
157
+
158
+ test('Emmit the tree:changed event', () => {
159
+ const eventSpy = vi.spyOn(fakeListTree, 'emmitEvent')
160
+ expect(eventSpy).not.toHaveBeenCalled()
161
+ fireEvent(fakeLi, new MouseEvent('click'))
162
+ expect(eventSpy).toHaveBeenCalledWith('changed', { isOpen: true })
163
+ })
164
+
165
+ })
@@ -0,0 +1,101 @@
1
+ /**
2
+ * ------------------------------------------------------------------
3
+ * Base component
4
+ * ------------------------------------------------------------------
5
+ * This class regroup common functionalities for other classes
6
+ *
7
+ * @author Natacha Herth
8
+ * @version 0.0.1
9
+ * @copyright Natacha Herth, design & web development
10
+ */
11
+
12
+ import ErrorMessage from "./_error"
13
+
14
+ export default class BaseComponent {
15
+
16
+ #NAME
17
+
18
+ /**
19
+ * Creates an instance
20
+ *
21
+ * @param {HTMLElement} el - The element
22
+ * @param {Object} options - The custom options
23
+ * @constructor
24
+ */
25
+ constructor(el, options = {}) {
26
+
27
+ // Check for errors
28
+ if (!(el instanceof HTMLElement)) throw new Error(ErrorMessage.instanceOf('el', 'HTMLElement'))
29
+ if (!(options instanceof Object)) throw new Error(ErrorMessage.instanceOf('options', 'Object'))
30
+
31
+ // Define the #NAME private properties
32
+ this.#NAME = this.constructor.name.toLowerCase() ?? ''
33
+
34
+ // Define the _element property
35
+ this._element = el
36
+
37
+ // Define the _options property by merging the options parameter with the static OPTIONS
38
+ const defaultOptions = this.constructor.OPTIONS ?? {}
39
+ this._options = this.mergeObject(defaultOptions, options)
40
+
41
+ }
42
+
43
+ /**
44
+ * Merge two object to a single one (accept multi-level)
45
+ *
46
+ * @param {Object} one
47
+ * @param {Object} two
48
+ * @returns {Object}
49
+ */
50
+ mergeObject(one, two) {
51
+
52
+ // Check for errors
53
+ if (!(one instanceof Object)) throw new Error(ErrorMessage.instanceOf('one', 'Object'))
54
+ if (!(two instanceof Object)) throw new Error(ErrorMessage.instanceOf('two', 'Object'))
55
+
56
+ // Reduce the objects in a single one
57
+ return Object.keys(one).reduce((obj, key) => {
58
+
59
+ // Define the final option (if key is an object => call the method )
60
+ const option = two.hasOwnProperty(key) ? (one[key] instanceof Object ? this.mergeObject(one[key], two[key]) : two[key]) : one[key]
61
+
62
+ // Merge option
63
+ return { ...obj, [key]: option }
64
+
65
+ }, {})
66
+
67
+ }
68
+
69
+ /**
70
+ * Create a CustomEvent
71
+ *
72
+ * @param {String} name - The name of the event
73
+ * @param {Object} data - The data to pass
74
+ * @param {HTMLElement} selector - The HTML element who will have the event
75
+ * @returns {CustomEvent}
76
+ */
77
+ emmitEvent(name, data = {}, selector = this._element) {
78
+
79
+ // Check for errors
80
+ if (typeof name !== 'string') throw new Error(ErrorMessage.typeOf('name', 'string'))
81
+ if (!(data instanceof Object)) throw new Error(ErrorMessage.instanceOf('data', 'Object'))
82
+ if (!(selector instanceof HTMLElement)) throw new Error(ErrorMessage.instanceOf('selector', 'HTMLElement'))
83
+
84
+ // Define the name of the event as classname:event
85
+ const eventName = `${this.#NAME}:${name}`
86
+
87
+ // Create a new CustomEvent
88
+ const newEvent = new CustomEvent(eventName, {
89
+ cancelable: true,
90
+ detail: data,
91
+ })
92
+
93
+ // Dispatch the event on the HTMLElement
94
+ selector.dispatchEvent(newEvent)
95
+
96
+ // Return the CustomEvent
97
+ return newEvent
98
+
99
+ }
100
+
101
+ }
@@ -0,0 +1,98 @@
1
+ /**
2
+ * ------------------------------------------------------------------
3
+ * Cookie
4
+ * ------------------------------------------------------------------
5
+ * This class create and manage the cookies
6
+ *
7
+ * @author Natacha Herth
8
+ * @version 0.0.1
9
+ * @copyright Natacha Herth, design & web development
10
+ */
11
+
12
+ import ErrorMessage from "./_error"
13
+
14
+ export default class Cookie {
15
+
16
+ #NAME
17
+
18
+ /**
19
+ * Creates an instance
20
+ *
21
+ * @param {string} name - The name of the cookie
22
+ * @constructor
23
+ */
24
+ constructor(name) {
25
+
26
+ // Check for errors
27
+ if (typeof name !== 'string') throw new Error(ErrorMessage.typeOf('name', 'string'))
28
+
29
+ // Define the static private properties
30
+ this.#NAME = name
31
+
32
+ }
33
+
34
+ /**
35
+ * Get the cookie value
36
+ * Code from {@link https://www.w3schools.com/js/js_cookies.asp W3School}.
37
+ *
38
+ * @returns {object}
39
+ */
40
+ get value() {
41
+
42
+ const name = `${this.#NAME}=`
43
+ let decodedCookie = decodeURIComponent(document.cookie)
44
+ let ca = decodedCookie.split(';')
45
+ for (let i = 0; i < ca.length; i++) {
46
+ let c = ca[i]
47
+ while (c.charAt(0) == ' ') {
48
+ c = c.substring(1)
49
+ }
50
+ if (c.indexOf(name) == 0) {
51
+ return JSON.parse(c.substring(name.length, c.length))
52
+ }
53
+ }
54
+ return {}
55
+
56
+ }
57
+
58
+ /**
59
+ * Set the object value as string in the cookie
60
+ *
61
+ * @param {object} value - Value of the cookie
62
+ */
63
+ set(value) {
64
+ if (!(value instanceof Object)) throw new Error(ErrorMessage.instanceOf('value', 'Object'))
65
+ document.cookie = `${this.#NAME}=${JSON.stringify(value)};SameSite=Lax`
66
+ }
67
+
68
+ /**
69
+ * Check if the cookie value has a specific key
70
+ *
71
+ * @param {string} key - The string to search
72
+ * @returns {boolean}
73
+ */
74
+ has(key) {
75
+ if (typeof key !== 'string') throw new Error(ErrorMessage.typeOf('key', 'string'))
76
+ return this.value.hasOwnProperty(key)
77
+ }
78
+
79
+ /**
80
+ * Get a specific cookie value per key
81
+ *
82
+ * @param {string} key - The string to search
83
+ * @returns
84
+ */
85
+ get(key) {
86
+ if (typeof key !== 'string') throw new Error(ErrorMessage.typeOf('key', 'string'))
87
+ return this.has(key) ? this.value[key] : null
88
+ }
89
+
90
+ /**
91
+ * Delete the cookie
92
+ *
93
+ */
94
+ delete() {
95
+ document.cookie = this.#NAME + "=;SameSite=Lax; expires = Thu, 01 Jan 1970 00:00:00 GMT"
96
+ }
97
+
98
+ }
@@ -0,0 +1,80 @@
1
+ /**
2
+ * ------------------------------------------------------------------
3
+ * Error
4
+ * ------------------------------------------------------------------
5
+ * This make global error message
6
+ *
7
+ * @author Natacha Herth
8
+ * @version 0.0.1
9
+ * @copyright Natacha Herth, design & web development
10
+ */
11
+
12
+ export default class ErrorMessage {
13
+
14
+ /**
15
+ * For: !(parameter instanceof type)
16
+ *
17
+ * @param {string} parameter
18
+ * @param {string} type
19
+ * @returns {string}
20
+ */
21
+ static instanceOf(parameter, type) {
22
+ return `Whoops, the "${parameter}" parameter must be an instance of ${type} !`
23
+ }
24
+
25
+ /**
26
+ * For: typeof parameter !=== type
27
+ *
28
+ * @param {string} parameter
29
+ * @param {string} type
30
+ * @returns {string}
31
+ */
32
+ static typeOf(parameter, type) {
33
+ return `Whoops, the "${parameter}" parameter must be a ${type} !`
34
+ }
35
+
36
+ /**
37
+ * For: ![values].includes(parameter)
38
+ *
39
+ * @param {string} parameter
40
+ * @param {string} type
41
+ * @returns {string}
42
+ */
43
+ static enumOf(parameter, values) {
44
+ return `Whoops, the "${parameter}" parameter must be as ${values} !`
45
+ }
46
+
47
+ /**
48
+ * For: !tag.length or document.querySelector(tag)
49
+ *
50
+ * @param {string} tag
51
+ * @returns {string}
52
+ * @returns {string}
53
+ */
54
+ static exist(tag) {
55
+ return `Whoops, there is no <${tag}> !`
56
+ }
57
+
58
+ /**
59
+ * For: !document.getElementById(id)
60
+ *
61
+ * @param {string} tag
62
+ * @param {string} id
63
+ * @returns {string}
64
+ */
65
+ static existById(tag, id) {
66
+ return `Whoops, there is no <${tag}> with the id "#${id}" !`
67
+ }
68
+
69
+ /**
70
+ * For: !tag.hasAttribute(attribute)
71
+ *
72
+ * @param {string} tag
73
+ * @param {string} attribute
74
+ * @returns {string}
75
+ */
76
+ static withAttribute(tag, attribute) {
77
+ return `Whoops, the <${tag}> must have the attribute [${attribute}] !`
78
+ }
79
+
80
+ }