desy-html 4.1.3 → 4.2.1

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/docs/index.html CHANGED
@@ -38,6 +38,18 @@
38
38
 
39
39
  <h2>Changelog (English)</h2>
40
40
  <p>What's new in the latest version of desy-html</p>
41
+ <h3>v.4.2.1</h3>
42
+ <ul class="text-sm">
43
+ <li>Minor fixes.</li>
44
+ </ul>
45
+ <h3>v.4.2.0</h3>
46
+ <ul class="text-sm">
47
+ <li>Checkboxes can be indeterminate at init.</li>
48
+ <li>Fixes in alert. Now it's read by screen readers.</li>
49
+ <li>Header now uses dropdowns.</li>
50
+ <li>Dropdowns, listboxes and tooltips now closes when loosing focus.</li>
51
+ <li>Minor improvements in documentation.</li>
52
+ </ul>
41
53
  <h3>v.4.1.3</h3>
42
54
  <ul class="text-sm">
43
55
  <li>Minor improvements.</li>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "desy-html",
3
- "version": "4.1.3",
3
+ "version": "4.2.1",
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
  "author": {
6
6
  "name": "Desy (SDA Servicios Digitales de Aragón)",
@@ -34,6 +34,26 @@ export function dropdownComponent(aria) {
34
34
  const buttonDropdown = modules[item].querySelector('[data-module = "c-dropdown-button"]');
35
35
  const tooltip = modules[item].querySelector('[data-module = "c-dropdown-tooltip"]');
36
36
  if(buttonDropdown && tooltip) {
37
+ const hideOnPopperBlur = {
38
+ /* https://atomiks.github.io/tippyjs/v6/plugins/#hideonpopperblur */
39
+ name: 'hideOnPopperBlur',
40
+ defaultValue: true,
41
+ fn(instance) {
42
+ return {
43
+ onCreate() {
44
+ instance.popper.addEventListener('focusout', (event) => {
45
+ if (
46
+ instance.props.hideOnPopperBlur &&
47
+ event.relatedTarget &&
48
+ !instance.popper.contains(event.relatedTarget)
49
+ ) {
50
+ instance.hide();
51
+ }
52
+ });
53
+ },
54
+ };
55
+ },
56
+ };
37
57
  const hideOnEsc = {
38
58
  /* https://atomiks.github.io/tippyjs/v6/plugins/#hideonesc */
39
59
  name: 'hideOnEsc',
@@ -68,7 +88,7 @@ export function dropdownComponent(aria) {
68
88
  arrow: false,
69
89
  offset: [0, -10],
70
90
  theme: '',
71
- plugins: [hideOnEsc],
91
+ plugins: [hideOnEsc,hideOnPopperBlur],
72
92
  role: false,
73
93
  aria: {
74
94
  content: 'auto'
@@ -96,7 +116,26 @@ export function listboxComponent(aria) {
96
116
 
97
117
  if(buttonListbox && tooltip) {
98
118
  const listbox = new aria.Listbox(list);
99
-
119
+ const hideOnPopperBlur = {
120
+ /* https://atomiks.github.io/tippyjs/v6/plugins/#hideonpopperblur */
121
+ name: 'hideOnPopperBlur',
122
+ defaultValue: true,
123
+ fn(instance) {
124
+ return {
125
+ onCreate() {
126
+ instance.popper.addEventListener('focusout', (event) => {
127
+ if (
128
+ instance.props.hideOnPopperBlur &&
129
+ event.relatedTarget &&
130
+ !instance.popper.contains(event.relatedTarget)
131
+ ) {
132
+ instance.hide();
133
+ }
134
+ });
135
+ },
136
+ };
137
+ },
138
+ };
100
139
  const hideOnEscOrEnter = {
101
140
  /* https://atomiks.github.io/tippyjs/v6/plugins/#hideonesc */
102
141
  name: 'hideOnEsc',
@@ -131,7 +170,7 @@ export function listboxComponent(aria) {
131
170
  arrow: false,
132
171
  offset: [0, -10],
133
172
  theme: '',
134
- plugins: [hideOnEscOrEnter],
173
+ plugins: [hideOnEscOrEnter,hideOnPopperBlur],
135
174
  role: false,
136
175
  aria: {
137
176
  content: 'auto'
@@ -210,6 +249,26 @@ export function tooltipComponent(aria) {
210
249
  const ariaContent = tooltipButton.matches('[data-type = "c-tooltip-button-complex"]') ? 'describedby' : 'labelledby';
211
250
  const tooltipTooltip = modules[item].querySelector('[data-module = "c-tooltip-tooltip"]');
212
251
  if(tooltipButton && tooltipTooltip) {
252
+ const hideOnPopperBlur = {
253
+ /* https://atomiks.github.io/tippyjs/v6/plugins/#hideonpopperblur */
254
+ name: 'hideOnPopperBlur',
255
+ defaultValue: true,
256
+ fn(instance) {
257
+ return {
258
+ onCreate() {
259
+ instance.popper.addEventListener('focusout', (event) => {
260
+ if (
261
+ instance.props.hideOnPopperBlur &&
262
+ event.relatedTarget &&
263
+ !instance.popper.contains(event.relatedTarget)
264
+ ) {
265
+ instance.hide();
266
+ }
267
+ });
268
+ },
269
+ };
270
+ },
271
+ };
213
272
  const hideOnEsc = {
214
273
  /* https://atomiks.github.io/tippyjs/v6/plugins/#hideonesc */
215
274
  name: 'hideOnEsc',
@@ -241,7 +300,7 @@ export function tooltipComponent(aria) {
241
300
  trigger: 'mouseenter focus',
242
301
  hideOnClick: false,
243
302
  theme: '',
244
- plugins: [hideOnEsc],
303
+ plugins: [hideOnEsc,hideOnPopperBlur],
245
304
  role: 'tooltip',
246
305
  aria: {
247
306
  content: ariaContent
@@ -5,12 +5,12 @@
5
5
  {{ componentButton(params.button) }}
6
6
  <div id="{{ params.id }}" {%- if params.classes %} class="{{ params.classes }}"{% endif %} {%- for attribute, value in params.attributes %} {{attribute}}="{{value}}"{% endfor %}>
7
7
  </div>
8
- <script type="text/template" id="{{ 'template-' + params.id }}">
8
+ <div class="hidden" id="{{ 'template-' + params.id }}">
9
9
  {% if caller %}
10
10
  {{ caller() }} {#- if statement allows usage of `call` to be optional -#}
11
11
  {% elseif params.caller %}
12
12
  {{ params.caller | safe }}
13
13
  {% endif %}
14
- </script>
14
+ </div>
15
15
  </div>
16
16
  <!-- /alert -->
@@ -609,5 +609,27 @@
609
609
  }
610
610
  ]
611
611
  }
612
+ },
613
+ {
614
+ "name": "indeterminate cheched",
615
+ "description": "isIndeterminate: true, indeterminateChecked: true",
616
+ "data": {
617
+ "idPrefix": "indeterminate-checked",
618
+ "name": "indeterminate-checked",
619
+ "classes": "c-checkboxes--sm",
620
+ "items": [
621
+ {
622
+ "value": "indeterminate-checked-item",
623
+ "text": "1 elemento seleccionado",
624
+ "isIndeterminate": true,
625
+ "indeterminateChecked": true,
626
+ "checked": false,
627
+ "classes": "-mt-base",
628
+ "label": {
629
+ "classes": "text-sm -mt-1"
630
+ }
631
+ }
632
+ ]
633
+ }
612
634
  }
613
635
  ] %}
@@ -70,17 +70,18 @@
70
70
  {% set itemHintId = id + "-item-hint" if hasHint else "" %}
71
71
  {% set itemDescribedBy = describedBy if not hasFieldset else "" %}
72
72
  {% set itemDescribedBy = (itemDescribedBy + " " + itemHintId) | trim %}
73
- <div x-data="{ isChecked: {% if not item.checked %}false{% else %}true{% endif %} }" class="{%- if params.hasDividers %} border-t border-b border-neutral-base -mb-px{% endif %} {%- if item.classes %} {{ item.classes }}{% endif %}">
73
+ <div x-data="{ isChecked: {% if not item.checked %}false{% else %}true{% endif %} }" {%- if item.indeterminateChecked %} x-init="$refs.inputCheck.indeterminate=$refs.inputCheck.readOnly=true"{% endif %} class="{%- if params.hasDividers %} border-t border-b border-neutral-base -mb-px{% endif %} {%- if item.classes %} {{ item.classes }}{% endif %}">
74
74
  <div class="relative flex items-start py-base">
75
75
  <div class="flex items-center mx-sm">
76
- <input x-model="isChecked" class="w-6 h-6 transition duration-150 ease-in-out border-black focus:border-black focus:shadow-outline-focus-input focus:ring-4 focus:ring-offset-0 focus:ring-warning-base disabled:bg-neutral-base disabled:border-neutral-base text-primary-base" id="{{ id }}" name="{{ name }}" type="checkbox" value="{{ item.value }}"
76
+ <input x-model="isChecked" x-ref="inputCheck" class="w-6 h-6 transition duration-150 ease-in-out border-black focus:border-black focus:shadow-outline-focus-input focus:ring-4 focus:ring-offset-0 focus:ring-warning-base disabled:bg-neutral-base disabled:border-neutral-base text-primary-base" id="{{ id }}" name="{{ name }}" type="checkbox" value="{{ item.value }}"
77
77
  {{-" checked" if item.checked }}
78
78
  {{-" disabled" if item.disabled }}
79
79
  {%- if item.conditional.html %} aria-controls="{{ conditionalId }}"{% endif -%}
80
80
  {%- if itemDescribedBy %} aria-describedby="{{ itemDescribedBy }}"{% endif -%}
81
81
  {%- if params.errorMessage %} aria-invalid="true"{% endif -%}
82
82
  {%- for attribute, value in item.attributes %} {{ attribute }}="{{ value }}"{% endfor -%}
83
- {%- if item.isIndeterminate %} onclick="if (this.readOnly) this.checked=this.readOnly=false; else if (!this.checked) this.readOnly=this.indeterminate=true;"{% endif %}>
83
+ {%- if item.isIndeterminate %} onclick="if (this.readOnly) this.checked=this.readOnly=false; else if (!this.checked) this.readOnly=this.indeterminate=true;"{% endif %}
84
+ {%- if item.indeterminateChecked %} onclick="if (this.readOnly) this.checked=this.readOnly=false; else if (!this.checked) this.readOnly=this.indeterminate=true;"{% endif %}>
84
85
  </div>
85
86
  <div class="pt-0.5 leading-5">
86
87
  {{ componentLabel({
@@ -74,6 +74,14 @@ params:
74
74
  type: boolean
75
75
  required: false
76
76
  description: If true, checkbox will be checked.
77
+ - name: isIndeterminate
78
+ type: boolean
79
+ required: false
80
+ description: If true, the checkbox will have an additional indeterminate state to show a partial true.
81
+ - name: indeterminateChecked
82
+ type: boolean
83
+ required: false
84
+ description: If true, the checkbox will have an indeterminate checked initial state. This will override isChecked value.
77
85
  - name: conditional
78
86
  type: boolean
79
87
  required: false
@@ -160,6 +160,7 @@
160
160
  @apply text-white;
161
161
 
162
162
  &:hover:not(disabled),
163
+ &:active:not(disabled),
163
164
  &.ds-hover:not(disabled) {
164
165
  @apply bg-black;
165
166
  @apply border-none;
@@ -1,23 +1,17 @@
1
+ {% from "components/dropdown/_macro.dropdown.njk" import componentDropdown %}
1
2
  <div class="ml-4 flex items-center lg:ml-6">
2
- <div x-data="{ isOpen: false }" class="ml-3 relative">
3
+ <div class="ml-3 relative">
3
4
  <div>
4
- <button id="header-dropdown-button" @click="isOpen = !isOpen" class="inline-flex items-center px-3 py-4 text-sm text-white focus:outline-none focus:ring-4 focus:ring-inset focus:ring-warning-base" aria-haspopup="true" x-bind:aria-expanded="String(isOpen)" x-on:keydown.escape="isOpen = false; document.getElementById('header-dropdown-button').focus();">
5
- <span class="inline-block align-middle text-right">{{ params.html | safe if params.html else params.text }}</span> <svg class="inline-block align-middle" viewBox="0 0 96 96" fill="currentColor" aria-hidden="true" focusable="false" width="1.5em" height="1.5em"><g><path d="M46.71 58.037a1.823 1.823 0 002.581 0L62.048 45.28a1.823 1.823 0 00-1.29-3.113H35.243a1.823 1.823 0 00-1.291 3.113z"/></g></svg>
6
- </button>
7
- </div>
8
- <div x-show="isOpen"
9
- x-transition:enter="transition ease-out duration-100 transform"
10
- x-transition:enter-start="opacity-0 scale-95"
11
- x-transition:enter-end="opacity-100 scale-100"
12
- x-transition:leave="transition ease-in duration-75 transform"
13
- x-transition:leave-start="opacity-100 scale-100"
14
- x-transition:leave-end="opacity-0 scale-95"
15
- @click.away="isOpen = false"
16
- x-on:keydown.escape="isOpen = false; document.getElementById('header-dropdown-button').focus();"
17
- class="origin-top-right absolute right-0 max-h-64 mt-2 border border-neutral-base overflow-y-auto shadow-md">
18
- <div class="bg-white shadow-xs">
19
- {{ caller() if caller }}
20
- </div>
5
+ {% call componentDropdown({
6
+ "text": params.html | safe if params.html else params.text,
7
+ "classes": "c-dropdown--header"
8
+ }) %}
9
+ {% if caller %}
10
+ {{ caller() }} {#- if statement allows usage of `call` to be optional -#}
11
+ {% elseif params.caller %}
12
+ {{ params.caller | safe }}
13
+ {% endif %}
14
+ {% endcall %}
21
15
  </div>
22
16
  </div>
23
17
  </div>
@@ -1,29 +1,21 @@
1
+ {% from "components/dropdown/_macro.dropdown.njk" import componentDropdown %}
2
+
3
+
1
4
  {% if params.items %}
2
5
  <div class="hidden lg:flex items-center">
3
- <div x-data="{ isOpen: false }" class="ml-3 relative">
4
- <h2 id="subnav-title">
5
- <button id="header-subnav-button" @click="isOpen = !isOpen" class="pr-2 pl-3 py-4 border-r border-l border-neutral-base text-sm text-white truncate focus:outline-none focus:ring-4 focus:ring-inset focus:ring-warning-base" aria-haspopup="true" x-bind:aria-expanded="String(isOpen)" x-on:keydown.escape="isOpen = false; document.getElementById('header-subnav-button').focus();">
6
- <span class="inline-block align-middle">{{ params.html | safe if params.html else params.text }}</span> <svg class="inline-block align-middle" viewBox="0 0 96 96" fill="currentColor" aria-hidden="true" focusable="false" width="1.5em" height="1.5em"><g><path d="M46.71 58.037a1.823 1.823 0 002.581 0L62.048 45.28a1.823 1.823 0 00-1.29-3.113H35.243a1.823 1.823 0 00-1.291 3.113z"/></g></svg>
7
- </button>
6
+ <div class="ml-3 py-2 relative border-r border-l border-neutral-base">
7
+ <h2 id="subnav-title" class="">
8
+ {% call componentDropdown({
9
+ "text": params.html | safe if params.html else params.text,
10
+ "classes": "c-dropdown--header"
11
+ }) %}
12
+ {% if caller %}
13
+ {{ caller() }} {#- if statement allows usage of `call` to be optional -#}
14
+ {% elseif params.caller %}
15
+ {{ params.caller | safe }}
16
+ {% endif %}
17
+ {% endcall %}
8
18
  </h2>
9
- <div x-show="isOpen"
10
- x-transition:enter="transition ease-out duration-100 transform"
11
- x-transition:enter-start="opacity-0 scale-95"
12
- x-transition:enter-end="opacity-100 scale-100"
13
- x-transition:leave="transition ease-in duration-75 transform"
14
- x-transition:leave-start="opacity-100 scale-100"
15
- x-transition:leave-end="opacity-0 scale-95"
16
- @click.away="isOpen = false"
17
- x-on:keydown.escape="isOpen = false; document.getElementById('header-subnav-button').focus();"
18
- class="origin-top-left absolute left-0 max-h-64 mt-2 border border-neutral-base overflow-y-auto shadow-md">
19
- <div class="bg-white shadow-xs">
20
- {% if caller %}
21
- {{ caller() }} {#- if statement allows usage of `call` to be optional -#}
22
- {% elseif params.caller %}
23
- {{ params.caller | safe }}
24
- {% endif %}
25
- </div>
26
- </div>
27
19
  </div>
28
20
  </div>
29
21
  {% else %}
@@ -336,6 +336,175 @@
336
336
  }
337
337
  }
338
338
  },
339
+ {
340
+ "name": "With one disabled parent item",
341
+ "data": {
342
+ "id": "with-disabled",
343
+ "idPrefix": "disabled-example",
344
+ "ariaLabel":"Menubar description",
345
+ "items": [
346
+ {
347
+ "text": "Menuitem",
348
+ "ariaLabel": "Menuitem",
349
+ "id": "menuitems-disabled-example-item-1-2",
350
+ "disabled": true,
351
+ "sub": {
352
+ "items": [
353
+ {
354
+ "role": "menuitem",
355
+ "text": "Subitem 1"
356
+ },
357
+ {
358
+ "role": "menuitem",
359
+ "text": "Subitem 2"
360
+ },
361
+ {
362
+ "role": "menuitem",
363
+ "text": "Subitem 3"
364
+ }
365
+ ],
366
+ "attributes": {
367
+ "aria-labelledby": "menuitems-disabled-example-item-1-2"
368
+ }
369
+ },
370
+ "classes": "mb-base mr-base"
371
+ },
372
+ {
373
+ "text": "Menuitemcheckbox",
374
+ "ariaLabel": "Menuitemcheckbox",
375
+ "id": "menuitems-disabled-example-item-2-2",
376
+ "classes": "mb-base mr-base",
377
+ "sub": {
378
+ "items": [
379
+ {
380
+ "role": "menuitemcheckbox",
381
+ "text": "Subitem 1"
382
+ },
383
+ {
384
+ "role": "menuitemcheckbox",
385
+ "text": "Subitem 2",
386
+ "checked": true
387
+ },
388
+ {
389
+ "role": "menuitemcheckbox",
390
+ "text": "Subitem 3"
391
+ }
392
+ ],
393
+ "attributes": {
394
+ "aria-labelledby": "menuitems-disabled-example-item-2-2"
395
+ }
396
+ }
397
+ },
398
+ {
399
+ "text": "Menuitemradio",
400
+ "ariaLabel": "Menuitemradio",
401
+ "id": "menuitems-disabled-example-item-3-2",
402
+ "sub": {
403
+ "items": [
404
+ {
405
+ "role": "group",
406
+ "text": "Group",
407
+ "items": [
408
+ {
409
+ "role": "menuitemradio",
410
+ "text": "Radio 1"
411
+ },
412
+ {
413
+ "role": "menuitemradio",
414
+ "text": "Radio 2",
415
+ "checked": true
416
+ },
417
+ {
418
+ "role": "menuitemradio",
419
+ "text": "Radio 3"
420
+ }
421
+ ]
422
+ }
423
+ ],
424
+ "attributes": {
425
+ "aria-labelledby": "menuitems-disabled-example-item-3-2"
426
+ }
427
+ },
428
+ "classes": "mb-base mr-base"
429
+ },
430
+ {
431
+ "text": "Mixed items",
432
+ "ariaLabel": "Mixeditems",
433
+ "id": "menuitems-disabled-example-item-4-2",
434
+ "sub": {
435
+ "items": [
436
+ {
437
+ "role": "group",
438
+ "ariaLabel": "Tamaño de letra",
439
+ "items": [
440
+ {
441
+ "role": "menuitem",
442
+ "text": "Tamaño mayor"
443
+ },
444
+ {
445
+ "role": "menuitem",
446
+ "text": "Tamaño menor"
447
+ }
448
+ ]
449
+ },
450
+ {
451
+ "role": "separator"
452
+ },
453
+ {
454
+ "role": "group",
455
+ "ariaLabel": "Estilo de letra",
456
+ "items": [
457
+ {
458
+ "role": "menuitemcheckbox",
459
+ "text": "Negritas"
460
+ },
461
+ {
462
+ "role": "menuitemcheckbox",
463
+ "text": "Itálicas"
464
+ }
465
+ ]
466
+ },
467
+ {
468
+ "role": "separator"
469
+ },
470
+ {
471
+ "role": "group",
472
+ "ariaLabel": "Estilo de texto",
473
+ "items": [
474
+ {
475
+ "role": "menuitemradio",
476
+ "text": "Ninguno"
477
+ },
478
+ {
479
+ "role": "menuitemradio",
480
+ "text": "Tachado"
481
+ },
482
+ {
483
+ "role": "menuitemradio",
484
+ "text": "Subrayado"
485
+ }
486
+ ]
487
+ }
488
+ ],
489
+ "attributes": {
490
+ "aria-labelledby": "menuitems-disabled-example-item-4-2"
491
+ }
492
+ },
493
+ "classes": "mb-base mr-base"
494
+ },
495
+ {
496
+ "text": "Menuitem solo",
497
+ "ariaLabel": "Menuitem solo",
498
+ "id": "menuitems-disabled-example-item-6-2",
499
+ "classes": "c-menubar__button--transparent mb-base mr-base",
500
+ "href": "#"
501
+ }
502
+ ],
503
+ "attributes": {
504
+ "aria-label": "Menubar description of use"
505
+ }
506
+ }
507
+ },
339
508
  {
340
509
  "name": "Small",
341
510
  "description": "Using modifier classes in items.",
@@ -56,6 +56,10 @@ params:
56
56
  type: text
57
57
  required: true
58
58
  description: aria-label for parent items. Should be similar as item text or item html text content.
59
+ - name: disabled
60
+ type: boolean
61
+ required: false
62
+ description: If disabled, the item will be disabled
59
63
  - name: sub
60
64
  type: boolean
61
65
  required: false