@natachah/vanilla-frontend 0.1.10 → 0.1.12

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.
@@ -65,8 +65,49 @@
65
65
 
66
66
  <h2>Javascript</h2>
67
67
  <p>This component is mostly in javascript, to use it you must import the javascript file and create a new Drawer object.</p>
68
- <p>You can customize the breakpoint when initiate the component.</p>
69
- <p>You can have a <b>Backdrop</b> if you want to make it more like a drawer opening on the front of the content.</p>
68
+ <p>You can have a <b>Backdrop</b> if you want to make it more like a drawer opening on the front of the content, you juste need a <code>#backdrop</code> somewhere on your page.</p>
69
+
70
+ <h3>Options</h3>
71
+
72
+ <table>
73
+ <thead>
74
+ <tr>
75
+ <th>Name</th>
76
+ <th>Description</th>
77
+ <th>Value</th>
78
+ </tr>
79
+ </thead>
80
+ <tbody>
81
+ <tr>
82
+ <td data-label="Name">
83
+ <p>breakpoint</p>
84
+ </td>
85
+ <td data-label="Description">
86
+ <p>The breakpoint to open/close the drawer</p>
87
+ </td>
88
+ <td data-label="Value">
89
+ <p><code>960</code> as an <code>int</code></p>
90
+ </td>
91
+ </tr>
92
+ <tr>
93
+ <td data-label="Name">
94
+ <p>cookie</p>
95
+ </td>
96
+ <td data-label="Description">
97
+ <p>The cookie name to save if you want to keep it open/close on refresh</p>
98
+ </td>
99
+ <td data-label="Value">
100
+ <p><code>false</code> by default, or a <code>string</code></p>
101
+ </td>
102
+ </tr>
103
+ </tbody>
104
+ </table>
105
+
106
+ <doc-code data-type="js">
107
+ import Drawer from '@natachah/vanilla-frontend/js/utilities/_drawer.js'
108
+ const drawer = document.getElementById('drawer')
109
+ if (drawer) new Drawer(drawer, { breakpoint : 960, cookkie: '_drawer-cookie' })
110
+ </doc-code>
70
111
 
71
112
  <blockquote>
72
113
  <p>Main use case are sidebar menu or main navigation menu.</p>
@@ -62,7 +62,8 @@
62
62
  <li><button disabled>List B (button disabled)</button></li>
63
63
  <li>List C</li>
64
64
  <li><a role="button" href="#">List D (link)</a></li>
65
- <li><a role="button">List E (link disabled)</a></li>
65
+ <li><span>List E</span><a role="button" href="#">Not only child (link)</a></li>
66
+ <li><a role="button">List F (link disabled)</a></li>
66
67
  </ul>
67
68
  </doc-demo>
68
69
 
@@ -126,7 +127,7 @@
126
127
  </doc-code>
127
128
  <doc-code id="scss" data-type="scss" role="tabpanel">
128
129
  $outline-variations: (
129
- list
130
+ list
130
131
  );
131
132
  </doc-code>
132
133
  </div>
@@ -161,7 +162,7 @@
161
162
  </doc-code>
162
163
  <doc-code id="scss" data-type="scss" role="tabpanel">
163
164
  $color-variations: (
164
- list: (primary)
165
+ list: (primary)
165
166
  );
166
167
  </doc-code>
167
168
  </div>
@@ -95,6 +95,43 @@
95
95
  </ul>
96
96
  </doc-code>
97
97
 
98
+ <h2>Manually move</h2>
99
+ <p>You can manually move the item by adding some button with <code>data-go="up"</code> or <code>data-go="down"</code> attribute</p>
100
+ <doc-demo>
101
+ <ul class="demo-sortable">
102
+ <li draggable="false">
103
+ <button data-go="up">UP</button><button data-go="down">Down</button>
104
+ Lorem, ipsum.
105
+ </li>
106
+ <li draggable="false">
107
+ <button data-go="up">UP</button><button data-go="down">Down</button>
108
+ Impedit, quod!
109
+ </li>
110
+ <li draggable="false">
111
+ <button data-go="up">UP</button><button data-go="down">Down</button>
112
+ Repudiandae, rerum.
113
+ </li>
114
+ </ul>
115
+ </doc-demo>
116
+
117
+ <doc-code>
118
+ <ul id="mySortableListWithBtn">
119
+ <li draggable="false">
120
+ <button data-go="up">UP</button><button data-go="down">Down</button>
121
+ Lorem, ipsum.
122
+ </li>
123
+ <li draggable="false">
124
+ <button data-go="up">UP</button><button data-go="down">Down</button>
125
+ Impedit, quod!
126
+ </li>
127
+ <li draggable="false">
128
+ <button data-go="up">UP</button><button data-go="down">Down</button>
129
+ Repudiandae, rerum.
130
+ </li>
131
+ </ul>
132
+ </doc-code>
133
+
134
+
98
135
  <h2 id="javascript">Javascript</h2>
99
136
  <p>To enable this component you need to import the javascript file and create a new Sortable object.</p>
100
137
  <h3 id="events">Events</h3>
@@ -18,7 +18,7 @@ class DocLayout extends HTMLElement {
18
18
  <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-pin-angle" viewBox="0 0 16 16">
19
19
  <path d="M9.828.722a.5.5 0 0 1 .354.146l4.95 4.95a.5.5 0 0 1 0 .707c-.48.48-1.072.588-1.503.588-.177 0-.335-.018-.46-.039l-3.134 3.134a6 6 0 0 1 .16 1.013c.046.702-.032 1.687-.72 2.375a.5.5 0 0 1-.707 0l-2.829-2.828-3.182 3.182c-.195.195-1.219.902-1.414.707s.512-1.22.707-1.414l3.182-3.182-2.828-2.829a.5.5 0 0 1 0-.707c.688-.688 1.673-.767 2.375-.72a6 6 0 0 1 1.013.16l3.134-3.133a3 3 0 0 1-.04-.461c0-.43.108-1.022.589-1.503a.5.5 0 0 1 .353-.146m.122 2.112v-.002zm0-.002v.002a.5.5 0 0 1-.122.51L6.293 6.878a.5.5 0 0 1-.511.12H5.78l-.014-.004a5 5 0 0 0-.288-.076 5 5 0 0 0-.765-.116c-.422-.028-.836.008-1.175.15l5.51 5.509c.141-.34.177-.753.149-1.175a5 5 0 0 0-.192-1.054l-.004-.013v-.001a.5.5 0 0 1 .12-.512l3.536-3.535a.5.5 0 0 1 .532-.115l.096.022c.087.017.208.034.344.034q.172.002.343-.04L9.927 2.028q-.042.172-.04.343a1.8 1.8 0 0 0 .062.46z"/>
20
20
  </svg>
21
- 0.1.10
21
+ 0.1.12
22
22
  </span>
23
23
  </li>
24
24
  <li>
package/js/_drawer.js CHANGED
@@ -12,11 +12,13 @@
12
12
 
13
13
  import BaseComponent from './utilities/_base-component'
14
14
  import ErrorMessage from "./utilities/_error"
15
+ import Cookie from "./utilities/_cookie"
15
16
 
16
17
  export default class Drawer extends BaseComponent {
17
18
 
18
19
  static OPTIONS = {
19
20
  breakpoint: 960,
21
+ cookie: false
20
22
  }
21
23
 
22
24
  /**
@@ -44,6 +46,8 @@ export default class Drawer extends BaseComponent {
44
46
 
45
47
  this._focus = this._element.querySelector('a,button') ?? null
46
48
 
49
+ this._cookie = this._options.cookie ? new Cookie(this._options.cookie) : null
50
+
47
51
  // Init the event listener
48
52
  this.#init()
49
53
 
@@ -56,30 +60,50 @@ export default class Drawer extends BaseComponent {
56
60
  */
57
61
  #init() {
58
62
 
59
- // On load check if need to open/close the drawer
60
- if (window.innerWidth > this._options.breakpoint && !this._isOpen) this.toggle()
63
+ const isOpenValue = window.innerWidth > this._options.breakpoint && !this._isOpen
64
+
65
+ // Init the default cookie
66
+ if (this._cookie && !this._cookie.has('open')) this._cookie.set({ 'open': isOpenValue })
67
+
68
+ // Init the default open or close
69
+ if (!this._cookie || (this._cookie.get('open') && !this._isOpen)) this.toggle()
61
70
 
62
71
  // On resize check if need to open/close the drawer
63
72
  window.onresize = () => {
64
73
  clearTimeout(this._timeout)
65
74
  this._timeout = setTimeout(() => {
66
- if ((window.innerWidth <= this._options.breakpoint && this._isOpen) || (window.innerWidth > this._options.breakpoint && !this._isOpen)) this.toggle()
75
+ if ((window.innerWidth > this._options.breakpoint && !this._isOpen) || (window.innerWidth < this._options.breakpoint && this._isOpen)) {
76
+ this.toggle()
77
+ this.#resetCookie()
78
+ }
67
79
  }, 250)
68
80
  }
69
81
 
70
82
  // On click on the button toggle the drawer
71
- this._buttons.forEach((button) => button.addEventListener('click', () => this.toggle(true)))
83
+ this._buttons.forEach((button) => button.addEventListener('click', () => {
84
+ this.toggle()
85
+ if (window.innerWidth > this._options.breakpoint) this.#resetCookie()
86
+ if (this._focus && this._isOpen) this._focus.focus()
87
+ }))
72
88
 
73
89
  // On click on the backdrop, close the drawer
74
90
  if (this._backdrop) this._backdrop.addEventListener('click', () => this.toggle())
75
91
 
76
92
  }
77
93
 
94
+ /**
95
+ * Reset the cookie
96
+ *
97
+ */
98
+ #resetCookie() {
99
+ if (this._cookie) this._cookie.set({ 'open': this._isOpen })
100
+ }
101
+
78
102
  /**
79
103
  * Toggle the drawer
80
104
  *
81
105
  */
82
- toggle(enableFocus = false) {
106
+ toggle() {
83
107
 
84
108
  // Change the state
85
109
  this._isOpen = !this._isOpen
@@ -93,9 +117,7 @@ export default class Drawer extends BaseComponent {
93
117
  // Change the [hidden] attribute on the drawer
94
118
  this._element.hidden = !this._isOpen
95
119
 
96
- // Toggle the focus
97
- if (enableFocus && this._focus && this._isOpen) this._focus.focus()
98
-
99
120
  }
100
121
 
122
+
101
123
  }
package/js/_sortable.js CHANGED
@@ -53,9 +53,12 @@ export default class Sortable extends BaseComponent {
53
53
 
54
54
  // Drag and drop events
55
55
  item.addEventListener('dragstart', () => this.#drag(item))
56
- item.addEventListener('dragenter', () => this.#move(item))
56
+ item.addEventListener('dragenter', () => this.#dragging(item))
57
57
  item.addEventListener('dragend', () => this.#drop(item))
58
58
 
59
+ const btns = item.querySelectorAll('[data-go]')
60
+ if (btns) btns.forEach(btn => btn.addEventListener('click', () => this.#move(item, btn.getAttribute('data-go') == 'up')))
61
+
59
62
  })
60
63
 
61
64
  }
@@ -100,7 +103,7 @@ export default class Sortable extends BaseComponent {
100
103
  * @param {HTMLElement} item - The current item
101
104
  * @private
102
105
  */
103
- #move(item) {
106
+ #dragging(item) {
104
107
 
105
108
  // Check for errors
106
109
  if (!(item instanceof HTMLElement)) throw new Error(ErrorMessage.instanceOf('item', 'HTMLElement'))
@@ -142,4 +145,26 @@ export default class Sortable extends BaseComponent {
142
145
 
143
146
  }
144
147
 
148
+ /**
149
+ * Manually move up and down
150
+ *
151
+ * @param {HTMLElement} item - The current item
152
+ * @private
153
+ */
154
+ #move(item, goUp = false) {
155
+
156
+ const sibling = goUp ? item.previousElementSibling : item.nextElementSibling
157
+
158
+ if (sibling) {
159
+ this._element.insertBefore(item, goUp ? sibling : sibling.nextElementSibling)
160
+ } else if (!goUp) {
161
+ this._element.appendChild(item)
162
+ }
163
+
164
+ // Run custom event
165
+ this.emmitEvent('moved', { items: this.items, current: item })
166
+
167
+ }
168
+
169
+
145
170
  }
@@ -12,6 +12,8 @@
12
12
  * - #Drag(): Emmit the sortable:drag event
13
13
  * - #Drop(): Remove the [aria-grabbed] attribute
14
14
  * - #Drop(): Emmit the sortable:drop event
15
+ * - #Move(): Go down on click and emmit the sortable:moved event
16
+ * - #Move(): Go up on click and emmit the sortable:moved event
15
17
  */
16
18
 
17
19
  import { describe, test, expect, beforeAll, vi } from "vitest"
@@ -29,9 +31,9 @@ beforeAll(() => {
29
31
 
30
32
  document.body.innerHTML =
31
33
  '<ul id="fakeList">' +
32
- '<li draggable="false">One</li>' +
33
- '<li draggable="false">Two</li>' +
34
- '<li draggable="false">Three</li>' +
34
+ '<li id="first" draggable="false"><button data-go="up">UP</button><button data-go="down">Down</button>One</li>' +
35
+ '<li draggable="false"><button data-go="up">UP</button><button data-go="down">Down</button>Two</li>' +
36
+ '<li draggable="false"><button data-go="up">UP</button><button data-go="down">Down</button>Three</li>' +
35
37
  '</ul>' +
36
38
  '<table id="fakeTable">' +
37
39
  '<tr draggable="false"><td data-handle="sortable">DRAG</td><td>One</td></tr>' +
@@ -41,7 +43,7 @@ beforeAll(() => {
41
43
 
42
44
  fakeListSortable = new Sortable(document.getElementById('fakeList'))
43
45
  fakeTableSortable = new Sortable(document.getElementById('fakeTable'))
44
- fakeListItem = document.querySelector('#fakeList li')
46
+ fakeListItem = document.getElementById('first')
45
47
 
46
48
  })
47
49
 
@@ -122,4 +124,23 @@ describe('#Drop()', () => {
122
124
  expect(eventSpy).toHaveBeenCalledWith('drop', { current: fakeListItem, items: fakeListSortable.items })
123
125
  })
124
126
 
127
+ })
128
+
129
+ describe('#Move()', () => {
130
+
131
+ test('Go down on click and emmit the sortable:moved event', () => {
132
+ const eventSpy = vi.spyOn(fakeListSortable, 'emmitEvent')
133
+ fireEvent(fakeListItem.querySelector('[data-go=down]'), new MouseEvent('click'))
134
+ expect(fakeListItem).toBe(document.getElementById('fakeList').children[1])
135
+ expect(eventSpy).toHaveBeenCalledWith('moved', { current: fakeListItem, items: fakeListSortable.items })
136
+ })
137
+
138
+ test('Go up on click and emmit the sortable:moved event', () => {
139
+ const eventSpy = vi.spyOn(fakeListSortable, 'emmitEvent')
140
+ expect(fakeListItem).toBe(document.getElementById('fakeList').children[1])
141
+ fireEvent(fakeListItem.querySelector('[data-go=up]'), new MouseEvent('click'))
142
+ expect(fakeListItem).toBe(document.getElementById('fakeList').children[0])
143
+ expect(eventSpy).toHaveBeenCalledWith('moved', { current: fakeListItem, items: fakeListSortable.items })
144
+ })
145
+
125
146
  })
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@natachah/vanilla-frontend",
3
- "version": "0.1.10",
3
+ "version": "0.1.12",
4
4
  "description": "A vanilla frontend framework",
5
5
  "keywords": [
6
6
  "html5",
@@ -129,7 +129,7 @@
129
129
  margin: 0;
130
130
  text-align: var(--list-text-align, left);
131
131
 
132
- &:has(a[role=button]:only-child, button:only-child) > * {
132
+ & > *:is(a[role=button]:only-child, button:only-child) {
133
133
  display: block;
134
134
  width: 100%;
135
135
  text-align: var(--list-text-align, left);