@lemonadejs/tabs 5.0.0 → 5.8.0

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.
package/README.md CHANGED
@@ -1,129 +1,131 @@
1
- # LemonadeJS Tabs
2
-
3
- [Official website and documentation is here](https://lemonadejs.net/components/tabs)
4
-
5
- Compatible with Vanilla JavaScript, LemonadeJS, React, Vue or Angular.
6
-
7
- The LemonadeJS JavaScript Tabs is a responsive and reactive component that creates selected tabs.
8
-
9
- ## Features
10
-
11
- - Lightweight: The JavaScript Tabs is only about 2 KBytes;
12
- - Integration: It can be used as a standalone library or integrated with any modern framework;
13
-
14
- ## Getting Started
15
-
16
- You can install using NPM or using directly from a CDN.
17
-
18
- ### npm Installation
19
-
20
- To install it in your project using npm, run the following command:
21
-
22
- ```bash
23
- $ npm install @lemonadejs/tabs
24
- ```
25
-
26
- ### CDN
27
-
28
- To use tabs via a CDN, include the following script tags in your HTML file:
29
-
30
- ```html
31
- <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/lemonadejs/dist/lemonade.min.js"></script>
32
- <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/@lemonadejs/tabs/dist/index.min.js"></script>
33
- <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@lemonadejs/tabs/dist/style.min.css" />
34
- ```
35
-
36
- ### Usage
37
-
38
- Quick example with Lemonade
39
-
40
- ```javascript
41
- import lemonade from 'lemonadejs'
42
- import Tabs from '@lemonadejs/tabs';
43
- import '@lemonadejs/tabs/dist/style.css';
44
-
45
- export default function App() {
46
- const self = this;
47
-
48
- return `<div>
49
- <Tabs :selected="0">
50
- <div title="Tab 1">Content of the first tab</div>
51
- <div title="Tab 2">Content of the second tab</div>
52
- </Tabs>
53
- </div>`
54
- }
55
- ```
56
-
57
- Quick example with React
58
-
59
- ```jsx
60
- import React, { useRef } from "react";
61
- import Tabs from "@lemonadejs/tabs/dist/react";
62
- import '@lemonadejs/tabs/dist/style.css';
63
-
64
- const data = [{ title: 'Tab 1', content: 'Content of first tab' }, { title: 'Tab 2', content: 'Content of second tab' }]
65
- export default function App() {
66
- const tabs = useRef();
67
- return (
68
- <>
69
- <Tabs selected={0} ref={tabs} data={data}/>
70
- </>
71
- );
72
- }
73
- ```
74
-
75
- Quick example with React
76
-
77
- ```vue
78
- <template>
79
- <Tabs :selected="0">
80
- <div title="Tab 1">Content of the first tab</div>
81
- <div title="Tab 2">Content of the second tab</div>
82
- </Tabs>
83
- </template>
84
-
85
- <script>
86
- import Tabs from '@lemonadejs/tabs/dist/vue';
87
- import '@lemonadejs/tabs/dist/style.css';
88
-
89
- export default {
90
- name: 'App',
91
- components: {
92
- Tabs,
93
- },
94
- };
95
- </script>
96
- ```
97
-
98
- [You can find more examples here in the official documentation.](https://lemonadejs.net/components/tabs)
99
-
100
- ### Configuration
101
-
102
- You can configure things such as tabs titles, tabs contents and selected tab.
103
-
104
- #### Settings
105
-
106
- | Property | Type | Description |
107
- | -------- | ---- | ----------- |
108
- | selected? | number | The index of the initially selected tab. Starts from 0. |
109
- | position? | string | The position of the tabs bar within the parent element. Use 'center' to center-align the tabs. |
110
- | data? | tabItem[] | An optional alternative method to provide the title and content that will serve as the basis for rendering the tabs. See more about the `tabItem` object in the Tab Item section below. |
111
- | round? | boolean | Dictates whether the tab style will feature rounded corners. |
112
- | onopen? | function | When a new tabs is opened. |
113
-
114
- #### Tab Item
115
-
116
- | Property | Description |
117
- | -------- | ----------- |
118
- | title | The title of the tab, serving as the label displayed on the tab options. |
119
- | content | The HTML content intended for this specific tab. |
120
-
121
-
122
- ## License
123
-
124
- The [LemonadeJS](https://lemonadejs.net) Tabs is released under the MIT.
125
-
126
- ## Other Tools
127
-
128
- - [jSuites](https://jsuites.net)
129
- - [Jspreadsheet Data Grid](https://jspreadsheet.com)
1
+ # LemonadeJS Tabs
2
+
3
+ [Official website and documentation is here](https://lemonadejs.net/components/tabs)
4
+
5
+ Compatible with Vanilla JavaScript, LemonadeJS, React, Vue or Angular.
6
+
7
+ The LemonadeJS JavaScript Tabs is a responsive and reactive component that creates selected tabs.
8
+
9
+ ## Features
10
+
11
+ - Lightweight: The JavaScript Tabs is only about 2 KBytes;
12
+ - Integration: It can be used as a standalone library or integrated with any modern framework;
13
+
14
+ ## Getting Started
15
+
16
+ You can install using NPM or using directly from a CDN.
17
+
18
+ ### npm Installation
19
+
20
+ To install it in your project using npm, run the following command:
21
+
22
+ ```bash
23
+ $ npm install @lemonadejs/tabs
24
+ ```
25
+
26
+ ### CDN
27
+
28
+ To use tabs via a CDN, include the following script tags in your HTML file:
29
+
30
+ ```html
31
+ <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/lemonadejs/dist/lemonade.min.js"></script>
32
+ <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/@lemonadejs/tabs/dist/index.min.js"></script>
33
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@lemonadejs/tabs/dist/style.min.css" />
34
+ ```
35
+
36
+ ### Usage
37
+
38
+ Quick example with Lemonade
39
+
40
+ ```javascript
41
+ import lemonade from 'lemonadejs';
42
+ import Tabs from '@lemonadejs/tabs';
43
+ import '@lemonadejs/tabs/dist/style.css';
44
+
45
+ export default function App() {
46
+ const self = this;
47
+
48
+ return `<div>
49
+ <Tabs :selected="0">
50
+ <div title="Tab 1">Content of the first tab</div>
51
+ <div title="Tab 2">Content of the second tab</div>
52
+ </Tabs>
53
+ </div>`;
54
+ }
55
+ ```
56
+
57
+ Quick example with React
58
+
59
+ ```jsx
60
+ import React, { useRef } from 'react';
61
+ import Tabs from '@lemonadejs/tabs/dist/react';
62
+ import '@lemonadejs/tabs/dist/style.css';
63
+
64
+ const data = [
65
+ { title: 'Tab 1', content: 'Content of first tab' },
66
+ { title: 'Tab 2', content: 'Content of second tab' },
67
+ ];
68
+ export default function App() {
69
+ const tabs = useRef();
70
+ return (
71
+ <>
72
+ <Tabs selected={0} ref={tabs} data={data} />
73
+ </>
74
+ );
75
+ }
76
+ ```
77
+
78
+ Quick example with React
79
+
80
+ ```vue
81
+ <template>
82
+ <Tabs :selected="0">
83
+ <div title="Tab 1">Content of the first tab</div>
84
+ <div title="Tab 2">Content of the second tab</div>
85
+ </Tabs>
86
+ </template>
87
+
88
+ <script>
89
+ import Tabs from '@lemonadejs/tabs/dist/vue';
90
+ import '@lemonadejs/tabs/dist/style.css';
91
+
92
+ export default {
93
+ name: 'App',
94
+ components: {
95
+ Tabs,
96
+ },
97
+ };
98
+ </script>
99
+ ```
100
+
101
+ [You can find more examples here in the official documentation.](https://lemonadejs.net/components/tabs)
102
+
103
+ ### Configuration
104
+
105
+ You can configure things such as tabs titles, tabs contents and selected tab.
106
+
107
+ #### Settings
108
+
109
+ | Property | Type | Description |
110
+ | --------- | --------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
111
+ | selected? | number | The index of the initially selected tab. Starts from 0. |
112
+ | position? | string | The position of the tabs bar within the parent element. Use 'center' to center-align the tabs. |
113
+ | data? | tabItem[] | An optional alternative method to provide the title and content that will serve as the basis for rendering the tabs. See more about the `tabItem` object in the Tab Item section below. |
114
+ | round? | boolean | Dictates whether the tab style will feature rounded corners. |
115
+ | onopen? | function | When a new tabs is opened. |
116
+
117
+ #### Tab Item
118
+
119
+ | Property | Description |
120
+ | -------- | ------------------------------------------------------------------------ |
121
+ | title | The title of the tab, serving as the label displayed on the tab options. |
122
+ | content | The HTML content intended for this specific tab. |
123
+
124
+ ## License
125
+
126
+ The [LemonadeJS](https://lemonadejs.net) Tabs is released under the MIT.
127
+
128
+ ## Other Tools
129
+
130
+ - [jSuites](https://jsuites.net)
131
+ - [Jspreadsheet Data Grid](https://jspreadsheet.com)
package/dist/index.d.ts CHANGED
@@ -10,6 +10,8 @@ declare namespace Tabs {
10
10
  interface Item {
11
11
  // Reference to an external DOM
12
12
  el: HTMLElement,
13
+ /** Material icon keyword */
14
+ icon?: string;
13
15
  // Tab header
14
16
  title: string,
15
17
  // HTML template
@@ -22,13 +24,21 @@ declare namespace Tabs {
22
24
  /** Selected tab */
23
25
  selected?: number;
24
26
  /** Tabs position */
25
- position?: 'center' | undefined;
27
+ position?: 'default' | 'center' | 'bottom' | undefined;
26
28
  /** Activate round borders */
27
29
  round?: boolean;
28
- /** On open event */
29
- onopen?: (instance: object, index: number) => void;
30
30
  /** Allow to create new tab button */
31
31
  allowCreate?: boolean;
32
+ /** Change tabs */
33
+ onchange?: (instance: object, value: number) => void;
34
+ /** On open event */
35
+ onopen?: (instance: object, index: number) => void;
36
+ /** Before create new tab */
37
+ onbeforecreate?: (instance: object, item: Item, position: number) => boolean | void;
38
+ /** On create new tab event */
39
+ oncreate?: (instance: object, item: Item, position: number) => void;
40
+ /** On change tab position event */
41
+ onchangeposition: (instance: object, fromIndex: number, toIndex: number) => void;
32
42
  }
33
43
 
34
44
  interface Instance {
@@ -42,8 +52,8 @@ declare namespace Tabs {
42
52
  position?: 'center' | undefined;
43
53
  /** Activate round borders */
44
54
  round?: boolean;
45
- /** On open event */
46
- onopen?: (instance: object, index: number) => void;
55
+ /** Allow to create new tab button */
56
+ allowCreate?: boolean;
47
57
  }
48
58
  }
49
59
 
package/dist/index.js CHANGED
@@ -8,12 +8,33 @@ if (! lemonade && typeof (require) === 'function') {
8
8
  global.Tabs = factory();
9
9
  }(this, (function () {
10
10
 
11
+ class CustomEvents extends Event {
12
+ constructor(type, props, options) {
13
+ super(type, {
14
+ bubbles: true,
15
+ composed: true,
16
+ ...options,
17
+ });
18
+
19
+ if (props) {
20
+ for (const key in props) {
21
+ // Avoid assigning if property already exists anywhere on `this`
22
+ if (! (key in this)) {
23
+ this[key] = props[key];
24
+ }
25
+ }
26
+ }
27
+ }
28
+ }
29
+
11
30
  // Dispatcher
12
- const Dispatch = function(type){
13
- if (typeof this[type] === 'function') {
14
- let args = Array.from(arguments);
15
- args.shift();
16
- this[type](...args)
31
+ const Dispatch = function(method, type, options) {
32
+ // Try calling the method directly if provided
33
+ if (typeof method === 'function') {
34
+ let a = Object.values(options);
35
+ return method(...a);
36
+ } else if (this.tagName) {
37
+ this.dispatchEvent(new CustomEvents(type, options));
17
38
  }
18
39
  }
19
40
 
@@ -37,9 +58,109 @@ if (! lemonade && typeof (require) === 'function') {
37
58
  }
38
59
  }
39
60
 
40
- const Tabs = function(children) {
61
+ const sorting = function(el, options) {
62
+ const obj = {};
63
+
64
+ let dragElement = null;
65
+
66
+ el.addEventListener('dragstart', function(e) {
67
+ let target = e.target;
68
+ if (target.nodeType === 3) {
69
+ if (target.parentNode.getAttribute('draggable') === 'true') {
70
+ target = target.parentNode;
71
+ } else {
72
+ e.preventDefault();
73
+ e.stopPropagation();
74
+ return;
75
+ }
76
+ }
77
+
78
+ if (target.getAttribute('draggable') === 'true') {
79
+ let position = Array.prototype.indexOf.call(target.parentNode.children, target);
80
+ dragElement = {
81
+ element: target,
82
+ o: position,
83
+ d: position
84
+ }
85
+ target.style.opacity = '0.25';
86
+ e.dataTransfer.setDragImage(target,0,0);
87
+ }
88
+ });
89
+
90
+ el.addEventListener('dragover', function(e) {
91
+ e.preventDefault();
92
+
93
+ if (dragElement && getElement(e.target) && e.target.getAttribute('draggable') == 'true' && dragElement.element != e.target) {
94
+ let element = e.target.clientWidth / 2 > e.offsetX ? e.target : e.target.nextSibling;
95
+ e.target.parentNode.insertBefore(dragElement.element, element);
96
+ dragElement.d = Array.prototype.indexOf.call(e.target.parentNode.children, dragElement.element);
97
+ }
98
+ });
99
+
100
+ el.addEventListener('dragleave', function(e) {
101
+ e.preventDefault();
102
+ });
103
+
104
+ el.addEventListener('dragend', function(e) {
105
+ e.preventDefault();
106
+
107
+ if (dragElement) {
108
+ let element = dragElement.o < dragElement.d ? e.target.parentNode.children[dragElement.o] : e.target.parentNode.children[dragElement.o].nextSibling
109
+ e.target.parentNode.insertBefore(dragElement.element, element);
110
+ dragElement.element.style.opacity = '';
111
+ dragElement = null;
112
+ }
113
+ });
114
+
115
+ el.addEventListener('drop', function(e) {
116
+ e.preventDefault();
117
+
118
+ if (dragElement) {
119
+ if (dragElement.o !== dragElement.d) {
120
+ if (typeof(options.ondrop) == 'function') {
121
+ options.ondrop(el, dragElement.o, dragElement.d, dragElement.element, e.target, e);
122
+ }
123
+ }
124
+
125
+ dragElement.element.style.opacity = '';
126
+ dragElement = null;
127
+ }
128
+ });
129
+
130
+ const getElement = function(element) {
131
+ var sorting = false;
132
+
133
+ function path (element) {
134
+ if (element === el) {
135
+ sorting = true;
136
+ }
137
+
138
+ if (! sorting) {
139
+ path(element.parentNode);
140
+ }
141
+ }
142
+
143
+ path(element);
144
+
145
+ return sorting;
146
+ }
147
+
148
+ for (let i = 0; i < el.children.length; i++) {
149
+ if (! el.children[i].hasAttribute('draggable')) {
150
+ el.children[i].setAttribute('draggable', 'true');
151
+ }
152
+ }
153
+
154
+ return el;
155
+ }
156
+
157
+ const Tabs = function(children, { onchange, onload }) {
41
158
  let self = this
42
159
 
160
+ // Event
161
+ let change = self.onchange;
162
+ self.onchange = null;
163
+
43
164
  // Add new tab
44
165
  let createButton;
45
166
 
@@ -77,7 +198,9 @@ if (! lemonade && typeof (require) === 'function') {
77
198
  }
78
199
  }
79
200
 
80
- const select = function (index) {
201
+ let props = ['title', 'selected', 'data-icon'];
202
+
203
+ const select = function(index) {
81
204
  // Make sure the index is a number
82
205
  index = parseInt(index);
83
206
  // Do not select tabs that does not exist
@@ -93,19 +216,19 @@ if (! lemonade && typeof (require) === 'function') {
93
216
 
94
217
  const init = function(selected) {
95
218
  let tabs = [];
219
+
96
220
  for (let i = 0; i < self.data.length; i++) {
97
221
  // Extract meta information from the DOM
98
- if (! self.data[i].title) {
99
- let ret = self.data[i].el.getAttribute('title');
100
- if (ret != null) {
101
- self.data[i].title = ret;
102
- }
103
- }
104
- if (! self.data[i].selected) {
105
- let ret = self.data[i].el.getAttribute('selected');
106
- if (ret != null) {
107
- self.data[i].selected = ret;
108
- }
222
+ if (props) {
223
+ props.forEach((prop) => {
224
+ let short = prop.replace('data-', '');
225
+ if (! self.data[i][short]) {
226
+ let ret = self.data[i].el.getAttribute(prop);
227
+ if (ret != null) {
228
+ self.data[i][short] = ret;
229
+ }
230
+ }
231
+ });
109
232
  }
110
233
  // Create tabs object
111
234
  tabs[i] = {
@@ -115,30 +238,68 @@ if (! lemonade && typeof (require) === 'function') {
115
238
  if (self.data[i].selected) {
116
239
  selected = i;
117
240
  }
241
+ if (self.data[i].icon) {
242
+ tabs[i].icon = self.data[i].icon;
243
+ }
118
244
 
119
- self.root.appendChild(self.data[i].el)
245
+ self.root.appendChild(self.data[i].el);
120
246
  }
247
+
121
248
  // Create headers
122
249
  self.tabs = tabs;
250
+
123
251
  // Default selected
124
252
  if (typeof(selected) !== 'undefined') {
125
253
  self.selected = selected;
126
254
  }
127
- // Add create new tab button
128
- if (createButton) {
129
- self.headers.appendChild(createButton);
255
+
256
+ if (props) {
257
+ // Add create new tab button
258
+ if (createButton) {
259
+ self.headers.appendChild(createButton);
260
+ }
261
+ // Add sorting
262
+ sorting(self.el.firstChild.firstChild, {
263
+ ondrop: (el, fromIndex, toIndex) => {
264
+ // Remove the item from its original position
265
+ const [movedItem] = self.data.splice(fromIndex, 1);
266
+ // Insert it into the new position
267
+ self.data.splice(toIndex, 0, movedItem);
268
+ // Make sure correct order
269
+ for (let i = 0; i < self.data.length; i++) {
270
+ self.root.appendChild(self.data[i].el);
271
+ }
272
+ // Select new position
273
+ self.selected = toIndex;
274
+ // Dispatch event
275
+ Dispatch.call(self, self.onchangeposition, 'changeposition', {
276
+ instance: self,
277
+ fromIndex: fromIndex,
278
+ toIndex: toIndex,
279
+ });
280
+ }
281
+ })
130
282
  }
283
+
284
+ props = null;
131
285
  }
132
286
 
133
- self.onload = function () {
134
- if (template) {
135
- extract(self.root, self);
136
- }
287
+ const create = function() {
288
+ // Create a new item
289
+ self.create({ title: 'Untitled' }, null, true);
290
+ }
137
291
 
138
- init(self.selected || 0);
292
+ const open = function(e) {
293
+ if (e.target.tagName === 'LI') {
294
+ // Avoid select something already selected
295
+ let index = Array.prototype.indexOf.call(e.target.parentNode.children, e.target);
296
+ if (index !== self.selected) {
297
+ self.selected = index;
298
+ }
299
+ }
139
300
  }
140
301
 
141
- self.keydown = function(e, s) {
302
+ const keydown = function(e, s) {
142
303
  let index = null;
143
304
  if (e.key === 'Enter') {
144
305
  self.click(e, s);
@@ -160,14 +321,32 @@ if (! lemonade && typeof (require) === 'function') {
160
321
  }
161
322
  }
162
323
 
163
- self.open = function (e) {
164
- if (e.target.tagName === 'LI') {
165
- // Avoid select something already selected
166
- let index = Array.prototype.indexOf.call(e.target.parentNode.children, e.target);
167
- if (index !== self.selected) {
168
- self.selected = index;
169
- }
324
+ onload(() => {
325
+ if (template) {
326
+ extract(self.root, self);
170
327
  }
328
+
329
+ init(self.selected || 0);
330
+ })
331
+
332
+ onchange((property) => {
333
+ if (property === 'selected') {
334
+ select(self.selected);
335
+
336
+ Dispatch.call(self, self.onopen, 'open', {
337
+ instance: self,
338
+ selected: self.selected,
339
+ });
340
+
341
+ Dispatch.call(self, change, 'change', {
342
+ instance: self,
343
+ value: self.selected,
344
+ });
345
+ }
346
+ })
347
+
348
+ self.open = function (index) {
349
+ self.selected = index;
171
350
  }
172
351
 
173
352
  self.create = function(item, position, select) {
@@ -175,6 +354,17 @@ if (! lemonade && typeof (require) === 'function') {
175
354
  if (typeof(item) !== 'object') {
176
355
  console.error('Item must be an object');
177
356
  } else {
357
+
358
+ let ret = Dispatch.call(self, self.onbeforecreate, 'beforecreate', {
359
+ instance: self,
360
+ item: item,
361
+ position: position,
362
+ });
363
+
364
+ if (ret === false) {
365
+ return false;
366
+ }
367
+
178
368
  // Create DOM
179
369
  item.el = document.createElement('div');
180
370
  // Create from content
@@ -198,28 +388,25 @@ if (! lemonade && typeof (require) === 'function') {
198
388
  } else {
199
389
  init(self.selected);
200
390
  }
201
- }
202
- }
203
-
204
- self.click = function() {
205
- // Create a new item
206
- self.create({ title: 'Untitled' }, null, true);
207
- }
208
391
 
209
- self.onchange = function (property) {
210
- if (property === 'selected') {
211
- select(self.selected);
392
+ self.tabs.forEach(item => {
393
+ item.el.setAttribute('draggable', 'true');
394
+ })
212
395
 
213
- Dispatch.call(self, 'onopen', self, self.selected);
396
+ Dispatch.call(self, self.oncreate, 'create', {
397
+ instance: self,
398
+ item: item,
399
+ position: position,
400
+ });
214
401
  }
215
402
  }
216
403
 
217
404
  self.allowCreate = !! self.allowCreate;
218
405
 
219
- return `<div class="lm-tabs" data-position="{{self.position}}" data-round="{{self.round}}">
406
+ return render => render`<div class="lm-tabs" data-position="{{self.position}}" data-round="{{self.round}}">
220
407
  <div role="tabs" class="lm-tabs-headers">
221
- <ul :ref="self.headers" :loop="self.tabs" :selected="self.selected" onclick="self.open" onkeydown="self.keydown" onfocusin="self.open"><li class="lm-tab" tabindex="0" role="tab">{{self.title}}</li></ul>
222
- <div data-visible="{{self.allowCreate}}" class="lm-tabs-insert-tab material-icons" role="insert-tab" onclick="self.click">add</div>
408
+ <ul :ref="self.headers" :loop="self.tabs" :selected="self.selected" onclick="${open}" onkeydown="${keydown}" onfocusin="${open}"><li class="lm-tab" tabindex="0" role="tab" data-icon="{{self.icon}}">{{self.title}}</li></ul>
409
+ <div data-visible="{{self.allowCreate}}" class="lm-tabs-insert-button" role="insert-tab" onclick="${create}">add</div>
223
410
  </div>
224
411
  <div :ref="self.root" class="lm-tabs-content">${template}</div>
225
412
  </div>`
package/dist/style.css CHANGED
@@ -1,78 +1,104 @@
1
+ .lm-tabs[data-position="bottom"] {
2
+ display: flex;
3
+ justify-content: center;
4
+ flex-direction: column-reverse;
5
+ }
6
+
1
7
  .lm-tabs .lm-tabs-content > div {
2
- padding: 15px 5px;
8
+ padding: 15px 5px;
3
9
  }
4
10
 
5
11
  .lm-tabs .lm-tabs-headers {
6
- display: flex;
7
- align-items: center;
8
- width: 100%;
12
+ display: flex;
13
+ align-items: center;
14
+ width: 100%;
9
15
  }
10
16
 
11
17
  .lm-tabs[data-position="center"] .lm-tabs-headers {
12
- margin: 0 auto;
13
- justify-content: center;
18
+ margin: 0 auto;
19
+ justify-content: center;
14
20
  }
15
21
 
16
22
  .lm-tabs .lm-tabs-headers > ul {
17
- list-style-type: none;
18
- display: flex;
19
- margin: 0;
20
- padding: 0;
21
- align-items: center;
23
+ list-style-type: none;
24
+ display: flex;
25
+ margin: 0;
26
+ padding: 0;
27
+ align-items: center;
22
28
  }
23
29
 
24
30
  .lm-tabs .lm-tabs-headers > ul > li {
25
- cursor: pointer;
26
- user-select: none;
27
- padding: 4px 24px;
28
- border: 1px solid #ccc;
29
- background-position: center;
30
- transition: background 0.8s;
31
+ cursor: pointer;
32
+ user-select: none;
33
+ padding: 4px 24px;
34
+ border: 1px solid #ccc;
35
+ background-position: center;
36
+ transition: background 0.8s;
37
+ display: flex;
38
+ flex-direction: column;
39
+ align-items: center;
31
40
  }
32
41
 
33
42
  .lm-tabs .lm-tabs-headers > ul > li.selected {
34
- background-color: #eee;
35
- color: #000;
43
+ background-color: #eee;
44
+ color: #000;
45
+ }
46
+
47
+ .lm-tabs .lm-tabs-headers > ul > li[data-icon]:before {
48
+ content: attr(data-icon);
49
+ font-family: "Material Symbols Outlined", "Material Icons", "FontAwesome";
50
+ font-size: 24px;
51
+ width: 24px;
52
+ height: 24px;
53
+ text-align: center;
54
+ color: var(--lm-icon-color, #777);
55
+ margin-bottom: 5px;
36
56
  }
37
57
 
38
58
  .lm-tabs[data-round="true"] .lm-tabs-headers > ul > li:first-of-type {
39
- border-top-left-radius: 3px;
40
- border-bottom-left-radius: 3px;
59
+ border-top-left-radius: 3px;
60
+ border-bottom-left-radius: 3px;
41
61
  }
42
62
 
43
63
  .lm-tabs[data-round="true"] .lm-tabs-headers > ul > li:last-of-type {
44
- border-top-right-radius: 3px;
45
- border-bottom-right-radius: 3px;
64
+ border-top-right-radius: 3px;
65
+ border-bottom-right-radius: 3px;
46
66
  }
47
67
 
48
68
  .lm-tabs .lm-tabs-headers > ul > li:not(:first-child) {
49
- border-left: 1px solid transparent;
69
+ border-left: 1px solid transparent;
50
70
  }
51
71
 
52
72
  .lm-tabs .lm-tabs-headers > ul > li:hover {
53
- background: #eee radial-gradient(circle, transparent 1%, #eee 1%) center/15000%;
73
+ background: #eee radial-gradient(circle, transparent 1%, #eee 1%) center/15000%;
54
74
  }
55
75
 
56
76
  .lm-tabs .lm-tabs-headers > ul > li:active {
57
- background-color: #ddd;
58
- background-size: 100%;
59
- transition: background 0s;
77
+ background-color: #ddd;
78
+ background-size: 100%;
79
+ transition: background 0s;
60
80
  }
61
81
 
62
82
  .lm-tabs .lm-tabs-content > div {
63
- display: none;
83
+ display: none;
64
84
  }
65
85
 
66
86
  .lm-tabs .lm-tabs-content > div.selected {
67
- display: block;
87
+ display: block;
68
88
  }
69
89
 
70
- .lm-tabs-insert-tab {
71
- margin-left: 5px;
72
- color: #555;
73
- cursor: pointer;
90
+ .lm-tabs-insert-button {
91
+ margin-left: 5px;
92
+ color: #555;
93
+ cursor: pointer;
94
+ font-family: "Material Symbols Outlined", "Material Icons", "FontAwesome";
95
+ font-size: 24px;
96
+ width: 24px;
97
+ height: 24px;
98
+ text-align: center;
99
+ line-height: 24px;
74
100
  }
75
101
 
76
- .lm-tabs div[data-visible='false'] {
77
- display: none;
78
- }
102
+ .lm-tabs div[data-visible="false"] {
103
+ display: none;
104
+ }
package/package.json CHANGED
@@ -1,20 +1,20 @@
1
- {
2
- "name": "@lemonadejs/tabs",
3
- "title": "JavaScript Tabs",
4
- "description": "LemonadeJS tabs is a JavaScript component to create tabs.",
5
- "author": {
6
- "name": "Contact <contact@lemonadejs.net>",
7
- "url": "https://lemonadejs.net"
8
- },
9
- "keywords": [
10
- "javascript tabs",
11
- "lemonadejs tabs",
12
- "js tabs",
13
- "tabs js"
14
- ],
15
- "dependencies": {
16
- "lemonadejs": "^5.0.3"
17
- },
18
- "main": "dist/index.js",
19
- "version": "5.0.0"
20
- }
1
+ {
2
+ "name": "@lemonadejs/tabs",
3
+ "title": "JavaScript Tabs",
4
+ "description": "LemonadeJS tabs is a JavaScript component to create tabs.",
5
+ "author": {
6
+ "name": "Contact <contact@lemonadejs.net>",
7
+ "url": "https://lemonadejs.net"
8
+ },
9
+ "keywords": [
10
+ "javascript tabs",
11
+ "lemonadejs tabs",
12
+ "js tabs",
13
+ "tabs js"
14
+ ],
15
+ "dependencies": {
16
+ "lemonadejs": "^5.3.2"
17
+ },
18
+ "main": "dist/index.js",
19
+ "version": "5.8.0"
20
+ }