@@ -13,12 +13,17 @@ export default class Render {
1313
1414 /**
1515 * Apply attrs map to element.
16- * @description Sets attributes, className, value, checked, disabled .
16+ * @description Sets attributes, className, value, boolean and form attrs .
1717 * @param element - Target element
1818 * @param attrs - Attribute key-value map
1919 */
2020 static applyAttrs ( element : Element , attrs : Types . Attrs ) : void {
2121 for ( const [ key , value ] of Object . entries ( attrs ) ) {
22+ if ( Constant . booleanAttrKeys . has ( key ) ) {
23+ if ( Render . applyBooleanAttr ( element , key , value ) ) {
24+ continue
25+ }
26+ }
2227 if ( value === undefined || value === null ) {
2328 continue
2429 }
@@ -40,20 +45,6 @@ export default class Render {
4045 element . value = attrValueStr
4146 continue
4247 }
43- if ( key === 'checked' && element instanceof HTMLInputElement ) {
44- element . checked = value === true || value === 'true'
45- continue
46- }
47- if (
48- key === 'disabled' &&
49- ( element instanceof HTMLInputElement ||
50- element instanceof HTMLButtonElement ||
51- element instanceof HTMLSelectElement ||
52- element instanceof HTMLTextAreaElement )
53- ) {
54- element . disabled = value === true || value === 'true'
55- continue
56- }
5748 try {
5849 element . setAttribute ( key , attrValueStr )
5950 } catch {
@@ -285,4 +276,86 @@ export default class Render {
285276 }
286277 return String ( layoutValue )
287278 }
279+
280+ /**
281+ * Apply boolean attribute to element.
282+ * @description Sets property and removes attribute when false.
283+ * @param element - Target DOM element
284+ * @param attrKey - Attribute name
285+ * @param attrValue - Attribute value
286+ * @returns True if attribute was applied
287+ */
288+ private static applyBooleanAttr (
289+ element : Element ,
290+ attrKey : string ,
291+ attrValue : unknown
292+ ) : boolean {
293+ const isAttrTruthy = attrValue !== undefined && attrValue !== null &&
294+ Render . toBoolean ( attrValue )
295+ if ( attrKey === 'checked' && element instanceof HTMLInputElement ) {
296+ element . checked = isAttrTruthy
297+ if ( ! isAttrTruthy ) {
298+ element . removeAttribute ( 'checked' )
299+ }
300+ return true
301+ }
302+ if ( attrKey === 'disabled' ) {
303+ if (
304+ element instanceof HTMLInputElement ||
305+ element instanceof HTMLButtonElement ||
306+ element instanceof HTMLSelectElement ||
307+ element instanceof HTMLTextAreaElement ||
308+ element instanceof HTMLFieldSetElement ||
309+ element instanceof HTMLOptGroupElement ||
310+ element instanceof HTMLOptionElement
311+ ) {
312+ element . disabled = isAttrTruthy
313+ if ( ! isAttrTruthy ) {
314+ element . removeAttribute ( 'disabled' )
315+ }
316+ return true
317+ }
318+ }
319+ if ( attrKey === 'readonly' ) {
320+ if ( element instanceof HTMLInputElement || element instanceof HTMLTextAreaElement ) {
321+ element . readOnly = isAttrTruthy
322+ if ( ! isAttrTruthy ) {
323+ element . removeAttribute ( 'readonly' )
324+ }
325+ return true
326+ }
327+ }
328+ if ( attrKey === 'selected' && element instanceof HTMLOptionElement ) {
329+ element . selected = isAttrTruthy
330+ if ( ! isAttrTruthy ) {
331+ element . removeAttribute ( 'selected' )
332+ }
333+ return true
334+ }
335+ if ( attrKey === 'inert' && element instanceof HTMLElement ) {
336+ element . inert = isAttrTruthy
337+ if ( ! isAttrTruthy ) {
338+ element . removeAttribute ( 'inert' )
339+ }
340+ return true
341+ }
342+ if ( attrKey === 'hidden' && element instanceof HTMLElement ) {
343+ element . hidden = isAttrTruthy
344+ if ( ! isAttrTruthy ) {
345+ element . removeAttribute ( 'hidden' )
346+ }
347+ return true
348+ }
349+ return false
350+ }
351+
352+ /**
353+ * Normalize attribute value to boolean.
354+ * @description True for true or 'true' string; otherwise false.
355+ * @param attrValue - Raw attribute value
356+ * @returns True when value is true or 'true'
357+ */
358+ private static toBoolean ( attrValue : unknown ) : boolean {
359+ return attrValue === true || attrValue === 'true'
360+ }
288361}
0 commit comments