@markout-lang/bootstrap-kit 0.2.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.
@@ -0,0 +1,44 @@
1
+ <lib>
2
+ <:import src="base.htm" />
3
+
4
+ <!---
5
+ The first of the kit's list-driven components. Where a component repeats
6
+ one shape over a list, its API is an array rather than a slot: the caller
7
+ describes the entries, the component owns the markup.
8
+
9
+ An entry is `{ name, link }`. The one without a `link` is the current
10
+ page, and gets `active` plus `aria-current` — the `<a>` stays in place
11
+ either way, since an anchor without an `href` renders as plain text.
12
+ -->
13
+ <:define tag="bs-breadcrumb:nav"
14
+ aria-label="breadcrumb"
15
+ class=${extra}
16
+
17
+ // parameters
18
+ :extra=${null} // extra classes for this instance
19
+ :items=${[
20
+ { name: 'Home', link: '#' },
21
+ { name: 'Library', link: '#' },
22
+ { name: 'Data' },
23
+ ]}
24
+ :divider=${null}
25
+
26
+ /*
27
+ Bootstrap reads the separator from a CSS custom property, and
28
+ `:style-` writes ordinary CSS properties — so this one goes
29
+ through the plain `style` attribute.
30
+ */
31
+ style=${divider ? `--bs-breadcrumb-divider: '${divider}'` : null}
32
+ >
33
+ <ol class="breadcrumb mb-0">
34
+ <li class="breadcrumb-item"
35
+ :for-each=${items}
36
+ :for-as="item"
37
+ :class-active=${!item.link}
38
+ aria-current=${item.link ? null : 'page'}>
39
+ <a href=${item.link ?? null}>${item.name}</a>
40
+ </li>
41
+ </ol>
42
+ </:define>
43
+
44
+ </lib>
@@ -0,0 +1,162 @@
1
+ <lib>
2
+ <:import src="base.htm" />
3
+
4
+ <!---
5
+ Bootstrap's button, as a real `<button>`.
6
+
7
+ `:toggle`/`:target`/`:dismiss` write the `data-bs-*` triplet every
8
+ JS-driven component in this kit is opened and closed by, so a trigger for
9
+ a modal, an offcanvas or a collapse is this same tag rather than a
10
+ component of its own:
11
+
12
+ <bs-button :toggle="modal" :target="#signup">Sign up</bs-button>
13
+ <bs-button :dismiss="modal" :variant="secondary">Close</bs-button>
14
+
15
+ Note the two spellings of "conditional attribute" used throughout the kit:
16
+ a plain `name=${expr}` sets a VALUE and removes the attribute when the
17
+ expression is `null`, while `:attr-name=${expr}` toggles PRESENCE, which
18
+ is what `disabled` and friends need.
19
+ -->
20
+ <:define tag="bs-button:button"
21
+
22
+ // parameters
23
+ :extra=${null} // extra classes for this instance
24
+ :variant=${'primary'}
25
+ :outline=${false}
26
+ :size=${null}
27
+ :active=${false}
28
+ :disabled=${false}
29
+ :type=${'button'}
30
+ :toggle=${null}
31
+ :target=${null}
32
+ :dismiss=${null}
33
+
34
+ // private
35
+ :_class=${[
36
+ 'btn',
37
+ variant ? `btn-${outline ? 'outline-' : ''}${variant}` : '',
38
+ size ? `btn-${size}` : '',
39
+ extra,
40
+ ].filter(s => s).join(' ')}
41
+
42
+ class=${_class}
43
+ type=${type}
44
+ :class-active=${active}
45
+ :attr-disabled=${disabled}
46
+ aria-pressed=${active ? 'true' : null}
47
+ data-bs-toggle=${toggle}
48
+ data-bs-target=${target}
49
+ data-bs-dismiss=${dismiss}
50
+ >
51
+ <:slot />
52
+ </:define>
53
+
54
+ <!---
55
+ The same styling on an `<a>`, for a link that is meant to look like a
56
+ button. Left as it is, it is an ordinary link; `:button` turns it into
57
+ one, and `:variant` then means what it means on `bs-button`.
58
+ -->
59
+ <:define tag="bs-link:a"
60
+
61
+ // parameters
62
+ :extra=${null} // extra classes for this instance
63
+ :href=${'#'}
64
+ :variant=${null}
65
+ :outline=${false}
66
+ :size=${null}
67
+ :active=${false}
68
+ :disabled=${false}
69
+ :button=${false}
70
+ :toggle=${null}
71
+ :target=${null}
72
+
73
+ // private
74
+ :_class=${[
75
+ button ? 'btn' : '',
76
+ button && variant ? `btn-${outline ? 'outline-' : ''}${variant}` : '',
77
+ button && size ? `btn-${size}` : '',
78
+ !button && variant ? `link-${variant}` : '',
79
+ extra,
80
+ ].filter(s => s).join(' ') || null}
81
+
82
+ class=${_class}
83
+ href=${href}
84
+ role=${button ? 'button' : null}
85
+ :class-active=${active}
86
+ :class-disabled=${disabled}
87
+ aria-disabled=${disabled ? 'true' : null}
88
+ data-bs-toggle=${toggle}
89
+ data-bs-target=${target}
90
+ >
91
+ <:slot />
92
+ </:define>
93
+
94
+ <!---
95
+ A button group. `:label` is Bootstrap's requirement, not this kit's: the
96
+ group needs an accessible name of its own, since the buttons inside only
97
+ name themselves.
98
+ -->
99
+ <:define tag="bs-button-group:div"
100
+
101
+ // parameters
102
+ :extra=${null} // extra classes for this instance
103
+ :label=${'Button group'}
104
+ :size=${null}
105
+ :vertical=${false}
106
+
107
+ // private
108
+ :_class=${[
109
+ vertical ? 'btn-group-vertical' : 'btn-group',
110
+ size ? `btn-group-${size}` : '',
111
+ extra,
112
+ ].filter(s => s).join(' ')}
113
+
114
+ class=${_class}
115
+ role="group"
116
+ aria-label=${label}
117
+ >
118
+ <:slot />
119
+ </:define>
120
+
121
+ <!---
122
+ A toolbar of groups: Bootstrap spaces groups apart differently to the
123
+ buttons inside one, and this is the wrapper that says so.
124
+ -->
125
+ <:define tag="bs-button-toolbar:div"
126
+ class="btn-toolbar ${extra ?? ''}"
127
+ role="toolbar"
128
+
129
+ // parameters
130
+ :extra=${null} // extra classes for this instance
131
+ :label=${'Toolbar'}
132
+ :gap=${2}
133
+
134
+ aria-label=${label}
135
+ :class-gap-1=${gap === 1}
136
+ :class-gap-2=${gap === 2}
137
+ :class-gap-3=${gap === 3}
138
+ >
139
+ <:slot />
140
+ </:define>
141
+
142
+ <!---
143
+ The dismiss "×". Nothing but `class="btn-close"`, but it carries an
144
+ accessible name and the dismissal target, both of which are easy to leave
145
+ off when writing it by hand.
146
+ -->
147
+ <:define tag="bs-close:button"
148
+ type="button"
149
+ class="btn-close ${extra ?? ''}"
150
+
151
+ // parameters
152
+ :extra=${null} // extra classes for this instance
153
+ :label=${'Close'}
154
+ :dismiss=${null}
155
+ :disabled=${false}
156
+
157
+ aria-label=${label}
158
+ :attr-disabled=${disabled}
159
+ data-bs-dismiss=${dismiss}
160
+ />
161
+
162
+ </lib>
package/parts/card.htm ADDED
@@ -0,0 +1,103 @@
1
+ <lib>
2
+ <:import src="base.htm" />
3
+
4
+ <!---
5
+ A card: parameters for the chrome, the slot for the content. Every region
6
+ other than the body is optional and only appears when its parameter is
7
+ given, which is the kit's general shape — a caller writes what the card
8
+ HAS, not the markup that produces it.
9
+
10
+ <bs-card :title="Card title" :footer="2 days ago">
11
+ <p class="card-text">Some quick example text.</p>
12
+ </bs-card>
13
+
14
+ The body is the one region a caller cannot reach with `:extra`, which
15
+ goes on the card itself -- hence `:bodyExtra`, for the padding Bootstrap
16
+ leaves to a utility class: `p-0` for a table or a code surface that runs
17
+ to the edges, `p-4` for a card that is mostly one paragraph.
18
+ -->
19
+ <:define tag="bs-card:div"
20
+
21
+ // parameters
22
+ :extra=${null} // extra classes for this instance
23
+ :bodyExtra=${null} // extra classes for the body: `p-0`, `p-4`, `d-flex`
24
+ :title=${null}
25
+ :subtitle=${null}
26
+ :header=${null}
27
+ :footer=${null}
28
+ :image=${null}
29
+ :imageAlt=${''}
30
+ :imageBottom=${false}
31
+ :variant=${null} // colours the whole card, e.g. 'primary'
32
+ :border=${null} // colours only the border
33
+ :align=${null} // 'center' | 'end'
34
+
35
+ // private
36
+ :_class=${[
37
+ 'card',
38
+ variant ? `text-bg-${variant}` : '',
39
+ border ? `border-${border}` : '',
40
+ align ? `text-${align}` : '',
41
+ extra,
42
+ ].filter(s => s).join(' ')}
43
+
44
+ class=${_class}
45
+ >
46
+ <img class="card-img-top"
47
+ :if=${image && !imageBottom}
48
+ src=${image}
49
+ alt=${imageAlt}>
50
+
51
+ <!---
52
+ A named slot inside an optional region: the header appears only when
53
+ there is one, and a caller can put markup in it rather than a string.
54
+ Both halves had to be built for this: a `<:slot>` cannot sit inside a
55
+ `:for-each`, and filling one nested inside a component's own scope used
56
+ to leave the fallback's binding pointing at markup that was gone.
57
+ -->
58
+ <div class="card-header"
59
+ :if=${header}><:slot name="header">${header}</:slot></div>
60
+
61
+ <div class=${bodyExtra ? `card-body ${bodyExtra}` : 'card-body'}>
62
+ <h5 class="card-title"
63
+ :if=${title}>${title}</h5>
64
+
65
+ <h6 class="card-subtitle mb-2 text-body-secondary"
66
+ :if=${subtitle}>${subtitle}</h6>
67
+
68
+ <:slot />
69
+ </div>
70
+
71
+ <div class="card-footer text-body-secondary"
72
+ :if=${footer}>${footer}</div>
73
+
74
+ <img class="card-img-bottom"
75
+ :if=${image && imageBottom}
76
+ src=${image}
77
+ alt=${imageAlt}>
78
+ </:define>
79
+
80
+ <!---
81
+ Equal-height, equal-width cards in a grid. Bootstrap wants the row
82
+ classes on a wrapper; this is that wrapper, named.
83
+ -->
84
+ <:define tag="bs-card-group:div"
85
+
86
+ // parameters
87
+ :extra=${null} // extra classes for this instance
88
+ :cols=${3}
89
+ :gap=${4}
90
+ :attached=${false} // a seamless strip instead of separate cards
91
+
92
+ // private
93
+ :_class=${attached
94
+ ? 'card-group'
95
+ : `row row-cols-1 row-cols-md-${cols} g-${gap}`}
96
+ :_groupClass=${extra ? `${_class} ${extra}` : _class}
97
+
98
+ class=${_groupClass}
99
+ >
100
+ <:slot />
101
+ </:define>
102
+
103
+ </lib>
@@ -0,0 +1,87 @@
1
+ <lib>
2
+ <:import src="base.htm" />
3
+
4
+ <!---
5
+ A carousel from an array of slides. A slide is
6
+ `{ image, alt, title, text }`.
7
+
8
+ Controls and indicators both have to point at the carousel's id, which is
9
+ derived from `$id` — three places that have to agree, and the reason this
10
+ is worth a component at all.
11
+ -->
12
+ <:define tag="bs-carousel:div"
13
+ class="carousel slide ${extra ?? ''}"
14
+
15
+ // parameters
16
+ :extra=${null} // extra classes for this instance
17
+ :slides=${[]}
18
+ :controls=${true}
19
+ :indicators=${true}
20
+ :captions=${true}
21
+ :fade=${false}
22
+ :ride=${true}
23
+ :interval=${5000}
24
+ :dark=${false}
25
+
26
+ // private
27
+ :_id=${`bs-carousel-${$id}`}
28
+ :_selector=${`#bs-carousel-${$id}`}
29
+ /*
30
+ the position is needed three times per slide and `:for-each`
31
+ binds the item, not its index, so it is carried on the item
32
+ */
33
+ :_slides=${slides.map((slide, i) => ({ ...slide, index: i }))}
34
+
35
+ id=${_id}
36
+ :class-carousel-fade=${fade}
37
+ data-bs-ride=${ride ? 'carousel' : null}
38
+ data-bs-interval=${interval}
39
+ data-bs-theme=${dark ? 'dark' : null}
40
+ >
41
+ <div class="carousel-indicators" :if=${indicators}>
42
+ <button type="button"
43
+ :for-each=${_slides}
44
+ :for-as="slide"
45
+ data-bs-target=${_selector}
46
+ data-bs-slide-to=${slide.index}
47
+ :class-active=${slide.index === 0}
48
+ aria-current=${slide.index === 0 ? 'true' : null}
49
+ aria-label="Slide ${slide.index + 1}"></button>
50
+ </div>
51
+
52
+ <div class="carousel-inner">
53
+ <div class="carousel-item"
54
+ :for-each=${_slides}
55
+ :for-as="slide"
56
+ :class-active=${slide.index === 0}>
57
+ <img class="d-block w-100"
58
+ src=${slide.image}
59
+ alt=${slide.alt ?? ''}>
60
+ <div class="carousel-caption d-none d-md-block"
61
+ :if=${captions && (slide.title || slide.text)}>
62
+ <h5 :if=${slide.title}>${slide.title}</h5>
63
+ <p :if=${slide.text}>${slide.text}</p>
64
+ </div>
65
+ </div>
66
+ </div>
67
+
68
+ <button class="carousel-control-prev"
69
+ type="button"
70
+ :if=${controls}
71
+ data-bs-target=${_selector}
72
+ data-bs-slide="prev">
73
+ <span class="carousel-control-prev-icon" aria-hidden="true"></span>
74
+ <span class="visually-hidden">Previous</span>
75
+ </button>
76
+
77
+ <button class="carousel-control-next"
78
+ type="button"
79
+ :if=${controls}
80
+ data-bs-target=${_selector}
81
+ data-bs-slide="next">
82
+ <span class="carousel-control-next-icon" aria-hidden="true"></span>
83
+ <span class="visually-hidden">Next</span>
84
+ </button>
85
+ </:define>
86
+
87
+ </lib>
@@ -0,0 +1,164 @@
1
+ <lib>
2
+ <:import src="base.htm" />
3
+
4
+ <!---
5
+ Checkbox, radio and switch are one component: in Bootstrap a switch IS a
6
+ checkbox with `.form-switch` on the wrapper, and a radio differs only by
7
+ `type`. `:type` picks between them.
8
+
9
+ A group of radios shares one `:name`, as it does in plain HTML — that is
10
+ what makes them exclusive, and the kit doesn't hide it.
11
+ -->
12
+ <:define tag="bs-check:div"
13
+
14
+ // parameters
15
+ :extra=${null} // extra classes for this instance
16
+ :label=${null}
17
+ :type=${'checkbox'} // 'checkbox' | 'radio' | 'switch'
18
+ :name=${null}
19
+ :value=${null}
20
+ :checked=${false}
21
+ :inline=${false}
22
+ :reverse=${false}
23
+ :disabled=${false}
24
+ :help=${null}
25
+
26
+ // private
27
+ :_id=${`bs-check-${$id}`}
28
+ :_helpId=${`bs-check-help-${$id}`}
29
+ :_type=${type === 'switch' ? 'checkbox' : type}
30
+
31
+ class="form-check ${extra ?? ''}"
32
+ :class-form-switch=${type === 'switch'}
33
+ :class-form-check-inline=${inline}
34
+ :class-form-check-reverse=${reverse}
35
+ >
36
+ <input class="form-check-input"
37
+ id=${_id}
38
+ type=${_type}
39
+ name=${name}
40
+ value=${value}
41
+ role=${type === 'switch' ? 'switch' : null}
42
+ aria-describedby=${help ? _helpId : null}
43
+ :attr-checked=${checked}
44
+ :attr-disabled=${disabled}
45
+ :on-change=${ev => checked = ev.target.checked}>
46
+
47
+ <label class="form-check-label"
48
+ for=${_id}>${label}</label>
49
+
50
+ <div class="form-text"
51
+ id=${_helpId}
52
+ :if=${help}>${help}</div>
53
+ </:define>
54
+
55
+ <!---
56
+ A whole group of radios or checkboxes from one array, sharing a name and
57
+ reporting the selection back through `:value`. Entries are strings or
58
+ `{ name, value, disabled }`, as in `bs-select`.
59
+ -->
60
+ <:define tag="bs-check-group:div"
61
+ class="mb-3 ${extra ?? ''}"
62
+ role="group"
63
+
64
+ // parameters
65
+ :extra=${null} // extra classes for this instance
66
+ :legend=${null}
67
+ :type=${'radio'}
68
+ :options=${[]}
69
+ :value=${null}
70
+ :inline=${false}
71
+ :disabled=${false}
72
+
73
+ // private
74
+ :_name=${`bs-check-group-${$id}`}
75
+ :_legendId=${`bs-check-group-legend-${$id}`}
76
+
77
+ aria-labelledby=${legend ? _legendId : null}
78
+ :_options=${options.map(o =>
79
+ typeof o === 'object' && o !== null
80
+ ? { name: o.name, value: o.value ?? o.name, disabled: !!o.disabled }
81
+ : { name: o, value: o, disabled: false })}
82
+ >
83
+ <!---
84
+ A `<div>` rather than `<fieldset>`/`<legend>`: Bootstrap floats a
85
+ legend, and a floated check input beside it wraps up onto the same
86
+ line. `role="group"` plus `aria-labelledby` says the same thing to a
87
+ screen reader without the float.
88
+ -->
89
+ <div class="form-label fs-6"
90
+ id=${_legendId}
91
+ :if=${legend}>${legend}</div>
92
+
93
+ <div class="form-check"
94
+ :for-each=${_options}
95
+ :for-as="option"
96
+ :class-form-switch=${type === 'switch'}
97
+ :class-form-check-inline=${inline}>
98
+ <input class="form-check-input"
99
+ id="${_name}-${option.value}"
100
+ type=${type === 'switch' ? 'checkbox' : type}
101
+ name=${_name}
102
+ value=${option.value}
103
+ :attr-checked=${option.value === value}
104
+ :attr-disabled=${disabled || option.disabled}
105
+ :on-change=${ev => value = ev.target.value}>
106
+ <label class="form-check-label"
107
+ for="${_name}-${option.value}">${option.name}</label>
108
+ </div>
109
+ </:define>
110
+
111
+ <!--- A range slider, with its label and its current value. -->
112
+ <:define tag="bs-range:div"
113
+ class="mb-3 ${extra ?? ''}"
114
+
115
+ // parameters
116
+ :extra=${null} // extra classes for this instance
117
+ :label=${null}
118
+ :name=${null}
119
+ :min=${0}
120
+ :max=${100}
121
+ :step=${1}
122
+ :value=${50}
123
+ :disabled=${false}
124
+ :showValue=${false}
125
+
126
+ // private
127
+ :_id=${`bs-range-${$id}`}
128
+ >
129
+ <!---
130
+ The label row, which either half can be alone in: `:showValue` with no
131
+ `:label` used to render nothing at all, since the row was gated on the
132
+ label.
133
+
134
+ A row rather than a `<label>` wrapping both, so the readout stays out
135
+ of the accessible name -- a label whose text is "50" is worse than no
136
+ label, and the range input announces its own value anyway. The
137
+ readout keeps its place at the right when it is the only thing here --
138
+ by swapping the justification rather than adding to it, since
139
+ Bootstrap emits `justify-content-end` before `justify-content-between`
140
+ and the two together leave `between` winning.
141
+ -->
142
+ <div class="form-label d-flex"
143
+ :class-justify-content-between=${label}
144
+ :class-justify-content-end=${!label}
145
+ :if=${label || showValue}>
146
+ <label for=${_id}
147
+ :if=${label}>${label}</label>
148
+ <span class="text-body-secondary"
149
+ :if=${showValue}>${value}</span>
150
+ </div>
151
+
152
+ <input class="form-range"
153
+ id=${_id}
154
+ type="range"
155
+ name=${name}
156
+ min=${min}
157
+ max=${max}
158
+ step=${step}
159
+ value=${value}
160
+ :attr-disabled=${disabled}
161
+ :on-input=${ev => value = Number(ev.target.value)}>
162
+ </:define>
163
+
164
+ </lib>
@@ -0,0 +1,31 @@
1
+ <lib>
2
+ <:import src="base.htm" />
3
+
4
+ <!---
5
+ A collapsible region. The trigger is deliberately not part of it —
6
+ anything can open a collapse, and often several things do — so the region
7
+ takes a `:name` and a `bs-button` points at it:
8
+
9
+ <bs-button :toggle="collapse" :target="#details">Details</bs-button>
10
+ <bs-collapse :name="details">…</bs-collapse>
11
+
12
+ `:horizontal` collapses width instead of height, in which case Bootstrap
13
+ needs the content to have a width of its own.
14
+ -->
15
+ <:define tag="bs-collapse:div"
16
+ class="collapse ${extra ?? ''}"
17
+
18
+ // parameters
19
+ :extra=${null} // extra classes for this instance
20
+ :name=${null}
21
+ :open=${false}
22
+ :horizontal=${false}
23
+
24
+ id=${name}
25
+ :class-show=${open}
26
+ :class-collapse-horizontal=${horizontal}
27
+ >
28
+ <:slot />
29
+ </:define>
30
+
31
+ </lib>
@@ -0,0 +1,86 @@
1
+ <lib>
2
+ <:import src="base.htm" />
3
+
4
+ <!---
5
+ A dropdown. Entries are `{ name, link, active, disabled, header, divider,
6
+ select }`; the three shapes Bootstrap draws differently — a divider, a
7
+ header, an item — are three optional regions over the same list.
8
+
9
+ The menu is tied to its toggle by `aria-labelledby`, and the id for that
10
+ comes from `$id`, which is unique per instance. That is the general
11
+ answer in this kit to "this widget needs an id": derive it, never ask the
12
+ caller for one, unless another component has to name it (see
13
+ `bs-accordion`).
14
+ -->
15
+ <:define tag="bs-dropdown:div"
16
+
17
+ // parameters
18
+ :extra=${null} // extra classes for this instance
19
+ :label=${'Dropdown'}
20
+ :items=${[
21
+ { name: 'Action', link: '#' },
22
+ { name: 'Another action', link: '#' },
23
+ { divider: true },
24
+ { name: 'Something else here', link: '#' },
25
+ ]}
26
+ :variant=${'primary'}
27
+ :outline=${false}
28
+ :size=${null}
29
+ :split=${false}
30
+ :direction=${'down'} // 'down' | 'up' | 'start' | 'end'
31
+ :align=${'start'} // 'start' | 'end'
32
+ :dark=${false}
33
+
34
+ // private
35
+ :_id=${`bs-dropdown-${$id}`}
36
+ :_class=${[direction === 'down' ? 'dropdown' : `drop${direction}`, extra]
37
+ .filter(s => s).join(' ')}
38
+ :_btnClass=${[
39
+ 'btn',
40
+ `btn-${outline ? 'outline-' : ''}${variant}`,
41
+ size ? `btn-${size}` : '',
42
+ ].filter(s => s).join(' ')}
43
+
44
+ class=${_class}
45
+ :class-btn-group=${split}
46
+ >
47
+ <!--- a split button keeps the label clickable on its own -->
48
+ <button type="button"
49
+ class=${_btnClass}
50
+ :if=${split}>${label}</button>
51
+
52
+ <button type="button"
53
+ id=${_id}
54
+ class=${_btnClass}
55
+ :class-dropdown-toggle
56
+ :class-dropdown-toggle-split=${split}
57
+ data-bs-toggle="dropdown"
58
+ aria-expanded="false">
59
+ <span :if=${!split}>${label}</span>
60
+ <span class="visually-hidden"
61
+ :else>Toggle dropdown</span>
62
+ </button>
63
+
64
+ <ul class="dropdown-menu"
65
+ :class-dropdown-menu-end=${align === 'end'}
66
+ data-bs-theme=${dark ? 'dark' : null}
67
+ aria-labelledby=${_id}>
68
+ <li :for-each=${items} :for-as="item">
69
+ <hr class="dropdown-divider"
70
+ :if=${item.divider}>
71
+
72
+ <h6 class="dropdown-header"
73
+ :else-if=${item.header}>${item.header}</h6>
74
+
75
+ <a class="dropdown-item"
76
+ :else
77
+ :class-active=${item.active}
78
+ :class-disabled=${item.disabled}
79
+ href=${item.link ?? null}
80
+ aria-current=${item.active ? 'true' : null}
81
+ :on-click=${() => item.select?.(item)}>${item.name}</a>
82
+ </li>
83
+ </ul>
84
+ </:define>
85
+
86
+ </lib>