desy-html 13.0.2 → 14.0.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.
@@ -358,6 +358,11 @@
358
358
  href: "examples-tree.html",
359
359
  text: "Tree",
360
360
  id: "page-examples-tree"
361
+ },
362
+ {
363
+ href: "examples-treegrid.html",
364
+ text: "Treegrid",
365
+ id: "page-examples-treegrid"
361
366
  }],
362
367
  attributes: {
363
368
  "id": "navegacion-ejemplos-offcanvas",
@@ -108,6 +108,8 @@ import componentToggle %}
108
108
  import componentTooltip %}
109
109
  {% from "components/tree/_macro.tree.njk"
110
110
  import componentTree %}
111
+ {% from "components/treegrid/_macro.treegrid.njk"
112
+ import componentTreegrid %}
111
113
 
112
114
 
113
115
  {% macro exampleRender(data) %}
@@ -296,6 +298,9 @@ import componentTree %}
296
298
  {{ componentTooltip(example.data) }}
297
299
  {% elseif exampleComponent == "tree" %}
298
300
  {{ componentTree(example.data) }}
301
+ {% elseif exampleComponent == "treegrid" %}
302
+ {{ componentTreegrid(example.data) }}
303
+ {% else %}
299
304
 
300
305
  {% endif %}
301
306
  </div>
@@ -176,6 +176,9 @@
176
176
  <div>
177
177
  <p class="c-paragraph-base"><a href="examples-tree.html" class="c-link">Tree</a></p>
178
178
  </div>
179
+ <div>
180
+ <p class="c-paragraph-base"><a href="examples-treegrid.html" class="c-link">Treegrid</a></p>
181
+ </div>
179
182
  </div>
180
183
  <div class="pb-2xl"></div>
181
184
  {% endblock %}
@@ -0,0 +1,8 @@
1
+ {% set title = "Treegrid. Componente, parámetros y ejemplos. Documentación de desy-html. Gobierno de Aragón" %}
2
+
3
+ {% set activePage = "page-componentes" %}
4
+ {% set activeComponent = "Treegrid" %}
5
+ {% extends "_template.examples.njk" %}
6
+ {% block contentBlock %}
7
+ {% import "components/treegrid/_examples.treegrid.njk" as exampleData %}
8
+ {% endblock %}
package/docs/index.html CHANGED
@@ -39,6 +39,10 @@
39
39
 
40
40
  <h2>Changelog (English)</h2>
41
41
  <p>What's new in the latest version of desy-html</p>
42
+ <h3>v.14.0.0</h3>
43
+ <ul class="text-sm">
44
+ <li>Added Treegrid component. Better gulp compilation with errors.</li>
45
+ </ul>
42
46
  <h3>v.13.0.2</h3>
43
47
  <ul class="text-sm">
44
48
  <li>Accesibility fixes in most of the component examples.</li>
package/gulpfile.js CHANGED
@@ -5,6 +5,7 @@ import gulp from 'gulp';
5
5
  import sourcemaps from 'gulp-sourcemaps';
6
6
  import clean from 'gulp-clean';
7
7
  import nunjucksRender from 'gulp-nunjucks-render';
8
+ import plumber from 'gulp-plumber';
8
9
  import browserSyncPackage from 'browser-sync';
9
10
  import postcss from 'gulp-postcss';
10
11
  import atimport from 'postcss-import';
@@ -75,7 +76,12 @@ function css() {
75
76
  tailwindcssNesting(),
76
77
  tailwindcss(TAILWIND_CONFIG),
77
78
  autoprefixer()
78
- ])
79
+ ]).on('error', function(err) {
80
+ console.log('\x1b[31m%s\x1b[0m', '=== POSTCSS ERROR ===');
81
+ console.log('\x1b[31m%s\x1b[0m', err.message);
82
+ console.log('\x1b[31m%s\x1b[0m', '===================');
83
+ process.exit(1);
84
+ })
79
85
  )
80
86
  .pipe(stripCssComments({preserve: false}))
81
87
  .pipe(footer('\n'))
@@ -89,6 +95,14 @@ function html() {
89
95
 
90
96
  function nunjucks() {
91
97
  return gulp.src(SOURCE_NUNJUCKS_DIR)
98
+ .pipe(plumber({
99
+ errorHandler: function(err) {
100
+ console.log('\x1b[31m%s\x1b[0m', '=== NUNJUCKS ERROR ===');
101
+ console.log('\x1b[31m%s\x1b[0m', 'Error: ' + err.message);
102
+ console.log('\x1b[31m%s\x1b[0m', '=====================');
103
+ process.exit(1);
104
+ }
105
+ }))
92
106
  .pipe(nunjucksRender({
93
107
  envOptions: {
94
108
  autoescape: true,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "desy-html",
3
- "version": "13.0.2",
3
+ "version": "14.0.0",
4
4
  "description": "desy-html contains the code you need to start building a user interface for Gobierno de Aragón government webapps.",
5
5
  "type": "module",
6
6
  "author": {
@@ -52,6 +52,7 @@
52
52
  "gulp-clean-css": "^4.3.0",
53
53
  "gulp-footer": "^2.1.0",
54
54
  "gulp-nunjucks-render": "^2.2.3",
55
+ "gulp-plumber": "^1.2.1",
55
56
  "gulp-postcss": "^9.0.1",
56
57
  "gulp-sourcemaps": "^2.6.5",
57
58
  "gulp-strip-css-comments": "^2.0.0",
@@ -43,6 +43,7 @@
43
43
  @import "../templates/components/toggle/_styles.toggle.css";
44
44
  @import "../templates/components/tooltip/_styles.tooltip.css";
45
45
  @import "../templates/components/tree/_styles.tree.css";
46
+ @import "../templates/components/treegrid/_styles.treegrid.css";
46
47
  @import "./component.form-group.css";
47
48
  @import "./component.tippy-box.css";
48
49
  @import "./component.headroom.css";
@@ -20,57 +20,290 @@ export function Tree(aria) {
20
20
  * An element with the role=tree attribute
21
21
  */
22
22
  aria.Tree = function (node) {
23
- // Check whether node is a DOM element
24
- if (typeof node !== 'object') {
25
- return;
26
- }
23
+ // Check whether node is a DOM element
24
+ if (typeof node !== 'object') {
25
+ return;
26
+ }
27
27
 
28
- this.domNode = node;
28
+ this.domNode = node;
29
29
 
30
- this.treeitems = [];
31
- this.firstChars = [];
30
+ this.treeitems = [];
31
+ this.firstChars = [];
32
32
 
33
- this.firstTreeitem = null;
34
- this.lastTreeitem = null;
33
+ this.firstTreeitem = null;
34
+ this.lastTreeitem = null;
35
35
 
36
- };
36
+ this.lazyRendering = false;
37
+ this.treeData = null;
38
+ this.params = null;
39
+ };
37
40
 
38
41
  aria.Tree.prototype.init = function () {
39
42
 
40
- function findTreeitems (node, tree, group) {
43
+ // Only if lazyRendering
44
+ const treeDataRaw = this.domNode.getAttribute('data-tree');
45
+ if (treeDataRaw) {
46
+ this.treeData = JSON.parse(treeDataRaw);
47
+ this.lazyRendering = true;
48
+ const paramsRaw = this.domNode.getAttribute('data-params');
49
+ if (paramsRaw) {
50
+ this.params = JSON.parse(paramsRaw);
51
+ this.describedBy = this.params.describedBy ?? "";
52
+ if (this.params.fieldset.describedBy)
53
+ this.describedBy = this.params.fieldset.describedBy;
54
+ this.hasFieldset = this.params.fieldset ?? false;
55
+ }
56
+ }
57
+
58
+ // initialize pop up menus
59
+ if (!this.domNode.getAttribute('role')) {
60
+ this.domNode.setAttribute('role', 'tree');
61
+ }
62
+
63
+ this.findTreeitems(this.domNode, this, false);
64
+
65
+ this.updateVisibleTreeitems();
66
+
67
+ this.firstTreeitem.domNode.tabIndex = 0;
68
+
69
+ };
41
70
 
42
- var elem = node.firstElementChild;
43
- var ti = group;
44
71
 
45
- while (elem) {
72
+ aria.Tree.prototype.findTreeitems = function (node, tree, group) {
73
+ var elem = node.firstElementChild;
74
+ var ti = group;
46
75
 
47
- if (elem.tagName.toLowerCase() === 'li') {
76
+ while (elem) {
77
+ if (elem.tagName.toLowerCase() === 'li') {
78
+ if (elem.dataset.treeProcessed !== 'true' || !this.lazyRendering) {
48
79
  ti = new aria.Treeitem(elem, tree, group);
49
80
  ti.init();
50
81
  tree.treeitems.push(ti);
51
82
  tree.firstChars.push(ti.label.substring(0, 1).toLowerCase());
83
+ if (this.lazyRendering) {
84
+ elem.dataset.treeProcessed = 'true';
85
+ elem.addEventListener('click', (event) => event.stopPropagation());
86
+ }
52
87
  }
88
+ }
53
89
 
54
- if (elem.firstElementChild) {
55
- findTreeitems(elem, tree, ti);
56
- }
90
+ if (elem.firstElementChild) {
91
+ this.findTreeitems(elem, tree, ti);
92
+ }
93
+
94
+ elem = elem.nextElementSibling;
95
+ }
96
+ };
57
97
 
58
- elem = elem.nextElementSibling;
98
+ function checkboxItem(item, id, name, type, params, describedBy, hasFieldset) {
99
+ name = name || item.name || '';
100
+ var hasHint = item.hint && (item.hint.text || item.hint.html);
101
+ var itemHintId = hasHint ? id + '-item-hint' : '';
102
+ var itemDescribed = (!hasFieldset ? describedBy : '') + (itemHintId ? ' ' + itemHintId : '');
103
+ itemDescribed = itemDescribed.trim();
104
+
105
+ // Wrapper
106
+ var html = '<div' +
107
+ ((params.hasDividers ? ' class="border-t border-b border-neutral-base -mb-px' : '') +
108
+ (item.classes ? ' ' + item.classes : '') + '"').replace('""', '') +
109
+ '>' +
110
+ '<div class="relative flex items-start py-xs">';
111
+
112
+ // Checkbox / Radio branch
113
+ if (type === 'checkbox' || type === 'radio' || typeof type === 'undefined') {
114
+ html += '<div class="flex items-center mx-sm">' +
115
+ '<input ' +
116
+ 'class="w-6 h-6 transition duration-150 ease-in-out border-black ' +
117
+ 'focus:border-black focus:shadow-outline-focus-input ' +
118
+ 'focus:ring-4 focus:ring-offset-0 focus:ring-warning-base ' +
119
+ 'disabled:bg-neutral-base disabled:border-neutral-base text-primary-base' +
120
+ ((item.isIndeterminate && item.indeterminateChecked)
121
+ ? ' c-checkboxes__indeterminate-active'
122
+ : '') + '"' +
123
+ ' id="' + id + '-input"' +
124
+ ' name="' + name + '"' +
125
+ (type === 'checkbox' ? ' type="checkbox" role="checkbox"' : ' type="radio"') +
126
+ ' value="' + (item.value || '') + '"' +
127
+ (item.checked ? ' checked' : '') +
128
+ (item.disabled ? ' disabled' : '') +
129
+ (itemDescribed ? ' aria-describedby="' + itemDescribed + '"' : '') +
130
+ (params.errorMessage ? ' aria-invalid="true"' : '');
131
+
132
+ if (item.isIndeterminate || item.indeterminateChecked) {
133
+ html += ' onclick="' +
134
+ "if (this.readOnly) this.checked=this.readOnly=false; " +
135
+ "else if (!this.checked) this.readOnly=this.indeterminate=true;" +
136
+ '"';
59
137
  }
138
+ html += '>' +
139
+ '</div>' + // cierre flex items-center
140
+ '<div class="flex-1 pt-0.5 leading-5">';
141
+
142
+ // Label
143
+ var lblCls = (item.label && item.label.classes)
144
+ ? item.label.classes
145
+ : 'block relative -top-xs -left-8 pl-8 py-xs';
146
+ html += '<label for="' + id + '-input" class="' + lblCls + '">';
147
+ html += item.html ? item.html : (item.text || '');
148
+ html += '</label>';
149
+
150
+ // Hint
151
+ if (hasHint) {
152
+ html += '<div id="' + itemHintId + '"' +
153
+ (item.hint.classes ? ' class="' + item.hint.classes + '"' : '') +
154
+ '>';
155
+ html += item.hint.html || item.hint.text;
156
+ html += '</div>';
157
+ }
158
+ html += '</div>'; // cierre flex-1
60
159
  }
61
160
 
62
- // initialize pop up menus
63
- if (!this.domNode.getAttribute('role')) {
64
- this.domNode.setAttribute('role', 'tree');
161
+ // Navigation branch
162
+ if (type === 'navigation') {
163
+ if (item.href) {
164
+ html += '<a' +
165
+ (id ? ' id="' + id + '-link"' : '') +
166
+ ' href="' + item.href + '"' +
167
+ ' class="block px-xs focus:bg-warning-base focus:outline-none ' +
168
+ 'focus:shadow-outline-focus focus:text-black' +
169
+ (item.classes ? ' ' + item.classes : '') +
170
+ (!item.disabled ? ' hover:text-primary-base hover:underline'
171
+ : ' no-underline pointer-events-none') + '"' +
172
+ (item.title ? ' title="' + item.title + '"' : '') +
173
+ (item.active ? ' aria-current="page"' : '') +
174
+ (item.disabled ? ' aria-disabled="true" tabindex="-1"' : '') +
175
+ (item.target ? ' target="' + item.target + '"' : '') +
176
+ '>';
177
+ html += item.active
178
+ ? '<strong class="font-bold">' +
179
+ (item.html || item.text) +
180
+ '</strong>'
181
+ : (item.html || item.text);
182
+ html += '</a>';
183
+ } else {
184
+ html += '<span' +
185
+ (id ? ' id="' + id + '-link"' : '') +
186
+ ' class="block px-xs' +
187
+ (item.classes ? ' ' + item.classes : '') + '"' +
188
+ (item.title ? ' title="' + item.title + '"' : '') +
189
+ '>';
190
+ html += item.active
191
+ ? '<strong class="font-bold">' +
192
+ (item.html || item.text) +
193
+ '</strong>'
194
+ : (item.html || item.text);
195
+ html += '</span>';
196
+ }
65
197
  }
66
198
 
67
- findTreeitems(this.domNode, this, false);
199
+ html += '</div></div>';
200
+ return html;
201
+ }
68
202
 
69
- this.updateVisibleTreeitems();
203
+ aria.Tree.prototype.childrenTree = function (itemNode, id, name, type, lazyRendering, onlySub, params, describedBy, hasFieldset) {
204
+ var html = '';
205
+
206
+ if (!onlySub) {
207
+ if (itemNode.sub) {
208
+ html += '<div class="w-full h-full">' +
209
+ '<div class="flex items-center relative ' +
210
+ 'focus:bg-warning-base focus:outline-none ' +
211
+ 'focus:shadow-outline-focus focus:text-black text-left' +
212
+ (itemNode.classes ? ' ' + itemNode.classes : '') + '"';
213
+ for (var a in itemNode.attributes || {}) {
214
+ html += ' ' + a + '="' + itemNode.attributes[a] + '"';
215
+ }
216
+ html += '>' +
217
+ '<span class="c-tree__icon absolute top-3 -left-4 flex items-center ' +
218
+ 'w-4 h-2.5 text-primary-base font-bold ' +
219
+ "after:content-[''] after:absolute after:-left-2 after:p-4\">" +
220
+ '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 10 10" ' +
221
+ 'width="10" height="10" aria-hidden="true" ' +
222
+ 'class="c-tree__minus">' +
223
+ '<path fill="currentColor" d="M9.286 5.714H.714a.714.714 0 010-1.428h8.572a.714.714 0 010 1.428z"/>' +
224
+ '</svg>' +
225
+ '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 10 10" ' +
226
+ 'width="10" height="10" aria-hidden="true" ' +
227
+ 'class="c-tree__plus">' +
228
+ '<path fill="currentColor" d="M9.286 4.286H5.893a.179.179 0 01-.179-.179V.714a.714.714 0 00-1.428 0v3.393a.179.179 0 01-.179.179H.714a.714.714 0 000 1.428h3.393a.179.179 0 01.179.179v3.393a.714.714 0 001.428 0V5.893a.179.179 0 01.179-.179h3.393a.714.714 0 000-1.428z"/>' +
229
+ '</svg>' +
230
+ '</span>' +
231
+ checkboxItem(itemNode, id, name, type, params, describedBy, hasFieldset) +
232
+ '</div>' +
233
+ '</div>';
234
+ } else {
235
+ html += checkboxItem(itemNode, id, name, type, params, describedBy, hasFieldset);
236
+ }
237
+ }
70
238
 
71
- this.firstTreeitem.domNode.tabIndex = 0;
239
+ if (itemNode.sub && itemNode.sub.items) {
240
+ html += '<ul role="group" class="c-tree__itemgroup' +
241
+ (itemNode.sub.classes ? ' ' + itemNode.sub.classes : '') + '"';
242
+ for (var b in itemNode.sub.attributes || {}) {
243
+ html += ' ' + b + '="' + itemNode.sub.attributes[b] + '"';
244
+ }
245
+ html += '>';
246
+
247
+ if (!lazyRendering || onlySub) {
248
+ var subLevel = 'sub-';
249
+ itemNode.sub.items.forEach((subitem, idx) => {
250
+ if (!subitem) return;
251
+ var subId = subitem.id
252
+ ? subitem.id
253
+ : subLevel + id + '-' + idx;
254
+ var clsBase = (type === 'navigation')
255
+ ? 'c-tree__item ml-5 my-sm origin-top-left focus:outline-none'
256
+ : 'c-tree__item ml-8 origin-top-left focus:outline-none';
257
+ var expanded = subitem.sub
258
+ ? ' aria-expanded="' + (subitem.expanded ? 'true' : 'false') + '"'
259
+ : '';
260
+
261
+ html += '<li class="' + clsBase + '" ' +
262
+ 'id="' + subId + '" ' +
263
+ 'role="treeitem" ' +
264
+ 'data-module="c-tree__item"' +
265
+ expanded +
266
+ '>';
267
+
268
+ if (subitem.sub) {
269
+ html += this.childrenTree(
270
+ subitem,
271
+ subId,
272
+ name,
273
+ type,
274
+ lazyRendering,
275
+ false,
276
+ params,
277
+ describedBy,
278
+ hasFieldset
279
+ );
280
+ } else {
281
+ html += '<div class="block' +
282
+ (subitem.classes ? ' ' + subitem.classes : '') +
283
+ (subitem.active ? ' font-bold' : '') +
284
+ '"' +
285
+ (subitem.title ? ' title="' + subitem.title + '"' : '') +
286
+ (subitem.active ? ' aria-current="page"' : '') +
287
+ '>';
288
+ if (subitem.active) {
289
+ html += '<div class="font-bold">' +
290
+ checkboxItem(subitem, subId, name, type, params, describedBy, hasFieldset) +
291
+ '</div>';
292
+ } else {
293
+ html += checkboxItem(subitem, subId, name, type, params, describedBy, hasFieldset);
294
+ }
295
+ html += '</div>';
296
+ }
297
+
298
+ html += '</li>';
299
+ });
300
+ }
72
301
 
73
- };
302
+ html += '</ul>';
303
+ }
304
+
305
+ return html;
306
+ }
74
307
 
75
308
  aria.Tree.prototype.setFocusToItem = function (treeitem) {
76
309
 
@@ -80,8 +313,12 @@ export function Tree(aria) {
80
313
  if (ti === treeitem) {
81
314
  ti.domNode.tabIndex = 0;
82
315
  ti.domNode.focus();
83
- }
84
- else {
316
+
317
+ var input = ti.domNode.querySelector('input');
318
+ if (input) {
319
+ ti.domNode.setAttribute('aria-checked', input.checked ? 'true' : 'false');
320
+ }
321
+ } else {
85
322
  ti.domNode.tabIndex = -1;
86
323
  }
87
324
  }
@@ -145,7 +382,58 @@ export function Tree(aria) {
145
382
  aria.Tree.prototype.expandTreeitem = function (currentItem) {
146
383
 
147
384
  if (currentItem.isExpandable) {
148
- currentItem.domNode.setAttribute('aria-expanded', true);
385
+ var node = currentItem.domNode;
386
+ node.setAttribute('aria-expanded', 'true');
387
+
388
+ if (this.lazyRendering && !node.dataset.childrenInjected) {
389
+
390
+ function findNodeById(data, targetId, parentId = '') {
391
+ for (let i = 0; i < data.length; i++) {
392
+ const item = data[i];
393
+
394
+ const currentId = item.id || (parentId ? 'sub-' + parentId + '-' + i : i);
395
+
396
+ if (currentId === targetId) {
397
+ return item;
398
+ }
399
+
400
+ if (item.sub?.items?.length) {
401
+ const result = findNodeById(item.sub.items, targetId, currentId);
402
+ if (result) return result;
403
+ }
404
+ }
405
+
406
+ return null;
407
+ }
408
+
409
+ var itemNode = findNodeById(this.treeData || [], node.id);
410
+
411
+ if (itemNode && itemNode.sub && itemNode.sub.items && itemNode.sub.items.length) {
412
+ var group = node.querySelector('ul[role="group"]');
413
+
414
+ var html = this.childrenTree(
415
+ itemNode,
416
+ node.id,
417
+ this.params.name,
418
+ this.params.type,
419
+ this.lazyRendering,
420
+ true,
421
+ this.params,
422
+ this.describedBy,
423
+ this.hasFieldset
424
+ );
425
+ var listItems = html
426
+ .replace(/^<ul[^>]*>/, '')
427
+ .replace(/<\/ul>$/, '');
428
+ group.insertAdjacentHTML('beforeend', listItems);
429
+ node.dataset.childrenInjected = 'true';
430
+ }
431
+ this.findTreeitems(this.domNode, this, currentItem);
432
+ // To sort because when add children dinnamically, the order is not guaranteed as should be.
433
+ this.treeitems.sort((a, b) => a.domNode.compareDocumentPosition(b.domNode) & Node.DOCUMENT_POSITION_FOLLOWING ? -1 : 1);
434
+ this.firstChars = this.treeitems.map(ti => ti.label.substring(0, 1).toLowerCase());
435
+ }
436
+
149
437
  this.updateVisibleTreeitems();
150
438
  }
151
439
 
@@ -171,9 +459,10 @@ export function Tree(aria) {
171
459
  } else {
172
460
  groupTreeitem = currentItem.groupTreeitem;
173
461
  }
174
-
175
462
  if (groupTreeitem) {
176
- groupTreeitem.domNode.setAttribute('aria-expanded', false);
463
+ var node = groupTreeitem.domNode;
464
+ node.setAttribute('aria-expanded', false);
465
+
177
466
  this.updateVisibleTreeitems();
178
467
  this.setFocusToItem(groupTreeitem);
179
468
  }