UNPKG

codice

Version:

Codice is a slim React components suite for code editing and displaying story. It provides an editor component and a code block component with syntax highlighting. Styling customization is enabled through CSS variables and HTML attributes.

162 lines (157 loc) 4.81 kB
'use client'; import { jsxs, jsx } from 'react/jsx-runtime'; import { forwardRef, useState, useRef, useEffect } from 'react'; import { f as fontSizeCss, S as ScopedStyle, C as CodeHeader, a as Code, g as getExtension } from './code-12s-Dto1Jf_T.js'; const R = `:scope[data-codice-editor]`; const EDITOR_CSS = `\ ${R} { --codice-text-color: transparent; --codice-background-color: transparent; --codice-caret-color: inherit; position: relative; overflow-y: scroll; display: flex; flex-direction: column; justify-content: stretch; scrollbar-width: none; } ${R} textarea { padding: calc(var(--codice-code-padding) * 0.75) calc(var(--codice-code-padding) * 0.5); } ${R} code, ${R} textarea { font-family: var(--codice-font-family); line-break: anywhere; overflow-wrap: break-word; scrollbar-width: none; line-height: 1.5; font-size: var(--codice-font-size); caret-color: var(--codice-caret-color); border: none; outline: none; width: 100%; } ${R} code { display: inline-block; width: 100%; margin-left: calc(var(--codice-code-line-number-width) - 2.5rem); ${''} } ${R} textarea::-webkit-scrollbar, ${R} textarea:focus::-webkit-scrollbar, ${R} textarea:hover::-webkit-scrollbar { width: 0; } ${R} [data-codice-content] { position: relative; } ${R} textarea { resize: none; display: block; color: var(--codice-text-color); background-color: var(--codice-background-color); position: absolute; top: 0; bottom: 0; left: 0; right: 0; height: 100%; overflow: hidden; } ${R}[data-codice-line-numbers="true"] textarea { padding-left: calc(var(--codice-code-line-number-width) + 2px); } ${R}[data-codice-line-numbers="false"] textarea { padding-left: var(--codice-code-padding); } `; // line number padding-left is [[width 24px] margin-right 16px] + 15px const css = ({ fontSize, lineNumbersWidth = '2.5rem', padding = '1rem', fontFamily = 'Consolas, Monaco, monospace' })=>{ return `\ ${EDITOR_CSS} ${R} { --codice-font-size: ${fontSizeCss(fontSize)}; --codice-code-line-number-width: ${lineNumbersWidth}; --codice-code-padding: ${padding}; --codice-font-family: ${fontFamily}; }`; }; function composeRefs(...refs) { return (node)=>{ refs.forEach((ref)=>{ if (typeof ref === 'function') { if (node) { ref(node); } } else if (ref) { if (node) { ref.current = node; } } }); }; } const Editor = /*#__PURE__*/ forwardRef(function Editor({ title, value = '', controls = true, lineNumbers = true, lineNumbersWidth, extension, padding, onChange = ()=>{}, fontSize, fontFamily, onChangeTitle = ()=>{}, ...props }, ref) { const [code, setCode] = useState(value); const textareaRef = useRef(null); function update(textContent) { setCode(textContent); onChange(textContent); } useEffect(()=>{ if (value !== code) { update(value); } }, [ value, code ]); function onInput(event) { const textContent = event.target.value || ''; update(textContent); } return /*#__PURE__*/ jsxs("div", { ...props, "data-codice": "editor", "data-codice-editor": true, // DOM attributes for selecting the stateful editor easily. // e.g. [data-codice-line-numbers="true"] "data-codice-title": title || '', "data-codice-controls": !!controls, "data-codice-line-numbers": !!lineNumbers, children: [ /*#__PURE__*/ jsx(ScopedStyle, { css: css({ fontSize, padding, lineNumbersWidth, fontFamily }) }), /*#__PURE__*/ jsx(CodeHeader, { title: title, controls: controls, onChangeTitle: onChangeTitle }), /*#__PURE__*/ jsxs("div", { "data-codice-content": true, children: [ /*#__PURE__*/ jsx(Code, { title: null, extension: extension || getExtension(title), controls: false, lineNumbers: lineNumbers, lineNumbersWidth: lineNumbersWidth, padding: padding, children: code }), /*#__PURE__*/ jsx("textarea", { ref: composeRefs(ref, textareaRef), value: code, onChange: onInput }) ] }) ] }); }); export { Editor as E };