From 9d39f8411b4494423e448b1ebf86f2c6070289f1 Mon Sep 17 00:00:00 2001 From: truffle Date: Sun, 24 May 2026 15:41:17 +0000 Subject: [PATCH] feat: add elum-pre and elum-code primitives Add a multi-line code block (`.elum-pre`) and an opt-in inline run (`.elum-code`) to the v0.1 surface, addressing the gap described in #4. - `pre.elum-pre` uses the existing surface/border/fg tokens and the shared monospace family. Horizontal scroll on overflow; no wrapping. - `data-language="..."` on `.elum-pre` surfaces a small uppercase label in the top-left via `::before`, using the same muted color and tracking as `.elum-toolbar-label`. - `code.elum-code` gives inline runs an explicit border + radius for prose that is already code-heavy. Plain `` continues to inherit from base.css for blended in-prose runs. Wires the new bundle through `src/index.css`, adds a copyable snippet pair in `core-patterns/snippets/index.html`, a Code card in `examples/playground.html` so all three themes can be reviewed at once, the matching contract test in `tests/core-css-contract.test.mjs`, and a usage section in `docs/component-usage.md`. All 23 existing tests still pass; new test covers the language tag hook and the scroll behavior. --- docs/component-usage.md | 8 ++++ examples/playground.html | 27 ++++++++++++ packages/core-css/src/components/code.css | 51 ++++++++++++++++++++++ packages/core-css/src/index.css | 1 + packages/core-patterns/snippets/index.html | 13 ++++++ tests/core-css-contract.test.mjs | 13 +++++- 6 files changed, 112 insertions(+), 1 deletion(-) create mode 100644 packages/core-css/src/components/code.css diff --git a/docs/component-usage.md b/docs/component-usage.md index 3a7e768..53eb8fc 100644 --- a/docs/component-usage.md +++ b/docs/component-usage.md @@ -144,3 +144,11 @@ Use semantic HTML first. Add ARIA only when native semantics are not enough. - **Responsive narrow rows:** `data-label` on each cell - **Numeric columns:** `data-numeric="true"` and `data-align="end"` - **Status column:** `data-column="status"` on header and cells to keep status output aligned + +## Code Block + +- **Block:** `
` wrapping a `` child for multi-line snippets
+- **Language tag:** `data-language="bash"`, `data-language="html"`, etc. surfaces a small uppercase label in the top-left of the block. Tag is decorative, not announced.
+- **Inline:** `` for short opt-in inline runs that need a stronger visual edge than the body `` default. Use plain `` for in-prose runs that should blend.
+- **Long lines:** the block scrolls horizontally; do not pre-wrap. Authors may add explicit line breaks for narrow surfaces.
+- Keep snippets short. For longer programs, link out to a file in the repo and quote the relevant block.
diff --git a/examples/playground.html b/examples/playground.html
index 9ba95f9..9443b3f 100644
--- a/examples/playground.html
+++ b/examples/playground.html
@@ -69,6 +69,7 @@
           "toolbar toolbar toolbar toolbar toolbar toolbar toolbar toolbar form form form form"
           "telemetry telemetry telemetry telemetry card card card card navigation navigation navigation navigation"
           "details details details details rows rows rows rows rows rows rows rows"
+          "code code code code code code code code code code code code"
           "states states states states states states states states states states states states";
       }
 
@@ -117,6 +118,10 @@
         grid-area: toolbar;
       }
 
+      .playground-code-preview {
+        grid-area: code;
+      }
+
       .state-matrix {
         display: grid;
         gap: 1rem;
@@ -138,6 +143,7 @@
             "card card card card card card telemetry telemetry telemetry telemetry telemetry telemetry"
             "navigation navigation navigation navigation navigation navigation details details details details details details"
             "rows rows rows rows rows rows rows rows rows rows rows rows"
+            "code code code code code code code code code code code code"
             "states states states states states states states states states states states states";
         }
 
@@ -170,6 +176,7 @@
             "toolbar toolbar toolbar toolbar toolbar toolbar toolbar toolbar toolbar toolbar toolbar toolbar"
             "navigation navigation navigation navigation navigation navigation navigation navigation navigation navigation navigation navigation"
             "rows rows rows rows rows rows rows rows rows rows rows rows"
+            "code code code code code code code code code code code code"
             "states states states states states states states states states states states states";
         }
 
@@ -449,6 +456,26 @@ 

Toolbar

+
+
+

Code

+
+

Inline runs and multi-line blocks with an optional language tag.

+ +

+ Install with + npm install elumkit + or copy the source. +

+ +
npm install elumkit
+npm run playground
+ +
<pre class="elum-pre" data-language="bash">
+  <code>echo hello</code>
+</pre>
+
+

Rows

diff --git a/packages/core-css/src/components/code.css b/packages/core-css/src/components/code.css new file mode 100644 index 0000000..19a44f7 --- /dev/null +++ b/packages/core-css/src/components/code.css @@ -0,0 +1,51 @@ +.elum-pre { + background: var(--elum-pre-bg, var(--elum-color-surface)); + border: var(--elum-border-width) solid var(--elum-color-border); + border-radius: var(--elum-radius-md); + color: var(--elum-color-fg); + font-family: var(--elum-font-family); + font-size: var(--elum-text-sm); + line-height: var(--elum-lh-normal); + margin: 0; + overflow-x: auto; + padding: var(--elum-space-3); + position: relative; + tab-size: 2; +} + +.elum-pre > code { + background: transparent; + border: 0; + color: inherit; + display: block; + font-family: inherit; + font-size: inherit; + padding: 0; +} + +.elum-pre[data-language] { + padding-top: calc(var(--elum-space-3) + var(--elum-space-3)); +} + +.elum-pre[data-language]::before { + color: var(--elum-color-muted); + content: attr(data-language); + font-size: var(--elum-text-xs); + font-weight: 600; + left: var(--elum-space-3); + letter-spacing: 0.06em; + pointer-events: none; + position: absolute; + text-transform: uppercase; + top: var(--elum-space-1); +} + +.elum-code { + background: var(--elum-code-bg, transparent); + border: var(--elum-border-width) solid var(--elum-color-border); + border-radius: var(--elum-radius-sm); + color: var(--elum-color-fg); + font-family: var(--elum-font-family); + font-size: 0.9em; + padding: 0 var(--elum-space-1); +} diff --git a/packages/core-css/src/index.css b/packages/core-css/src/index.css index fccdb20..c34bc74 100644 --- a/packages/core-css/src/index.css +++ b/packages/core-css/src/index.css @@ -9,3 +9,4 @@ @import "./components/tabs.css"; @import "./components/toolbar.css"; @import "./components/query.css"; +@import "./components/code.css"; diff --git a/packages/core-patterns/snippets/index.html b/packages/core-patterns/snippets/index.html index d5d7ea5..fbe44d2 100644 --- a/packages/core-patterns/snippets/index.html +++ b/packages/core-patterns/snippets/index.html @@ -195,4 +195,17 @@

Card Title

10:42 + +

Install the kit with npm install elumkit or copy the source.

+ +
npm install elumkit
+npm run playground
+open http://localhost:4173/examples/playground.html
+ +
<article class="elum-card elum-card-labeled">
+  <header class="elum-card-header">
+    <h2 class="elum-card-title">Card Title</h2>
+  </header>
+  <p>Dense, readable surface content.</p>
+</article>
diff --git a/tests/core-css-contract.test.mjs b/tests/core-css-contract.test.mjs index 44a9812..a8fdcc8 100644 --- a/tests/core-css-contract.test.mjs +++ b/tests/core-css-contract.test.mjs @@ -14,6 +14,7 @@ const DATA_CSS = readFileSync("packages/core-css/src/components/data.css", "utf8 const TABS_CSS = readFileSync("packages/core-css/src/components/tabs.css", "utf8"); const TOOLBAR_CSS = readFileSync("packages/core-css/src/components/toolbar.css", "utf8"); const QUERY_CSS = readFileSync("packages/core-css/src/components/query.css", "utf8"); +const CODE_CSS = readFileSync("packages/core-css/src/components/code.css", "utf8"); const INDEX_CSS = readFileSync("packages/core-css/src/index.css", "utf8"); const INDEX_CSS_PATH = "packages/core-css/src/index.css"; const PUBLIC_CSS = [ @@ -28,6 +29,7 @@ const PUBLIC_CSS = [ TABS_CSS, TOOLBAR_CSS, QUERY_CSS, + CODE_CSS, ].join("\n"); const THEMES = ["dust", "iron", "neon"]; @@ -72,7 +74,7 @@ function contrastRatio(firstColor, secondColor) { } test("core CSS entrypoint imports the public bundles", () => { - for (const bundle of ["tokens", "base", "button", "form", "card", "feedback", "telemetry", "data", "tabs", "toolbar", "query"]) { + for (const bundle of ["tokens", "base", "button", "form", "card", "feedback", "telemetry", "data", "tabs", "toolbar", "query", "code"]) { assert.match(INDEX_CSS, new RegExp(`@import ".+${bundle}\\.css";`)); } }); @@ -145,6 +147,8 @@ test("component CSS exposes current public class surfaces", () => { "elum-meter", "elum-list", "elum-table", + "elum-pre", + "elum-code", ]) { assert.match(PUBLIC_CSS, new RegExp(`\\.${className}\\b`)); } @@ -175,3 +179,10 @@ test("tabs scroll horizontally and show focus", () => { assert.match(TABS_CSS, /\.elum-tab:focus-visible\s*{[^}]*outline:/s); assert.doesNotMatch(TABS_CSS, /\.elum-tab\[aria-current="page"\]\s*{[^}]*box-shadow:/s); }); + +test("code block scrolls horizontally and exposes language tag hook", () => { + assert.match(CODE_CSS, /\.elum-pre\s*{[^}]*overflow-x:\s*auto;/s); + assert.match(CODE_CSS, /\.elum-pre\s*{[^}]*font-family:\s*var\(--elum-font-family\);/s); + assert.match(CODE_CSS, /\.elum-pre\[data-language\]::before\s*{[^}]*content:\s*attr\(data-language\);/s); + assert.match(CODE_CSS, /\.elum-pre\[data-language\]::before\s*{[^}]*color:\s*var\(--elum-color-muted\);/s); +});