"
`)
expect(renderToString(
test
)).toMatchInlineSnapshot(`
- "
"
`)
diff --git a/src/code/code.tsx b/src/code/code.tsx
index ebf6cfd..9544a01 100644
--- a/src/code/code.tsx
+++ b/src/code/code.tsx
@@ -1,8 +1,10 @@
+'use client'
+
import { tokenize, generate } from 'sugar-high'
-import { css, headerCss } from './css'
+import { css, HEADER_CSS } from './css'
import * as presets from 'sugar-high/presets'
import { useMemo } from 'react'
-import { Style } from '../style'
+import { ScopedStyle } from '../style'
const getPresetByExt = (ext: string) => {
switch (ext) {
@@ -102,7 +104,7 @@ export function CodeHeader({
data-codice-header
data-codice-header-controls={controls}
>
-
+
{controls ? (
@@ -161,8 +163,6 @@ export function Code({
asMarkup?: boolean
extension?: string
} & React.HTMLAttributes
) {
- const styles = css({ fontSize, lineNumbers, lineNumbersWidth, padding })
-
const lineElements = useMemo(() =>
asMarkup
? code
@@ -172,8 +172,13 @@ export function Code({
return (
// Add both attribute because it's both root component and child component (of editor)
-
-
+
+
{lineElements}
diff --git a/src/code/css.ts b/src/code/css.ts
index 59a50e7..3ba693b 100644
--- a/src/code/css.ts
+++ b/src/code/css.ts
@@ -2,35 +2,43 @@ import { fontSizeCss } from '../style'
const C = `:scope[data-codice-code]`
const H = `:scope[data-codice-header]`
+const L = `:scope[data-codice-line-numbers="true"]`
+const FL = `:scope[data-codice-line-numbers="false"]`
-const baseCss = () => {
- return `\
+const BASE_CSS = `\
+${C} {
+ --codice-code-line-number-color: #a4a4a4;
+ --codice-code-highlight-color: #555555;
+ --codice-control-color: #8d8989;
+}
+${C} [data-codice-code-content] {
+ padding-bottom: var(--codice-code-padding);
+ padding-top: calc(var(--codice-code-padding) * 0.5);
+}
${C} pre {
white-space: pre-wrap;
margin: 0;
}
${C} code {
+ display: block;
border: none;
}
${C} .sh__line {
display: inline-block;
width: 100%;
}
-${C} .sh__line:has(> [data-codice-code-line-number]) {
- padding-left: var(--codice-code-line-number-width);
-}
${C} .sh__line[data-highlight] {
background-color: var(--codice-code-highlight-color);
}
`
-}
-export const headerCss = () => {
- return `\
+export const HEADER_CSS = `\
${H} {
position: relative;
display: flex;
- padding: 16px 22px 8px;
+ padding: calc(var(--codice-code-padding) * 0.75)
+ var(--codice-code-padding)
+ calc(var(--codice-code-padding) * 0.25);
align-items: center;
}
${H} [data-codice-title] {
@@ -61,13 +69,15 @@ ${H} [data-codice-control] {
background-color: var(--codice-control-color);
}
`
-}
-const lineNumbersCss = () => `\
-${C} code {
+const LINE_NUMBER_CSS = `\
+${L} code {
counter-reset: codice-code-line-number;
}
-${C} [data-codice-code-line-number] {
+${L} .sh__line:has(> [data-codice-code-line-number]) {
+ padding-left: var(--codice-code-line-number-width);
+}
+${L} [data-codice-code-line-number] {
counter-increment: codice-code-line-number 1;
content: counter(codice-code-line-number);
display: inline-block;
@@ -78,31 +88,29 @@ ${C} [data-codice-code-line-number] {
user-select: none;
color: var(--codice-code-line-number-color);
}
+${FL} .sh__line {
+ padding-left: var(--codice-code-padding);
+}
`
+const CODE_CSS = `${BASE_CSS}\n${HEADER_CSS}\n${LINE_NUMBER_CSS}`
+
export const css = ({
fontSize,
- lineNumbers,
lineNumbersWidth = '2.5rem',
padding = '1rem',
}: {
fontSize: string | number | undefined
- lineNumbers: boolean
lineNumbersWidth: string
padding: string
}): string => {
const fz = fontSizeCss(fontSize)
return `\
+${CODE_CSS}
${C} {
- --codice-code-line-number-color: #a4a4a4;
- --codice-code-highlight-color: #555555;
- --codice-control-color: #8d8989;
--codice-font-size: ${fz};
--codice-code-line-number-width: ${lineNumbersWidth};
--codice-code-padding: ${padding};
}
-${baseCss()}
-${headerCss()}
-${lineNumbers ? lineNumbersCss() : ''}
`
}
\ No newline at end of file
diff --git a/src/editor/css.ts b/src/editor/css.ts
index d88556b..cbd2426 100644
--- a/src/editor/css.ts
+++ b/src/editor/css.ts
@@ -2,26 +2,11 @@ import { fontSizeCss } from '../style'
const R = `:scope[data-codice-editor]`
-export const css = ({
- fontSize,
- lineNumbersWidth = '2.5rem',
- padding = '1rem',
- fontFamily = 'Consolas, Monaco, monospace',
-}: {
- fontSize?: string | number
- lineNumbersWidth: string
- padding: string
- fontFamily: string
-}) => {
- return `\
+export const EDITOR_CSS = `\
${R} {
--codice-text-color: transparent;
--codice-background-color: transparent;
--codice-caret-color: inherit;
- --codice-font-size: ${fontSizeCss(fontSize)};
- --codice-code-line-number-width: ${lineNumbersWidth};
- --codice-code-padding: ${padding};
- --codice-font-family: ${fontFamily};
position: relative;
overflow-y: scroll;
@@ -30,13 +15,18 @@ ${R} {
justify-content: stretch;
scrollbar-width: none;
}
+${R} [data-codice-content] {
+ padding: 0 calc(var(--codice-code-padding) / 2);
+}
+${R} textarea {
+ padding: calc(var(--codice-code-padding) * 0.5) calc(var(--codice-code-padding) / 2);
+}
${R} code,
${R} textarea {
font-family: var(--codice-font-family);
line-break: anywhere;
overflow-wrap: break-word;
scrollbar-width: none;
- padding: calc(var(--codice-code-padding) * 1.5) var(--codice-code-padding);
line-height: 1.5;
font-size: var(--codice-font-size);
caret-color: var(--codice-caret-color);
@@ -70,9 +60,29 @@ ${R} textarea {
height: 100%;
overflow: hidden;
}
-${R} [data-codice-line-numbers="true"] textarea {
- padding-left: calc(var(--codice-code-line-number-width) + var(--codice-code-padding));
+${R}[data-codice-line-numbers="true"] textarea {
+ padding-left: calc(var(--codice-code-line-number-width) + calc(var(--codice-code-padding) / 2) + 2px);
}
`
// line number padding-left is [[width 24px] margin-right 16px] + 15px
+
+export const css = ({
+ fontSize,
+ lineNumbersWidth = '2.5rem',
+ padding = '1rem',
+ fontFamily = 'Consolas, Monaco, monospace',
+}: {
+ fontSize?: string | number
+ lineNumbersWidth: string
+ padding: string
+ fontFamily: string
+}) => {
+ return `\
+${EDITOR_CSS}
+${R} {
+ --codice-font-size: ${fontSizeCss(fontSize)};
+ --codice-code-line-number-width: ${lineNumbersWidth};
+ --codice-code-padding: ${padding};
+ --codice-font-family: ${fontFamily};
+}`
}
\ No newline at end of file
diff --git a/src/editor/editor.test.tsx b/src/editor/editor.test.tsx
index 9b73666..eaeb28d 100644
--- a/src/editor/editor.test.tsx
+++ b/src/editor/editor.test.tsx
@@ -14,10 +14,6 @@ describe('Code', () => {
--codice-text-color: transparent;
--codice-background-color: transparent;
--codice-caret-color: inherit;
- --codice-font-size: inherit;
- --codice-code-line-number-width: 2.5rem;
- --codice-code-padding: 1rem;
- --codice-font-family: Consolas, Monaco, monospace;
position: relative;
overflow-y: scroll;
@@ -26,13 +22,18 @@ describe('Code', () => {
justify-content: stretch;
scrollbar-width: none;
}
+ :scope[data-codice-editor] [data-codice-content] {
+ padding: 0 calc(var(--codice-code-padding) / 2);
+ }
+ :scope[data-codice-editor] textarea {
+ padding: calc(var(--codice-code-padding) * 0.5) calc(var(--codice-code-padding) / 2);
+ }
:scope[data-codice-editor] code,
:scope[data-codice-editor] textarea {
font-family: var(--codice-font-family);
line-break: anywhere;
overflow-wrap: break-word;
scrollbar-width: none;
- padding: calc(var(--codice-code-padding) * 1.5) var(--codice-code-padding);
line-height: 1.5;
font-size: var(--codice-font-size);
caret-color: var(--codice-caret-color);
@@ -66,15 +67,23 @@ describe('Code', () => {
height: 100%;
overflow: hidden;
}
- :scope[data-codice-editor] [data-codice-line-numbers="true"] textarea {
- padding-left: calc(var(--codice-code-line-number-width) + var(--codice-code-padding));
+ :scope[data-codice-editor][data-codice-line-numbers="true"] textarea {
+ padding-left: calc(var(--codice-code-line-number-width) + calc(var(--codice-code-padding) / 2) + 2px);
}
+ :scope[data-codice-editor] {
+ --codice-font-size: inherit;
+ --codice-code-line-number-width: 2.5rem;
+ --codice-code-padding: 1rem;
+ --codice-font-family: Consolas, Monaco, monospace;
+ }
}"
`)
@@ -197,10 +218,6 @@ describe('Code', () => {
--codice-text-color: transparent;
--codice-background-color: transparent;
--codice-caret-color: inherit;
- --codice-font-size: inherit;
- --codice-code-line-number-width: 2.5rem;
- --codice-code-padding: 1rem;
- --codice-font-family: Consolas, Monaco, monospace;
position: relative;
overflow-y: scroll;
@@ -209,13 +226,18 @@ describe('Code', () => {
justify-content: stretch;
scrollbar-width: none;
}
+ :scope[data-codice-editor] [data-codice-content] {
+ padding: 0 calc(var(--codice-code-padding) / 2);
+ }
+ :scope[data-codice-editor] textarea {
+ padding: calc(var(--codice-code-padding) * 0.5) calc(var(--codice-code-padding) / 2);
+ }
:scope[data-codice-editor] code,
:scope[data-codice-editor] textarea {
font-family: var(--codice-font-family);
line-break: anywhere;
overflow-wrap: break-word;
scrollbar-width: none;
- padding: calc(var(--codice-code-padding) * 1.5) var(--codice-code-padding);
line-height: 1.5;
font-size: var(--codice-font-size);
caret-color: var(--codice-caret-color);
@@ -249,15 +271,23 @@ describe('Code', () => {
height: 100%;
overflow: hidden;
}
- :scope[data-codice-editor] [data-codice-line-numbers="true"] textarea {
- padding-left: calc(var(--codice-code-line-number-width) + var(--codice-code-padding));
+ :scope[data-codice-editor][data-codice-line-numbers="true"] textarea {
+ padding-left: calc(var(--codice-code-line-number-width) + calc(var(--codice-code-padding) / 2) + 2px);
}
+ :scope[data-codice-editor] {
+ --codice-font-size: inherit;
+ --codice-code-line-number-width: 2.5rem;
+ --codice-code-padding: 1rem;
+ --codice-font-family: Consolas, Monaco, monospace;
+ }
}"
`)
@@ -380,10 +422,6 @@ describe('Code', () => {
--codice-text-color: transparent;
--codice-background-color: transparent;
--codice-caret-color: inherit;
- --codice-font-size: inherit;
- --codice-code-line-number-width: 2.5rem;
- --codice-code-padding: 1rem;
- --codice-font-family: Consolas, Monaco, monospace;
position: relative;
overflow-y: scroll;
@@ -392,13 +430,18 @@ describe('Code', () => {
justify-content: stretch;
scrollbar-width: none;
}
+ :scope[data-codice-editor] [data-codice-content] {
+ padding: 0 calc(var(--codice-code-padding) / 2);
+ }
+ :scope[data-codice-editor] textarea {
+ padding: calc(var(--codice-code-padding) * 0.5) calc(var(--codice-code-padding) / 2);
+ }
:scope[data-codice-editor] code,
:scope[data-codice-editor] textarea {
font-family: var(--codice-font-family);
line-break: anywhere;
overflow-wrap: break-word;
scrollbar-width: none;
- padding: calc(var(--codice-code-padding) * 1.5) var(--codice-code-padding);
line-height: 1.5;
font-size: var(--codice-font-size);
caret-color: var(--codice-caret-color);
@@ -432,33 +475,38 @@ describe('Code', () => {
height: 100%;
overflow: hidden;
}
- :scope[data-codice-editor] [data-codice-line-numbers="true"] textarea {
- padding-left: calc(var(--codice-code-line-number-width) + var(--codice-code-padding));
+ :scope[data-codice-editor][data-codice-line-numbers="true"] textarea {
+ padding-left: calc(var(--codice-code-line-number-width) + calc(var(--codice-code-padding) / 2) + 2px);
}
- }"
`)
diff --git a/src/editor/editor.tsx b/src/editor/editor.tsx
index e05a65c..c43f5ce 100644
--- a/src/editor/editor.tsx
+++ b/src/editor/editor.tsx
@@ -1,8 +1,9 @@
'use client'
import { useEffect, useState, useRef, forwardRef } from 'react'
-import { Code } from '../code'
-import { CodeHeader, getExtension } from '../code/code'
+import { CodeHeader, getExtension, Code } from '../code/code'
+import { ScopedStyle } from '../style'
+import { css } from './css'
function composeRefs(...refs: React.Ref
[]) {
return (node: HTMLElement | null) => {
@@ -20,16 +21,19 @@ function composeRefs(...refs: React.Ref[]) {
}
}
-const Editor = forwardRef(function EditorComponent(
+export const Editor = forwardRef(function Editor(
{
title,
value = '',
- controls,
- lineNumbers,
+ controls = true,
+ lineNumbers = true,
lineNumbersWidth,
extension,
padding,
onChange = () => {},
+ fontSize,
+ fontFamily,
+ ...props
}: {
title?: string
value?: string
@@ -39,6 +43,9 @@ const Editor = forwardRef(function EditorComponent(
padding?: string
extension?: string
onChange?: (code: string) => void
+ } & {
+ fontSize?: string | number
+ fontFamily?: string
} & React.HTMLAttributes,
ref: React.Ref
) {
@@ -62,7 +69,17 @@ const Editor = forwardRef(function EditorComponent(
}
return (
- <>
+
+
{/* Display the header outside of the matched textarea and code, by default display controls */}
@@ -81,8 +98,6 @@ const Editor = forwardRef(function EditorComponent(
- >
+
)
})
-
-export { Editor }
diff --git a/src/editor/index.tsx b/src/editor/index.tsx
index 0833c59..26a04ae 100644
--- a/src/editor/index.tsx
+++ b/src/editor/index.tsx
@@ -1,50 +1,2 @@
-import { Editor as EditorClient } from './editor'
-import { css } from './css'
-import { Style } from '../style'
+export { Editor } from './editor'
-export type EditorProps = React.HTMLAttributes &
- Exclude[0], 'id'> & {
- fontSize?: string | number
- fontFamily?: string
- }
-
-export function Editor(props: EditorProps) {
- const {
- title,
- value,
- onChange,
- controls = true,
- lineNumbers = true,
- lineNumbersWidth,
- padding,
- fontSize,
- fontFamily,
- extension,
- ...restProps
- } = props
- const editorProps = {
- title,
- value,
- onChange,
- controls,
- lineNumbers,
- lineNumbersWidth,
- padding,
- extension,
- }
- return (
-
-
-
-
- )
-}
diff --git a/src/style.tsx b/src/style.tsx
index 4910e65..13586e0 100644
--- a/src/style.tsx
+++ b/src/style.tsx
@@ -1,4 +1,4 @@
-export function Style({ css }: { css: string }) {
+export function ScopedStyle({ css }: { css: string }) {
return (