edu-webcomponents 1.30.1 → 1.31.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/CHANGELOG.md +9 -2
- package/README.md +66 -0
- package/demo/index.html +45 -0
- package/index.js +1 -0
- package/package.json +1 -1
- package/src/edu-badge/EduBadge.stories.js +171 -0
- package/src/edu-badge/index.js +1 -0
- package/src/edu-badge/src/EduBadge.js +164 -0
- package/src/edu-badge/test/EduBadge.test.js +20 -0
package/CHANGELOG.md
CHANGED
|
@@ -4,10 +4,17 @@ All notable changes to this project will be documented in this file. Dates are d
|
|
|
4
4
|
|
|
5
5
|
Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
|
|
6
6
|
|
|
7
|
+
#### [v1.31.0](https://github.com/eduardocruzpalacios/edu-webcomponents/compare/v1.30.1...v1.31.0)
|
|
8
|
+
|
|
9
|
+
- feat: add EduLabel component [`d8945dd`](https://github.com/eduardocruzpalacios/edu-webcomponents/commit/d8945dd56f839fe34010f1859d99b54e3367bbd1)
|
|
10
|
+
|
|
7
11
|
#### [v1.30.1](https://github.com/eduardocruzpalacios/edu-webcomponents/compare/v1.30.0...v1.30.1)
|
|
8
12
|
|
|
9
|
-
|
|
10
|
-
|
|
13
|
+
> 20 January 2026
|
|
14
|
+
|
|
15
|
+
- docs: include accessibility features in README.md [`0876421`](https://github.com/eduardocruzpalacios/edu-webcomponents/commit/08764219fa28a92d178d398efe0b2f2ca83375d3)
|
|
16
|
+
- chore: release v1.30.1 [`1c13ee8`](https://github.com/eduardocruzpalacios/edu-webcomponents/commit/1c13ee8b6ec7af8f380af0c38b88136897125b27)
|
|
17
|
+
- fix: format code [`7e6c4bb`](https://github.com/eduardocruzpalacios/edu-webcomponents/commit/7e6c4bbde4565d526962650f2cabf339aff36a3a)
|
|
11
18
|
|
|
12
19
|
#### [v1.30.0](https://github.com/eduardocruzpalacios/edu-webcomponents/compare/v1.29.0...v1.30.0)
|
|
13
20
|
|
package/README.md
CHANGED
|
@@ -48,6 +48,72 @@ Or import individual components:
|
|
|
48
48
|
|
|
49
49
|
## 📚 Components
|
|
50
50
|
|
|
51
|
+
### 🏷️ Badge
|
|
52
|
+
|
|
53
|
+
A small status indicator or label component perfect for displaying counts, categories, or status information.
|
|
54
|
+
|
|
55
|
+
**Properties:**
|
|
56
|
+
- `text` (String) - Badge text content (default: `''`)
|
|
57
|
+
- `variant` (String) - Color variant: `'default'`, `'primary'`, `'success'`, `'warning'`, `'error'`, or `'info'` (default: `'default'`)
|
|
58
|
+
- `size` (String) - Size variant: `'small'`, `'medium'`, or `'large'` (default: `'medium'`)
|
|
59
|
+
- `aria-label` (String) - Accessibility label
|
|
60
|
+
- `aria-live` (String) - Announces dynamic changes to screen readers: `'polite'` or `'assertive'`
|
|
61
|
+
- `decorative` (Boolean) - Marks badge as decorative (hidden from screen readers)
|
|
62
|
+
|
|
63
|
+
**Accessibility:**
|
|
64
|
+
- Uses `role="status"` for screen reader announcements (non-decorative badges)
|
|
65
|
+
- Supports `aria-live` attribute for dynamic content announcements
|
|
66
|
+
- Automatically adds `aria-atomic="true"` when `aria-live` is set
|
|
67
|
+
- Decorative mode (`decorative` property) hides badge from screen readers with `aria-hidden="true"`
|
|
68
|
+
- Customizable ARIA labels for better context
|
|
69
|
+
- Semantic color choices with sufficient contrast ratios
|
|
70
|
+
- Full dark mode support with optimized color schemes
|
|
71
|
+
|
|
72
|
+
**Usage:**
|
|
73
|
+
|
|
74
|
+
```html
|
|
75
|
+
<!-- Basic badge -->
|
|
76
|
+
<edu-badge text="New"></edu-badge>
|
|
77
|
+
|
|
78
|
+
<!-- Colored variants -->
|
|
79
|
+
<edu-badge text="Active" variant="success"></edu-badge>
|
|
80
|
+
<edu-badge text="Pending" variant="warning"></edu-badge>
|
|
81
|
+
<edu-badge text="Error" variant="error"></edu-badge>
|
|
82
|
+
<edu-badge text="Info" variant="info"></edu-badge>
|
|
83
|
+
<edu-badge text="Primary" variant="primary"></edu-badge>
|
|
84
|
+
|
|
85
|
+
<!-- Different sizes -->
|
|
86
|
+
<edu-badge text="Small" size="small" variant="primary"></edu-badge>
|
|
87
|
+
<edu-badge text="Medium" size="medium" variant="primary"></edu-badge>
|
|
88
|
+
<edu-badge text="Large" size="large" variant="primary"></edu-badge>
|
|
89
|
+
|
|
90
|
+
<!-- Notification count with live updates -->
|
|
91
|
+
<span>Messages
|
|
92
|
+
<edu-badge
|
|
93
|
+
text="5"
|
|
94
|
+
variant="primary"
|
|
95
|
+
size="small"
|
|
96
|
+
aria-live="polite"
|
|
97
|
+
aria-label="5 unread messages">
|
|
98
|
+
</edu-badge>
|
|
99
|
+
</span>
|
|
100
|
+
|
|
101
|
+
<!-- Decorative badge (category tag) -->
|
|
102
|
+
<edu-badge text="JavaScript" variant="info" decorative></edu-badge>
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
**JavaScript:**
|
|
106
|
+
|
|
107
|
+
```javascript
|
|
108
|
+
import { EduBadge } from 'edu-webcomponents';
|
|
109
|
+
|
|
110
|
+
const badge = document.querySelector('edu-badge');
|
|
111
|
+
badge.text = '10';
|
|
112
|
+
badge.variant = 'error';
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
51
117
|
### 🔘 Button
|
|
52
118
|
|
|
53
119
|
A customizable button component with hover effects and disabled state.
|
package/demo/index.html
CHANGED
|
@@ -114,6 +114,51 @@
|
|
|
114
114
|
A collection of reusable web components built with Lit
|
|
115
115
|
</p>
|
|
116
116
|
|
|
117
|
+
<!-- Badge Component -->
|
|
118
|
+
<section class="section">
|
|
119
|
+
<h2>Badge</h2>
|
|
120
|
+
<p>Small status indicators and labels for displaying counts, categories, or status.</p>
|
|
121
|
+
|
|
122
|
+
<div class="demo-item">
|
|
123
|
+
<div class="demo-label">All Variants</div>
|
|
124
|
+
<div class="button-group">
|
|
125
|
+
<edu-badge .text=${'Default'} .variant=${'default'}></edu-badge>
|
|
126
|
+
<edu-badge .text=${'Primary'} .variant=${'primary'}></edu-badge>
|
|
127
|
+
<edu-badge .text=${'Success'} .variant=${'success'}></edu-badge>
|
|
128
|
+
<edu-badge .text=${'Warning'} .variant=${'warning'}></edu-badge>
|
|
129
|
+
<edu-badge .text=${'Error'} .variant=${'error'}></edu-badge>
|
|
130
|
+
<edu-badge .text=${'Info'} .variant=${'info'}></edu-badge>
|
|
131
|
+
</div>
|
|
132
|
+
</div>
|
|
133
|
+
|
|
134
|
+
<div class="demo-item">
|
|
135
|
+
<div class="demo-label">All Sizes</div>
|
|
136
|
+
<div class="button-group">
|
|
137
|
+
<edu-badge .text=${'Small'} .variant=${'primary'} .size=${'small'}></edu-badge>
|
|
138
|
+
<edu-badge .text=${'Medium'} .variant=${'primary'} .size=${'medium'}></edu-badge>
|
|
139
|
+
<edu-badge .text=${'Large'} .variant=${'primary'} .size=${'large'}></edu-badge>
|
|
140
|
+
</div>
|
|
141
|
+
</div>
|
|
142
|
+
|
|
143
|
+
<div class="demo-item">
|
|
144
|
+
<div class="demo-label">Notification Counts</div>
|
|
145
|
+
<div class="button-group">
|
|
146
|
+
<span>Messages <edu-badge .text=${'5'} .variant=${'primary'} .size=${'small'}></edu-badge></span>
|
|
147
|
+
<span>Alerts <edu-badge .text=${'12'} .variant=${'error'} .size=${'small'}></edu-badge></span>
|
|
148
|
+
<span>Updates <edu-badge .text=${'3'} .variant=${'info'} .size=${'small'}></edu-badge></span>
|
|
149
|
+
</div>
|
|
150
|
+
</div>
|
|
151
|
+
|
|
152
|
+
<div class="demo-item">
|
|
153
|
+
<div class="demo-label">Status Badges</div>
|
|
154
|
+
<div class="button-group">
|
|
155
|
+
<edu-badge .text=${'Active'} .variant=${'success'}></edu-badge>
|
|
156
|
+
<edu-badge .text=${'Pending'} .variant=${'warning'}></edu-badge>
|
|
157
|
+
<edu-badge .text=${'Inactive'} .variant=${'error'}></edu-badge>
|
|
158
|
+
</div>
|
|
159
|
+
</div>
|
|
160
|
+
</section>
|
|
161
|
+
|
|
117
162
|
<!-- Button Component -->
|
|
118
163
|
<section class="section">
|
|
119
164
|
<h2>Button</h2>
|
package/index.js
CHANGED
package/package.json
CHANGED
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import { html } from 'lit';
|
|
2
|
+
import './index.js';
|
|
3
|
+
|
|
4
|
+
export default {
|
|
5
|
+
title: 'Edu web components/EduBadge',
|
|
6
|
+
tags: ['autodocs'],
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
const createStory = args => {
|
|
10
|
+
const story = ({ text, variant, size } = args) => html`
|
|
11
|
+
<edu-badge .text=${text} .variant=${variant} .size=${size}></edu-badge>
|
|
12
|
+
`;
|
|
13
|
+
story.parameters = {
|
|
14
|
+
controls: { expanded: true },
|
|
15
|
+
docs: { source: { type: 'code' } },
|
|
16
|
+
};
|
|
17
|
+
story.argTypes = {
|
|
18
|
+
text: {
|
|
19
|
+
control: 'text',
|
|
20
|
+
description: 'Badge text content',
|
|
21
|
+
name: 'text',
|
|
22
|
+
},
|
|
23
|
+
variant: {
|
|
24
|
+
control: 'select',
|
|
25
|
+
options: ['default', 'primary', 'success', 'warning', 'error', 'info'],
|
|
26
|
+
description:
|
|
27
|
+
'Color variant: default / primary / success / warning / error / info',
|
|
28
|
+
name: 'variant',
|
|
29
|
+
},
|
|
30
|
+
size: {
|
|
31
|
+
control: 'select',
|
|
32
|
+
options: ['small', 'medium', 'large'],
|
|
33
|
+
description: 'Size variant: small / medium / large',
|
|
34
|
+
name: 'size',
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
story.args = args;
|
|
38
|
+
return story;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const defaultArgs = {
|
|
42
|
+
text: 'Badge',
|
|
43
|
+
variant: 'default',
|
|
44
|
+
size: 'medium',
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
export const EduBadgeDefault = createStory({ ...defaultArgs });
|
|
48
|
+
export const EduBadgePrimary = createStory({
|
|
49
|
+
...defaultArgs,
|
|
50
|
+
variant: 'primary',
|
|
51
|
+
});
|
|
52
|
+
export const EduBadgeSuccess = createStory({
|
|
53
|
+
...defaultArgs,
|
|
54
|
+
variant: 'success',
|
|
55
|
+
});
|
|
56
|
+
export const EduBadgeWarning = createStory({
|
|
57
|
+
...defaultArgs,
|
|
58
|
+
variant: 'warning',
|
|
59
|
+
});
|
|
60
|
+
export const EduBadgeError = createStory({ ...defaultArgs, variant: 'error' });
|
|
61
|
+
export const EduBadgeInfo = createStory({ ...defaultArgs, variant: 'info' });
|
|
62
|
+
|
|
63
|
+
export const EduBadgeSmall = createStory({
|
|
64
|
+
...defaultArgs,
|
|
65
|
+
variant: 'primary',
|
|
66
|
+
size: 'small',
|
|
67
|
+
});
|
|
68
|
+
export const EduBadgeLarge = createStory({
|
|
69
|
+
...defaultArgs,
|
|
70
|
+
variant: 'primary',
|
|
71
|
+
size: 'large',
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
export const AllVariants = () => {
|
|
75
|
+
const story = () => html`
|
|
76
|
+
<div
|
|
77
|
+
style="display: flex; gap: 1rem; flex-wrap: wrap; align-items: center;"
|
|
78
|
+
>
|
|
79
|
+
<edu-badge text="Default" variant="default"></edu-badge>
|
|
80
|
+
<edu-badge text="Primary" variant="primary"></edu-badge>
|
|
81
|
+
<edu-badge text="Success" variant="success"></edu-badge>
|
|
82
|
+
<edu-badge text="Warning" variant="warning"></edu-badge>
|
|
83
|
+
<edu-badge text="Error" variant="error"></edu-badge>
|
|
84
|
+
<edu-badge text="Info" variant="info"></edu-badge>
|
|
85
|
+
</div>
|
|
86
|
+
`;
|
|
87
|
+
story.parameters = {
|
|
88
|
+
controls: { disable: true },
|
|
89
|
+
docs: { source: { type: 'code' } },
|
|
90
|
+
};
|
|
91
|
+
return story();
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
export const AllSizes = () => {
|
|
95
|
+
const story = () => html`
|
|
96
|
+
<div
|
|
97
|
+
style="display: flex; gap: 1rem; flex-wrap: wrap; align-items: center;"
|
|
98
|
+
>
|
|
99
|
+
<edu-badge text="Small" variant="primary" size="small"></edu-badge>
|
|
100
|
+
<edu-badge text="Medium" variant="primary" size="medium"></edu-badge>
|
|
101
|
+
<edu-badge text="Large" variant="primary" size="large"></edu-badge>
|
|
102
|
+
</div>
|
|
103
|
+
`;
|
|
104
|
+
story.parameters = {
|
|
105
|
+
controls: { disable: true },
|
|
106
|
+
docs: { source: { type: 'code' } },
|
|
107
|
+
};
|
|
108
|
+
return story();
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
export const UseCases = () => {
|
|
112
|
+
const story = () => html`
|
|
113
|
+
<div style="display: flex; flex-direction: column; gap: 2rem;">
|
|
114
|
+
<div>
|
|
115
|
+
<h3>Status Indicators</h3>
|
|
116
|
+
<div style="display: flex; gap: 1rem; flex-wrap: wrap;">
|
|
117
|
+
<edu-badge text="Active" variant="success"></edu-badge>
|
|
118
|
+
<edu-badge text="Pending" variant="warning"></edu-badge>
|
|
119
|
+
<edu-badge text="Inactive" variant="error"></edu-badge>
|
|
120
|
+
</div>
|
|
121
|
+
</div>
|
|
122
|
+
|
|
123
|
+
<div>
|
|
124
|
+
<h3>Notification Counts</h3>
|
|
125
|
+
<div
|
|
126
|
+
style="display: flex; gap: 1rem; align-items: center; flex-wrap: wrap;"
|
|
127
|
+
>
|
|
128
|
+
<span
|
|
129
|
+
>Messages
|
|
130
|
+
<edu-badge text="5" variant="primary" size="small"></edu-badge
|
|
131
|
+
></span>
|
|
132
|
+
<span
|
|
133
|
+
>Alerts
|
|
134
|
+
<edu-badge text="12" variant="error" size="small"></edu-badge
|
|
135
|
+
></span>
|
|
136
|
+
<span
|
|
137
|
+
>Updates <edu-badge text="3" variant="info" size="small"></edu-badge
|
|
138
|
+
></span>
|
|
139
|
+
</div>
|
|
140
|
+
</div>
|
|
141
|
+
|
|
142
|
+
<div>
|
|
143
|
+
<h3>Category Tags</h3>
|
|
144
|
+
<div style="display: flex; gap: 0.5rem; flex-wrap: wrap;">
|
|
145
|
+
<edu-badge text="JavaScript" variant="info" size="small"></edu-badge>
|
|
146
|
+
<edu-badge
|
|
147
|
+
text="Web Components"
|
|
148
|
+
variant="primary"
|
|
149
|
+
size="small"
|
|
150
|
+
></edu-badge>
|
|
151
|
+
<edu-badge text="Lit" variant="success" size="small"></edu-badge>
|
|
152
|
+
<edu-badge text="CSS" variant="warning" size="small"></edu-badge>
|
|
153
|
+
</div>
|
|
154
|
+
</div>
|
|
155
|
+
|
|
156
|
+
<div>
|
|
157
|
+
<h3>Version Badge</h3>
|
|
158
|
+
<div style="display: flex; gap: 1rem;">
|
|
159
|
+
<edu-badge text="v1.0.0" variant="default"></edu-badge>
|
|
160
|
+
<edu-badge text="Beta" variant="warning"></edu-badge>
|
|
161
|
+
<edu-badge text="New" variant="success"></edu-badge>
|
|
162
|
+
</div>
|
|
163
|
+
</div>
|
|
164
|
+
</div>
|
|
165
|
+
`;
|
|
166
|
+
story.parameters = {
|
|
167
|
+
controls: { disable: true },
|
|
168
|
+
docs: { source: { type: 'code' } },
|
|
169
|
+
};
|
|
170
|
+
return story();
|
|
171
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { EduBadge } from './src/EduBadge.js';
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import { html, css, LitElement } from 'lit';
|
|
2
|
+
import { colorsConstants, typographyConstants } from '../../stylesConstants.js';
|
|
3
|
+
|
|
4
|
+
export class EduBadge extends LitElement {
|
|
5
|
+
static styles = [
|
|
6
|
+
colorsConstants,
|
|
7
|
+
typographyConstants,
|
|
8
|
+
css`
|
|
9
|
+
:host {
|
|
10
|
+
display: inline-block;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.badge {
|
|
14
|
+
display: inline-flex;
|
|
15
|
+
align-items: center;
|
|
16
|
+
justify-content: center;
|
|
17
|
+
font-family: inherit;
|
|
18
|
+
font-weight: 600;
|
|
19
|
+
border-radius: 12px;
|
|
20
|
+
white-space: nowrap;
|
|
21
|
+
line-height: 1;
|
|
22
|
+
transition: background-color 0.2s ease-in-out;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/* Size variants */
|
|
26
|
+
.badge--small {
|
|
27
|
+
padding: 0.25rem 0.5rem;
|
|
28
|
+
font-size: 0.75rem;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.badge--medium {
|
|
32
|
+
padding: 0.375rem 0.75rem;
|
|
33
|
+
font-size: 0.875rem;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
.badge--large {
|
|
37
|
+
padding: 0.5rem 1rem;
|
|
38
|
+
font-size: 1rem;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/* Color variants - Light mode */
|
|
42
|
+
.badge--default {
|
|
43
|
+
background-color: var(--greyLight);
|
|
44
|
+
color: var(--blackLight);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.badge--primary {
|
|
48
|
+
background-color: var(--primary);
|
|
49
|
+
color: var(--primaryForeground);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.badge--success {
|
|
53
|
+
background-color: #4caf50;
|
|
54
|
+
color: #ffffff;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.badge--warning {
|
|
58
|
+
background-color: #ff9800;
|
|
59
|
+
color: #000000;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.badge--error {
|
|
63
|
+
background-color: #f44336;
|
|
64
|
+
color: #ffffff;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
.badge--info {
|
|
68
|
+
background-color: #2196f3;
|
|
69
|
+
color: #ffffff;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/* Dark mode support */
|
|
73
|
+
@media (prefers-color-scheme: dark) {
|
|
74
|
+
.badge--default {
|
|
75
|
+
background-color: var(--greyLight);
|
|
76
|
+
color: var(--primaryForeground);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
.badge--primary {
|
|
80
|
+
background-color: #4db8ff;
|
|
81
|
+
color: #000000;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.badge--success {
|
|
85
|
+
background-color: #66bb6a;
|
|
86
|
+
color: #000000;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.badge--warning {
|
|
90
|
+
background-color: #ffa726;
|
|
91
|
+
color: #000000;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
.badge--error {
|
|
95
|
+
background-color: #ef5350;
|
|
96
|
+
color: #ffffff;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
.badge--info {
|
|
100
|
+
background-color: #42a5f5;
|
|
101
|
+
color: #000000;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
`,
|
|
105
|
+
];
|
|
106
|
+
|
|
107
|
+
static properties = {
|
|
108
|
+
text: { type: String },
|
|
109
|
+
variant: { type: String },
|
|
110
|
+
size: { type: String },
|
|
111
|
+
ariaLabel: { type: String, attribute: 'aria-label' },
|
|
112
|
+
ariaLive: { type: String, attribute: 'aria-live' },
|
|
113
|
+
decorative: { type: Boolean },
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
constructor() {
|
|
117
|
+
super();
|
|
118
|
+
this.text = '';
|
|
119
|
+
this.variant = 'default';
|
|
120
|
+
this.size = 'medium';
|
|
121
|
+
this.ariaLabel = '';
|
|
122
|
+
this.ariaLive = '';
|
|
123
|
+
this.decorative = false;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
render() {
|
|
127
|
+
const classes = `badge badge--${this.size} badge--${this.variant}`;
|
|
128
|
+
|
|
129
|
+
// Decorative badges should be hidden from screen readers
|
|
130
|
+
if (this.decorative) {
|
|
131
|
+
return html`
|
|
132
|
+
<span class=${classes} aria-hidden="true"> ${this.text} </span>
|
|
133
|
+
`;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Accessibility attributes
|
|
137
|
+
const ariaAttrs = {
|
|
138
|
+
role: 'status',
|
|
139
|
+
'aria-label': this.ariaLabel || this.text,
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
// Add aria-live for dynamic content (like notification counts)
|
|
143
|
+
if (this.ariaLive) {
|
|
144
|
+
ariaAttrs['aria-live'] = this.ariaLive;
|
|
145
|
+
ariaAttrs['aria-atomic'] = 'true';
|
|
146
|
+
} else {
|
|
147
|
+
ariaAttrs['aria-live'] = 'off';
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
return html`
|
|
151
|
+
<span
|
|
152
|
+
class=${classes}
|
|
153
|
+
role=${ariaAttrs.role}
|
|
154
|
+
aria-label=${ariaAttrs['aria-label']}
|
|
155
|
+
aria-live=${ariaAttrs['aria-live']}
|
|
156
|
+
?aria-atomic=${!!ariaAttrs['aria-atomic']}
|
|
157
|
+
>
|
|
158
|
+
${this.text}
|
|
159
|
+
</span>
|
|
160
|
+
`;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
customElements.define('edu-badge', EduBadge);
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { html } from 'lit';
|
|
2
|
+
import { fixture, expect } from '@open-wc/testing';
|
|
3
|
+
|
|
4
|
+
import '../index.js';
|
|
5
|
+
|
|
6
|
+
describe('EduBadge', () => {
|
|
7
|
+
it('renders the text content', async () => {
|
|
8
|
+
const text = 'Test Badge';
|
|
9
|
+
const el = await fixture(html`<edu-badge text=${text}></edu-badge>`);
|
|
10
|
+
|
|
11
|
+
const badge = el.shadowRoot.querySelector('.badge');
|
|
12
|
+
expect(badge.textContent.trim()).to.equal(text);
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it('passes the a11y audit', async () => {
|
|
16
|
+
const el = await fixture(html`<edu-badge text="Badge"></edu-badge>`);
|
|
17
|
+
|
|
18
|
+
await expect(el).shadowDom.to.be.accessible();
|
|
19
|
+
});
|
|
20
|
+
});
|