@f-ewald/components 1.19.0 → 1.20.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,19 @@
1
+ /** Result of splitting a document into its optional front matter and body. */
2
+ export interface FrontMatterResult {
3
+ /** Parsed front matter key-value pairs, or `null` if none was found. */
4
+ data: Record<string, unknown> | null;
5
+ /** The document text with the front matter block (if any) removed. */
6
+ body: string;
7
+ }
8
+ /**
9
+ * Splits a leading `---`-delimited YAML front matter block off a document.
10
+ *
11
+ * Only treats the block as front matter if it parses as a non-empty plain
12
+ * object — this avoids misreading a markdown horizontal rule (also `---`) as
13
+ * front matter, and tolerates malformed YAML typed mid-edit by falling back
14
+ * to treating the whole document as plain body text.
15
+ */
16
+ export declare function parseFrontMatter(text: string): FrontMatterResult;
17
+ /** Stringifies a parsed front matter value for key-value table display. */
18
+ export declare function formatFrontMatterValue(value: unknown): string;
19
+ //# sourceMappingURL=front-matter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"front-matter.d.ts","sourceRoot":"","sources":["../../src/utils/front-matter.ts"],"names":[],"mappings":"AAEA,8EAA8E;AAC9E,MAAM,WAAW,iBAAiB;IAChC,wEAAwE;IACxE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IACrC,sEAAsE;IACtE,IAAI,EAAE,MAAM,CAAC;CACd;AAID;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,iBAAiB,CAkBhE;AAED,2EAA2E;AAC3E,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAI7D"}
@@ -0,0 +1,37 @@
1
+ import { parse } from "yaml";
2
+ const FRONT_MATTER_PATTERN = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?/;
3
+ /**
4
+ * Splits a leading `---`-delimited YAML front matter block off a document.
5
+ *
6
+ * Only treats the block as front matter if it parses as a non-empty plain
7
+ * object — this avoids misreading a markdown horizontal rule (also `---`) as
8
+ * front matter, and tolerates malformed YAML typed mid-edit by falling back
9
+ * to treating the whole document as plain body text.
10
+ */
11
+ export function parseFrontMatter(text) {
12
+ const match = text.match(FRONT_MATTER_PATTERN);
13
+ if (!match)
14
+ return { data: null, body: text };
15
+ try {
16
+ const parsed = parse(match[1]);
17
+ if (parsed === null ||
18
+ typeof parsed !== "object" ||
19
+ Array.isArray(parsed) ||
20
+ Object.keys(parsed).length === 0) {
21
+ return { data: null, body: text };
22
+ }
23
+ return { data: parsed, body: text.slice(match[0].length) };
24
+ }
25
+ catch {
26
+ return { data: null, body: text };
27
+ }
28
+ }
29
+ /** Stringifies a parsed front matter value for key-value table display. */
30
+ export function formatFrontMatterValue(value) {
31
+ if (Array.isArray(value))
32
+ return value.map(formatFrontMatterValue).join(", ");
33
+ if (value !== null && typeof value === "object")
34
+ return JSON.stringify(value);
35
+ return String(value);
36
+ }
37
+ //# sourceMappingURL=front-matter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"front-matter.js","sourceRoot":"","sources":["../../src/utils/front-matter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,MAAM,CAAC;AAU7B,MAAM,oBAAoB,GAAG,mCAAmC,CAAC;AAEjE;;;;;;;GAOG;AACH,MAAM,UAAU,gBAAgB,CAAC,IAAY;IAC3C,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,oBAAoB,CAAC,CAAC;IAC/C,IAAI,CAAC,KAAK;QAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IAE9C,IAAI,CAAC;QACH,MAAM,MAAM,GAAY,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QACxC,IACE,MAAM,KAAK,IAAI;YACf,OAAO,MAAM,KAAK,QAAQ;YAC1B,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC;YACrB,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,MAAM,KAAK,CAAC,EAChC,CAAC;YACD,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;QACpC,CAAC;QACD,OAAO,EAAE,IAAI,EAAE,MAAiC,EAAE,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC;IACxF,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IACpC,CAAC;AACH,CAAC;AAED,2EAA2E;AAC3E,MAAM,UAAU,sBAAsB,CAAC,KAAc;IACnD,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC,GAAG,CAAC,sBAAsB,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC9E,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IAC9E,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC;AACvB,CAAC","sourcesContent":["import { parse } from \"yaml\";\n\n/** Result of splitting a document into its optional front matter and body. */\nexport interface FrontMatterResult {\n /** Parsed front matter key-value pairs, or `null` if none was found. */\n data: Record<string, unknown> | null;\n /** The document text with the front matter block (if any) removed. */\n body: string;\n}\n\nconst FRONT_MATTER_PATTERN = /^---\\r?\\n([\\s\\S]*?)\\r?\\n---\\r?\\n?/;\n\n/**\n * Splits a leading `---`-delimited YAML front matter block off a document.\n *\n * Only treats the block as front matter if it parses as a non-empty plain\n * object — this avoids misreading a markdown horizontal rule (also `---`) as\n * front matter, and tolerates malformed YAML typed mid-edit by falling back\n * to treating the whole document as plain body text.\n */\nexport function parseFrontMatter(text: string): FrontMatterResult {\n const match = text.match(FRONT_MATTER_PATTERN);\n if (!match) return { data: null, body: text };\n\n try {\n const parsed: unknown = parse(match[1]);\n if (\n parsed === null ||\n typeof parsed !== \"object\" ||\n Array.isArray(parsed) ||\n Object.keys(parsed).length === 0\n ) {\n return { data: null, body: text };\n }\n return { data: parsed as Record<string, unknown>, body: text.slice(match[0].length) };\n } catch {\n return { data: null, body: text };\n }\n}\n\n/** Stringifies a parsed front matter value for key-value table display. */\nexport function formatFrontMatterValue(value: unknown): string {\n if (Array.isArray(value)) return value.map(formatFrontMatterValue).join(\", \");\n if (value !== null && typeof value === \"object\") return JSON.stringify(value);\n return String(value);\n}\n"]}
@@ -33,6 +33,11 @@ defines the details used when creating or reviewing components.
33
33
  - White map rings, image-overlay controls, avatar foregrounds, and celebratory
34
34
  confetti may remain literal when their contrast is intentionally independent
35
35
  of the surrounding theme.
36
+ - There is no dedicated secondary accent color. `tab-bar`'s inactive-tab
37
+ indicator reuses `--ui-border` (a shared line beneath the whole strip, with
38
+ the active tab's `--ui-primary` line drawn on top of it) rather than
39
+ introducing a new token — the same precedent as `ui-button`'s `secondary`
40
+ variant, which is realized via `--ui-border`/`--ui-text-muted`, not a hue.
36
41
 
37
42
  ## Typography
38
43
 
@@ -125,6 +130,10 @@ literal values are migrated onto them.
125
130
  - Modal/centered overlays expose a name, `role="dialog"`, `aria-modal`, initial
126
131
  focus, Escape behavior, focus containment, and focus restoration.
127
132
  - Collapsible controls expose `aria-expanded` and `aria-controls`.
133
+ - Tab strips (`tab-bar`/`tab-item`) follow the WAI-ARIA tabs pattern:
134
+ `role="tablist"/"tab"/"tabpanel"`, `aria-selected`, roving tabindex, and
135
+ automatic activation (arrow keys both move focus and select; Home/End jump
136
+ to the first/last tab).
128
137
  - Charts expose a concise accessible data summary.
129
138
  - Decorative icons/keycaps inside already-labelled controls are hidden from
130
139
  assistive technology; standalone equivalents expose their own name.
@@ -135,7 +144,8 @@ literal values are migrated onto them.
135
144
  - Metadata-only tags may omit standalone playground sections when their full
136
145
  behavior is demonstrated through a parent:
137
146
  `calendar-entry`, `gallery-item`, `gallery-item-variant`, `kanban-card`,
138
- `kanban-column`, and `timeline-entry` (shown through `timeline-container`).
147
+ `kanban-column`, `tab-item` (shown through `tab-bar`), and `timeline-entry`
148
+ (shown through `timeline-container`).
139
149
  - Styleless inline formatters may omit empty `static styles`/token imports:
140
150
  `distance-value`, `live-timer`, `relative-time`, and `roman-numeral`.
141
151
  - Domain visuals may deliberately diverge in geometry and data color, but their
@@ -0,0 +1,61 @@
1
+ # `<markdown-editor>`
2
+
3
+ GitHub-style markdown editor: a "Write" tab holding a plain textarea and a
4
+ "Preview" tab rendering the markdown body (via `markdown-view`). Leading
5
+ YAML front matter (a `---`-delimited block) is detected, parsed, and shown
6
+ as a key-value table above the rendered body rather than as raw text.
7
+
8
+ ## Install
9
+
10
+ ```js
11
+ import "@f-ewald/components/markdown-editor.js";
12
+ ```
13
+
14
+ ## Usage
15
+
16
+ ```html
17
+ <markdown-editor></markdown-editor>
18
+ <script type="module">
19
+ const el = document.querySelector("markdown-editor");
20
+ el.value = `---
21
+ title: Weekly status
22
+ author: Ada Lovelace
23
+ tags: [engineering, updates]
24
+ ---
25
+
26
+ # Weekly status
27
+
28
+ Some **markdown** content here.`;
29
+ el.addEventListener("input", (e) => console.log(e.detail.value));
30
+ </script>
31
+ ```
32
+
33
+ ## Attributes / properties
34
+
35
+ | Property | Attribute | Type | Default | Description |
36
+ | --- | --- | --- | --- | --- |
37
+ | `value` | `value` | `string` | `""` | Full raw document text, including any front matter block. |
38
+ | `rows` | `rows` | `number` | `12` | Visible row count for the Write tab's textarea. |
39
+ | `placeholder` | `placeholder` | `string` | `""` | Placeholder text shown when the Write tab is empty. |
40
+
41
+ ## Events
42
+
43
+ | Event | Description |
44
+ | --- | --- |
45
+ | `input` | Fires on every keystroke in the Write tab; detail: { value: string }. |
46
+ | `change` | Native change semantics (on blur, if the value changed); detail: { value: string }. |
47
+
48
+ ## Slots
49
+
50
+ _None._
51
+
52
+ ## CSS custom properties
53
+
54
+ | Custom property |
55
+ | --- |
56
+ | `--ui-font` |
57
+ | `--ui-font-size-sm` |
58
+ | `--ui-font-weight-medium` |
59
+ | `--ui-line-height-normal` |
60
+ | `--ui-text` |
61
+ | `--ui-text-muted` |
@@ -0,0 +1,64 @@
1
+ # `<tab-bar>`
2
+
3
+ WAI-ARIA tabs pattern (automatic activation, roving tabindex) driving a
4
+ strip of declarative `tab-item` children. `tab-bar` renders the `role="tab"`
5
+ button strip itself, reading `label`/`value`/`selected` off each slotted
6
+ `tab-item`; each `tab-item` owns its own visibility via its reflected
7
+ `selected` attribute.
8
+
9
+ The active tab's underline uses `--ui-primary`; a `--ui-border` line spans
10
+ the full strip beneath every tab, standing in for the inactive state since
11
+ this design system has no dedicated secondary accent color.
12
+
13
+ ## Install
14
+
15
+ ```js
16
+ import "@f-ewald/components/tab-bar.js";
17
+ ```
18
+
19
+ ## Usage
20
+
21
+ ```html
22
+ <tab-bar label="Project sections">
23
+ <tab-item label="Overview" value="overview" selected>Overview content</tab-item>
24
+ <tab-item label="Activity" value="activity">Activity content</tab-item>
25
+ <tab-item label="Settings" value="settings">Settings content</tab-item>
26
+ </tab-bar>
27
+ <script type="module">
28
+ document.querySelector("tab-bar").addEventListener("change", (e) => console.log(e.detail.value));
29
+ </script>
30
+ ```
31
+
32
+ ## Attributes / properties
33
+
34
+ | Property | Attribute | Type | Default | Description |
35
+ | --- | --- | --- | --- | --- |
36
+ | `label` | `label` | `string` | `""` | Accessible name for the tablist (e.g. "Editor mode"). |
37
+
38
+ ## Events
39
+
40
+ | Event | Description |
41
+ | --- | --- |
42
+ | `change` | The active tab changed via click or keyboard; detail: `TabChangeDetail`. |
43
+
44
+ ## Slots
45
+
46
+ | Slot | Description |
47
+ | --- | --- |
48
+ | `(default)` | `tab-item` elements. |
49
+
50
+ ## CSS custom properties
51
+
52
+ | Custom property |
53
+ | --- |
54
+ | `--ui-border` |
55
+ | `--ui-focus-ring` |
56
+ | `--ui-font` |
57
+ | `--ui-font-size-sm` |
58
+ | `--ui-font-weight-medium` |
59
+ | `--ui-font-weight-semibold` |
60
+ | `--ui-line-height-tight` |
61
+ | `--ui-primary` |
62
+ | `--ui-radius-sm` |
63
+ | `--ui-text` |
64
+ | `--ui-text-muted` |
@@ -0,0 +1,40 @@
1
+ # `<tab-item>`
2
+
3
+ A single labeled panel inside a `tab-bar`. Renders its default slot as an
4
+ ARIA `tabpanel`, shown or hidden based on `selected` — `tab-bar` reads
5
+ `label`/`value` to build its tab strip and toggles `selected` on the
6
+ active panel.
7
+
8
+ ## Install
9
+
10
+ ```js
11
+ import "@f-ewald/components/tab-item.js";
12
+ ```
13
+
14
+ ## Usage
15
+
16
+ ```html
17
+ <tab-item></tab-item>
18
+ ```
19
+
20
+ ## Attributes / properties
21
+
22
+ | Property | Attribute | Type | Default | Description |
23
+ | --- | --- | --- | --- | --- |
24
+ | `label` | `label` | `string` | `""` | Text shown in the tab-bar's tab button for this panel. |
25
+ | `value` | `value` | `string` | `""` | Stable identifier reported in `tab-bar`'s `change` event; defaults to `label`. |
26
+ | `selected` | `selected` | `boolean` | `false` | Whether this panel is the active one; `tab-bar` owns this. |
27
+
28
+ ## Events
29
+
30
+ _None._
31
+
32
+ ## Slots
33
+
34
+ | Slot | Description |
35
+ | --- | --- |
36
+ | `(default)` | Panel content, shown only while `selected`. |
37
+
38
+ ## CSS custom properties
39
+
40
+ _None._
package/llms.txt CHANGED
@@ -1120,6 +1120,37 @@ Example:
1120
1120
  </script>
1121
1121
  ```
1122
1122
 
1123
+ ## <markdown-editor>
1124
+
1125
+ GitHub-style markdown editor: a "Write" tab holding a plain textarea and a
1126
+ "Preview" tab rendering the markdown body (via `markdown-view`). Leading
1127
+ YAML front matter (a `---`-delimited block) is detected, parsed, and shown
1128
+ as a key-value table above the rendered body rather than as raw text.
1129
+
1130
+ Import: `import "@f-ewald/components/markdown-editor.js";`
1131
+
1132
+ Properties: `value` (attribute `value`) : string, default ""; `rows` (attribute `rows`) : number, default 12; `placeholder` (attribute `placeholder`) : string, default ""
1133
+ Events: `input`, `change`
1134
+ CSS custom properties: `--ui-font`, `--ui-font-size-sm`, `--ui-font-weight-medium`, `--ui-line-height-normal`, `--ui-text`, `--ui-text-muted`
1135
+
1136
+ Example:
1137
+ ```html
1138
+ <markdown-editor></markdown-editor>
1139
+ <script type="module">
1140
+ const el = document.querySelector("markdown-editor");
1141
+ el.value = `---
1142
+ title: Weekly status
1143
+ author: Ada Lovelace
1144
+ tags: [engineering, updates]
1145
+ ---
1146
+
1147
+ # Weekly status
1148
+
1149
+ Some **markdown** content here.`;
1150
+ el.addEventListener("input", (e) => console.log(e.detail.value));
1151
+ </script>
1152
+ ```
1153
+
1123
1154
  ## <markdown-view>
1124
1155
 
1125
1156
  Renders a markdown string as sanitized, styled HTML — headings, lists,
@@ -1682,6 +1713,54 @@ Example:
1682
1713
  <status-pill label="Blocked" color="danger"></status-pill>
1683
1714
  ```
1684
1715
 
1716
+ ## <tab-bar>
1717
+
1718
+ WAI-ARIA tabs pattern (automatic activation, roving tabindex) driving a
1719
+ strip of declarative `tab-item` children. `tab-bar` renders the `role="tab"`
1720
+ button strip itself, reading `label`/`value`/`selected` off each slotted
1721
+ `tab-item`; each `tab-item` owns its own visibility via its reflected
1722
+ `selected` attribute.
1723
+
1724
+ The active tab's underline uses `--ui-primary`; a `--ui-border` line spans
1725
+ the full strip beneath every tab, standing in for the inactive state since
1726
+ this design system has no dedicated secondary accent color.
1727
+
1728
+ Import: `import "@f-ewald/components/tab-bar.js";`
1729
+
1730
+ Properties: `label` (attribute `label`) : string, default ""
1731
+ Events: `change`
1732
+ CSS custom properties: `--ui-border`, `--ui-focus-ring`, `--ui-font`, `--ui-font-size-sm`, `--ui-font-weight-medium`, `--ui-font-weight-semibold`, `--ui-line-height-tight`, `--ui-primary`, `--ui-radius-sm`, `--ui-text`, `--ui-text-muted`
1733
+
1734
+ Example:
1735
+ ```html
1736
+ <tab-bar label="Project sections">
1737
+ <tab-item label="Overview" value="overview" selected>Overview content</tab-item>
1738
+ <tab-item label="Activity" value="activity">Activity content</tab-item>
1739
+ <tab-item label="Settings" value="settings">Settings content</tab-item>
1740
+ </tab-bar>
1741
+ <script type="module">
1742
+ document.querySelector("tab-bar").addEventListener("change", (e) => console.log(e.detail.value));
1743
+ </script>
1744
+ ```
1745
+
1746
+ ## <tab-item>
1747
+
1748
+ A single labeled panel inside a `tab-bar`. Renders its default slot as an
1749
+ ARIA `tabpanel`, shown or hidden based on `selected` — `tab-bar` reads
1750
+ `label`/`value` to build its tab strip and toggles `selected` on the
1751
+ active panel.
1752
+
1753
+ Import: `import "@f-ewald/components/tab-item.js";`
1754
+
1755
+ Properties: `label` (attribute `label`) : string, default ""; `value` (attribute `value`) : string, default ""; `selected` (attribute `selected`) : boolean, default false
1756
+ Events: none
1757
+ CSS custom properties: none
1758
+
1759
+ Example:
1760
+ ```html
1761
+ <tab-item></tab-item>
1762
+ ```
1763
+
1685
1764
  ## <text-area>
1686
1765
 
1687
1766
  Plain multi-line text field — a thin, tokenized wrapper around a native
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@f-ewald/components",
3
3
  "private": false,
4
- "version": "1.19.0",
4
+ "version": "1.20.0",
5
5
  "description": "A collection of universally usable web components for various tasks.",
6
6
  "type": "module",
7
7
  "main": "dist/index.js",
@@ -67,6 +67,7 @@
67
67
  "lit": "^3.3.3",
68
68
  "mapbox-gl": "^3.9.0",
69
69
  "marked": "^18.0.7",
70
+ "yaml": "^2.9.0",
70
71
  "zod": "^4.4.3"
71
72
  },
72
73
  "publishConfig": {