@doyosi/laraisy 1.0.2 → 1.0.4

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@doyosi/laraisy",
3
- "version": "1.0.2",
3
+ "version": "1.0.4",
4
4
  "type": "module",
5
5
  "description": "Missing Laravel / Tailwind v4.1 & Daisy UI 5.1.14 Javascript Plugins",
6
6
  "main": "src/index.js",
package/src/DSSvgFetch.js CHANGED
@@ -1,70 +1,70 @@
1
- /**
2
- * DSSvgFetch
3
- * Fetches SVG files and injects them inline.
4
- * Replaces <svg> classes with those defined in data-class.
5
- */
6
- export default class DSSvgFetch {
7
- constructor(options = {}) {
8
- this.config = {
9
- selector: '.icon-fetch-web',
10
- attribute: 'data-svg',
11
- classAttribute: 'data-class', // New config for the class data
12
- ...options
13
- };
14
-
15
- this.svgCache = new Map();
16
- }
17
-
18
- init() {
19
- const elements = document.querySelectorAll(this.config.selector);
20
-
21
- elements.forEach(element => {
22
- if (element.dataset.svgProcessed) return;
23
- this.processElement(element);
24
- });
25
- }
26
-
27
- async processElement(element) {
28
- const url = element.getAttribute(this.config.attribute);
29
- const customClasses = element.getAttribute(this.config.classAttribute);
30
-
31
- if (!url) return;
32
-
33
- try {
34
- element.dataset.svgProcessed = 'true';
35
-
36
- // 1. Fetch content (or get from cache)
37
- const svgContent = await this.fetchSvg(url);
38
-
39
- // 2. Inject HTML
40
- element.innerHTML = svgContent;
41
-
42
- // 3. Apply custom classes if data-class exists
43
- if (customClasses) {
44
- const svg = element.querySelector('svg');
45
- if (svg) {
46
- // setAttribute overwrites the entire 'class' attribute,
47
- // effectively removing old classes and adding the new ones.
48
- svg.setAttribute('class', customClasses);
49
- }
50
- }
51
-
52
- } catch (error) {
53
- console.error(`DSSvgFetch: Failed to load ${url}`, error);
54
- delete element.dataset.svgProcessed;
55
- }
56
- }
57
-
58
- async fetchSvg(url) {
59
- if (this.svgCache.has(url)) {
60
- return this.svgCache.get(url);
61
- }
62
-
63
- const response = await fetch(url);
64
- if (!response.ok) throw new Error(`HTTP ${response.status}`);
65
-
66
- const text = await response.text();
67
- this.svgCache.set(url, text);
68
- return text;
69
- }
1
+ /**
2
+ * DSSvgFetch
3
+ * Fetches SVG files and injects them inline.
4
+ * Replaces <svg> classes with those defined in data-class.
5
+ */
6
+ export class DSSvgFetch {
7
+ constructor(options = {}) {
8
+ this.config = {
9
+ selector: '.icon-fetch-web',
10
+ attribute: 'data-svg',
11
+ classAttribute: 'data-class', // New config for the class data
12
+ ...options
13
+ };
14
+
15
+ this.svgCache = new Map();
16
+ }
17
+
18
+ init() {
19
+ const elements = document.querySelectorAll(this.config.selector);
20
+
21
+ elements.forEach(element => {
22
+ if (element.dataset.svgProcessed) return;
23
+ this.processElement(element);
24
+ });
25
+ }
26
+
27
+ async processElement(element) {
28
+ const url = element.getAttribute(this.config.attribute);
29
+ const customClasses = element.getAttribute(this.config.classAttribute);
30
+
31
+ if (!url) return;
32
+
33
+ try {
34
+ element.dataset.svgProcessed = 'true';
35
+
36
+ // 1. Fetch content (or get from cache)
37
+ const svgContent = await this.fetchSvg(url);
38
+
39
+ // 2. Inject HTML
40
+ element.innerHTML = svgContent;
41
+
42
+ // 3. Apply custom classes if data-class exists
43
+ if (customClasses) {
44
+ const svg = element.querySelector('svg');
45
+ if (svg) {
46
+ // setAttribute overwrites the entire 'class' attribute,
47
+ // effectively removing old classes and adding the new ones.
48
+ svg.setAttribute('class', customClasses);
49
+ }
50
+ }
51
+
52
+ } catch (error) {
53
+ console.error(`DSSvgFetch: Failed to load ${url}`, error);
54
+ delete element.dataset.svgProcessed;
55
+ }
56
+ }
57
+
58
+ async fetchSvg(url) {
59
+ if (this.svgCache.has(url)) {
60
+ return this.svgCache.get(url);
61
+ }
62
+
63
+ const response = await fetch(url);
64
+ if (!response.ok) throw new Error(`HTTP ${response.status}`);
65
+
66
+ const text = await response.text();
67
+ this.svgCache.set(url, text);
68
+ return text;
69
+ }
70
70
  }
package/src/DSTabs.js CHANGED
@@ -139,24 +139,33 @@ export class DSTabs {
139
139
  }
140
140
 
141
141
  _cacheElements() {
142
- // Find all buttons with data-tab attribute within the container
142
+ // 1. Find Buttons (always in main container)
143
143
  this.buttons = Array.from(this.container.querySelectorAll(this.cfg.buttonSelector));
144
144
 
145
- // Find the tabs container
146
- this.tabsContainer = this.container.querySelector(this.cfg.tabsContainer);
147
-
148
- // Find all radio inputs and content pairs within the tabs container
149
- if (this.tabsContainer) {
150
- this.radios = Array.from(this.tabsContainer.querySelectorAll(this.cfg.radioSelector));
151
- this.contents = Array.from(this.tabsContainer.querySelectorAll(this.cfg.contentSelector));
145
+ // 2. Determine Scope for Content/Radios
146
+ // If tabsContainer is configured AND exists, strictly scope to it.
147
+ // Otherwise, search within the entire main container (flexible mode).
148
+ let searchScope = this.container;
149
+ if (this.cfg.tabsContainer) {
150
+ const scopedEl = this.container.querySelector(this.cfg.tabsContainer);
151
+ if (scopedEl) {
152
+ this.tabsContainer = scopedEl;
153
+ searchScope = scopedEl;
154
+ } else {
155
+ this.tabsContainer = null;
156
+ }
152
157
  } else {
153
- this.radios = [];
154
- this.contents = [];
158
+ this.tabsContainer = null;
155
159
  }
156
160
 
157
- // Build a map of tab name -> { button, radio, content }
161
+ // 3. Find Radios and Content within that scope
162
+ this.radios = Array.from(searchScope.querySelectorAll(this.cfg.radioSelector));
163
+ this.contents = Array.from(searchScope.querySelectorAll(this.cfg.contentSelector));
164
+
165
+ // 4. Initialize Map
158
166
  this._tabMap = new Map();
159
167
 
168
+ // Group buttons by tab name
160
169
  this.buttons.forEach(button => {
161
170
  const tabName = button.dataset.tab;
162
171
  if (!this._tabMap.has(tabName)) {
@@ -165,15 +174,35 @@ export class DSTabs {
165
174
  this._tabMap.get(tabName).buttons.push(button);
166
175
  });
167
176
 
168
- // Associate radios with their following content divs
169
- this.radios.forEach((radio, index) => {
177
+ // Associate Radios (by data-tab)
178
+ this.radios.forEach(radio => {
170
179
  const tabName = radio.dataset.tab;
171
180
  if (this._tabMap.has(tabName)) {
172
181
  this._tabMap.get(tabName).radio = radio;
173
- // The content div follows the radio input
174
- if (this.contents[index]) {
175
- this._tabMap.get(tabName).content = this.contents[index];
176
- }
182
+ }
183
+ });
184
+
185
+ // Associate Content (Improved Logic)
186
+ // Strategy: Match by data-tab first. If content lacks data-tab, fall back to index/order.
187
+ const unmappedContents = [...this.contents]; // Copy to track what's used
188
+
189
+ // Pass 1: Link content elements that explicitly have data-tab="..."
190
+ this._tabMap.forEach((data, name) => {
191
+ const matchIndex = unmappedContents.findIndex(c => c.dataset.tab === name);
192
+ if (matchIndex > -1) {
193
+ data.content = unmappedContents[matchIndex];
194
+ unmappedContents[matchIndex] = null; // Mark as used
195
+ }
196
+ });
197
+
198
+ // Pass 2: Link remaining content to remaining tabs by order (legacy support)
199
+ let remainingIndex = 0;
200
+ const remainingContents = unmappedContents.filter(c => c !== null);
201
+
202
+ this._tabMap.forEach((data) => {
203
+ if (!data.content && remainingContents[remainingIndex]) {
204
+ data.content = remainingContents[remainingIndex];
205
+ remainingIndex++;
177
206
  }
178
207
  });
179
208
  }