@@ -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}
179226exports . default = HTMLCodeBlockElement ;
0 commit comments