nuxt-ui-basekit 0.2.0 → 0.2.1

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.
@@ -1,13 +1,13 @@
1
1
  <script setup lang="ts">
2
2
  /**
3
- * Rahmen für ein Diagramm: Karte, Titel, Legende und der Umschalter auf die
4
- * Tabellenansicht.
3
+ * The frame around a chart: card, title, legend, and the switch to the table
4
+ * view.
5
5
  *
6
- * Der Umschalter ist keine Zugabe. Ein Diagramm codiert Werte über Farbe und
7
- * Länge; wer davon nichts hatFarbfehlsichtigkeit, Screenreader, Ausdruck —
8
- * braucht dieselben Zahlen in lesbarer Form. Deshalb bringt jede Karte hier
9
- * ihre Tabelle mit, und deshalb ist der Umschalter sichtbar und nicht in einem
10
- * Menü versteckt.
6
+ * That switch is not a nicety. A chart encodes values through colour and
7
+ * length; anyone who gets nothing out of that a colour vision deficiency, a
8
+ * screen reader, a printout needs the same numbers in readable form. Which
9
+ * is why every card here brings its table along, and why the switch is visible
10
+ * rather than buried in a menu.
11
11
  */
12
12
  import { computed, ref } from 'vue'
13
13
  import { useBaseKitLabels } from '../../composables/useBaseKit'
@@ -15,11 +15,11 @@ import { useBaseKitLabels } from '../../composables/useBaseKit'
15
15
  const props = withDefaults(defineProps<{
16
16
  title: string
17
17
  subtitle?: string
18
- /** Wohin die Karte führt. Ohne Ziel bleibt der Titel ein Titel. */
18
+ /** Where the card leads. Without a target the title stays a title. */
19
19
  href?: string
20
- /** Diagramm ausgrauen, während im Hintergrund nachgeladen wird. */
20
+ /** Grey the chart out while something reloads in the background. */
21
21
  stale?: boolean
22
- /** Ohne Tabellen-Slot entfällt der Umschalter. */
22
+ /** Without a table slot the switch disappears. */
23
23
  tableAvailable?: boolean
24
24
  }>(), {
25
25
  subtitle: undefined,
@@ -1,10 +1,10 @@
1
1
  <script setup lang="ts">
2
2
  /**
3
- * Ein Verhältnis gegen eine bekannte Grenze„so viele von so vielen".
3
+ * A ratio against a known limitthis many of that many.
4
4
  *
5
- * Ein Meter setzt voraus, dass es ein Ganzes gibt. Wo keins existiert (Bytes
6
- * ohne Kontingent, Anzahl ohne Obergrenze), gehört die Zahl in eine Kachel und
7
- * nicht hierher; ein voller Balken behauptete sonst eine erreichte Grenze.
5
+ * A meter presupposes that a whole exists. Where none does bytes without a
6
+ * quota, a count without a ceiling the number belongs in a tile and not
7
+ * here; a full bar would otherwise claim a limit had been reached.
8
8
  */
9
9
  import { computed } from 'vue'
10
10
  import { baseKitChartColor, useChartFormat } from '../../composables/useChartPalette'
@@ -1,16 +1,15 @@
1
1
  import { computed, inject, type ComputedRef, type InjectionKey } from 'vue'
2
2
 
3
3
  /**
4
- * Der einzige Draht zwischen den BaseKit-Komponenten und der Anwendung,
5
- * die sie einsetzt.
4
+ * The only wire between the BaseKit components and the application using them.
6
5
  *
7
- * Die Komponenten sollen in jedem Nuxt-Projekt laufen. Sie dürfen deshalb
8
- * weder `vue-i18n` aufrufen noch Übersetzungsschlüssel kennen: `t('common.search')`
9
- * gibt es nur in der einen Anwendung, die diesen Schlüssel führt, und ein
10
- * Paket, das solche Schlüssel voraussetzt, ist keins.
6
+ * The components are meant to run in any Nuxt project. That rules out calling
7
+ * `vue-i18n` and it rules out knowing translation keys: `t('common.search')`
8
+ * exists only in the one application that carries that key, and a package
9
+ * which presupposes such keys is not a package.
11
10
  *
12
- * Stattdessen reicht die Anwendung Sprache und Beschriftungen einmal herein
13
- * in einem Plugin, das die Werte aus ihrer eigenen Quelle zieht:
11
+ * Instead the application hands language and labels in once, from a plugin
12
+ * that pulls the values out of its own source:
14
13
  *
15
14
  * // plugins/basekit.ts
16
15
  * export default defineNuxtPlugin((nuxtApp) => {
@@ -21,39 +20,35 @@ import { computed, inject, type ComputedRef, type InjectionKey } from 'vue'
21
20
  * nuxtApp.vueApp.provide(baseKitKey, config)
22
21
  * })
23
22
  *
24
- * Wer eine andere Sprache fährt, überschreibt die Tabelle vollständig die
25
- * Voreinstellung unten ist englisch und deckt nur den Fall ab, dass niemand
26
- * etwas bereitstellt.
23
+ * Provide nothing and the defaults below apply. One thing worth knowing when
24
+ * the values come from an i18n library: `useI18n()` requires a component setup
25
+ * context and throws inside a plugin. Take the instance from `nuxtApp.$i18n`,
26
+ * and only when the `computed` is read.
27
27
  *
28
- * Wer nichts bereitstellt, bekommt die Voreinstellungen unten. Wichtig, wenn
29
- * die Werte aus einer i18n-Bibliothek kommen: `useI18n()` verlangt einen
30
- * Komponenten-Setup-Kontext und wirft im Plugin. Die Instanz gehört über
31
- * `nuxtApp.$i18n` geholt, und zwar erst beim Lesen des `computed`.
28
+ * Over `provide`/`inject` rather than `useNuxtApp()`: that way the components
29
+ * also run in a Vitest mount without a Nuxt context, and two requests share
30
+ * nothing under SSR.
32
31
  *
33
- * Über `provide`/`inject`, nicht über `useNuxtApp()`: so laufen die
34
- * Komponenten auch in einem Vitest-Mount ohne Nuxt-Kontext, und unter SSR
35
- * teilen sich zwei Anfragen nichts.
36
- *
37
- * Einzelne Beschriftungen bleiben weiterhin als Prop überschreibbar — hier
38
- * steht nur, was ohne Zutun herauskommt.
32
+ * Individual labels stay overridable as props what follows only decides what
33
+ * comes out when nothing is passed.
39
34
  */
40
35
  export interface BaseKitLabels {
41
- /** Suchfeld über Listen und Auswahl-Dialogen. */
36
+ /** Search field above lists and pickers. */
42
37
  search: string
43
- /** Filter-Eintrag „ohne Einschränkung". */
38
+ /** Filter entry for "no restriction". */
44
39
  all: string
45
40
  select: string
46
41
  change: string
47
42
  edit: string
48
43
  cancel: string
49
44
  confirm: string
50
- /** Überschrift der Rückfrage, wenn der Aufrufer keine mitgibt. */
45
+ /** Heading of the confirmation when the caller passes none. */
51
46
  confirmTitle: string
52
- /** Text der Rückfrage, wenn der Aufrufer keinen mitgibt. */
47
+ /** Body of the confirmation when the caller passes none. */
53
48
  confirmBody: string
54
- /** Leere Listees gibt noch nichts. */
49
+ /** Empty listnothing exists yet. */
55
50
  empty: string
56
- /** Leere Listedie Suche greift, findet aber nichts. */
51
+ /** Empty listthe search ran and found nothing. */
57
52
  noResults: string
58
53
  noResultsHint: string
59
54
  back: string
@@ -62,15 +57,15 @@ export interface BaseKitLabels {
62
57
  perPage: string
63
58
  iconChoose: string
64
59
  iconEmpty: string
65
- /** Auswahl aufhebenim Symbolwähler die leere Wahl. */
60
+ /** Clearing the choice the empty option in the icon picker. */
66
61
  iconClear: string
67
62
  chartAsTable: string
68
63
  chartAsChart: string
69
- /** 1–25 von 300" — als Funktion, weil die Zahlen mitten im Satz stehen. */
64
+ /** "1–25 of 300" — a function, because the numbers sit inside the sentence. */
70
65
  paginationRange: (range: { from: number, to: number, total: number }) => string
71
66
  /**
72
- * Werkzeugleiste des Markdown-Editors. Eigene Gruppe, weil die Begriffe nur
73
- * dort vorkommen und die obere Ebene sonst zur Hälfte aus ihnen bestünde.
67
+ * Toolbar of the Markdown editor. Its own group, because the terms occur
68
+ * nowhere else and the top level would otherwise be half made of them.
74
69
  */
75
70
  markdown: {
76
71
  bold: string
@@ -82,24 +77,24 @@ export interface BaseKitLabels {
82
77
  quote: string
83
78
  code: string
84
79
  link: string
85
- /** Abfrage beim Setzen eines Links. */
80
+ /** Prompt shown when setting a link. */
86
81
  linkPrompt: string
87
82
  }
88
83
  }
89
84
 
90
85
  export interface BaseKitConfig {
91
86
  /**
92
- * BCP-47-Kennung für `Intl` — steuert Tausendertrennung, Prozent- und
93
- * Datumsformate in den Diagrammen.
87
+ * BCP-47 tag for `Intl` — drives thousands separators, percentages and date
88
+ * formats in the charts.
94
89
  */
95
90
  locale: string
96
91
  labels: BaseKitLabels
97
92
  }
98
93
 
99
94
  /**
100
- * Voreinstellung: englisch. Das Paket weiß nicht, in welcher Sprache die
101
- * Anwendung läuft, und Englisch ist die Sprache, die am wenigsten Leser
102
- * ausschließt. Wer deutsch fährt, reicht `BASEKIT_DEFAULTS_DE` herein.
95
+ * Defaults: English. The package cannot know what language the application
96
+ * runs in, and English is the one that shuts out the fewest readers. Anything
97
+ * else is handed in through the plugin above.
103
98
  */
104
99
  export const BASEKIT_DEFAULTS: BaseKitConfig = {
105
100
  locale: 'en-US',
@@ -144,16 +139,16 @@ export const BASEKIT_DEFAULTS: BaseKitConfig = {
144
139
  export const baseKitKey: InjectionKey<ComputedRef<BaseKitConfig>> = Symbol('basekit')
145
140
 
146
141
  /**
147
- * Konfiguration für eine BaseKit-Komponente. Ohne bereitgestellten Wert
148
- * greifen die Voreinstellungen die Komponente rendert dann auf Englisch,
149
- * statt leere Beschriftungen zu zeigen.
142
+ * Configuration for a BaseKit component. With nothing provided the defaults
143
+ * apply the component then renders in English instead of showing empty
144
+ * labels.
150
145
  */
151
146
  export function useBaseKit(): ComputedRef<BaseKitConfig> {
152
147
  const provided = inject(baseKitKey, null)
153
148
  return provided ?? computed(() => BASEKIT_DEFAULTS)
154
149
  }
155
150
 
156
- /** Kurzform für den häufigen Fall, dass nur die Beschriftungen gebraucht werden. */
151
+ /** Short form for the common case of only needing the labels. */
157
152
  export function useBaseKitLabels(): ComputedRef<BaseKitLabels> {
158
153
  const config = useBaseKit()
159
154
  return computed(() => config.value.labels)
@@ -2,17 +2,17 @@ import { computed } from 'vue'
2
2
  import { useBaseKit } from './useBaseKit'
3
3
 
4
4
  /**
5
- * Reihenfarben und Zahlenformate für die `BaseKitChart*`-Komponenten.
5
+ * Series colours and number formats for the `BaseKitChart*` components.
6
6
  *
7
- * Die Farben stehen als CSS-Variablen in `main.css` und sind als **Satz**
8
- * geprüft Reihenfolge inklusive. Deshalb gibt es hier nur einen Zugriff per
9
- * Index und keine Erzeugung: eine sechste Farbe wäre unter einer
10
- * Farbfehlsichtigkeit von einer der fünf nicht mehr zu unterscheiden.
11
- * Wer mehr Reihen hat, fasst zusammen.
7
+ * The colours live as CSS variables in `app/assets/css/basekit.css` and are
8
+ * validated as a **set**, order included. That is why there is lookup by index
9
+ * here and no generation: a sixth colour would be indistinguishable from one
10
+ * of the five under a colour vision deficiency. More series than that means
11
+ * grouping them.
12
12
  */
13
13
  export const BASEKIT_CHART_SLOTS = 5
14
14
 
15
- /** Farbe für Reihe `index` (0-basiert). Ab Slot 6 die zurückgenommene Graustufe. */
15
+ /** Colour for series `index`, zero-based. From slot 6 on, the muted grey. */
16
16
  export function baseKitChartColor(index: number): string {
17
17
  return index < BASEKIT_CHART_SLOTS
18
18
  ? `var(--basekit-chart-${index + 1})`
@@ -33,7 +33,7 @@ export function useChartFormat(): {
33
33
  return new Intl.NumberFormat(locale.value).format(value)
34
34
  }
35
35
 
36
- /** Für Werte an Marken und in Kacheln: 12.400 12,4 Tsd. */
36
+ /** For values on ticks and in tiles: 12,400 becomes 12.4K. */
37
37
  function compact(value: number): string {
38
38
  return value < 10000
39
39
  ? number(value)
@@ -41,9 +41,9 @@ export function useChartFormat(): {
41
41
  }
42
42
 
43
43
  /**
44
- * Anteil in Prozent. Abgerundet, solange nicht alles erreicht ist sonst
45
- * würde 9.999 von 10.000 als 100 %" durchgehen und die eine fehlende
46
- * Übersetzung wäre weggerundet.
44
+ * A share in percent, rounded down as long as the whole has not been
45
+ * reached — otherwise 9,999 out of 10,000 would pass as "100%" and the one
46
+ * missing item would be rounded out of sight.
47
47
  */
48
48
  function percent(value: number, total: number): string {
49
49
  if (total <= 0) return '—'
@@ -61,8 +61,8 @@ export function useChartFormat(): {
61
61
  }
62
62
 
63
63
  /**
64
- * Dezimalpräfixe (kB, MB, GB) nicht KiB/MiB. Speicheranbieter rechnen so
65
- * ab, und die Zahl soll zu der auf der Rechnung passen.
64
+ * Decimal prefixes (kB, MB, GB), not KiB/MiB. Storage is billed that way,
65
+ * and the number here should match the one on the invoice.
66
66
  */
67
67
  function bytes(value: number): string {
68
68
  const units = ['B', 'kB', 'MB', 'GB', 'TB']
@@ -76,7 +76,7 @@ export function useChartFormat(): {
76
76
  return `${new Intl.NumberFormat(locale.value, { maximumFractionDigits: digits }).format(size)} ${units[unit]}`
77
77
  }
78
78
 
79
- /** Laufzeit als 14 h 20 min", unter einer Stunde nur Minuten. */
79
+ /** Runtime as "14 h 20 min"; below an hour, minutes only. */
80
80
  function duration(seconds: number): string {
81
81
  const total = Math.max(0, Math.round(seconds / 60))
82
82
  const hours = Math.floor(total / 60)
@@ -1,16 +1,16 @@
1
1
  import { onBeforeUnmount, onMounted, ref, type Ref } from 'vue'
2
2
 
3
3
  /**
4
- * Misst die Breite eines Containers, damit ein SVG in echten Pixeln zeichnen
5
- * kann statt über eine skalierte `viewBox`.
4
+ * Measures a container so an SVG can draw in real pixels instead of going
5
+ * through a scaled `viewBox`.
6
6
  *
7
- * Der Unterschied ist die Schrift: eine `viewBox`, die auf Containerbreite
8
- * hochgerechnet wird, zieht Achsenbeschriftung und Werte mit hoch auf einer
9
- * breiten Karte steht dann 15-px-Text, wo 11 gemeint waren. Mit gemessener
10
- * Breite bleibt Text Text und nur die Geometrie wächst.
7
+ * The difference is the type: a `viewBox` scaled up to container width drags
8
+ * axis labels and values up with ita wide card then shows 15px text where
9
+ * 11 was meant. With a measured width, text stays text and only the geometry
10
+ * grows.
11
11
  *
12
- * Vor dem Mounten (SSR, erster Frame) gilt `fallback`. Das Diagramm ist damit
13
- * sofort da und rückt einmal zurecht, statt zu flackern.
12
+ * Before mount (SSR, first frame) `fallback` applies. The chart is therefore
13
+ * there straight away and settles once, rather than flickering.
14
14
  */
15
15
  export function useChartWidth(fallback = 640): {
16
16
  el: Ref<HTMLElement | null>
@@ -25,8 +25,8 @@ export function useChartWidth(fallback = 640): {
25
25
 
26
26
  observer = new ResizeObserver((entries) => {
27
27
  const measured = entries[0]?.contentRect.width ?? 0
28
- // Unter 240 px wird die Geometrie unbrauchbar; dann lieber schmal
29
- // zeichnen und den Container scrollen lassen.
28
+ // Below 240px the geometry becomes useless; draw narrow and let the
29
+ // container scroll instead.
30
30
  if (measured > 0) width.value = Math.max(240, Math.round(measured))
31
31
  })
32
32
  observer.observe(el.value)
@@ -2,10 +2,10 @@ import { useConfirmStore } from '../stores/confirm'
2
2
  import type { BaseKitConfirmOptions } from '../stores/confirm'
3
3
 
4
4
  /**
5
- * Bestätigungsabfrage als Ersatz für natives `window.confirm`.
5
+ * A confirmation prompt in place of the native `window.confirm`.
6
6
  *
7
- * Öffnet das global gemountete `BaseKitConfirmModal` und liefert ein Promise,
8
- * das mit `true`/`false` auflöst.
7
+ * Opens the globally mounted `BaseKitConfirmModal` and returns a promise that
8
+ * resolves to `true` or `false`.
9
9
  *
10
10
  * const confirm = useConfirm()
11
11
  * if (!(await confirm({ description: t('…'), color: 'error', confirmLabel: t('common.delete') }))) return
@@ -1,32 +1,32 @@
1
1
  import { defineStore } from 'pinia'
2
2
  import { ref } from 'vue'
3
3
 
4
- /** Optionen für eine Bestätigungsabfrage. */
4
+ /** Options for one confirmation prompt. */
5
5
  export interface BaseKitConfirmOptions {
6
- /** Titel des Dialogs (Default: `common.confirm.title`). */
6
+ /** Dialog title. Falls back to the `confirmTitle` label. */
7
7
  title?: string
8
- /** Erklärtext / Konsequenzbei Destruktivem ausformulieren. */
8
+ /** Explanation or consequencespell it out for anything destructive. */
9
9
  description?: string
10
- /** Beschriftung des Bestätigen-Buttons (Default: `common.confirm.confirm`). */
10
+ /** Label of the confirm button. Falls back to the `confirm` label. */
11
11
  confirmLabel?: string
12
- /** Beschriftung des Abbrechen-Buttons (Default: `common.cancel`). */
12
+ /** Label of the cancel button. Falls back to the `cancel` label. */
13
13
  cancelLabel?: string
14
- /** Farbe des Bestätigen-Buttons — `error` für destruktive Aktionen. */
14
+ /** Colour of the confirm button — `error` for destructive actions. */
15
15
  color?: 'error' | 'primary'
16
- /** Optionales Icon am Bestätigen-Button. */
16
+ /** Optional icon on the confirm button. */
17
17
  icon?: string
18
18
  }
19
19
 
20
20
  /**
21
- * Zentraler Bestätigungs-Storeersetzt native `window.confirm`-Dialoge durch
22
- * eine gethemte, dark-mode-fähige Abfrage.
21
+ * The confirmation store replaces native `window.confirm` dialogs with a
22
+ * themed, dark-mode-capable prompt.
23
23
  *
24
- * `ask()` öffnet das global gemountete `BaseKitConfirmModal` und liefert ein
25
- * Promise, das mit `true` (bestätigt) oder `false` (abgebrochen/geschlossen)
26
- * auflöst. Der Resolver lebt außerhalb der Reaktivität, damit genau eine
27
- * Antwort pro Abfrage zurückgeht.
24
+ * `ask()` opens the globally mounted `BaseKitConfirmModal` and returns a
25
+ * promise resolving to `true` (confirmed) or `false` (cancelled or closed).
26
+ * The resolver lives outside reactivity so exactly one answer goes back per
27
+ * prompt.
28
28
  *
29
- * Genutzt über das Composable `useConfirm()`:
29
+ * Used through the `useConfirm()` composable:
30
30
  * const confirm = useConfirm()
31
31
  * if (!(await confirm({ description: t('…'), color: 'error' }))) return
32
32
  */
@@ -36,7 +36,7 @@ export const useConfirmStore = defineStore('basekit:confirm', () => {
36
36
  let resolver: ((value: boolean) => void) | null = null
37
37
 
38
38
  function ask(opts: BaseKitConfirmOptions = {}): Promise<boolean> {
39
- // Läuft noch eine Abfrage, wird sie als abgebrochen aufgelöst.
39
+ // A prompt still running is resolved as cancelled.
40
40
  resolver?.(false)
41
41
  options.value = opts
42
42
  open.value = true
@@ -45,7 +45,7 @@ export const useConfirmStore = defineStore('basekit:confirm', () => {
45
45
  })
46
46
  }
47
47
 
48
- /** Abfrage beantworten und Dialog schließen. */
48
+ /** Answer the prompt and close the dialog. */
49
49
  function settle(value: boolean): void {
50
50
  open.value = false
51
51
  resolver?.(value)
@@ -1,14 +1,12 @@
1
1
  /**
2
- * HTML Markdown (turndown). Zwei Einsätze, beide nur im Admin/Editor — daher
3
- * bewusst getrennt von `markdown.ts` (das im öffentlichen Widget-Bundle steckt
4
- * und turndown nicht mitziehen soll):
5
- * - Tiptap speichert HTML → hier nach Markdown serialisieren.
6
- * - Legacy-Text-Blöcke mit rohem `config.html` einmalig nach Markdown wandeln.
2
+ * HTML to Markdown, through turndown. Kept apart from `markdown.ts` on
3
+ * purpose: that one may end up in a public bundle and should not drag turndown
4
+ * along, while this one is only ever needed where something is edited.
7
5
  *
8
- * **turndown wird bewusst erst beim ersten Aufruf geladen.** Das Paket ist
9
- * CommonJS; ein Import auf Modulebene landet im Server-Bundle und wirft dort
10
- * beim Rendern „require is not defined in ES module scope". Der Editor läuft
11
- * ohnehin nur im Browserauf dem Server wird die Funktion nie aufgerufen.
6
+ * **turndown is loaded lazily, and that is deliberate.** The package is
7
+ * CommonJS; an import at module level lands in the server bundle and throws
8
+ * "require is not defined in ES module scope" while rendering. The editor runs
9
+ * in the browser anywayon the server this function is never called.
12
10
  */
13
11
  type Turndown = { turndown: (html: string) => string }
14
12
 
@@ -18,14 +16,14 @@ function service(): Turndown | null {
18
16
  if (instance) return instance
19
17
  if (import.meta.server) return null
20
18
 
21
- // Synchroner Zugriff auf ein bereits geladenes Modul: der Editor ruft
22
- // `prepare()` beim Einhängen auf, bevor gespeichert werden kann.
19
+ // Synchronous access to an already loaded module: the editor calls
20
+ // `prepare()` on mount, well before anything can be saved.
23
21
  return instance
24
22
  }
25
23
 
26
24
  /**
27
- * Lädt turndown im Browser vor. Die Editor-Komponenten rufen das beim
28
- * Einhängen auf, damit {@link htmlToMarkdown} danach synchron bleiben kann.
25
+ * Preloads turndown in the browser. The editor components call this on mount
26
+ * so {@link htmlToMarkdown} can stay synchronous afterwards.
29
27
  */
30
28
  export async function prepareHtmlToMarkdown(): Promise<void> {
31
29
  if (instance || import.meta.server) return
@@ -40,8 +38,8 @@ export async function prepareHtmlToMarkdown(): Promise<void> {
40
38
  export function htmlToMarkdown(html?: string | null): string {
41
39
  if (!html) return ''
42
40
  const td = service()
43
- // Ohne geladenes turndown (Server, oder prepare() vergessen) lieber das
44
- // Original zurückgeben als eine Ausnahme zu werfen der Text ginge sonst
45
- // beim Speichern verloren.
41
+ // Without turndown loaded — on the server, or when prepare() was forgotten
42
+ // return the original rather than throwing: the text would otherwise be
43
+ // lost on save.
46
44
  return td ? td.turndown(String(html)).trim() : String(html)
47
45
  }
@@ -1,15 +1,16 @@
1
1
  import MarkdownIt from 'markdown-it'
2
2
 
3
3
  /**
4
- * Markdown HTML für den Text-Block (`richtext`-Widget, jetzt Markdown).
4
+ * Markdown to HTML.
5
5
  *
6
- * Bewusst `html: false`: roher HTML im Markdown wird NICHT durchgereicht — das
7
- * schließt die wichtigste XSS-Lücke ohne separaten Sanitizer (markdown-it
8
- * blockt zudem `javascript:`-Links per Default-`validateLink`). `linkify` macht
9
- * nackte URLs klickbar, `typographer` glättet Anführungszeichen/Bindestriche.
6
+ * `html: false` on purpose: raw HTML inside the Markdown is NOT passed
7
+ * through. That closes the biggest XSS hole without a separate sanitizer —
8
+ * markdown-it also blocks `javascript:` links through its default
9
+ * `validateLink`. `linkify` makes bare URLs clickable, `typographer` smooths
10
+ * quotes and dashes.
10
11
  *
11
- * Geteilt zwischen Anzeige und Editor-Vorschau, damit
12
- * Bearbeiten und Ausgabe identisch aussehen.
12
+ * Shared between display and editor preview, so that editing and output look
13
+ * the same.
13
14
  */
14
15
  const md: MarkdownIt = new MarkdownIt({
15
16
  html: false,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nuxt-ui-basekit",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "Markenfreie Basis-Komponenten für Nuxt 4 auf Nuxt UI — Tabellen, Reiter, Diagramme, Auswahl und Leerzustände als Nuxt-Layer.",
5
5
  "keywords": [
6
6
  "nuxt",