Skip to content

Commit

Permalink
Merge pull request #57 from WebCoder49/typescript-declarations
Browse files Browse the repository at this point in the history
Typescript declarations, and major changes to make closer to `<textarea>`
  • Loading branch information
WebCoder49 committed Jun 30, 2023
2 parents 179584e + 2913a19 commit af067e6
Show file tree
Hide file tree
Showing 12 changed files with 649 additions and 109 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
.vscode
debug.html
debug.html
debug/
30 changes: 23 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,23 +1,33 @@
# code-input

![Click to Switch](https://img.shields.io/static/v1?label=&message=Click%20to%20Switch:%20&color=grey&style=for-the-badge)[![GitHub](https://img.shields.io/static/v1?label=&message=GitHub&color=navy&style=for-the-badge&logo=github)](https://github.com/WebCoder49/code-input)[![NPM](https://img.shields.io/static/v1?label=&message=NPM&color=red&style=for-the-badge&logo=npm)](https://www.npmjs.com/package/@webcoder49/code-input)

[![View License](https://img.shields.io/github/license/webcoder49/code-input?style=for-the-badge)](LICENSE) [![View Releases](https://img.Shields.io/github/v/release/webcoder49/code-input?style=for-the-badge)](https://github.com/WebCoder49/code-input/releases) [![View the demo on CodePen](https://img.shields.io/static/v1?label=Demo&message=on%20CodePen&color=orange&logo=codepen&style=for-the-badge)](https://codepen.io/WebCoder49/details/jOypJOx)

> ___Fully customisable syntax-highlighted textareas.___ [[🚀 View the Demo](https://codepen.io/WebCoder49/details/jOypJOx)]
> ___Fully customisable, editable syntax-highlighted textareas that can be placed in any HTML form.___ [[🚀 View the Demo](https://codepen.io/WebCoder49/details/jOypJOx)]
![Using code-input with many different themes](https://user-images.githubusercontent.com/69071853/133924472-05edde5c-23e7-4350-a41b-5a74d2dc1a9a.gif)
*This demonstration uses themes from [Prism.js](https://prismjs.com/) and [highlight.js](https://highlightjs.org/), two syntax-highlighting programs which work well and have compatibility built-in with code-input.*
*This demonstration uses themes from [Prism.js](https://prismjs.com/) and [highlight.js](https://highlightjs.org/), two syntax-highlighting programs which work well with and have compatibility built-in with code-input.*

*A frontend JavaScript library, with:*<br/>
[![TypeScript Bindings - Click to Use](https://img.shields.io/static/v1?label=TypeScript%20Bindings&message=Click%20to%20Use&style=for-the-badge&color=blue&logo=typescript&logoColor=white)](https://github.com/WebCoder49/code-input-for-typescript)

---

## What does it do?
**`code-input`** lets you **turn any ordinary JavaScript syntax-highlighting theme and program into customisable syntax-highlighted textareas** using an HTML custom element. It uses vanilla CSS to superimpose a `textarea` on a `pre code` block, then handles indentations, scrolling and fixes any resulting bugs with JavaScript. To see how it works in more detail, please see [this CSS-Tricks article](https://css-tricks.com/creating-an-editable-textarea-that-supports-syntax-highlighted-code/ "Creating an Editable Textarea That Supports Syntax-Highlighted Code") I wrote.

## What are the advantages of using code-input, and what can it be used for?
Unlike other front-end code-editor projects, the simplicity of how `code-input` works means it is **highly customisable**. As it is not a full-featured editor, you can **choose what features you want it to include, and use your favourite syntax-highlighting algorithms and themes**.

The `<code-input>` element works like a `<textarea>` and therefore **works in HTML5 forms and supports using the `value` and `placeholder` attributes, as well as the `onchange` event.**
The `<code-input>` element works like a `<textarea>` and therefore **works in HTML5 forms and supports using the `name`, `value` and `placeholder` attributes, events like `onchange`, form resets, to name a few...** [(Demo)](https://codepen.io/WebCoder49/details/JjmqjZv)

`code-input` has also accumulated many **features in optional [plugins](./plugins/README.md)** from open-source contributions, allowing you to choose any features you want. If a feature you want is not present, [please open an issue / contribute it!](#contributing)

## 🚀 Getting Started With `code-input` (in 4 simple steps)

## [`code-input` also supports TypeScript (click)](https://github.com/WebCoder49/code-input-for-typescript)

`code-input` is designed to be **both easy to use and customisable**. Here's how to use it to create syntax-highlighted textareas:

### 1. Import `code-input`
Expand All @@ -42,8 +52,8 @@ From JSDelivr CDN (click)

```html
<!--In the <head>-->
<script src="https://cdn.jsdelivr.net/gh/WebCoder49/code-input@1.3/code-input.min.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/WebCoder49/code-input@1.3/code-input.min.css">
<script src="https://cdn.jsdelivr.net/gh/WebCoder49/code-input@2.0/code-input.min.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/WebCoder49/code-input@2.0/code-input.min.css">
```
</details>

Expand All @@ -62,7 +72,7 @@ The next step is to set up a `template` to link `code-input` to your syntax-high

- *Custom:*
```js
codeInput.registerTemplate("syntax-highlighted", codeInput.templates.custom(
codeInput.registerTemplate("syntax-highlighted", new codeInput.Template(
function(result_element) { /* Highlight function - with `pre code` code element */
/* Highlight code in result_element - code is already escaped so it doesn't become HTML */
},
Expand Down Expand Up @@ -105,8 +115,14 @@ Now that you have registered a template, you can use the custom `<code-input>` e
```
*or*
```HTML
<code-input lang="HTML" placeholder="Type code here" value="<a href='https://github.com/WebCoder49/code-input'>code-input</a>" template="syntax-highlighted" onchange="console.log('Your code is', this.value)"></code-input>
<code-input lang="HTML" placeholder="Type code here" template="syntax-highlighted" onchange="console.log('Your code is', this.value)">&lt; href='https://github.com/WebCoder49/code-input'>code-input&lt;/a></code-input>
```

## Contributing
If you have any features you would like to add to `code-input`, or have found any bugs, please [open an issue](https://github.com/WebCoder49/code-input/issues) or [fork and submit a pull request](https://github.com/WebCoder49/code-input/fork)! All contributions to this open-source project would be greatly appreciated.


|[![Contributors](https://contrib.rocks/image?repo=WebCoder49%2Fcode-input)](https://github.com/WebCoder49/code-input/graphs/contributors)|
|---|
|...have contributed pull requests so far.|
|(source: [contrib.rocks](https://contrib.rocks))|
14 changes: 14 additions & 0 deletions code-input.css
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,14 @@ code-input textarea, code-input:not(.code-input_pre-element-styled) pre code, co
width: calc(100% - var(--padding, 16px) * 2);
height: calc(100% - var(--padding, 16px) * 2);
}

code-input:not(.code-input_loaded) {
margin: 0px!important;
margin-bottom: calc(-1 * var(--padding, 16px))!important;
padding: var(--padding, 16px)!important;
border: 0;
}

code-input:not(.code-input_pre-element-styled) pre, code-input.code-input_pre-element-styled pre code {
/* Remove all margin and padding from others */
margin: 0px!important;
Expand Down Expand Up @@ -67,6 +75,12 @@ code-input pre {
z-index: 0;
}

code-input:not(.code-input_loaded) pre, code-input:not(.code-input_loaded) textarea {
opacity: 0;
}
code-input:not(.code-input_loaded)::after {
color: #ccc;
}

/* Make textarea almost completely transparent */

Expand Down
242 changes: 242 additions & 0 deletions code-input.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,242 @@
export as namespace codeInput;

/**
* Plugins are imported from the plugins folder. They will then
* provide custom extra functionality to code-input elements.
*/
export abstract class Plugin {
/**
* Create a Plugin
*
* @param {Array<string>} observedAttributes - The HTML attributes to watch for this plugin, and report any
* modifications to the `codeInput.Plugin.attributeChanged` method.
*/
constructor(observedAttributes: Array<string>)
/**
* Runs before code is highlighted.
* @param {codeInput.CodeInput} codeInput - The codeInput element
*/
beforeHighlight(codeInput: CodeInput): void
/**
* Runs after code is highlighted.
* @param {codeInput.CodeInput} codeInput - The codeInput element
*/
afterHighlight(codeInput: CodeInput): void
/**
* Runs before elements are added into a code-input element.
* @param {codeInput.CodeInput} codeInput - The codeInput element
*/
beforeElementsAdded(codeInput: CodeInput): void
/**
* Runs after elements are added into a code-input element (useful for adding events to the textarea).
* @param {codeInput.CodeInput} codeInput - The codeInput element
*/
afterElementsAdded(codeInput: CodeInput): void
/**
* Runs when an attribute of a code-input element is changed (you must add the attribute name to `codeInput.Plugin.observedAttributes` first).
* @param {codeInput.CodeInput} codeInput - The codeInput element
* @param {string} name - The name of the attribute
* @param {string} oldValue - The value of the attribute before it was changed
* @param {string} newValue - The value of the attribute after it is changed
*/
attributeChanged(codeInput: CodeInput, name: string, oldValue: string, newValue: string): void
/**
* The HTML attributes to watch for this plugin, and report any
* modifications to the `codeInput.Plugin.attributeChanged` method.
*/
observedAttributes: Array<string>
}

/**
* Before using any plugin in this namespace, please ensure you import its JavaScript
* files (in the plugins folder), or continue to get a more detailed error in the developer
* console.
*
* Where plugins are stored, after they are imported. The plugin
* file assigns them a space in this object.
* For adding completely new syntax-highlighting algorithms, please see `codeInput.templates`.
*
* Key - plugin name
*
* Value - plugin object
* @type {Object}
*/
export namespace plugins {
/**
* JavaScript example of a plugin, which brings extra,
* non-central optional functionality to code-input.
* Instances of plugins can be passed in in an array
* to the `plugins` argument when registering a template,
* for example like this:
* ```javascript
* codeInput.registerTemplate("syntax-highlighted", codeInput.templates.hljs(hljs, [new codeInput.plugins.Test()]));
* ```
*/
class Test extends Plugin {
constructor();
}

/**
* Display a popup under the caret using the text in the code-input element. This works well with autocomplete suggestions.
* Files: autocomplete.js / autocomplete.css
*/
class Autocomplete extends Plugin {
/**
* Pass in a function to display the popup that takes in (popup element, textarea, textarea.selectionEnd).
* @param {function} updatePopupCallback a function to display the popup that takes in (popup element, textarea, textarea.selectionEnd).
*/
constructor(updatePopupCallback: (popupElem: HTMLElement, textarea: HTMLTextAreaElement, selectionEnd: number) => void);
}

/**
* Autodetect the language live and change the `lang` attribute using the syntax highlighter's
* autodetect capabilities. Works with highlight.js only.
* Files: autodetect.js
*/
class Autodetect extends Plugin {
constructor();
}

/**
* Debounce the update and highlighting function
* https://medium.com/@jamischarles/what-is-debouncing-2505c0648ff1
* Files: debounce-update.js
*/
class DebounceUpdate extends Plugin {
/**
* Create a debounced update plugin to pass into a template.
* @param {Number} delayMs Delay, in ms, to wait until updating the syntax highlighting
*/
constructor(delayMs: number);
}

/**
* Adds indentation using the `Tab` key, and auto-indents after a newline, as well as making it
* possible to indent/unindent multiple lines using Tab/Shift+Tab
* Files: indent.js
*/
class Indent extends Plugin {
constructor();
}

/**
* Render special characters and control characters as a symbol with their hex code.
* Files: special-chars.js, special-chars.css
*/
class SpecialChars extends Plugin {
/**
* Create a special characters plugin instance.
* Default = covers many non-renderable ASCII characters.
* @param {Boolean} colorInSpecialChars Whether or not to give special characters custom background colors based on their hex code
* @param {Boolean} inheritTextColor If `colorInSpecialChars` is false, forces the color of the hex code to inherit from syntax highlighting. Otherwise, the base color of the `pre code` element is used to give contrast to the small characters.
* @param {RegExp} specialCharRegExp The regular expression which matches special characters
*/
constructor(colorInSpecialChars?: boolean, inheritTextColor?: boolean, specialCharRegExp?: RegExp);
}
}

/**
* Register a plugin class under `codeInput.plugins`.
* @param {string} pluginName The identifier of the plugin: if it is `"foo"`, `new codeInput.plugins.foo(`...`)` will instantiate it, etc.
* @param {Object} pluginClass The class of the plugin, created with `class extends codeInput.plugin {`...`}`
*/
export function registerPluginClass(pluginName: string, pluginClass: Object): void;

/**
* Please see `codeInput.templates.prism` or `codeInput.templates.hljs`.
* Templates are used in `<code-input>` elements and once registered with
* `codeInput.registerTemplate` will be in charge of the highlighting
* algorithm and settings for all code-inputs with a `template` attribute
* matching the registered name.
*/
export class Template {
/**
* **When `includeCodeInputInHighlightFunc` is `false`, `highlight` takes only the `<pre><code>` element as a parameter.**
*
* Constructor to create a custom template instance. Pass this into `codeInput.registerTemplate` to use it.
* I would strongly recommend using the built-in simpler template `codeInput.templates.prism` or `codeInput.templates.hljs`.
* @param {Function} highlight - a callback to highlight the code, that takes an HTML `<code>` element inside a `<pre>` element as a parameter
* @param {boolean} preElementStyled - is the `<pre>` element CSS-styled as well as the `<code>` element? If true, `<pre>` element's scrolling is synchronised; if false, `<code>` element's scrolling is synchronised.
* @param {boolean} isCode - is this for writing code? If true, the code-input's lang HTML attribute can be used, and the `<code>` element will be given the class name 'language-[lang attribute's value]'.
* @param {false} includeCodeInputInHighlightFunc - Setting this to true passes the `<code-input>` element as a second argument to the highlight function.
* @param {codeInput.Plugin[]} plugins - An array of plugin objects to add extra features - see `codeInput.Plugin`
* @returns template object
*/
constructor(highlight?: (code: HTMLElement) => void, preElementStyled?: boolean, isCode?: boolean, includeCodeInputInHighlightFunc?: false, plugins?: Plugin[])
/**
* **When `includeCodeInputInHighlightFunc` is `true`, `highlight` takes two parameters: the `<pre><code>` element, and the `<code-input>` element.**
*
* Constructor to create a custom template instance. Pass this into `codeInput.registerTemplate` to use it.
* I would strongly recommend using the built-in simpler template `codeInput.templates.prism` or `codeInput.templates.hljs`.
* @param {Function} highlight - a callback to highlight the code, that takes an HTML `<code>` element inside a `<pre>` element as a parameter
* @param {boolean} preElementStyled - is the `<pre>` element CSS-styled as well as the `<code>` element? If true, `<pre>` element's scrolling is synchronised; if false, `<code>` element's scrolling is synchronised.
* @param {boolean} isCode - is this for writing code? If true, the code-input's lang HTML attribute can be used, and the `<code>` element will be given the class name 'language-[lang attribute's value]'.
* @param {true} includeCodeInputInHighlightFunc - Setting this to true passes the `<code-input>` element as a second argument to the highlight function.
* @param {codeInput.Plugin[]} plugins - An array of plugin objects to add extra features - see `codeInput.Plugin`
* @returns template object
*/
constructor(highlight?: (code: HTMLElement, codeInput: CodeInput) => void, preElementStyled?: boolean, isCode?: boolean, includeCodeInputInHighlightFunc?: true, plugins?: Plugin[])
highlight: Function
preElementStyled: boolean
isCode: boolean
includeCodeInputInHighlightFunc: boolean
plugins: Plugin[]
}

/**
* Shortcut functions for creating templates.
* Each code-input element has a template attribute that
* tells it which template to use.
* Each template contains functions and preferences that
* run the syntax-highlighting and let code-input control
* the highlighting.
*
* For creating a custom template from scratch, please
* use `new codeInput.Template(...)`.
*
* For adding small pieces of functionality, please see `codeInput.plugins`.
*/
export namespace templates {
/**
* Constructor to create a template that uses Prism.js syntax highlighting (https://prismjs.com/)
* @param {Object} prism Import Prism.js, then after that import pass the `Prism` object as this parameter.
* @param {codeInput.Plugin[]} plugins - An array of plugin objects to add extra features - see `codeInput.plugins`
* @returns template object
*/
function prism(prism: Object, plugins?: Plugin[]): Template
/**
* Constructor to create a template that uses highlight.js syntax highlighting (https://highlightjs.org/)
* @param {Object} hljs Import highlight.js, then after that import pass the `hljs` object as this parameter.
* @param {codeInput.Plugin[]} plugins - An array of plugin objects to add extra features - see `codeInput.plugins`
* @returns template object
*/
function hljs(hljs: Object, plugins?: Plugin[]): Template
/**
* Constructor to create a proof-of-concept template that gives a message if too many characters are typed.
* @param {codeInput.Plugin[]} plugins - An array of plugin objects to add extra features - see `codeInput.plugins`
* @returns template object
*/
function characterLimit(plugins?: Plugin[]): Template
/**
* Constructor to create a proof-of-concept template that shows text in a repeating series of colors.
* @param {string[]} rainbowColors - An array of CSS colors, in the order each color will be shown
* @param {string} delimiter - The character used to split up parts of text where each part is a different colour (e.g. "" = characters, " " = words)
* @param {codeInput.Plugin[]} plugins - An array of plugin objects to add extra features - see `codeInput.plugins`
* @returns template object
*/
function rainbowText(rainbowColors?: string[], delimiter?: string, plugins?: Plugin[]): Template
}

/**
* A `<code-input>` element, an instance of an `HTMLElement`, and the result
* of `document.createElement("code-input")`.
*/
export class CodeInput extends HTMLElement { }

/**
* Register a template so code-input elements with a template attribute that equals the templateName will use the template.
* See `codeInput.templates` for constructors to create templates.
* @param {string} templateName - the name to register the template under
* @param {Object} template - a Template object instance - see `codeInput.templates`
*/
export function registerTemplate(templateName: string, template: Template): void;
Loading

0 comments on commit af067e6

Please sign in to comment.