Skip to content

Commit 1c3a9ea

Browse files
authored
Merge pull request #212 from WebCoder49/autogrow
Add autogrow plugin
2 parents 8436c2d + 443c121 commit 1c3a9ea

File tree

14 files changed

+233
-37
lines changed

14 files changed

+233
-37
lines changed

code-input.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ code-input textarea, code-input pre, code-input pre * {
9999
tab-size: inherit!important;
100100
text-align: inherit!important;
101101
}
102-
code-input textarea, code-input pre, code-input pre code {
102+
code-input pre, code-input pre code {
103103
overflow: visible!important;
104104
}
105105

code-input.js

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -555,8 +555,15 @@ var codeInput = {
555555
*/
556556
syncSize() {
557557
// Synchronise the size of the pre/code and textarea elements
558-
this.textareaElement.style.height = getComputedStyle(this.getStyledHighlightingElement()).height;
559-
this.textareaElement.style.width = getComputedStyle(this.getStyledHighlightingElement()).width;
558+
// Set directly as well as via the variable so precedence
559+
// not lowered, breaking CSS backwards compatibility.
560+
const height = getComputedStyle(this.getStyledHighlightingElement()).height;
561+
this.textareaElement.style.height = height;
562+
this.internalStyle.setProperty("--code-input_synced-height", height);
563+
564+
const width = getComputedStyle(this.getStyledHighlightingElement()).width;
565+
this.textareaElement.style.width = width;
566+
this.internalStyle.setProperty("--code-input_synced-width", width);
560567
}
561568

562569
/**
@@ -788,6 +795,14 @@ var codeInput = {
788795

789796
this.innerHTML = ""; // Clear Content
790797

798+
// Add internal style as non-externally-overridable alternative to style attribute for e.g. syncing color
799+
this.classList.add("code-input_styles_" + codeInput.stylesheetI);
800+
const stylesheet = document.createElement("style");
801+
stylesheet.innerHTML = "code-input.code-input_styles_" + codeInput.stylesheetI + " {}";
802+
this.appendChild(stylesheet);
803+
this.internalStyle = stylesheet.sheet.cssRules[0].style;
804+
codeInput.stylesheetI++;
805+
791806
// Synchronise attributes to textarea
792807
for(let i = 0; i < this.attributes.length; i++) {
793808
let attribute = this.attributes[i].name;
@@ -855,14 +870,11 @@ var codeInput = {
855870
this.syncSize();
856871
});
857872
resizeObserver.observe(this);
858-
859-
860-
this.classList.add("code-input_styles_" + codeInput.stylesheetI);
861-
const stylesheet = document.createElement("style");
862-
stylesheet.innerHTML = "code-input.code-input_styles_" + codeInput.stylesheetI + " {}";
863-
this.appendChild(stylesheet);
864-
this.internalStyle = stylesheet.sheet.cssRules[0].style;
865-
codeInput.stylesheetI++;
873+
874+
// Must resize when this content resizes, for autogrow plugin
875+
// support.
876+
resizeObserver.observe(this.preElement);
877+
resizeObserver.observe(this.codeElement);
866878

867879
// Synchronise colors
868880
const preColorChangeCallback = (evt) => {

docs/interface/css/_index.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,11 @@ title = 'Styling `code-input` elements with CSS'
1414
* For now, elements on top of `code-input` elements should have a CSS `z-index` at least 3 greater than the `code-input` element.
1515

1616
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.
17+
18+
## Methods of resizing
19+
20+
`code-input` elements default to having a fixed height and filling the width of their container while the code inside scrolls, and you can set the ordinary CSS properties (for example `height` and `width`) to change this size. You can also make the size more flexible using CSS:
21+
22+
* The [CSS `resize` property (see link)](https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Properties/resize) can be used on `code-input` elements to give them the manual resizing handle `textarea`s often come with, when the web browser supports it. For example, `<code-input style="resize: both;"`... gives:
23+
![A syntax-highlighted code input element with diagonal lines in the corner, which can be dragged to resize the element.](resize-both-screenshot.png)
24+
* You can also make a `code-input` element resize automatically to fit its contents - use [the Autosize plugin](../../plugins/#playground-preset-autosize) for that.
5.79 KB
Loading

docs/plugins/_index.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,41 @@ Right now, you can only add one plugin of each type (e.g. one SelectTokenCallbac
124124
</html>
125125
```
126126

127+
#### `Autogrow`: Let code-input elements resize to fit their content (optionally between limits) {#playground-preset-prism-line-numbers}
128+
129+
```
130+
<!DOCTYPE html>
131+
<html>
132+
<body>
133+
<!--For convenience, this demo uses files from JSDelivr CDN; for more privacy and security download and host them yourself.-->
134+
<!--Prism+code-input-->
135+
<script src="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/components/prism-core.min.js" data-manual></script><!--Remove data-manual if also using Prism normally-->
136+
<script src="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/plugins/autoloader/prism-autoloader.min.js"></script>
137+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/themes/prism.min.css"></link>
138+
<script src="https://cdn.jsdelivr.net/gh/WebCoder49/code-input@2.7/code-input.min.js"></script>
139+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/WebCoder49/code-input@2.7/code-input.min.css">
140+
141+
142+
<!--Import-->
143+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/WebCoder49/code-input@2.7/plugins/autogrow.min.css"/>
144+
145+
<script>
146+
codeInput.registerTemplate("syntax-highlighted", new codeInput.templates.Prism(Prism, [
147+
// CSS only - don't pass here
148+
]));
149+
</script>
150+
<p>Enter newlines to grow vertically:</p>
151+
<code-input class="code-input_autogrow_height" language="Markdown"></code-input>
152+
<p>Type to grow horizontally:</p>
153+
<code-input class="code-input_autogrow_width" language="Markdown"></code-input>
154+
<p>Grows vertically between 100px and 200px:</p>
155+
<code-input class="code-input_autogrow_height" style="--code-input_autogrow_min-height: 100px; --code-input_autogrow_max-height: 200px;" language="Markdown"></code-input>
156+
<p>Grows horizontally between 100px and 200px:</p>
157+
<code-input class="code-input_autogrow_width" style="--code-input_autogrow_min-width: 100px; --code-input_autogrow_max-width: 200px;" language="Markdown"></code-input>
158+
</body>
159+
</html>
160+
```
161+
127162
#### `FindAndReplace`: Add an openable dialog to find and replace matches to a search term, including highlighting the matches {#playground-preset-find-and-replace}
128163

129164
```

plugins/README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,13 @@ Files: [autodetect.js](./autodetect.js)
2929

3030
[🚀 *Demo*](https://v2.code-input-js.org/plugins/#playground-preset-autodetect)
3131

32+
### Autogrow
33+
Make code-input elements resize automatically and fit their content live using CSS classes, optionally between a minimum and maximum size specified using CSS variables.
34+
35+
Files: [autogrow.css](./autogrow.css) (NO JS FILE)
36+
37+
[🚀 *Demo*](https://v2.code-input-js.org/plugins/#playground-preset-autogrow)
38+
3239
### Find and Replace
3340
Add Find-and-Replace (Ctrl+F for find, Ctrl+H for replace by default, or when JavaScript triggers it) functionality to the code editor.
3441

plugins/autocomplete.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ codeInput.plugins.Autocomplete = class extends codeInput.Plugin {
6565
// Hasn't saved text in test pre to find pos
6666
// Need to regenerate text in test pre
6767
return this.getCaretCoordinates(codeInput, textarea, charIndex, false);
68-
}
68+
}
6969
afterSpan = spans[1];
7070
} else {
7171
/* Inspired by https://github.com/component/textarea-caret-position */
@@ -74,7 +74,8 @@ codeInput.plugins.Autocomplete = class extends codeInput.Plugin {
7474
let beforeSpan = document.createElement("span");
7575
beforeSpan.textContent = textarea.value.substring(0, charIndex);
7676
afterSpan = document.createElement("span");
77-
afterSpan.textContent = "."; // Placeholder
77+
afterSpan.textContent = ""; // Text here would potentially make the
78+
// invisible pre and thus the autogrowing code-input element wider
7879

7980
// Clear test pre - https://developer.mozilla.org/en-US/docs/Web/API/Node/removeChild
8081
while (testPosElem.firstChild) {

plugins/autogrow.css

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/**
2+
* Make code-input elements resize automatically and fit their content live using CSS
3+
* classes, optionally between a minimum and maximum size specified using CSS variables.
4+
*
5+
* Files: autogrow.css
6+
*/
7+
8+
/* Inspired greatly by https://css-tricks.com/the-cleanest-trick-for-autogrowing-textareas/
9+
and the fact code-input.js already implements the article's main structure. */
10+
11+
code-input.code-input_autogrow_height {
12+
--code-input_autogrow_min-height: 0px;
13+
--code-input_autogrow_max-height: calc(infinity * 1px);
14+
height: max-content;
15+
max-height: var(--code-input_autogrow_max-height);
16+
}
17+
code-input.code-input_autogrow_height textarea {
18+
height: calc(var(--code-input_autogrow_min-height) - var(--padding-top, 16px) - var(--padding-bottom, 16px))!important; /* So minimum height possible while containing highlighted code */
19+
min-height: max(var(--code-input_synced-height), calc(100% - var(--padding-top, 16px) - var(--padding-bottom, 16px)));
20+
}
21+
code-input.code-input_autogrow_height > pre,
22+
code-input.code-input_autogrow_height > pre code {
23+
min-height: calc(var(--code-input_autogrow_min-height) - var(--padding-top, 16px) - var(--padding-bottom, 16px));
24+
}
25+
26+
code-input.code-input_autogrow_width {
27+
--code-input_autogrow_min-width: 100px;
28+
--code-input_autogrow_max-width: 100%;
29+
width: max-content; /* Using unset rather than max-content makes always 100% width. */
30+
max-width: var(--code-input_autogrow_max-width);
31+
}
32+
code-input.code-input_autogrow_width textarea {
33+
width: calc(var(--code-input_autogrow_min-width) - var(--padding-left, 16px) - var(--padding-right, 16px))!important; /* So minimum width possible while containing highlighted code */
34+
min-width: max(var(--code-input_synced-width), calc(100% - var(--padding-left, 16px) - var(--padding-right, 16px)));
35+
}
36+
code-input.code-input_autogrow_width pre code,
37+
code-input.code-input_autogrow_width pre {
38+
min-width: calc(var(--code-input_autogrow_min-width) - var(--padding-left, 16px) - var(--padding-right, 16px));
39+
}
40+
41+
/* FindAndReplace / GoToLine dialog visibility */
42+
code-input.code-input_autogrow_width:has(.code-input_go-to-line_dialog:not(.code-input_go-to-line_hidden-dialog)) {
43+
--code-input_autogrow_min-width: 300px;
44+
}
45+
code-input.code-input_autogrow_height:has(.code-input_go-to-line_dialog:not(.code-input_go-to-line_hidden-dialog)) {
46+
--code-input_autogrow_min-height: 150px;
47+
}
48+
code-input.code-input_autogrow_width:has(.code-input_find-and-replace_dialog:not(.code-input_find-and-replace_hidden-dialog)) {
49+
--code-input_autogrow_min-width: 500px;
50+
}
51+
code-input.code-input_autogrow_height:has(.code-input_find-and-replace_dialog:not(.code-input_find-and-replace_hidden-dialog)) {
52+
--code-input_autogrow_min-height: 170px;
53+
}

plugins/find-and-replace.css

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,14 @@
1515
/* Find-and-replace dialog */
1616

1717
@keyframes code-input_find-and-replace_roll-in {
18-
0% {opacity: 0; transform: translateY(-34px);}
19-
100% {opacity: 1; transform: translateY(0px);}
20-
}
21-
22-
@keyframes code-input_find-and-replace_roll-out {
23-
0% {opacity: 1;top: 0;}
24-
100% {opacity: 0;top: -34px;}
18+
0% {
19+
opacity: 0;
20+
transform: translateY(-34px);
21+
}
22+
100% {
23+
opacity: 1;
24+
transform: translateY(0px);
25+
}
2526
}
2627

2728
.code-input_find-and-replace_dialog {
@@ -38,14 +39,11 @@
3839

3940
.code-input_find-and-replace_dialog:not(.code-input_find-and-replace_hidden-dialog) {
4041
animation: code-input_find-and-replace_roll-in .2s;
41-
opacity: 1;
42-
pointer-events: all;
42+
display: block;
4343
}
4444

4545
.code-input_find-and-replace_dialog.code-input_find-and-replace_hidden-dialog {
46-
animation: code-input_find-and-replace_roll-out .2s;
47-
opacity: 0;
48-
pointer-events: none;
46+
display: none;
4947
}
5048

5149
.code-input_find-and-replace_dialog input::placeholder {

plugins/go-to-line.css

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
@keyframes code-input_go-to-line_roll-in {
2-
0% {opacity: 0; transform: translateY(-34px);}
3-
100% {opacity: 1; transform: translateY(0px);}
4-
}
5-
6-
@keyframes code-input_go-to-line_roll-out {
7-
0% {opacity: 1; transform: translateY(0px);}
8-
100% {opacity: 0; transform: translateY(-34px);}
2+
0% {
3+
opacity: 0;
4+
transform: translateY(-34px);
5+
}
6+
100% {
7+
opacity: 1;
8+
transform: translateY(0px);
9+
}
910
}
1011

1112
.code-input_go-to-line_dialog {
@@ -21,14 +22,11 @@
2122

2223
.code-input_go-to-line_dialog:not(.code-input_go-to-line_hidden-dialog) {
2324
animation: code-input_go-to-line_roll-in .2s;
24-
opacity: 1;
25-
pointer-events: all;
25+
display: block;
2626
}
2727

2828
.code-input_go-to-line_dialog.code-input_go-to-line_hidden-dialog {
29-
animation: code-input_go-to-line_roll-out .2s;
30-
opacity: 0;
31-
pointer-events: none;
29+
display: none;
3230
}
3331

3432
.code-input_go-to-line_dialog input::placeholder {

0 commit comments

Comments
 (0)