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); +});