Skip to content

Commit 41c06c3

Browse files
⚙️ 0.1.0
1 parent 98e4267 commit 41c06c3

6 files changed

+126
-56
lines changed

dist/class/HTMLCodeBlockElement.d.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,19 +23,19 @@ export default class HTMLCodeBlockElement extends HTMLElement {
2323
* @returns - The value of the label attribute
2424
*/
2525
get label(): string;
26-
set label(name: string);
26+
set label(value: string);
2727
/**
2828
* Language Mode
2929
* @returns - The value of the language attribute
3030
*/
31-
get language(): string;
32-
set language(name: string);
31+
get language(): any;
32+
set language(value: any);
3333
/**
3434
* Flag to display the UI
3535
* @returns - With or without controls attribute
3636
* */
3737
get controls(): boolean;
38-
set controls(flag: boolean);
38+
set controls(value: boolean);
3939
static get observedAttributes(): string[];
4040
attributeChangedCallback(attrName: string, oldValue: string, newValue: string): void;
4141
connectedCallback(): void;

dist/class/HTMLCodeBlockElement.js

Lines changed: 92 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,26 @@ class HTMLCodeBlockElement extends HTMLElement {
2727
}
2828
return endgine.highlightAuto(src);
2929
}
30-
#shadowRoot;
30+
#slots = (() => {
31+
/**
32+
* @param name - The value of name attribute for the slot element
33+
* @returns - The slot element
34+
*/
35+
const mkslot = (name, id) => {
36+
const slot = document.createElement('slot');
37+
slot.name = name;
38+
if (id) {
39+
slot.id = id;
40+
}
41+
return slot;
42+
};
43+
return {
44+
name: mkslot('name', 'name'),
45+
copyButton: mkslot('copy-button'),
46+
code: mkslot('code'),
47+
};
48+
})();
49+
#a11yName;
3150
#codeBlock;
3251
#codeWrap;
3352
/** Actual value of the accessor `value` */
@@ -44,13 +63,16 @@ class HTMLCodeBlockElement extends HTMLElement {
4463
return;
4564
}
4665
/** The resulting syntax-highlighted markup */
47-
const markup = HTMLCodeBlockElement.highlight(this.#value, {
66+
const { value: markup } = HTMLCodeBlockElement.highlight(this.#value, {
4867
language: this.#language,
49-
}).value;
68+
});
5069
// initialize
5170
this.textContent = '';
71+
this.#a11yName.textContent = this.#label;
72+
this.#slots.name.hidden = !this.#label;
5273
this.#codeBlock.textContent = '';
5374
this.#codeBlock.insertAdjacentHTML('afterbegin', markup);
75+
this.append(this.#a11yName);
5476
this.append(this.#codeWrap);
5577
};
5678
/** @returns - Syntax Highlighted Source Code */
@@ -68,14 +90,14 @@ class HTMLCodeBlockElement extends HTMLElement {
6890
get label() {
6991
return this.#label;
7092
}
71-
set label(name) {
72-
// TODO: Accessiblity Treeにアクセシブルネームを提供する
73-
this.#label = name || '';
74-
if (this.#label) {
75-
this.setAttribute('label', name);
93+
set label(value) {
94+
if (value === null) {
95+
this.#label = '';
96+
this.removeAttribute('label');
7697
}
7798
else {
78-
this.removeAttribute('label');
99+
this.#label = String(value);
100+
this.setAttribute('label', this.#label);
79101
}
80102
this.#render();
81103
}
@@ -86,13 +108,14 @@ class HTMLCodeBlockElement extends HTMLElement {
86108
get language() {
87109
return this.#language;
88110
}
89-
set language(name) {
90-
this.#language = name || '';
91-
if (this.#language) {
92-
this.setAttribute('language', name);
111+
set language(value) {
112+
if (value === null) {
113+
this.#language = '';
114+
this.removeAttribute('language');
93115
}
94116
else {
95-
this.removeAttribute('language');
117+
this.#language = String(value);
118+
this.setAttribute('language', this.#language);
96119
}
97120
this.#render();
98121
}
@@ -103,9 +126,9 @@ class HTMLCodeBlockElement extends HTMLElement {
103126
get controls() {
104127
return this.#controls;
105128
}
106-
set controls(flag) {
107-
// TODO: コピーボタン、ラベルの表示切り替え
108-
this.#controls = flag;
129+
set controls(value) {
130+
// TODO: コピーボタンの表示切り替え
131+
this.#controls = value;
109132
if (this.#controls) {
110133
this.setAttribute('controls', '');
111134
}
@@ -131,7 +154,7 @@ class HTMLCodeBlockElement extends HTMLElement {
131154
// string
132155
case 'label':
133156
case 'language':
134-
this[attrName] = newValue || '';
157+
this[attrName] = newValue;
135158
break;
136159
// boolean
137160
case 'controls':
@@ -143,37 +166,61 @@ class HTMLCodeBlockElement extends HTMLElement {
143166
}
144167
constructor() {
145168
super();
169+
/* -------------------------------------------------------------------------
170+
* Setup Shadow DOM contents
171+
* ---------------------------------------------------------------------- */
146172
/**
147-
* @param name - The value of name attribute for the slot element
148-
* @returns - The slot element
173+
* The container of minimum text that will be read even
174+
* if the accessible name (label attribute value) is omitted.
149175
*/
150-
const mkslot = (name) => {
151-
const slot = document.createElement('slot');
152-
slot.name = name;
153-
return slot;
154-
};
155-
const slots = [
156-
mkslot('label'),
157-
mkslot('copy-button'),
158-
mkslot('code'),
159-
];
160-
const pre = document.createElement('pre');
161-
const code = document.createElement('code');
162-
code.tabIndex = 0;
163-
code.className = 'hljs'; // TODO: Make it variable
164-
pre.slot = 'code';
165-
pre.append(code);
166-
// Hard private props initialize
167-
this.#value = (this.textContent || '').replace(/^\n/, '');
168-
this.#label = this.getAttribute('label') || '';
169-
this.#language = this.getAttribute('language') || '';
170-
this.#controls = this.getAttribute('controls') !== null;
171-
this.#shadowRoot = this.attachShadow({
176+
const a11yNamePrefix = (() => {
177+
const span = document.createElement('span');
178+
span.id = 'semantics';
179+
span.hidden = true;
180+
span.textContent = 'Code Block';
181+
return span;
182+
})();
183+
/** Container of accessible names (label attribute values). */
184+
const a11yName = (() => {
185+
const span = document.createElement('span');
186+
span.slot = 'name';
187+
span.textContent = this.getAttribute('label') || '';
188+
return span;
189+
})();
190+
const codeElm = (() => {
191+
const code = document.createElement('code');
192+
code.tabIndex = 0;
193+
code.className = 'hljs'; // TODO: Make it variable
194+
return code;
195+
})();
196+
const preElm = (() => {
197+
const pre = document.createElement('pre');
198+
pre.slot = 'code';
199+
pre.append(codeElm);
200+
return pre;
201+
})();
202+
const container = (() => {
203+
const div = document.createElement('div');
204+
div.append(...Object.values(this.#slots));
205+
div.setAttribute('role', 'group');
206+
div.setAttribute('aria-labelledby', 'semantics name');
207+
return div;
208+
})();
209+
const shadowRoot = this.attachShadow({
172210
mode: 'closed',
173211
});
174-
this.#codeBlock = code;
175-
this.#codeWrap = pre;
176-
this.#shadowRoot.append(...slots);
212+
shadowRoot.append(a11yNamePrefix);
213+
shadowRoot.append(container);
214+
/* -------------------------------------------------------------------------
215+
* Hard private props initialize
216+
* ---------------------------------------------------------------------- */
217+
this.#value = (this.textContent || '').replace(/^\n/, '').replace(/\n$/, '');
218+
this.#label = a11yName.textContent || '';
219+
this.#language = this.getAttribute('language') || '';
220+
this.#controls = this.getAttribute('controls') !== null;
221+
this.#a11yName = a11yName;
222+
this.#codeBlock = codeElm;
223+
this.#codeWrap = preElm;
177224
}
178225
}
179226
exports.default = HTMLCodeBlockElement;

dist/utils/add-style.js

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,30 @@ const style = document.createElement('style');
55
const link = document.querySelector('head link, head style');
66
style.textContent = `
77
code-block {
8+
position: relative;
89
margin: 1em 0;
910
display: block;
11+
font-size: 80%;
1012
font-family: Consolas, Monaco, monospace;
1113
}
14+
code-block span[slot="name"] {
15+
position: absolute;
16+
top: 0;
17+
left: 0;
18+
padding: 0 5px;
19+
max-width: 90%;
20+
color: #fff;
21+
white-space: pre;
22+
line-height: 1.5;
23+
overflow: hidden;
24+
text-overflow: ellipsis;
25+
background: #75758a;
26+
box-sizing: border-box;
27+
}
28+
code-block pre,
29+
code-block code {
30+
font-family: inherit;
31+
}
1232
code-block pre {
1333
margin: 0;
1434
}
@@ -18,7 +38,10 @@ style.textContent = `
1838
font-size: 100%;
1939
overflow-x: auto;
2040
}
21-
`;
41+
code-block[label]:not([label=""]) pre code {
42+
padding-top: 2em;
43+
}
44+
`;
2245
if (link) {
2346
link.before(style);
2447
}

lib/html-code-block-element.all.min.js

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lib/html-code-block-element.common.min.js

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lib/html-code-block-element.core.min.js

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)