@webcoder49/code-input 2.6.8 → 2.7.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/code-input.css CHANGED
@@ -20,7 +20,14 @@ code-input {
20
20
  top: 0;
21
21
  left: 0;
22
22
 
23
- color: black;
23
+ /* CSS variables rather than inline styles used for values synced from JavaScript
24
+ to keep low precedence and thus overridability
25
+ The variable names may change and are for internal use. */
26
+ /* --code-input_highlight-text-color: Set by JS to be base text color of pre code element */
27
+ /* --code-input_no-override-color: Set by JS for very short time to get whether color has been overriden */
28
+ color: var(--code-input_no-override-color, black);
29
+ /* --code-input_default-caret-color: Set by JS to be same as color property - currentColor won't work because it's lazily evaluated so gives transparent for the textarea */
30
+ caret-color: var(--code-input_default-caret-color, inherit);
24
31
  background-color: white;
25
32
 
26
33
  /* Normal inline styles */
@@ -36,7 +43,6 @@ code-input {
36
43
  text-align: start;
37
44
  line-height: 1.5; /* Inherited to child elements */
38
45
  tab-size: 2;
39
- caret-color: darkgrey;
40
46
  white-space: pre;
41
47
  padding: 0!important; /* Use --padding to set the code-input element's padding */
42
48
  display: grid;
@@ -44,7 +50,7 @@ code-input {
44
50
  grid-template-rows: 100%;
45
51
  }
46
52
 
47
- code-input * {
53
+ code-input :not(.code-input_dialog-container *) {
48
54
  box-sizing: content-box; /* Make height, width work consistently no matter the box-sizing of ancestors; dialogs can be styled as wanted so are excluded. */
49
55
  }
50
56
 
@@ -68,6 +74,12 @@ code-input textarea, code-input:not(.code-input_pre-element-styled) pre code, co
68
74
  code-input:not(.code-input_pre-element-styled) pre code, code-input.code-input_pre-element-styled pre {
69
75
  height: max-content;
70
76
  width: max-content;
77
+
78
+
79
+ /* Allow colour change to reflect properly;
80
+ transition-behavior: allow-discrete could be used but this is better supported and
81
+ works with the color property. */
82
+ transition: color 0.001s;
71
83
  }
72
84
 
73
85
  code-input:not(.code-input_pre-element-styled) pre, code-input.code-input_pre-element-styled pre code {
@@ -118,12 +130,13 @@ code-input pre {
118
130
  /* Make textarea almost completely transparent, except for caret and placeholder */
119
131
 
120
132
  code-input textarea:not([data-code-input-fallback]) {
121
- color: transparent;
122
133
  background: transparent;
123
- caret-color: inherit!important; /* Or choose your favourite color */
134
+ color: transparent;
135
+ caret-color: inherit;
124
136
  }
125
- code-input textarea::placeholder {
126
- color: lightgrey;
137
+ code-input textarea:not([data-code-input-fallback]):placeholder-shown {
138
+ /* Show placeholder */
139
+ color: var(--code-input_highlight-text-color, inherit);
127
140
  }
128
141
 
129
142
  /* Can be scrolled */
@@ -163,6 +176,11 @@ code-input .code-input_dialog-container {
163
176
 
164
177
  /* Dialog boxes' text is based on text-direction */
165
178
  text-align: inherit;
179
+
180
+ /* Allow colour change to reflect properly;
181
+ * transition-behavior: allow-discrete could be used but this is * better supported and works with the color property. */
182
+ color: inherit;
183
+ transition: color 0.001s;
166
184
  }
167
185
 
168
186
  [dir=rtl] code-input .code-input_dialog-container, code-input[dir=rtl] .code-input_dialog-container {
@@ -252,11 +270,13 @@ code-input:not(.code-input_loaded) pre, code-input:not(.code-input_loaded) texta
252
270
  code-input:has(textarea[data-code-input-fallback]) {
253
271
  padding: 0!important; /* Padding now in the textarea */
254
272
  box-sizing: content-box;
273
+
274
+ caret-color: revert; /* JS not setting the colour since no highlighting */
255
275
  }
256
276
  code-input textarea[data-code-input-fallback] {
257
277
  overflow: auto;
258
278
  background-color: inherit;
259
- color: inherit;
279
+ color: var(--code-input_highlight-text-color, inherit);
260
280
 
261
281
  /* Don't overlap with message */
262
282
  min-height: calc(100% - var(--padding-top, 16px) - 2em - var(--padding-bottom, 16px));
package/code-input.js CHANGED
@@ -152,6 +152,8 @@ var codeInput = {
152
152
  }
153
153
  },
154
154
 
155
+ stylesheetI: 0, // Increments to give different classes to each code-input element so they can have custom styles synchronised internally without affecting the inline style
156
+
155
157
  /**
156
158
  * Please see `codeInput.templates.prism` or `codeInput.templates.hljs`.
157
159
  * Templates are used in `<code-input>` elements and once registered with
@@ -445,6 +447,16 @@ var codeInput = {
445
447
  */
446
448
  dialogContainerElement = null;
447
449
 
450
+ /**
451
+ * Like style attribute, but with a specificity of 1
452
+ * element, 1 class. Present so styles can be set on only
453
+ * this element while giving other code freedom of use of
454
+ * the style attribute.
455
+ *
456
+ * For internal use only.
457
+ */
458
+ internalStyle = null;
459
+
448
460
  /**
449
461
  * Form-Associated Custom Element Callbacks
450
462
  * https://html.spec.whatwg.org/multipage/custom-elements.html#custom-elements-face-example
@@ -530,22 +542,75 @@ var codeInput = {
530
542
  this.pluginEvt("afterHighlight");
531
543
  }
532
544
 
545
+ getStyledHighlightingElement() {
546
+ if(this.templateObject.preElementStyled) {
547
+ return this.preElement;
548
+ } else {
549
+ return this.codeElement;
550
+ }
551
+ }
552
+
533
553
  /**
534
554
  * Set the size of the textarea element to the size of the pre/code element.
535
555
  */
536
556
  syncSize() {
537
557
  // Synchronise the size of the pre/code and textarea elements
538
- if(this.templateObject.preElementStyled) {
539
- this.style.backgroundColor = getComputedStyle(this.preElement).backgroundColor;
540
- this.textareaElement.style.height = getComputedStyle(this.preElement).height;
541
- this.textareaElement.style.width = getComputedStyle(this.preElement).width;
542
- } else {
543
- this.style.backgroundColor = getComputedStyle(this.codeElement).backgroundColor;
544
- this.textareaElement.style.height = getComputedStyle(this.codeElement).height;
545
- this.textareaElement.style.width = getComputedStyle(this.codeElement).width;
558
+ this.textareaElement.style.height = getComputedStyle(this.getStyledHighlightingElement()).height;
559
+ this.textareaElement.style.width = getComputedStyle(this.getStyledHighlightingElement()).width;
560
+ }
561
+
562
+ /**
563
+ * If the color attribute has been defined on the
564
+ * code-input element by external code, return true.
565
+ * Otherwise, make the aspects the color affects
566
+ * (placeholder and caret colour) be the base colour
567
+ * of the highlighted text, for best contrast, and
568
+ * return false.
569
+ */
570
+ isColorOverridenSyncIfNot() {
571
+ const oldTransition = this.style.transition;
572
+ this.style.transition = "unset";
573
+ window.requestAnimationFrame(() => {
574
+ this.internalStyle.setProperty("--code-input_no-override-color", "rgb(0, 0, 0)");
575
+ if(getComputedStyle(this).color == "rgb(0, 0, 0)") {
576
+ // May not be overriden
577
+ this.internalStyle.setProperty("--code-input_no-override-color", "rgb(255, 255, 255)");
578
+ if(getComputedStyle(this).color == "rgb(255, 255, 255)") {
579
+ // Definitely not overriden
580
+ this.internalStyle.removeProperty("--code-input_no-override-color");
581
+ this.style.transition = oldTransition;
582
+
583
+ const highlightedTextColor = getComputedStyle(this.getStyledHighlightingElement()).color;
584
+
585
+ this.internalStyle.setProperty("--code-input_highlight-text-color", highlightedTextColor);
586
+ this.internalStyle.setProperty("--code-input_default-caret-color", highlightedTextColor);
587
+ return false;
588
+ }
589
+ }
590
+ this.internalStyle.removeProperty("--code-input_no-override-color");
591
+ this.style.transition = oldTransition;
592
+ });
593
+
594
+ return true;
595
+ }
596
+
597
+ /**
598
+ * Update the aspects the color affects
599
+ * (placeholder and caret colour) to the correct
600
+ * colour: either that defined on the code-input
601
+ * element, or if none is defined externally the
602
+ * base colour of the highlighted text.
603
+ */
604
+ syncColorCompletely() {
605
+ // color of code-input element
606
+ if(this.isColorOverridenSyncIfNot()) {
607
+ // color overriden
608
+ this.internalStyle.removeProperty("--code-input_highlight-text-color");
609
+ this.internalStyle.setProperty("--code-input_default-caret-color", getComputedStyle(this).color);
546
610
  }
547
611
  }
548
612
 
613
+
549
614
  /**
550
615
  * Show some instructions to the user only if they are using keyboard navigation - for example, a prompt on how to navigate with the keyboard if Tab is repurposed.
551
616
  * @param {string} instructions The instructions to display only if keyboard navigation is being used. If it's blank, no instructions will be shown.
@@ -741,7 +806,6 @@ var codeInput = {
741
806
  this.codeElement = code;
742
807
  pre.append(code);
743
808
  this.append(pre);
744
-
745
809
  if (this.templateObject.isCode) {
746
810
  if (lang != undefined && lang != "") {
747
811
  code.classList.add("language-" + lang.toLowerCase());
@@ -780,7 +844,44 @@ var codeInput = {
780
844
  // The only element that could be resized is this code-input element.
781
845
  this.syncSize();
782
846
  });
783
- resizeObserver.observe(this.textareaElement);
847
+ resizeObserver.observe(this);
848
+
849
+
850
+ // Add internal style as non-externally-overridable alternative to style attribute for e.g. syncing color
851
+ this.classList.add("code-input_styles_" + codeInput.stylesheetI);
852
+ const stylesheet = document.createElement("style");
853
+ stylesheet.innerHTML = "code-input.code-input_styles_" + codeInput.stylesheetI + " {}";
854
+ this.appendChild(stylesheet);
855
+ this.internalStyle = stylesheet.sheet.cssRules[0].style;
856
+ codeInput.stylesheetI++;
857
+
858
+ // Synchronise colors
859
+ const preColorChangeCallback = (evt) => {
860
+ if(evt.propertyName == "color") {
861
+ this.isColorOverridenSyncIfNot();
862
+ }
863
+ };
864
+ this.preElement.addEventListener("transitionend", preColorChangeCallback);
865
+ this.preElement.addEventListener("-webkit-transitionend", preColorChangeCallback);
866
+ const thisColorChangeCallback = (evt) => {
867
+ if(evt.propertyName == "color") {
868
+ this.syncColorCompletely();
869
+ }
870
+ if(evt.target == this.dialogContainerElement) {
871
+ evt.stopPropagation();
872
+ // Prevent bubbling because code-input
873
+ // transitionend is separate
874
+ }
875
+ };
876
+ // Not on this element so CSS transition property does not override publicly-visible one
877
+ this.dialogContainerElement.addEventListener("transitionend", thisColorChangeCallback);
878
+ this.dialogContainerElement.addEventListener("-webkit-transitionend", thisColorChangeCallback);
879
+
880
+ // For when this code-input element has an externally-defined, different-duration transition
881
+ this.addEventListener("transitionend", thisColorChangeCallback);
882
+ this.addEventListener("-webkit-transitionend", thisColorChangeCallback);
883
+
884
+ this.syncColorCompletely();
784
885
 
785
886
  this.classList.add("code-input_loaded");
786
887
  }
@@ -938,7 +1039,9 @@ var codeInput = {
938
1039
  code.classList.add("language-" + newValue);
939
1040
  }
940
1041
 
941
- if (mainTextarea.placeholder == oldValue) mainTextarea.placeholder = newValue;
1042
+ if (mainTextarea.placeholder == oldValue || oldValue == null && mainTextarea.placeholder == "") {
1043
+ mainTextarea.placeholder = newValue;
1044
+ }
942
1045
 
943
1046
  this.scheduleHighlight();
944
1047
 
@@ -1 +1 @@
1
- code-input{display:block;overflow-y:auto;overflow-x:auto;position:relative;top:0;left:0;color:#000;background-color:#fff;margin:8px;--padding:16px;--padding-left:var(--padding, 16px);--padding-right:var(--padding, 16px);--padding-top:var(--padding, 16px);--padding-bottom:var(--padding, 16px);height:250px;font-size:inherit;font-family:monospace;text-align:start;line-height:1.5;tab-size:2;caret-color:#a9a9a9;white-space:pre;padding:0!important;display:grid;grid-template-columns:100%;grid-template-rows:100%}code-input *{box-sizing:content-box}code-input textarea,code-input.code-input_pre-element-styled pre,code-input:not(.code-input_pre-element-styled) pre code{margin:0!important;padding-left:var(--padding-left,16px)!important;padding-right:var(--padding-right,16px)!important;padding-top:var(--padding-top,16px)!important;padding-bottom:var(--padding-bottom,16px)!important;border:0;min-width:calc(100% - var(--padding-left,16px) - var(--padding-right,16px));min-height:calc(100% - var(--padding-top,16px) - var(--padding-bottom,16px));overflow:hidden;resize:none;grid-row:1;grid-column:1;display:block}code-input.code-input_pre-element-styled pre,code-input:not(.code-input_pre-element-styled) pre code{height:max-content;width:max-content}code-input.code-input_pre-element-styled pre code,code-input:not(.code-input_pre-element-styled) pre{margin:0!important;padding:0!important;border:0!important}code-input pre,code-input pre *,code-input textarea{font-size:inherit!important;font-family:inherit!important;line-height:inherit!important;tab-size:inherit!important;text-align:inherit!important}code-input textarea[dir=auto]+pre{unicode-bidi:plaintext}code-input textarea[dir=ltr]+pre{direction:ltr}code-input textarea[dir=rtl]+pre{direction:rtl}code-input pre,code-input textarea{grid-column:1;grid-row:1}code-input textarea:not([data-code-input-fallback]){z-index:1}code-input pre{z-index:0}code-input textarea:not([data-code-input-fallback]){color:transparent;background:0 0;caret-color:inherit!important}code-input textarea::placeholder{color:#d3d3d3}code-input pre,code-input textarea{white-space:inherit;word-spacing:normal;word-break:normal;word-wrap:normal}code-input textarea{resize:none;outline:0!important}code-input:has(textarea:focus):not(.code-input_mouse-focused){outline:2px solid currentColor}code-input .code-input_dialog-container{z-index:2;position:sticky;grid-row:1;grid-column:1;top:0;left:0;margin:0;padding:0;height:0;width:100%;text-align:inherit}[dir=rtl] code-input .code-input_dialog-container,code-input[dir=rtl] .code-input_dialog-container{left:unset;right:0}code-input .code-input_dialog-container .code-input_keyboard-navigation-instructions{top:0;left:0;display:block;position:absolute;top:0;left:0;background-color:#000;color:#fff;padding:2px;padding-left:var(--padding-left,16px);padding-right:var(--padding-right,16px);margin:0;text-wrap:balance;overflow-x:hidden;overflow-y:auto;width:100%;box-sizing:border-box;height:3em}code-input .code-input_dialog-container .code-input_keyboard-navigation-instructions:empty,code-input.code-input_mouse-focused .code-input_dialog-container .code-input_keyboard-navigation-instructions,code-input:not(:has(textarea:not([data-code-input-fallback]):focus)) .code-input_dialog-container .code-input_keyboard-navigation-instructions{display:none}code-input:not(:has(.code-input_keyboard-navigation-instructions:empty)):has(textarea:not([data-code-input-fallback]):focus):not(.code-input_mouse-focused) textarea,code-input:not(:has(.code-input_keyboard-navigation-instructions:empty)):has(textarea:not([data-code-input-fallback]):focus):not(.code-input_mouse-focused).code-input_pre-element-styled pre,code-input:not(:has(.code-input_keyboard-navigation-instructions:empty)):has(textarea:not([data-code-input-fallback]):focus):not(.code-input_mouse-focused):not(.code-input_pre-element-styled) pre code{padding-top:calc(var(--padding-top,16px) + 3em)!important;min-height:calc(100% - var(--padding-top,16px) - 3em - var(--padding-bottom,16px))}code-input:not(.code-input_loaded){padding-left:var(--padding-left,16px)!important;padding-right:var(--padding-right,16px)!important;padding:var(--padding-top,16px)!important;padding:var(--padding-bottom,16px)!important;overflow:hidden;display:block;box-sizing:border-box}code-input:not(.code-input_loaded)::after{content:"No highlighting. JavaScript support is disabled or insufficient, or codeInput.registerTemplate has not been called.";display:block;position:absolute;bottom:0;left:var(--padding-left,16px);width:calc(100% - var(--padding-left,1.6px) - var(--padding-right,1.6px));overflow-x:auto;border-top:1px solid currentColor;outline-top:0;background-color:inherit;color:inherit;margin:0;padding:0;height:2em}code-input:not(.code-input_loaded) pre,code-input:not(.code-input_loaded) textarea:not([data-code-input-fallback]){opacity:0}code-input:has(textarea[data-code-input-fallback]){padding:0!important;box-sizing:content-box}code-input textarea[data-code-input-fallback]{overflow:auto;background-color:inherit;color:inherit;min-height:calc(100% - var(--padding-top,16px) - 2em - var(--padding-bottom,16px))}
1
+ code-input{color:var(--code-input_no-override-color,black);caret-color:var(--code-input_default-caret-color,inherit);--padding:16px;--padding-left:var(--padding,16px);--padding-right:var(--padding,16px);--padding-top:var(--padding,16px);--padding-bottom:var(--padding,16px);height:250px;font-size:inherit;text-align:start;tab-size:2;white-space:pre;background-color:#fff;grid-template-rows:100%;grid-template-columns:100%;margin:8px;font-family:monospace;line-height:1.5;display:grid;position:relative;top:0;left:0;overflow:auto;padding:0!important}code-input :not(.code-input_dialog-container *){box-sizing:content-box}code-input textarea,code-input:not(.code-input_pre-element-styled) pre code,code-input.code-input_pre-element-styled pre{min-width:calc(100% - var(--padding-left,16px) - var(--padding-right,16px));min-height:calc(100% - var(--padding-top,16px) - var(--padding-bottom,16px));resize:none;border:0;grid-area:1/1;display:block;overflow:hidden;padding-left:var(--padding-left,16px)!important;padding-right:var(--padding-right,16px)!important;padding-top:var(--padding-top,16px)!important;padding-bottom:var(--padding-bottom,16px)!important;margin:0!important}code-input:not(.code-input_pre-element-styled) pre code,code-input.code-input_pre-element-styled pre{width:max-content;height:max-content;transition:color 1ms}code-input:not(.code-input_pre-element-styled) pre,code-input.code-input_pre-element-styled pre code{border:0!important;margin:0!important;padding:0!important}code-input textarea,code-input pre,code-input pre *{font-size:inherit!important;font-family:inherit!important;line-height:inherit!important;tab-size:inherit!important;text-align:inherit!important}code-input textarea[dir=auto]+pre{unicode-bidi:plaintext}code-input textarea[dir=ltr]+pre{direction:ltr}code-input textarea[dir=rtl]+pre{direction:rtl}code-input textarea,code-input pre{grid-area:1/1}code-input textarea:not([data-code-input-fallback]){z-index:1}code-input pre{z-index:0}code-input textarea:not([data-code-input-fallback]){color:#0000;caret-color:inherit;background:0 0}code-input textarea:not([data-code-input-fallback]):placeholder-shown{color:var(--code-input_highlight-text-color,inherit)}code-input textarea,code-input pre{white-space:inherit;word-spacing:normal;word-break:normal;word-wrap:normal}code-input textarea{resize:none;outline:none!important}code-input:has(textarea:focus):not(.code-input_mouse-focused){outline:2px solid}code-input .code-input_dialog-container{z-index:2;width:100%;height:0;text-align:inherit;color:inherit;grid-area:1/1;margin:0;padding:0;transition:color 1ms;position:sticky;top:0;left:0}[dir=rtl] code-input .code-input_dialog-container,code-input[dir=rtl] .code-input_dialog-container{left:unset;right:0}code-input .code-input_dialog-container .code-input_keyboard-navigation-instructions{color:#fff;padding:2px;padding-left:var(--padding-left,16px);padding-right:var(--padding-right,16px);text-wrap:balance;box-sizing:border-box;background-color:#000;width:100%;height:3em;margin:0;display:block;position:absolute;top:0;left:0;overflow:hidden auto}code-input:not(:has(textarea:not([data-code-input-fallback]):focus)) .code-input_dialog-container .code-input_keyboard-navigation-instructions,code-input.code-input_mouse-focused .code-input_dialog-container .code-input_keyboard-navigation-instructions,code-input .code-input_dialog-container .code-input_keyboard-navigation-instructions:empty{display:none}code-input:not(:has(.code-input_keyboard-navigation-instructions:empty)):has(textarea:not([data-code-input-fallback]):focus):not(.code-input_mouse-focused) textarea,code-input:not(:has(.code-input_keyboard-navigation-instructions:empty)):has(textarea:not([data-code-input-fallback]):focus):not(.code-input_mouse-focused):not(.code-input_pre-element-styled) pre code,code-input:not(:has(.code-input_keyboard-navigation-instructions:empty)):has(textarea:not([data-code-input-fallback]):focus):not(.code-input_mouse-focused).code-input_pre-element-styled pre{min-height:calc(100% - var(--padding-top,16px) - 3em - var(--padding-bottom,16px));padding-top:calc(var(--padding-top,16px) + 3em)!important}code-input:not(.code-input_loaded){box-sizing:border-box;display:block;overflow:hidden;padding-left:var(--padding-left,16px)!important;padding-right:var(--padding-right,16px)!important;padding:var(--padding-top,16px)!important;padding:var(--padding-bottom,16px)!important}code-input:not(.code-input_loaded):after{content:"No highlighting. JavaScript support is disabled or insufficient, or codeInput.registerTemplate has not been called.";bottom:0;left:var(--padding-left,16px);width:calc(100% - var(--padding-left,1.6px) - var(--padding-right,1.6px));outline-top:0;background-color:inherit;color:inherit;border-top:1px solid;height:2em;margin:0;padding:0;display:block;position:absolute;overflow-x:auto}code-input:not(.code-input_loaded) pre,code-input:not(.code-input_loaded) textarea:not([data-code-input-fallback]){opacity:0}code-input:has(textarea[data-code-input-fallback]){box-sizing:content-box;caret-color:revert;padding:0!important}code-input textarea[data-code-input-fallback]{background-color:inherit;color:var(--code-input_highlight-text-color,inherit);min-height:calc(100% - var(--padding-top,16px) - 2em - var(--padding-bottom,16px));overflow:auto}
package/code-input.min.js CHANGED
@@ -9,4 +9,4 @@
9
9
  * @license MIT
10
10
  *
11
11
  * **<https://code-input-js.org>**
12
- */"use strict";var codeInput={observedAttributes:["value","placeholder","language","lang","template"],textareaSyncAttributes:["value","min","max","type","pattern","autocomplete","autocorrect","autofocus","cols","dirname","disabled","form","maxlength","minlength","name","placeholder","readonly","required","rows","spellcheck","wrap"],textareaSyncEvents:["change","selectionchange","invalid","input","focus","blur","focusin","focusout"],usedTemplates:{},defaultTemplate:void 0,templateNotYetRegisteredQueue:{},registerTemplate:function(a,b){if(!("string"==typeof a||a instanceof String))throw TypeError(`code-input: Name of template "${a}" must be a string.`);if(!("function"==typeof b.highlight||b.highlight instanceof Function))throw TypeError(`code-input: Template for "${a}" invalid, because the highlight function provided is not a function; it is "${b.highlight}". Please make sure you use one of the constructors in codeInput.templates, and that you provide the correct arguments.`);if(!("boolean"==typeof b.includeCodeInputInHighlightFunc||b.includeCodeInputInHighlightFunc instanceof Boolean))throw TypeError(`code-input: Template for "${a}" invalid, because the includeCodeInputInHighlightFunc value provided is not a true or false; it is "${b.includeCodeInputInHighlightFunc}". Please make sure you use one of the constructors in codeInput.templates, and that you provide the correct arguments.`);if(!("boolean"==typeof b.preElementStyled||b.preElementStyled instanceof Boolean))throw TypeError(`code-input: Template for "${a}" invalid, because the preElementStyled value provided is not a true or false; it is "${b.preElementStyled}". Please make sure you use one of the constructors in codeInput.templates, and that you provide the correct arguments.`);if(!("boolean"==typeof b.isCode||b.isCode instanceof Boolean))throw TypeError(`code-input: Template for "${a}" invalid, because the isCode value provided is not a true or false; it is "${b.isCode}". Please make sure you use one of the constructors in codeInput.templates, and that you provide the correct arguments.`);if(!Array.isArray(b.plugins))throw TypeError(`code-input: Template for "${a}" invalid, because the plugin array provided is not an array; it is "${b.plugins}". Please make sure you use one of the constructors in codeInput.templates, and that you provide the correct arguments.`);if(b.plugins.forEach((c,d)=>{if(!(c instanceof codeInput.Plugin))throw TypeError(`code-input: Template for "${a}" invalid, because the plugin provided at index ${d} is not valid; it is "${b.plugins[d]}". Please make sure you use one of the constructors in codeInput.templates, and that you provide the correct arguments.`)}),codeInput.usedTemplates[a]=b,a in codeInput.templateNotYetRegisteredQueue)for(let c in codeInput.templateNotYetRegisteredQueue[a]){const d=codeInput.templateNotYetRegisteredQueue[a][c];d.templateObject=b,d.setup()}if(null==codeInput.defaultTemplate&&(codeInput.defaultTemplate=a,void 0 in codeInput.templateNotYetRegisteredQueue))for(let a in codeInput.templateNotYetRegisteredQueue[void 0]){const c=codeInput.templateNotYetRegisteredQueue[void 0][a];c.templateObject=b,c.setup()}},Template:class{constructor(a=function(){},b=!0,c=!0,d=!1,e=[]){this.highlight=a,this.preElementStyled=b,this.isCode=c,this.includeCodeInputInHighlightFunc=d,this.plugins=e}highlight=function(){};preElementStyled=!0;isCode=!0;includeCodeInputInHighlightFunc=!1;plugins=[]},templates:{prism(a,b=[]){return new codeInput.templates.Prism(a,b)},hljs(a,b=[]){return new codeInput.templates.Hljs(a,b)},characterLimit(a){return{highlight:function(a,b,c=[]){let d=+b.getAttribute("data-character-limit"),e=b.escapeHtml(b.value.slice(0,d)),f=b.escapeHtml(b.value.slice(d));a.innerHTML=`${e}<mark class="overflow">${f}</mark>`,0<f.length&&(a.innerHTML+=` <mark class="overflow-msg">${b.getAttribute("data-overflow-msg")||"(Character limit reached)"}</mark>`)},includeCodeInputInHighlightFunc:!0,preElementStyled:!0,isCode:!1,plugins:a}},rainbowText(a=["red","orangered","orange","goldenrod","gold","green","darkgreen","navy","blue","magenta"],b="",c=[]){return{highlight:function(a,b){let c=[],d=b.value.split(b.template.delimiter);for(let e=0;e<d.length;e++)c.push(`<span style="color: ${b.template.rainbowColors[e%b.template.rainbowColors.length]}">${b.escapeHtml(d[e])}</span>`);a.innerHTML=c.join(b.template.delimiter)},includeCodeInputInHighlightFunc:!0,preElementStyled:!0,isCode:!1,rainbowColors:a,delimiter:b,plugins:c}},character_limit(){return this.characterLimit([])},rainbow_text(a=["red","orangered","orange","goldenrod","gold","green","darkgreen","navy","blue","magenta"],b="",c=[]){return this.rainbowText(a,b,c)},custom(a=function(){},b=!0,c=!0,d=!1,e=[]){return{highlight:a,includeCodeInputInHighlightFunc:d,preElementStyled:b,isCode:c,plugins:e}}},plugins:new Proxy({},{get(a,b){if(a[b]==null)throw ReferenceError(`code-input: Plugin '${b}' is not defined. Please ensure you import the necessary files from the plugins folder in the WebCoder49/code-input repository, in the <head> of your HTML, before the plugin is instatiated.`);return a[b]}}),Plugin:class{constructor(a){a.forEach(a=>{codeInput.observedAttributes.push(a)})}addTranslations(a,b){for(const c in b)a[c]=b[c]}beforeHighlight(){}afterHighlight(){}beforeElementsAdded(){}afterElementsAdded(){}attributeChanged(){}},CodeInput:class extends HTMLElement{constructor(){super()}templateObject=null;textareaElement=null;preElement=null;codeElement=null;dialogContainerElement=null;static formAssociated=!0;boundEventCallbacks={};pluginEvt(a,b){for(let c in this.templateObject.plugins){let d=this.templateObject.plugins[c];a in d&&(b===void 0?d[a](this):d[a](this,...b))}}needsHighlight=!1;originalAriaDescription;scheduleHighlight(){this.needsHighlight=!0}animateFrame(){this.needsHighlight&&(this.update(),this.needsHighlight=!1),window.requestAnimationFrame(this.animateFrame.bind(this))}update(){let a=this.codeElement,b=this.value;b+="\n",a.innerHTML=this.escapeHtml(b),this.pluginEvt("beforeHighlight"),this.templateObject.includeCodeInputInHighlightFunc?this.templateObject.highlight(a,this):this.templateObject.highlight(a),this.syncSize(),this.pluginEvt("afterHighlight")}syncSize(){this.templateObject.preElementStyled?(this.style.backgroundColor=getComputedStyle(this.preElement).backgroundColor,this.textareaElement.style.height=getComputedStyle(this.preElement).height,this.textareaElement.style.width=getComputedStyle(this.preElement).width):(this.style.backgroundColor=getComputedStyle(this.codeElement).backgroundColor,this.textareaElement.style.height=getComputedStyle(this.codeElement).height,this.textareaElement.style.width=getComputedStyle(this.codeElement).width)}setKeyboardNavInstructions(a,b){this.dialogContainerElement.querySelector(".code-input_keyboard-navigation-instructions").innerText=a,b?this.textareaElement.setAttribute("aria-description",this.originalAriaDescription+". "+a):this.textareaElement.setAttribute("aria-description",a)}escapeHtml(a){return a.replace(/&/g,"&amp;").replace(/</g,"&lt;")}unescapeHtml(a){return a.replace(/&amp;/g,"&").replace(/&lt;/g,"<").replace(/&gt;/g,">")}getTemplate(){let a;return a=null==this.getAttribute("template")?codeInput.defaultTemplate:this.getAttribute("template"),a in codeInput.usedTemplates?codeInput.usedTemplates[a]:(a in codeInput.templateNotYetRegisteredQueue||(codeInput.templateNotYetRegisteredQueue[a]=[]),void codeInput.templateNotYetRegisteredQueue[a].push(this))}setup(){if(null!=this.textareaElement)return;this.classList.add("code-input_registered"),this.mutationObserver=new MutationObserver(this.mutationObserverCallback.bind(this)),this.mutationObserver.observe(this,{attributes:!0,attributeOldValue:!0}),this.classList.add("code-input_registered"),this.templateObject.preElementStyled&&this.classList.add("code-input_pre-element-styled");const a=this.querySelector("textarea[data-code-input-fallback]");let b,c,d,e,f,g=!1;a&&(a===document.activeElement&&(g=!0),b=a.selectionStart,c=a.selectionEnd,d=a.selectionDirection,e=a.scrollLeft,f=a.scrollTop);let h;if(a){let b=a.getAttributeNames();for(let c=0;c<b.length;c++){const d=b[c];"data-code-input-fallback"!=d&&(this.hasAttribute(d)||this.setAttribute(d,a.getAttribute(d)))}h=a.value,this.innerHTML=this.escapeHtml(h)}else h=this.unescapeHtml(this.innerHTML);h=h||this.getAttribute("value")||"",this.pluginEvt("beforeElementsAdded");const i=this.getAttribute("language")||this.getAttribute("lang"),j=this.getAttribute("placeholder")||i||"";this.initialValue=h;const k=document.createElement("textarea");k.placeholder=j,""!=h&&(k.value=h),k.innerHTML=this.innerHTML,this.hasAttribute("spellcheck")||k.setAttribute("spellcheck","false"),k.setAttribute("tabindex",this.getAttribute("tabindex")||0),this.setAttribute("tabindex",-1),this.originalAriaDescription=this.getAttribute("aria-description")||"Code input field",this.addEventListener("mousedown",()=>{this.classList.add("code-input_mouse-focused"),window.setTimeout(()=>{this.syncSize()},0)}),k.addEventListener("blur",()=>{this.classList.remove("code-input_mouse-focused"),window.setTimeout(()=>{this.syncSize()},0)}),k.addEventListener("focus",()=>{window.setTimeout(()=>{this.syncSize()},0)}),this.innerHTML="";for(let a,b=0;b<this.attributes.length;b++)a=this.attributes[b].name,(codeInput.textareaSyncAttributes.includes(a)||"aria-"==a.substring(0,5))&&k.setAttribute(a,this.getAttribute(a));k.addEventListener("input",()=>{this.value=this.textareaElement.value}),this.textareaElement=k,this.append(k),this.setupTextareaSyncEvents(this.textareaElement);let l=document.createElement("code"),m=document.createElement("pre");m.setAttribute("aria-hidden","true"),m.setAttribute("tabindex","-1"),m.setAttribute("inert",!0),this.preElement=m,this.codeElement=l,m.append(l),this.append(m),this.templateObject.isCode&&i!=null&&""!=i&&l.classList.add("language-"+i.toLowerCase());let n=document.createElement("div");n.classList.add("code-input_dialog-container"),this.append(n),this.dialogContainerElement=n;let o=document.createElement("div");o.classList.add("code-input_keyboard-navigation-instructions"),n.append(o),this.pluginEvt("afterElementsAdded"),this.dispatchEvent(new CustomEvent("code-input_load")),this.value=h,b!==void 0&&(k.setSelectionRange(b,c,d),k.scrollTo(f,e)),g&&k.focus(),this.animateFrame();const p=new ResizeObserver(()=>{this.syncSize()});p.observe(this.textareaElement),this.classList.add("code-input_loaded")}escape_html(a){return this.escapeHtml(a)}get_template(){return this.getTemplate()}get template(){return this.templateObject}set template(a){}connectedCallback(){if(this.templateObject=this.getTemplate(),null!=this.templateObject&&(this.classList.add("code-input_registered"),"loading"===document.readyState?window.addEventListener("DOMContentLoaded",this.setup.bind(this)):this.setup()),"loading"===document.readyState)window.addEventListener("DOMContentLoaded",()=>{const a=this.querySelector("textarea[data-code-input-fallback]");a&&this.setupTextareaSyncEvents(a)});else{const a=this.querySelector("textarea[data-code-input-fallback]");a&&this.setupTextareaSyncEvents(a)}}mutationObserverCallback(a){for(const b of a)if("attributes"===b.type){for(let a=0;a<codeInput.observedAttributes.length;a++)if(b.attributeName==codeInput.observedAttributes[a])return this.attributeChangedCallback(b.attributeName,b.oldValue,super.getAttribute(b.attributeName));for(let a=0;a<codeInput.textareaSyncAttributes.length;a++)if(b.attributeName==codeInput.textareaSyncAttributes[a])return this.attributeChangedCallback(b.attributeName,b.oldValue,super.getAttribute(b.attributeName));if("aria-"==b.attributeName.substring(0,5))return this.attributeChangedCallback(b.attributeName,b.oldValue,super.getAttribute(b.attributeName))}}disconnectedCallback(){this.mutationObserver&&this.mutationObserver.disconnect()}attributeChangedCallback(a,b,c){if(this.isConnected)switch(this.pluginEvt("attributeChanged",[a,b,c]),a){case"value":this.value=c;break;case"template":this.templateObject=codeInput.usedTemplates[c||codeInput.defaultTemplate],this.templateObject.preElementStyled?this.classList.add("code-input_pre-element-styled"):this.classList.remove("code-input_pre-element-styled"),this.scheduleHighlight();break;case"lang":case"language":let d=this.codeElement,e=this.textareaElement;if(null!=c&&(c=c.toLowerCase(),d.classList.contains(`language-${c}`)))break;null!==b&&(b=b.toLowerCase(),d.classList.remove("language-"+b),d.parentElement.classList.remove("language-"+b)),d.classList.remove("language-none"),d.parentElement.classList.remove("language-none"),null!=c&&""!=c&&d.classList.add("language-"+c),e.placeholder==b&&(e.placeholder=c),this.scheduleHighlight();break;default:codeInput.textareaSyncAttributes.includes(a)||"aria-"==a.substring(0,5)?null==c||null==c?this.textareaElement.removeAttribute(a):this.textareaElement.setAttribute(a,c):codeInput.textareaSyncAttributes.regexp.forEach(b=>{a.match(b)&&(null==c?this.textareaElement.removeAttribute(a):this.textareaElement.setAttribute(a,c))})}}setupTextareaSyncEvents(a){for(let b=0;b<codeInput.textareaSyncEvents.length;b++){const c=codeInput.textareaSyncEvents[b];a.addEventListener(c,a=>{a.bubbles||this.dispatchEvent(new a.constructor(a.type,a))})}}addEventListener(a,b,c=void 0){let d=function(a){"function"==typeof b?b(a):b&&b.handleEvent&&b.handleEvent(a)}.bind(this);if(this.boundEventCallbacks[b]=d,!codeInput.textareaSyncEvents.includes(a))void 0===c?super.addEventListener(a,d):super.addEventListener(a,d,c);else if(this.boundEventCallbacks[b]=d,void 0===c){if(null==this.textareaElement){const b=this.querySelector("textarea[data-code-input-fallback]");b&&b.addEventListener(a,d),this.addEventListener("code-input_load",()=>{this.textareaElement.addEventListener(a,d)})}else this.textareaElement.addEventListener(a,d);}else if(null==this.textareaElement){const b=this.querySelector("textarea[data-code-input-fallback]");b&&b.addEventListener(a,d,c),this.addEventListener("code-input_load",()=>{this.textareaElement.addEventListener(a,d,c)})}else this.textareaElement.addEventListener(a,d,c)}removeEventListener(a,b,c=void 0){let d=this.boundEventCallbacks[b];if(!codeInput.textareaSyncEvents.includes(a))void 0===c?super.removeEventListener(a,d):super.removeEventListener(a,d,c);else if(void 0===c){if(null==this.textareaElement){const b=this.querySelector("textarea[data-code-input-fallback]");b&&b.removeEventListener(a,d),this.addEventListener("code-input_load",()=>{this.textareaElement.removeEventListener(a,d)})}else this.textareaElement.removeEventListener(a,d);}else if(null==this.textareaElement){const b=this.querySelector("textarea[data-code-input-fallback]");b&&b.removeEventListener(a,d,c),this.addEventListener("code-input_load",()=>{this.textareaElement.removeEventListener(a,d,c)})}else this.textareaElement.removeEventListener(a,d,c)}getTextareaProperty(a,b=void 0){if(this.textareaElement)return this.textareaElement[a];else{const c=this.querySelector("textarea[data-code-input-fallback]");if(c)return c[a];if(void 0===b)throw new Error("Cannot get "+a+" of an unregistered code-input element without a data-code-input-fallback textarea.");return b}}setTextareaProperty(a,b,c=!0){if(this.textareaElement)this.textareaElement[a]=b;else{const d=this.querySelector("textarea[data-code-input-fallback]");if(d)d[a]=b;else{if(!c)return(!1);throw new Error("Cannot set "+a+" of an unregistered code-input element without a data-code-input-fallback textarea.")}}return(!0)}get autocomplete(){return this.getAttribute("autocomplete")}set autocomplete(a){return this.setAttribute("autocomplete",a)}get cols(){return this.getTextareaProperty("cols",+this.getAttribute("cols"))}set cols(a){this.setAttribute("cols",a)}get defaultValue(){return this.initialValue}set defaultValue(a){this.initialValue=a}get textContent(){return this.initialValue}set textContent(a){this.initialValue=a}get dirName(){return this.getAttribute("dirName")||""}set dirName(a){this.setAttribute("dirname",a)}get disabled(){return this.hasAttribute("disabled")}set disabled(a){a?this.setAttribute("disabled",!0):this.removeAttribute("disabled")}get form(){return this.getTextareaProperty("form")}get labels(){return this.getTextareaProperty("labels")}get maxLength(){const a=+this.getAttribute("maxlength");return isNaN(a)?-1:a}set maxLength(a){-1==a?this.removeAttribute("maxlength"):this.setAttribute("maxlength",a)}get minLength(){const a=+this.getAttribute("minlength");return isNaN(a)?-1:a}set minLength(a){-1==a?this.removeAttribute("minlength"):this.setAttribute("minlength",a)}get name(){return this.getAttribute("name")||""}set name(a){this.setAttribute("name",a)}get placeholder(){return this.getAttribute("placeholder")||""}set placeholder(a){this.setAttribute("placeholder",a)}get readOnly(){return this.hasAttribute("readonly")}set readOnly(a){a?this.setAttribute("readonly",!0):this.removeAttribute("readonly")}get required(){return this.hasAttribute("readonly")}set required(a){a?this.setAttribute("readonly",!0):this.removeAttribute("readonly")}get rows(){return this.getTextareaProperty("rows",+this.getAttribute("rows"))}set rows(a){this.setAttribute("rows",a)}get selectionDirection(){return this.getTextareaProperty("selectionDirection")}set selectionDirection(a){this.setTextareaProperty("selectionDirection",a)}get selectionEnd(){return this.getTextareaProperty("selectionEnd")}set selectionEnd(a){this.setTextareaProperty("selectionEnd",a)}get selectionStart(){return this.getTextareaProperty("selectionStart")}set selectionStart(a){this.setTextareaProperty("selectionStart",a)}get textLength(){return this.value.length}get type(){return"textarea"}get validationMessage(){return this.getTextareaProperty("validationMessage")}get validity(){return this.getTextareaProperty("validationMessage")}get value(){return this.getTextareaProperty("value",this.getAttribute("value")||this.innerHTML)}set value(a){a=a||"",this.setTextareaProperty("value",a,!1)?this.textareaElement&&this.scheduleHighlight():this.innerHTML=a}get willValidate(){return this.getTextareaProperty("willValidate",this.disabled||this.readOnly)}get wrap(){return this.getAttribute("wrap")||""}set wrap(a){this.setAttribute("wrap",a)}getTextareaMethod(a){if(this.textareaElement)return this.textareaElement[a].bind(this.textareaElement);else{const b=this.querySelector("textarea[data-code-input-fallback]");if(b)return b[a].bind(b);throw new Error("Cannot call "+a+" on an unregistered code-input element without a data-code-input-fallback textarea.")}}blur(a={}){this.getTextareaMethod("blur")(a)}checkValidity(){return this.getTextareaMethod("checkValidity")()}focus(a={}){this.getTextareaMethod("focus")(a)}reportValidity(){return this.getTextareaMethod("reportValidity")()}setCustomValidity(a){this.getTextareaMethod("setCustomValidity")(a)}setRangeText(a,b=this.selectionStart,c=this.selectionEnd,d="preserve"){this.getTextareaMethod("setRangeText")(a,b,c,d),this.textareaElement&&this.scheduleHighlight()}setSelectionRange(a,b,c="none"){this.getTextareaMethod("setSelectionRange")(a,b,c)}pluginData={};formResetCallback(){this.value=this.initialValue}}};{class a extends codeInput.Template{constructor(a,b=[],c=!0){super(a.highlightElement,c,!0,!1,b)}}codeInput.templates.Prism=a;class b extends codeInput.Template{constructor(a,b=[],c=!1){super(function(b){b.removeAttribute("data-highlighted"),a.highlightElement(b)},c,!0,!1,b)}}codeInput.templates.Hljs=b}customElements.define("code-input",codeInput.CodeInput);
12
+ */"use strict";var codeInput={observedAttributes:["value","placeholder","language","lang","template"],textareaSyncAttributes:["value","min","max","type","pattern","autocomplete","autocorrect","autofocus","cols","dirname","disabled","form","maxlength","minlength","name","placeholder","readonly","required","rows","spellcheck","wrap"],textareaSyncEvents:["change","selectionchange","invalid","input","focus","blur","focusin","focusout"],usedTemplates:{},defaultTemplate:void 0,templateNotYetRegisteredQueue:{},registerTemplate:function(a,b){if(!("string"==typeof a||a instanceof String))throw TypeError(`code-input: Name of template "${a}" must be a string.`);if(!("function"==typeof b.highlight||b.highlight instanceof Function))throw TypeError(`code-input: Template for "${a}" invalid, because the highlight function provided is not a function; it is "${b.highlight}". Please make sure you use one of the constructors in codeInput.templates, and that you provide the correct arguments.`);if(!("boolean"==typeof b.includeCodeInputInHighlightFunc||b.includeCodeInputInHighlightFunc instanceof Boolean))throw TypeError(`code-input: Template for "${a}" invalid, because the includeCodeInputInHighlightFunc value provided is not a true or false; it is "${b.includeCodeInputInHighlightFunc}". Please make sure you use one of the constructors in codeInput.templates, and that you provide the correct arguments.`);if(!("boolean"==typeof b.preElementStyled||b.preElementStyled instanceof Boolean))throw TypeError(`code-input: Template for "${a}" invalid, because the preElementStyled value provided is not a true or false; it is "${b.preElementStyled}". Please make sure you use one of the constructors in codeInput.templates, and that you provide the correct arguments.`);if(!("boolean"==typeof b.isCode||b.isCode instanceof Boolean))throw TypeError(`code-input: Template for "${a}" invalid, because the isCode value provided is not a true or false; it is "${b.isCode}". Please make sure you use one of the constructors in codeInput.templates, and that you provide the correct arguments.`);if(!Array.isArray(b.plugins))throw TypeError(`code-input: Template for "${a}" invalid, because the plugin array provided is not an array; it is "${b.plugins}". Please make sure you use one of the constructors in codeInput.templates, and that you provide the correct arguments.`);if(b.plugins.forEach((c,d)=>{if(!(c instanceof codeInput.Plugin))throw TypeError(`code-input: Template for "${a}" invalid, because the plugin provided at index ${d} is not valid; it is "${b.plugins[d]}". Please make sure you use one of the constructors in codeInput.templates, and that you provide the correct arguments.`)}),codeInput.usedTemplates[a]=b,a in codeInput.templateNotYetRegisteredQueue)for(let c in codeInput.templateNotYetRegisteredQueue[a]){const d=codeInput.templateNotYetRegisteredQueue[a][c];d.templateObject=b,d.setup()}if(null==codeInput.defaultTemplate&&(codeInput.defaultTemplate=a,void 0 in codeInput.templateNotYetRegisteredQueue))for(let a in codeInput.templateNotYetRegisteredQueue[void 0]){const c=codeInput.templateNotYetRegisteredQueue[void 0][a];c.templateObject=b,c.setup()}},stylesheetI:0,Template:class{constructor(a=function(){},b=!0,c=!0,d=!1,e=[]){this.highlight=a,this.preElementStyled=b,this.isCode=c,this.includeCodeInputInHighlightFunc=d,this.plugins=e}highlight=function(){};preElementStyled=!0;isCode=!0;includeCodeInputInHighlightFunc=!1;plugins=[]},templates:{prism(a,b=[]){return new codeInput.templates.Prism(a,b)},hljs(a,b=[]){return new codeInput.templates.Hljs(a,b)},characterLimit(a){return{highlight:function(a,b,c=[]){let d=+b.getAttribute("data-character-limit"),e=b.escapeHtml(b.value.slice(0,d)),f=b.escapeHtml(b.value.slice(d));a.innerHTML=`${e}<mark class="overflow">${f}</mark>`,0<f.length&&(a.innerHTML+=` <mark class="overflow-msg">${b.getAttribute("data-overflow-msg")||"(Character limit reached)"}</mark>`)},includeCodeInputInHighlightFunc:!0,preElementStyled:!0,isCode:!1,plugins:a}},rainbowText(a=["red","orangered","orange","goldenrod","gold","green","darkgreen","navy","blue","magenta"],b="",c=[]){return{highlight:function(a,b){let c=[],d=b.value.split(b.template.delimiter);for(let e=0;e<d.length;e++)c.push(`<span style="color: ${b.template.rainbowColors[e%b.template.rainbowColors.length]}">${b.escapeHtml(d[e])}</span>`);a.innerHTML=c.join(b.template.delimiter)},includeCodeInputInHighlightFunc:!0,preElementStyled:!0,isCode:!1,rainbowColors:a,delimiter:b,plugins:c}},character_limit(){return this.characterLimit([])},rainbow_text(a=["red","orangered","orange","goldenrod","gold","green","darkgreen","navy","blue","magenta"],b="",c=[]){return this.rainbowText(a,b,c)},custom(a=function(){},b=!0,c=!0,d=!1,e=[]){return{highlight:a,includeCodeInputInHighlightFunc:d,preElementStyled:b,isCode:c,plugins:e}}},plugins:new Proxy({},{get(a,b){if(a[b]==null)throw ReferenceError(`code-input: Plugin '${b}' is not defined. Please ensure you import the necessary files from the plugins folder in the WebCoder49/code-input repository, in the <head> of your HTML, before the plugin is instatiated.`);return a[b]}}),Plugin:class{constructor(a){a.forEach(a=>{codeInput.observedAttributes.push(a)})}addTranslations(a,b){for(const c in b)a[c]=b[c]}beforeHighlight(){}afterHighlight(){}beforeElementsAdded(){}afterElementsAdded(){}attributeChanged(){}},CodeInput:class extends HTMLElement{constructor(){super()}templateObject=null;textareaElement=null;preElement=null;codeElement=null;dialogContainerElement=null;internalStyle=null;static formAssociated=!0;boundEventCallbacks={};pluginEvt(a,b){for(let c in this.templateObject.plugins){let d=this.templateObject.plugins[c];a in d&&(b===void 0?d[a](this):d[a](this,...b))}}needsHighlight=!1;originalAriaDescription;scheduleHighlight(){this.needsHighlight=!0}animateFrame(){this.needsHighlight&&(this.update(),this.needsHighlight=!1),window.requestAnimationFrame(this.animateFrame.bind(this))}update(){let a=this.codeElement,b=this.value;b+="\n",a.innerHTML=this.escapeHtml(b),this.pluginEvt("beforeHighlight"),this.templateObject.includeCodeInputInHighlightFunc?this.templateObject.highlight(a,this):this.templateObject.highlight(a),this.syncSize(),this.pluginEvt("afterHighlight")}getStyledHighlightingElement(){return this.templateObject.preElementStyled?this.preElement:this.codeElement}syncSize(){this.textareaElement.style.height=getComputedStyle(this.getStyledHighlightingElement()).height,this.textareaElement.style.width=getComputedStyle(this.getStyledHighlightingElement()).width}isColorOverridenSyncIfNot(){const a=this.style.transition;return this.style.transition="unset",window.requestAnimationFrame(()=>{if(this.internalStyle.setProperty("--code-input_no-override-color","rgb(0, 0, 0)"),"rgb(0, 0, 0)"==getComputedStyle(this).color&&(this.internalStyle.setProperty("--code-input_no-override-color","rgb(255, 255, 255)"),"rgb(255, 255, 255)"==getComputedStyle(this).color)){this.internalStyle.removeProperty("--code-input_no-override-color"),this.style.transition=a;const b=getComputedStyle(this.getStyledHighlightingElement()).color;return this.internalStyle.setProperty("--code-input_highlight-text-color",b),this.internalStyle.setProperty("--code-input_default-caret-color",b),!1}this.internalStyle.removeProperty("--code-input_no-override-color"),this.style.transition=a}),!0}syncColorCompletely(){this.isColorOverridenSyncIfNot()&&(this.internalStyle.removeProperty("--code-input_highlight-text-color"),this.internalStyle.setProperty("--code-input_default-caret-color",getComputedStyle(this).color))}setKeyboardNavInstructions(a,b){this.dialogContainerElement.querySelector(".code-input_keyboard-navigation-instructions").innerText=a,b?this.textareaElement.setAttribute("aria-description",this.originalAriaDescription+". "+a):this.textareaElement.setAttribute("aria-description",a)}escapeHtml(a){return a.replace(/&/g,"&amp;").replace(/</g,"&lt;")}unescapeHtml(a){return a.replace(/&amp;/g,"&").replace(/&lt;/g,"<").replace(/&gt;/g,">")}getTemplate(){let a;return a=null==this.getAttribute("template")?codeInput.defaultTemplate:this.getAttribute("template"),a in codeInput.usedTemplates?codeInput.usedTemplates[a]:(a in codeInput.templateNotYetRegisteredQueue||(codeInput.templateNotYetRegisteredQueue[a]=[]),void codeInput.templateNotYetRegisteredQueue[a].push(this))}setup(){if(null!=this.textareaElement)return;this.classList.add("code-input_registered"),this.mutationObserver=new MutationObserver(this.mutationObserverCallback.bind(this)),this.mutationObserver.observe(this,{attributes:!0,attributeOldValue:!0}),this.classList.add("code-input_registered"),this.templateObject.preElementStyled&&this.classList.add("code-input_pre-element-styled");const a=this.querySelector("textarea[data-code-input-fallback]");let b,c,d,e,f,g=!1;a&&(a===document.activeElement&&(g=!0),b=a.selectionStart,c=a.selectionEnd,d=a.selectionDirection,e=a.scrollLeft,f=a.scrollTop);let h;if(a){let b=a.getAttributeNames();for(let c=0;c<b.length;c++){const d=b[c];"data-code-input-fallback"!=d&&(this.hasAttribute(d)||this.setAttribute(d,a.getAttribute(d)))}h=a.value,this.innerHTML=this.escapeHtml(h)}else h=this.unescapeHtml(this.innerHTML);h=h||this.getAttribute("value")||"",this.pluginEvt("beforeElementsAdded");const i=this.getAttribute("language")||this.getAttribute("lang"),j=this.getAttribute("placeholder")||i||"";this.initialValue=h;const k=document.createElement("textarea");k.placeholder=j,""!=h&&(k.value=h),k.innerHTML=this.innerHTML,this.hasAttribute("spellcheck")||k.setAttribute("spellcheck","false"),k.setAttribute("tabindex",this.getAttribute("tabindex")||0),this.setAttribute("tabindex",-1),this.originalAriaDescription=this.getAttribute("aria-description")||"Code input field",this.addEventListener("mousedown",()=>{this.classList.add("code-input_mouse-focused"),window.setTimeout(()=>{this.syncSize()},0)}),k.addEventListener("blur",()=>{this.classList.remove("code-input_mouse-focused"),window.setTimeout(()=>{this.syncSize()},0)}),k.addEventListener("focus",()=>{window.setTimeout(()=>{this.syncSize()},0)}),this.innerHTML="";for(let a,b=0;b<this.attributes.length;b++)a=this.attributes[b].name,(codeInput.textareaSyncAttributes.includes(a)||"aria-"==a.substring(0,5))&&k.setAttribute(a,this.getAttribute(a));k.addEventListener("input",()=>{this.value=this.textareaElement.value}),this.textareaElement=k,this.append(k),this.setupTextareaSyncEvents(this.textareaElement);let l=document.createElement("code"),m=document.createElement("pre");m.setAttribute("aria-hidden","true"),m.setAttribute("tabindex","-1"),m.setAttribute("inert",!0),this.preElement=m,this.codeElement=l,m.append(l),this.append(m),this.templateObject.isCode&&i!=null&&""!=i&&l.classList.add("language-"+i.toLowerCase());let n=document.createElement("div");n.classList.add("code-input_dialog-container"),this.append(n),this.dialogContainerElement=n;let o=document.createElement("div");o.classList.add("code-input_keyboard-navigation-instructions"),n.append(o),this.pluginEvt("afterElementsAdded"),this.dispatchEvent(new CustomEvent("code-input_load")),this.value=h,b!==void 0&&(k.setSelectionRange(b,c,d),k.scrollTo(f,e)),g&&k.focus(),this.animateFrame();const p=new ResizeObserver(()=>{this.syncSize()});p.observe(this),this.classList.add("code-input_styles_"+codeInput.stylesheetI);const q=document.createElement("style");q.innerHTML="code-input.code-input_styles_"+codeInput.stylesheetI+" {}",this.appendChild(q),this.internalStyle=q.sheet.cssRules[0].style,codeInput.stylesheetI++;const r=a=>{"color"==a.propertyName&&this.isColorOverridenSyncIfNot()};this.preElement.addEventListener("transitionend",r),this.preElement.addEventListener("-webkit-transitionend",r);const s=a=>{"color"==a.propertyName&&this.syncColorCompletely(),a.target==this.dialogContainerElement&&a.stopPropagation()};this.dialogContainerElement.addEventListener("transitionend",s),this.dialogContainerElement.addEventListener("-webkit-transitionend",s),this.addEventListener("transitionend",s),this.addEventListener("-webkit-transitionend",s),this.syncColorCompletely(),this.classList.add("code-input_loaded")}escape_html(a){return this.escapeHtml(a)}get_template(){return this.getTemplate()}get template(){return this.templateObject}set template(a){}connectedCallback(){if(this.templateObject=this.getTemplate(),null!=this.templateObject&&(this.classList.add("code-input_registered"),"loading"===document.readyState?window.addEventListener("DOMContentLoaded",this.setup.bind(this)):this.setup()),"loading"===document.readyState)window.addEventListener("DOMContentLoaded",()=>{const a=this.querySelector("textarea[data-code-input-fallback]");a&&this.setupTextareaSyncEvents(a)});else{const a=this.querySelector("textarea[data-code-input-fallback]");a&&this.setupTextareaSyncEvents(a)}}mutationObserverCallback(a){for(const b of a)if("attributes"===b.type){for(let a=0;a<codeInput.observedAttributes.length;a++)if(b.attributeName==codeInput.observedAttributes[a])return this.attributeChangedCallback(b.attributeName,b.oldValue,super.getAttribute(b.attributeName));for(let a=0;a<codeInput.textareaSyncAttributes.length;a++)if(b.attributeName==codeInput.textareaSyncAttributes[a])return this.attributeChangedCallback(b.attributeName,b.oldValue,super.getAttribute(b.attributeName));if("aria-"==b.attributeName.substring(0,5))return this.attributeChangedCallback(b.attributeName,b.oldValue,super.getAttribute(b.attributeName))}}disconnectedCallback(){this.mutationObserver&&this.mutationObserver.disconnect()}attributeChangedCallback(a,b,c){if(this.isConnected)switch(this.pluginEvt("attributeChanged",[a,b,c]),a){case"value":this.value=c;break;case"template":this.templateObject=codeInput.usedTemplates[c||codeInput.defaultTemplate],this.templateObject.preElementStyled?this.classList.add("code-input_pre-element-styled"):this.classList.remove("code-input_pre-element-styled"),this.scheduleHighlight();break;case"lang":case"language":let d=this.codeElement,e=this.textareaElement;if(null!=c&&(c=c.toLowerCase(),d.classList.contains(`language-${c}`)))break;null!==b&&(b=b.toLowerCase(),d.classList.remove("language-"+b),d.parentElement.classList.remove("language-"+b)),d.classList.remove("language-none"),d.parentElement.classList.remove("language-none"),null!=c&&""!=c&&d.classList.add("language-"+c),(e.placeholder==b||null==b&&""==e.placeholder)&&(e.placeholder=c),this.scheduleHighlight();break;default:codeInput.textareaSyncAttributes.includes(a)||"aria-"==a.substring(0,5)?null==c||null==c?this.textareaElement.removeAttribute(a):this.textareaElement.setAttribute(a,c):codeInput.textareaSyncAttributes.regexp.forEach(b=>{a.match(b)&&(null==c?this.textareaElement.removeAttribute(a):this.textareaElement.setAttribute(a,c))})}}setupTextareaSyncEvents(a){for(let b=0;b<codeInput.textareaSyncEvents.length;b++){const c=codeInput.textareaSyncEvents[b];a.addEventListener(c,a=>{a.bubbles||this.dispatchEvent(new a.constructor(a.type,a))})}}addEventListener(a,b,c=void 0){let d=function(a){"function"==typeof b?b(a):b&&b.handleEvent&&b.handleEvent(a)}.bind(this);if(this.boundEventCallbacks[b]=d,!codeInput.textareaSyncEvents.includes(a))void 0===c?super.addEventListener(a,d):super.addEventListener(a,d,c);else if(this.boundEventCallbacks[b]=d,void 0===c){if(null==this.textareaElement){const b=this.querySelector("textarea[data-code-input-fallback]");b&&b.addEventListener(a,d),this.addEventListener("code-input_load",()=>{this.textareaElement.addEventListener(a,d)})}else this.textareaElement.addEventListener(a,d);}else if(null==this.textareaElement){const b=this.querySelector("textarea[data-code-input-fallback]");b&&b.addEventListener(a,d,c),this.addEventListener("code-input_load",()=>{this.textareaElement.addEventListener(a,d,c)})}else this.textareaElement.addEventListener(a,d,c)}removeEventListener(a,b,c=void 0){let d=this.boundEventCallbacks[b];if(!codeInput.textareaSyncEvents.includes(a))void 0===c?super.removeEventListener(a,d):super.removeEventListener(a,d,c);else if(void 0===c){if(null==this.textareaElement){const b=this.querySelector("textarea[data-code-input-fallback]");b&&b.removeEventListener(a,d),this.addEventListener("code-input_load",()=>{this.textareaElement.removeEventListener(a,d)})}else this.textareaElement.removeEventListener(a,d);}else if(null==this.textareaElement){const b=this.querySelector("textarea[data-code-input-fallback]");b&&b.removeEventListener(a,d,c),this.addEventListener("code-input_load",()=>{this.textareaElement.removeEventListener(a,d,c)})}else this.textareaElement.removeEventListener(a,d,c)}getTextareaProperty(a,b=void 0){if(this.textareaElement)return this.textareaElement[a];else{const c=this.querySelector("textarea[data-code-input-fallback]");if(c)return c[a];if(void 0===b)throw new Error("Cannot get "+a+" of an unregistered code-input element without a data-code-input-fallback textarea.");return b}}setTextareaProperty(a,b,c=!0){if(this.textareaElement)this.textareaElement[a]=b;else{const d=this.querySelector("textarea[data-code-input-fallback]");if(d)d[a]=b;else{if(!c)return(!1);throw new Error("Cannot set "+a+" of an unregistered code-input element without a data-code-input-fallback textarea.")}}return(!0)}get autocomplete(){return this.getAttribute("autocomplete")}set autocomplete(a){return this.setAttribute("autocomplete",a)}get cols(){return this.getTextareaProperty("cols",+this.getAttribute("cols"))}set cols(a){this.setAttribute("cols",a)}get defaultValue(){return this.initialValue}set defaultValue(a){this.initialValue=a}get textContent(){return this.initialValue}set textContent(a){this.initialValue=a}get dirName(){return this.getAttribute("dirName")||""}set dirName(a){this.setAttribute("dirname",a)}get disabled(){return this.hasAttribute("disabled")}set disabled(a){a?this.setAttribute("disabled",!0):this.removeAttribute("disabled")}get form(){return this.getTextareaProperty("form")}get labels(){return this.getTextareaProperty("labels")}get maxLength(){const a=+this.getAttribute("maxlength");return isNaN(a)?-1:a}set maxLength(a){-1==a?this.removeAttribute("maxlength"):this.setAttribute("maxlength",a)}get minLength(){const a=+this.getAttribute("minlength");return isNaN(a)?-1:a}set minLength(a){-1==a?this.removeAttribute("minlength"):this.setAttribute("minlength",a)}get name(){return this.getAttribute("name")||""}set name(a){this.setAttribute("name",a)}get placeholder(){return this.getAttribute("placeholder")||""}set placeholder(a){this.setAttribute("placeholder",a)}get readOnly(){return this.hasAttribute("readonly")}set readOnly(a){a?this.setAttribute("readonly",!0):this.removeAttribute("readonly")}get required(){return this.hasAttribute("readonly")}set required(a){a?this.setAttribute("readonly",!0):this.removeAttribute("readonly")}get rows(){return this.getTextareaProperty("rows",+this.getAttribute("rows"))}set rows(a){this.setAttribute("rows",a)}get selectionDirection(){return this.getTextareaProperty("selectionDirection")}set selectionDirection(a){this.setTextareaProperty("selectionDirection",a)}get selectionEnd(){return this.getTextareaProperty("selectionEnd")}set selectionEnd(a){this.setTextareaProperty("selectionEnd",a)}get selectionStart(){return this.getTextareaProperty("selectionStart")}set selectionStart(a){this.setTextareaProperty("selectionStart",a)}get textLength(){return this.value.length}get type(){return"textarea"}get validationMessage(){return this.getTextareaProperty("validationMessage")}get validity(){return this.getTextareaProperty("validationMessage")}get value(){return this.getTextareaProperty("value",this.getAttribute("value")||this.innerHTML)}set value(a){a=a||"",this.setTextareaProperty("value",a,!1)?this.textareaElement&&this.scheduleHighlight():this.innerHTML=a}get willValidate(){return this.getTextareaProperty("willValidate",this.disabled||this.readOnly)}get wrap(){return this.getAttribute("wrap")||""}set wrap(a){this.setAttribute("wrap",a)}getTextareaMethod(a){if(this.textareaElement)return this.textareaElement[a].bind(this.textareaElement);else{const b=this.querySelector("textarea[data-code-input-fallback]");if(b)return b[a].bind(b);throw new Error("Cannot call "+a+" on an unregistered code-input element without a data-code-input-fallback textarea.")}}blur(a={}){this.getTextareaMethod("blur")(a)}checkValidity(){return this.getTextareaMethod("checkValidity")()}focus(a={}){this.getTextareaMethod("focus")(a)}reportValidity(){return this.getTextareaMethod("reportValidity")()}setCustomValidity(a){this.getTextareaMethod("setCustomValidity")(a)}setRangeText(a,b=this.selectionStart,c=this.selectionEnd,d="preserve"){this.getTextareaMethod("setRangeText")(a,b,c,d),this.textareaElement&&this.scheduleHighlight()}setSelectionRange(a,b,c="none"){this.getTextareaMethod("setSelectionRange")(a,b,c)}pluginData={};formResetCallback(){this.value=this.initialValue}}};{class a extends codeInput.Template{constructor(a,b=[],c=!0){super(a.highlightElement,c,!0,!1,b)}}codeInput.templates.Prism=a;class b extends codeInput.Template{constructor(a,b=[],c=!1){super(function(b){b.removeAttribute("data-highlighted"),a.highlightElement(b)},c,!0,!1,b)}}codeInput.templates.Hljs=b}customElements.define("code-input",codeInput.CodeInput);
package/docs/_index.md CHANGED
@@ -11,7 +11,11 @@ Aiming to be [more <mark>flexible</mark>, <mark>lightweight</mark>,
11
11
  [HTML forms](interface/forms), the [`<textarea>` JavaScript interface](interface/js), more languages and
12
12
  more use cases.
13
13
 
14
- *code-input.js is free, libre, open source software under the MIT (AKA Expat) license.* **Download it [from the Git repository](https://github.com/WebCoder49/code-input/tree/v2.6.8), [in a ZIP archive](/release/code-input-js-v2.6.8.zip), [in a TAR.GZ archive](/release/code-input-js-v2.6.8.tar.gz), or from `@webcoder49/code-input` on the NPM registry ([Yarn](https://yarnpkg.com/package?name=@webcoder49/code-input), [NPM](https://npmjs.com/package/@webcoder49/code-input), etc.).**
14
+ ## Download
15
+
16
+ *code-input.js is free, libre, open source software under the MIT (AKA Expat) license.* **Download it [from the Git repository](https://github.com/WebCoder49/code-input/tree/v2.7.0), [in a ZIP archive](/release/code-input-js-v2.7.0.zip), [in a TAR.GZ archive](/release/code-input-js-v2.7.0.tar.gz), or from `@webcoder49/code-input` on the NPM registry ([Yarn](https://yarnpkg.com/package?name=@webcoder49/code-input), [NPM](https://npmjs.com/package/@webcoder49/code-input), etc.).**
17
+
18
+ [Want to contribute to the code? You're very welcome to! See here.](#contributing)
15
19
 
16
20
  ## Get Started with a Demo
17
21
 
@@ -308,6 +312,8 @@ something like [CodeMirror](https://codemirror.net/),
308
312
  [Ace](https://ace.c9.io/) or
309
313
  [Monaco](https://microsoft.github.io/monaco-editor/).
310
314
 
315
+ `code-input.js` is also improving and an even more lightweight, flexible and clean major version 3 is being planned. Please come and participate with your feedback/ideas [on GitHub](https://github.com/WebCoder49/code-input/issues/190) or [via email to code-input-js+v3@webcoder49.dev](mailto:code-input-js+v3@webcoder49.dev)!
316
+
311
317
  ## Read Enough?
312
318
  **If you don't need web framework integration, get started with the commented tutorials by example on this page, for [Prism.js](#playground-preset-prism), [highlight.js](#playground-preset-hljs), or [another highlighter](#playground-preset-custom). If you're using ECMAScript modules or a web framework, start [here](modules-and-frameworks).**
313
319
 
@@ -7,6 +7,10 @@ title = 'Styling `code-input` elements with CSS'
7
7
  > Contributors: 2025 Oliver Geer
8
8
 
9
9
  `code-input` elements can be styled like `textarea` elements in most cases; however, there are some exceptions:
10
- * The CSS variable `--padding` should be used rather than the property `padding` (e.g. `<code-input style="--padding: 10px;">...`), or `--padding-left`, `--padding-right`, `--padding-top` and `--padding-bottom` instead of the CSS properties of the same names. For technical reasons, the value must have a unit (i.e. `0px`, not `0`).
10
+ * The CSS variable `--padding` should be used rather than the property `padding` (e.g. `<code-input style="--padding: 10px;">...`), or `--padding-left`, `--padding-right`, `--padding-top` and `--padding-bottom` instead of the CSS properties of the same names. For technical reasons, the value must have a unit (i.e. `0px`, not `0`). To avoid overcomplicating the code, this padding is always *included in* any width/heights of `code-input` elements, so if you want to style `textarea`s and `code-input` elements with best consistency set `box-sizing: border-box` on them.
11
11
  * Background colours set on `code-input` elements will not work with highlighters that set background colours themselves - use `(code-input's selector) pre[class*="language-"]` for Prism.js or `.hljs` for highlight.js to target the highlighted element with higher specificity than the highlighter's theme. You may also set the `background-color` of the code-input element for its appearance when its template is unregistered / there is no JavaScript.
12
+ * The caret and placeholder colour by default follow and give good contrast with the highlighted theme. Setting a CSS rule for `color` and/or `caret-color` properties on the code-input element will override this behaviour.
13
+ * For technical reasons, `code-input:focus` won't match anything. Use `code-input:has(textarea:focus)` instead.
12
14
  * For now, elements on top of `code-input` elements should have a CSS `z-index` at least 3 greater than the `code-input` element.
15
+
16
+ Please do **not** use `className` in JavaScript referring to code-input elements, because the code-input library needs to add its own classes to code-input elements for easier progressive enhancement. You can, however, use `classList` and `style` as much as you want - it will make your code cleaner anyway.
@@ -6,6 +6,19 @@ title = '`code-input` vs the `textarea` in JavaScript'
6
6
 
7
7
  > Contributors: 2025 Oliver Geer
8
8
 
9
- Once registered, `code-input` elements support the JavaScript properties and events used with a `textarea` element, because they are built around them. Try swapping out your `textarea` element in your JavaScript application for a `code-input`! If it doesn't work, [submit a bug report](https://github.com/WebCoder49/code-input/issues).
9
+ [Once registered](#code-input_load), `code-input` elements support the JavaScript properties and events used with a `textarea` element, because they are built around them. Try swapping out your `textarea` element in your JavaScript application for a `code-input`! If it doesn't work, [submit a bug report](https://github.com/WebCoder49/code-input/issues).
10
10
 
11
11
  If you want to replace a `textarea` with a `code-input` in an application that doesn't need JavaScript, [look here](../forms). We support HTML5 forms, and progressive enhancement so JavaScript isn't needed!
12
+
13
+ ## The `code-input_load` event {code-input_load}
14
+
15
+ Each `code-input` element fires a `code-input_load` event when it, its template and its plugins have been fully registered. You should carry out initialisation code for `code-input` elements in a handler for this event:
16
+ ```javascript
17
+ // TODO: Get code-input element as codeInputElement
18
+ codeInputElement.addEventListener("code-input_load", () => {
19
+ // TODO: Initialisation code
20
+ // TODO: Add event handlers to the element here.
21
+ });
22
+ ```
23
+
24
+ For backwards compatibility, you should also implement the subset of the functionality that doesn't require `code-input.js` on the `<textarea data-code-input-fallback>` element before load, if you have one. For backwards compatibility and technical reasons, event handlers registered in HTML attributes like `onchange` of the textarea will be passed to the code-input element when it is registered, but event listeners registered like that above will not - this should be cleaned up in major version 3.
@@ -95,6 +95,7 @@ Right now, you can only add one plugin of each type (e.g. one SelectTokenCallbac
95
95
  let autocompleteButton = document.createElement("button");
96
96
  autocompleteButton.innerHTML = "<i>" + tag.substring(0, start_tag.length) + "</i>" + tag.substring(start_tag.length, tag.length);
97
97
  autocompleteButton.addEventListener("click", () => {
98
+ textarea.parentElement.focus();
98
99
  document.execCommand("insertText", false, tag.substring(start_tag.length, tag.length));
99
100
  popupElem.innerHTML = ""; // On popup
100
101
  });
@@ -103,18 +104,18 @@ Right now, you can only add one plugin of each type (e.g. one SelectTokenCallbac
103
104
  });
104
105
 
105
106
  if(popupElem.firstElementChild != null) {
106
- popupElem.firstElementChild.innerHTML += "[Tab]";
107
+ popupElem.firstElementChild.innerHTML += "[Tab]";
107
108
  }
108
109
  textarea.addEventListener("keydown", (event) => {
109
- if(event.key == "Tab" && popupElem.firstElementChild != null) {
110
- popupElem.firstElementChild.click();
111
- event.preventDefault();
112
- }
110
+ if(event.key == "Tab" && popupElem.firstElementChild != null) {
111
+ popupElem.firstElementChild.click();
112
+ event.preventDefault();
113
+ }
113
114
  })
114
115
  }
115
116
  // Pass at register
116
117
  codeInput.registerTemplate("syntax-highlighted", new codeInput.templates.Prism(Prism, [
117
- new codeInput.plugins.Autocomplete(updatePopup) // See above
118
+ new codeInput.plugins.Autocomplete(updatePopup) // See above
118
119
  ]));
119
120
  </script>
120
121
  <p>Start typing some HTML tags to see the autocomplete in action. You can click an autocomplete suggestion, or press the Tab key to select the first.</p>
@@ -154,6 +154,8 @@ var codeInput = {
154
154
  }
155
155
  },
156
156
 
157
+ stylesheetI: 0, // Increments to give different classes to each code-input element so they can have custom styles synchronised internally without affecting the inline style
158
+
157
159
  /**
158
160
  * Please see `codeInput.templates.prism` or `codeInput.templates.hljs`.
159
161
  * Templates are used in `<code-input>` elements and once registered with
@@ -343,6 +345,16 @@ var codeInput = {
343
345
  */
344
346
  dialogContainerElement = null;
345
347
 
348
+ /**
349
+ * Like style attribute, but with a specificity of 1
350
+ * element, 1 class. Present so styles can be set on only
351
+ * this element while giving other code freedom of use of
352
+ * the style attribute.
353
+ *
354
+ * For internal use only.
355
+ */
356
+ internalStyle = null;
357
+
346
358
  /**
347
359
  * Form-Associated Custom Element Callbacks
348
360
  * https://html.spec.whatwg.org/multipage/custom-elements.html#custom-elements-face-example
@@ -428,22 +440,75 @@ var codeInput = {
428
440
  this.pluginEvt("afterHighlight");
429
441
  }
430
442
 
443
+ getStyledHighlightingElement() {
444
+ if(this.templateObject.preElementStyled) {
445
+ return this.preElement;
446
+ } else {
447
+ return this.codeElement;
448
+ }
449
+ }
450
+
431
451
  /**
432
452
  * Set the size of the textarea element to the size of the pre/code element.
433
453
  */
434
454
  syncSize() {
435
455
  // Synchronise the size of the pre/code and textarea elements
436
- if(this.templateObject.preElementStyled) {
437
- this.style.backgroundColor = getComputedStyle(this.preElement).backgroundColor;
438
- this.textareaElement.style.height = getComputedStyle(this.preElement).height;
439
- this.textareaElement.style.width = getComputedStyle(this.preElement).width;
440
- } else {
441
- this.style.backgroundColor = getComputedStyle(this.codeElement).backgroundColor;
442
- this.textareaElement.style.height = getComputedStyle(this.codeElement).height;
443
- this.textareaElement.style.width = getComputedStyle(this.codeElement).width;
456
+ this.textareaElement.style.height = getComputedStyle(this.getStyledHighlightingElement()).height;
457
+ this.textareaElement.style.width = getComputedStyle(this.getStyledHighlightingElement()).width;
458
+ }
459
+
460
+ /**
461
+ * If the color attribute has been defined on the
462
+ * code-input element by external code, return true.
463
+ * Otherwise, make the aspects the color affects
464
+ * (placeholder and caret colour) be the base colour
465
+ * of the highlighted text, for best contrast, and
466
+ * return false.
467
+ */
468
+ isColorOverridenSyncIfNot() {
469
+ const oldTransition = this.style.transition;
470
+ this.style.transition = "unset";
471
+ window.requestAnimationFrame(() => {
472
+ this.internalStyle.setProperty("--code-input_no-override-color", "rgb(0, 0, 0)");
473
+ if(getComputedStyle(this).color == "rgb(0, 0, 0)") {
474
+ // May not be overriden
475
+ this.internalStyle.setProperty("--code-input_no-override-color", "rgb(255, 255, 255)");
476
+ if(getComputedStyle(this).color == "rgb(255, 255, 255)") {
477
+ // Definitely not overriden
478
+ this.internalStyle.removeProperty("--code-input_no-override-color");
479
+ this.style.transition = oldTransition;
480
+
481
+ const highlightedTextColor = getComputedStyle(this.getStyledHighlightingElement()).color;
482
+
483
+ this.internalStyle.setProperty("--code-input_highlight-text-color", highlightedTextColor);
484
+ this.internalStyle.setProperty("--code-input_default-caret-color", highlightedTextColor);
485
+ return false;
486
+ }
487
+ }
488
+ this.internalStyle.removeProperty("--code-input_no-override-color");
489
+ this.style.transition = oldTransition;
490
+ });
491
+
492
+ return true;
493
+ }
494
+
495
+ /**
496
+ * Update the aspects the color affects
497
+ * (placeholder and caret colour) to the correct
498
+ * colour: either that defined on the code-input
499
+ * element, or if none is defined externally the
500
+ * base colour of the highlighted text.
501
+ */
502
+ syncColorCompletely() {
503
+ // color of code-input element
504
+ if(this.isColorOverridenSyncIfNot()) {
505
+ // color overriden
506
+ this.internalStyle.removeProperty("--code-input_highlight-text-color");
507
+ this.internalStyle.setProperty("--code-input_default-caret-color", getComputedStyle(this).color);
444
508
  }
445
509
  }
446
510
 
511
+
447
512
  /**
448
513
  * Show some instructions to the user only if they are using keyboard navigation - for example, a prompt on how to navigate with the keyboard if Tab is repurposed.
449
514
  * @param {string} instructions The instructions to display only if keyboard navigation is being used. If it's blank, no instructions will be shown.
@@ -639,7 +704,6 @@ var codeInput = {
639
704
  this.codeElement = code;
640
705
  pre.append(code);
641
706
  this.append(pre);
642
-
643
707
  if (this.templateObject.isCode) {
644
708
  if (lang != undefined && lang != "") {
645
709
  code.classList.add("language-" + lang.toLowerCase());
@@ -678,7 +742,44 @@ var codeInput = {
678
742
  // The only element that could be resized is this code-input element.
679
743
  this.syncSize();
680
744
  });
681
- resizeObserver.observe(this.textareaElement);
745
+ resizeObserver.observe(this);
746
+
747
+
748
+ // Add internal style as non-externally-overridable alternative to style attribute for e.g. syncing color
749
+ this.classList.add("code-input_styles_" + codeInput.stylesheetI);
750
+ const stylesheet = document.createElement("style");
751
+ stylesheet.innerHTML = "code-input.code-input_styles_" + codeInput.stylesheetI + " {}";
752
+ this.appendChild(stylesheet);
753
+ this.internalStyle = stylesheet.sheet.cssRules[0].style;
754
+ codeInput.stylesheetI++;
755
+
756
+ // Synchronise colors
757
+ const preColorChangeCallback = (evt) => {
758
+ if(evt.propertyName == "color") {
759
+ this.isColorOverridenSyncIfNot();
760
+ }
761
+ };
762
+ this.preElement.addEventListener("transitionend", preColorChangeCallback);
763
+ this.preElement.addEventListener("-webkit-transitionend", preColorChangeCallback);
764
+ const thisColorChangeCallback = (evt) => {
765
+ if(evt.propertyName == "color") {
766
+ this.syncColorCompletely();
767
+ }
768
+ if(evt.target == this.dialogContainerElement) {
769
+ evt.stopPropagation();
770
+ // Prevent bubbling because code-input
771
+ // transitionend is separate
772
+ }
773
+ };
774
+ // Not on this element so CSS transition property does not override publicly-visible one
775
+ this.dialogContainerElement.addEventListener("transitionend", thisColorChangeCallback);
776
+ this.dialogContainerElement.addEventListener("-webkit-transitionend", thisColorChangeCallback);
777
+
778
+ // For when this code-input element has an externally-defined, different-duration transition
779
+ this.addEventListener("transitionend", thisColorChangeCallback);
780
+ this.addEventListener("-webkit-transitionend", thisColorChangeCallback);
781
+
782
+ this.syncColorCompletely();
682
783
 
683
784
  this.classList.add("code-input_loaded");
684
785
  }
@@ -836,7 +937,9 @@ var codeInput = {
836
937
  code.classList.add("language-" + newValue);
837
938
  }
838
939
 
839
- if (mainTextarea.placeholder == oldValue) mainTextarea.placeholder = newValue;
940
+ if (mainTextarea.placeholder == oldValue || oldValue == null && mainTextarea.placeholder == "") {
941
+ mainTextarea.placeholder = newValue;
942
+ }
840
943
 
841
944
  this.scheduleHighlight();
842
945
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webcoder49/code-input",
3
- "version": "2.6.8",
3
+ "version": "2.7.0",
4
4
  "description": "An editable &lt;textarea&gt; that supports *any* syntax highlighting algorithm, for code or something else. Also, added plugins.",
5
5
  "browser": "code-input.js",
6
6
  "exports": {
@@ -1 +1 @@
1
- code-input .code-input_autocomplete_popup{display:block;position:absolute;margin-top:1em;z-index:100}code-input .code-input_autocomplete_testpos{opacity:0}
1
+ code-input .code-input_autocomplete_popup{z-index:100;margin-top:1em;display:block;position:absolute}code-input .code-input_autocomplete_testpos{opacity:0}
@@ -1 +1 @@
1
- .code-input_find-and-replace_find-match{color:inherit;text-shadow:none!important;background-color:#ff0!important}.code-input_find-and-replace_find-match-focused,.code-input_find-and-replace_find-match-focused *{background-color:#f80!important;color:#000!important}.code-input_find-and-replace_start-newline::before{content:"⤶"}@keyframes code-input_find-and-replace_roll-in{0%{opacity:0;transform:translateY(-34px)}100%{opacity:1;transform:translateY(0)}}@keyframes code-input_find-and-replace_roll-out{0%{opacity:1;top:0}100%{opacity:0;top:-34px}}.code-input_find-and-replace_dialog{position:absolute;top:0;right:14px;padding:6px;padding-top:8px;border:solid 1px #00000044;background-color:#fff;border-radius:6px;box-shadow:0 .2em 1em .2em rgba(0,0,0,.16)}.code-input_find-and-replace_dialog:not(.code-input_find-and-replace_hidden-dialog){animation:code-input_find-and-replace_roll-in .2s;opacity:1;pointer-events:all}.code-input_find-and-replace_dialog.code-input_find-and-replace_hidden-dialog{animation:code-input_find-and-replace_roll-out .2s;opacity:0;pointer-events:none}.code-input_find-and-replace_dialog input::placeholder{font-size:80%}.code-input_find-and-replace_dialog input{position:relative;width:240px;height:32px;top:-3px;font-size:large;color:#000000aa;border:0}.code-input_find-and-replace_dialog input.code-input_find-and-replace_error{color:#ff0000aa}.code-input_find-and-replace_dialog button,.code-input_find-and-replace_dialog input[type=checkbox]{display:inline-block;line-height:24px;font-size:22px;cursor:pointer;appearance:none;width:min-content;margin:5px;padding:5px;border:0;background-color:#ddd;text-align:center;color:#000;vertical-align:top}.code-input_find-and-replace_dialog input[type=checkbox].code-input_find-and-replace_case-sensitive-checkbox::before{content:"Aa"}.code-input_find-and-replace_dialog input[type=checkbox].code-input_find-and-replace_reg-exp-checkbox::before{content:".*"}.code-input_find-and-replace_dialog button:hover,.code-input_find-and-replace_dialog input[type=checkbox]:hover{background-color:#bbb}.code-input_find-and-replace_dialog input[type=checkbox]:checked{background-color:#222;color:#fff}.code-input_find-and-replace_match-description{display:block;color:#444}.code-input_find-and-replace_dialog button,.code-input_find-and-replace_dialog details summary{cursor:pointer}.code-input_find-and-replace_dialog button.code-input_find-and-replace_button-hidden{opacity:0;pointer-events:none}.code-input_find-and-replace_dialog span{display:block;float:right;margin:5px;padding:5px;width:24px;line-height:24px;font-family:system-ui;font-size:22px;font-weight:500;text-align:center;border-radius:50%;color:#000;opacity:.6}.code-input_find-and-replace_dialog span:before{content:"\00d7"}.code-input_find-and-replace_dialog span:hover{opacity:.8;background-color:#00000018}
1
+ .code-input_find-and-replace_find-match{color:inherit;text-shadow:none!important;background-color:#ff0!important}.code-input_find-and-replace_find-match-focused,.code-input_find-and-replace_find-match-focused *{color:#000!important;background-color:#f80!important}.code-input_find-and-replace_start-newline:before{content:"⤶"}@keyframes code-input_find-and-replace_roll-in{0%{opacity:0;transform:translateY(-34px)}to{opacity:1;transform:translateY(0)}}@keyframes code-input_find-and-replace_roll-out{0%{opacity:1;top:0}to{opacity:0;top:-34px}}.code-input_find-and-replace_dialog{background-color:#fff;border:1px solid #0004;border-radius:6px;padding:8px 6px 6px;position:absolute;top:0;right:14px;box-shadow:0 .2em 1em .2em #00000029}.code-input_find-and-replace_dialog:not(.code-input_find-and-replace_hidden-dialog){opacity:1;pointer-events:all;animation:.2s code-input_find-and-replace_roll-in}.code-input_find-and-replace_dialog.code-input_find-and-replace_hidden-dialog{opacity:0;pointer-events:none;animation:.2s code-input_find-and-replace_roll-out}.code-input_find-and-replace_dialog input::placeholder{font-size:80%}.code-input_find-and-replace_dialog input{color:#000a;border:0;width:240px;height:32px;font-size:large;position:relative;top:-3px}.code-input_find-and-replace_dialog input.code-input_find-and-replace_error{color:#f00a}.code-input_find-and-replace_dialog button,.code-input_find-and-replace_dialog input[type=checkbox]{cursor:pointer;appearance:none;text-align:center;color:#000;vertical-align:top;background-color:#ddd;border:0;width:min-content;margin:5px;padding:5px;font-size:22px;line-height:24px;display:inline-block}.code-input_find-and-replace_dialog input[type=checkbox].code-input_find-and-replace_case-sensitive-checkbox:before{content:"Aa"}.code-input_find-and-replace_dialog input[type=checkbox].code-input_find-and-replace_reg-exp-checkbox:before{content:".*"}.code-input_find-and-replace_dialog button:hover,.code-input_find-and-replace_dialog input[type=checkbox]:hover{background-color:#bbb}.code-input_find-and-replace_dialog input[type=checkbox]:checked{color:#fff;background-color:#222}.code-input_find-and-replace_match-description{color:#444;display:block}.code-input_find-and-replace_dialog details summary,.code-input_find-and-replace_dialog button{cursor:pointer}.code-input_find-and-replace_dialog button.code-input_find-and-replace_button-hidden{opacity:0;pointer-events:none}.code-input_find-and-replace_dialog span{float:right;text-align:center;color:#000;opacity:.6;border-radius:50%;width:24px;margin:5px;padding:5px;font-family:system-ui;font-size:22px;font-weight:500;line-height:24px;display:block}.code-input_find-and-replace_dialog span:before{content:"×"}.code-input_find-and-replace_dialog span:hover{opacity:.8;background-color:#00000018}
@@ -1 +1 @@
1
- @keyframes code-input_go-to-line_roll-in{0%{opacity:0;transform:translateY(-34px)}100%{opacity:1;transform:translateY(0)}}@keyframes code-input_go-to-line_roll-out{0%{opacity:1;transform:translateY(0)}100%{opacity:0;transform:translateY(-34px)}}.code-input_go-to-line_dialog{position:absolute;top:0;right:14px;padding:6px;padding-top:8px;border:solid 1px #00000044;background-color:#fff;border-radius:6px;box-shadow:0 .2em 1em .2em rgba(0,0,0,.16)}.code-input_go-to-line_dialog:not(.code-input_go-to-line_hidden-dialog){animation:code-input_go-to-line_roll-in .2s;opacity:1;pointer-events:all}.code-input_go-to-line_dialog.code-input_go-to-line_hidden-dialog{animation:code-input_go-to-line_roll-out .2s;opacity:0;pointer-events:none}.code-input_go-to-line_dialog input::placeholder{font-size:80%}.code-input_go-to-line_dialog input{position:relative;width:240px;height:32px;top:-3px;font-size:large;color:#000000aa;border:0}.code-input_go-to-line_dialog input.code-input_go-to-line_error{color:#ff0000aa}.code-input_go-to-line_dialog span{display:inline-block;width:24px;line-height:24px;font-family:system-ui;font-size:22px;font-weight:500;text-align:center;border-radius:50%;color:#000;opacity:.6;vertical-align:top}.code-input_go-to-line_dialog span:before{content:"\00d7"}.code-input_go-to-line_dialog span:hover{opacity:.8;background-color:#00000018}.code-input_go-to-line_dialog p{font-family:monospace;width:264px;margin:0;overflow:hidden;white-space:wrap}
1
+ @keyframes code-input_go-to-line_roll-in{0%{opacity:0;transform:translateY(-34px)}to{opacity:1;transform:translateY(0)}}@keyframes code-input_go-to-line_roll-out{0%{opacity:1;transform:translateY(0)}to{opacity:0;transform:translateY(-34px)}}.code-input_go-to-line_dialog{background-color:#fff;border:1px solid #0004;border-radius:6px;padding:8px 6px 6px;position:absolute;top:0;right:14px;box-shadow:0 .2em 1em .2em #00000029}.code-input_go-to-line_dialog:not(.code-input_go-to-line_hidden-dialog){opacity:1;pointer-events:all;animation:.2s code-input_go-to-line_roll-in}.code-input_go-to-line_dialog.code-input_go-to-line_hidden-dialog{opacity:0;pointer-events:none;animation:.2s code-input_go-to-line_roll-out}.code-input_go-to-line_dialog input::placeholder{font-size:80%}.code-input_go-to-line_dialog input{color:#000a;border:0;width:240px;height:32px;font-size:large;position:relative;top:-3px}.code-input_go-to-line_dialog input.code-input_go-to-line_error{color:#f00a}.code-input_go-to-line_dialog span{text-align:center;color:#000;opacity:.6;vertical-align:top;border-radius:50%;width:24px;font-family:system-ui;font-size:22px;font-weight:500;line-height:24px;display:inline-block}.code-input_go-to-line_dialog span:before{content:"×"}.code-input_go-to-line_dialog span:hover{opacity:.8;background-color:#00000018}.code-input_go-to-line_dialog p{width:264px;white-space:wrap;margin:0;font-family:monospace;overflow:hidden}
@@ -1 +1 @@
1
- .line-numbers code-input textarea,.line-numbers code-input.code-input_pre-element-styled pre,.line-numbers code-input:not(.code-input_pre-element-styled) pre code,code-input.line-numbers textarea,code-input.line-numbers.code-input_pre-element-styled pre,code-input.line-numbers:not(.code-input_pre-element-styled) pre code{padding-left:max(3.8em,var(--padding-left,16px))!important}.line-numbers code-input,code-input.line-numbers{grid-template-columns:calc(100% - max(0em,calc(3.8em - var(--padding-left,16px))))}.line-numbers code-input .code-input_dialog-container,code-input.line-numbers .code-input_dialog-container{width:calc(100% + max(0em,calc(3.8em - var(--padding-left,16px))))}code-input pre[class*=language-].line-numbers>code{position:static}code-input .line-numbers .line-numbers-rows{left:max(0,calc(var(--padding-left,16px) - 3.8em));top:var(--padding-top)}code-input:not(:has(.code-input_keyboard-navigation-instructions:empty)):has(textarea:not([data-code-input-fallback]):focus):not(.code-input_mouse-focused) .line-numbers .line-numbers-rows{top:calc(var(--padding-top) + 3em)}
1
+ code-input.line-numbers textarea,code-input.line-numbers.code-input_pre-element-styled pre,code-input.line-numbers:not(.code-input_pre-element-styled) pre code,.line-numbers code-input textarea,.line-numbers code-input.code-input_pre-element-styled pre,.line-numbers code-input:not(.code-input_pre-element-styled) pre code{padding-left:max(3.8em,var(--padding-left,16px))!important}code-input.line-numbers,.line-numbers code-input{grid-template-columns:calc(100% - max(0em,calc(3.8em - var(--padding-left,16px))))}code-input.line-numbers .code-input_dialog-container,.line-numbers code-input .code-input_dialog-container{width:calc(100% + max(0em,calc(3.8em - var(--padding-left,16px))))}code-input pre[class*=language-].line-numbers>code{position:static}code-input .line-numbers .line-numbers-rows{left:max(0em,calc(var(--padding-left,16px) - 3.8em));top:var(--padding-top)}code-input:not(:has(.code-input_keyboard-navigation-instructions:empty)):has(textarea:not([data-code-input-fallback]):focus):not(.code-input_mouse-focused) .line-numbers .line-numbers-rows{top:calc(var(--padding-top) + 3em)}
@@ -1,5 +1 @@
1
- :root,body{--code-input_special-chars_0:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAFCAYAAACAcVaiAAAAAXNSR0IArs4c6QAAABtJREFUGFdjZGBgYPj///9/RhCAMcA0bg6yHgAPmh/6BoxTcQAAAABJRU5ErkJgggAA');--code-input_special-chars_1:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAFCAYAAACAcVaiAAAAAXNSR0IArs4c6QAAABZJREFUGFdjZGBgYPj///9/RhAggwMAitIUBr9U6sYAAAAASUVORK5CYII=');--code-input_special-chars_2:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAFCAYAAACAcVaiAAAAAXNSR0IArs4c6QAAAB9JREFUGFdj/P///38GKGCEMUCCjCgyYBFGRrAKFBkAuLYT9kYcIu0AAAAASUVORK5CYII=');--code-input_special-chars_3:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAFCAYAAACAcVaiAAAAAXNSR0IArs4c6QAAABhJREFUGFdj/P///38GKGCEMUCCjMTJAACYiBPyG8sfAgAAAABJRU5ErkJggg==');--code-input_special-chars_4:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAFCAYAAACAcVaiAAAAAXNSR0IArs4c6QAAAB5JREFUGFdj/P///39GRkZGMI3BYYACRhgDrAKZAwAYxhvyz0DRIQAAAABJRU5ErkJggg==');--code-input_special-chars_5:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAFCAYAAACAcVaiAAAAAXNSR0IArs4c6QAAACJJREFUGFdj/P///38GKGAEcRgZGRlBfDAHLgNjgFUgywAAuR4T9hxJl2YAAAAASUVORK5CYII=');--code-input_special-chars_6:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAFCAYAAACAcVaiAAAAAXNSR0IArs4c6QAAACBJREFUGFdj/P///38GKGAEcRgZGRlBfDAHQwasAlkGABcdF/Y4yco2AAAAAElFTkSuQmCC');--code-input_special-chars_7:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAFCAYAAACAcVaiAAAAAXNSR0IArs4c6QAAABZJREFUGFdj/P///38GKGCEMUCCRHIAWMgT8kue3bQAAAAASUVORK5CYII=');--code-input_special-chars_8:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAFCAYAAACAcVaiAAAAAXNSR0IArs4c6QAAABlJREFUGFdj/P///38GKGAEcRgZGSE0cTIAvHcb8v+mIfAAAAAASUVORK5CYII=');--code-input_special-chars_9:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAFCAYAAACAcVaiAAAAAXNSR0IArs4c6QAAAB9JREFUGFdj/P///38GKGAEcRgZGSE0igxMCVgGmQMAPqcX8hWL1K0AAAAASUVORK5CYII=');--code-input_special-chars_A:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAFCAYAAACAcVaiAAAAAXNSR0IArs4c6QAAACBJREFUGFdjZGBgYPj///9/RhCAMcA0iADJggCmDEw5ALdxH/aGuYHqAAAAAElFTkSuQmCC');--code-input_special-chars_B:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAFCAYAAACAcVaiAAAAAXNSR0IArs4c6QAAABlJREFUGFdj/P///38GBgYGRhAAceA0cTIAvc0b/vRDnVoAAAAASUVORK5CYII=');--code-input_special-chars_C:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAFCAYAAACAcVaiAAAAAXNSR0IArs4c6QAAAB5JREFUGFdjZGBgYPj///9/EM0IYjAyMjIS4CDrAQC57hP+uLwvFQAAAABJRU5ErkJggg==');--code-input_special-chars_D:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAFCAYAAACAcVaiAAAAAXNSR0IArs4c6QAAABtJREFUGFdj/P///38GBgYGRhAAceA0fg5MDwAveh/6ToN9VwAAAABJRU5ErkJggg==');--code-input_special-chars_E:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAFCAYAAACAcVaiAAAAAXNSR0IArs4c6QAAABxJREFUGFdj/P///38GKGAEcRgZGRlBfDCHsAwA2UwT+mVIH1MAAAAASUVORK5CYII=');--code-input_special-chars_F:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAFCAYAAACAcVaiAAAAAXNSR0IArs4c6QAAAB5JREFUGFdj/P///38GKGAEcRgZGRlBfDAHtwxMGQDZZhP+BnB1kwAAAABJRU5ErkJggg==')}.code-input_special-char{display:inline-block;position:relative;top:0;left:0;height:1em;overflow:hidden;text-decoration:none;text-shadow:none;vertical-align:middle;outline:.1px solid currentColor;color:transparent;font-size:0;--hex-0:var(
2
- --code-input_special-chars_0);--hex-1:var(
3
- --code-input_special-chars_0);--hex-2:var(
4
- --code-input_special-chars_0);--hex-3:var(
5
- --code-input_special-chars_0)}.code-input_special-char::before{margin-left:50%;transform:translate(-50%,0);content:" ";background-color:var(--code-input_special-char_color,currentColor);image-rendering:pixelated;display:inline-block;width:calc(100%-2px);height:100%;mask-image:var(--hex-0),var(--hex-1),var(--hex-2),var(--hex-3);mask-repeat:no-repeat,no-repeat,no-repeat,no-repeat;mask-size:min(40%,.25em),min(40%,.25em),min(40%,.25em),min(40%,.25em);mask-position:10% 10%,90% 10%,10% 90%,90% 90%;-webkit-mask-image:var(--hex-0),var(--hex-1),var(--hex-2),var(--hex-3);-webkit-mask-repeat:no-repeat,no-repeat,no-repeat,no-repeat;-webkit-mask-size:min(40%,.25em),min(40%,.25em),min(40%,.25em),min(40%,.25em);-webkit-mask-position:10% 10%,min(90%,.5em) 10%,10% 90%,min(90%,.5em) 90%}.code-input_special-char_zero-width{z-index:1;width:1em;margin-left:-.5em;margin-right:-.5em;position:relative;opacity:.75}.code-input_special-char_one-byte::before{height:1.5em;top:-1em;content:attr(data-hex2)}.code-input_special-char_one-byte::after{height:1.5em;bottom:-1em;content:attr(data-hex3)}
1
+ :root,body{--code-input_special-chars_0:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAFCAYAAACAcVaiAAAAAXNSR0IArs4c6QAAABtJREFUGFdjZGBgYPj///9/RhCAMcA0bg6yHgAPmh/6BoxTcQAAAABJRU5ErkJgggAA);--code-input_special-chars_1:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAFCAYAAACAcVaiAAAAAXNSR0IArs4c6QAAABZJREFUGFdjZGBgYPj///9/RhAggwMAitIUBr9U6sYAAAAASUVORK5CYII=);--code-input_special-chars_2:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAFCAYAAACAcVaiAAAAAXNSR0IArs4c6QAAAB9JREFUGFdj/P///38GKGCEMUCCjCgyYBFGRrAKFBkAuLYT9kYcIu0AAAAASUVORK5CYII=);--code-input_special-chars_3:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAFCAYAAACAcVaiAAAAAXNSR0IArs4c6QAAABhJREFUGFdj/P///38GKGCEMUCCjMTJAACYiBPyG8sfAgAAAABJRU5ErkJggg==);--code-input_special-chars_4:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAFCAYAAACAcVaiAAAAAXNSR0IArs4c6QAAAB5JREFUGFdj/P///39GRkZGMI3BYYACRhgDrAKZAwAYxhvyz0DRIQAAAABJRU5ErkJggg==);--code-input_special-chars_5:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAFCAYAAACAcVaiAAAAAXNSR0IArs4c6QAAACJJREFUGFdj/P///38GKGAEcRgZGRlBfDAHLgNjgFUgywAAuR4T9hxJl2YAAAAASUVORK5CYII=);--code-input_special-chars_6:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAFCAYAAACAcVaiAAAAAXNSR0IArs4c6QAAACBJREFUGFdj/P///38GKGAEcRgZGRlBfDAHQwasAlkGABcdF/Y4yco2AAAAAElFTkSuQmCC);--code-input_special-chars_7:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAFCAYAAACAcVaiAAAAAXNSR0IArs4c6QAAABZJREFUGFdj/P///38GKGCEMUCCRHIAWMgT8kue3bQAAAAASUVORK5CYII=);--code-input_special-chars_8:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAFCAYAAACAcVaiAAAAAXNSR0IArs4c6QAAABlJREFUGFdj/P///38GKGAEcRgZGSE0cTIAvHcb8v+mIfAAAAAASUVORK5CYII=);--code-input_special-chars_9:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAFCAYAAACAcVaiAAAAAXNSR0IArs4c6QAAAB9JREFUGFdj/P///38GKGAEcRgZGSE0igxMCVgGmQMAPqcX8hWL1K0AAAAASUVORK5CYII=);--code-input_special-chars_A:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAFCAYAAACAcVaiAAAAAXNSR0IArs4c6QAAACBJREFUGFdjZGBgYPj///9/RhCAMcA0iADJggCmDEw5ALdxH/aGuYHqAAAAAElFTkSuQmCC);--code-input_special-chars_B:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAFCAYAAACAcVaiAAAAAXNSR0IArs4c6QAAABlJREFUGFdj/P///38GBgYGRhAAceA0cTIAvc0b/vRDnVoAAAAASUVORK5CYII=);--code-input_special-chars_C:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAFCAYAAACAcVaiAAAAAXNSR0IArs4c6QAAAB5JREFUGFdjZGBgYPj///9/EM0IYjAyMjIS4CDrAQC57hP+uLwvFQAAAABJRU5ErkJggg==);--code-input_special-chars_D:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAFCAYAAACAcVaiAAAAAXNSR0IArs4c6QAAABtJREFUGFdj/P///38GBgYGRhAAceA0fg5MDwAveh/6ToN9VwAAAABJRU5ErkJggg==);--code-input_special-chars_E:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAFCAYAAACAcVaiAAAAAXNSR0IArs4c6QAAABxJREFUGFdj/P///38GKGAEcRgZGRlBfDCHsAwA2UwT+mVIH1MAAAAASUVORK5CYII=);--code-input_special-chars_F:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAFCAYAAACAcVaiAAAAAXNSR0IArs4c6QAAAB5JREFUGFdj/P///38GKGAEcRgZGRlBfDAHtwxMGQDZZhP+BnB1kwAAAABJRU5ErkJggg==)}.code-input_special-char{height:1em;text-shadow:none;vertical-align:middle;color:#0000;--hex-0:var(--code-input_special-chars_0);--hex-1:var(--code-input_special-chars_0);--hex-2:var(--code-input_special-chars_0);--hex-3:var(--code-input_special-chars_0);outline:.1px solid;font-size:0;text-decoration:none;display:inline-block;position:relative;top:0;left:0;overflow:hidden}.code-input_special-char:before{content:" ";background-color:var(--code-input_special-char_color,currentColor);image-rendering:pixelated;width:calc(100%-2px);height:100%;mask-image:var(--hex-0),var(--hex-1),var(--hex-2),var(--hex-3);mask-position:10% 10%,90% 10%,10% 90%,90% 90%;mask-size:min(40%,.25em),min(40%,.25em),min(40%,.25em),min(40%,.25em);mask-repeat:no-repeat,no-repeat,no-repeat,no-repeat;-webkit-mask-image:var(--hex-0),var(--hex-1),var(--hex-2),var(--hex-3);margin-left:50%;display:inline-block;transform:translate(-50%);-webkit-mask-position:10% 10%,min(90%,.5em) 10%,10% 90%,min(90%,.5em) 90%;-webkit-mask-size:min(40%,.25em),min(40%,.25em),min(40%,.25em),min(40%,.25em);-webkit-mask-repeat:no-repeat,no-repeat,no-repeat,no-repeat}.code-input_special-char_zero-width{z-index:1;opacity:.75;width:1em;margin-left:-.5em;margin-right:-.5em;position:relative}.code-input_special-char_one-byte:before{content:attr(data-hex2);height:1.5em;top:-1em}.code-input_special-char_one-byte:after{content:attr(data-hex3);height:1.5em;bottom:-1em}