diff --git a/design/.thumbnail b/design/.thumbnail new file mode 100644 index 0000000..138b726 Binary files /dev/null and b/design/.thumbnail differ diff --git a/design/DM360.dc.html b/design/DM360.dc.html new file mode 100644 index 0000000..8c489a4 --- /dev/null +++ b/design/DM360.dc.html @@ -0,0 +1,769 @@ + + + + + + + + + + + + + + + + +
+ + +
+
+ Audi + DataMetric360 +
Willkommen
+

Die App holt ihre Daten von deinem eigenen Server. Trag einmal die Adresse ein und füge deinen Zugangs-Token ein. Danach läuft alles von selbst.

+ + + + + + + + +
+ Verbinden + + {{ icons.code }}QR-Code scannen + +
+

Den QR-Code zeigt dir dein Server unter „DataMetric360 → Gerät verbinden“. Deine Daten bleiben auf deinem Server.

+
+
+
+ + + + + + +
+
+ + {{ icons.arrowLeft }} + +
+ {{ eyebrow }} +
{{ title }}
+
+ + + {{ icons.caution }}Offline · Stand {{ offlineTime }} + + + + {{ icons.settings }} + +
+ + +
Server nicht erreichbar. Du siehst die zuletzt geladenen Daten von {{ offlineDate }}, {{ offlineTime }} Uhr.
+
+ +
+ + + + + + {{ icons.overTheAir }} + + Fahrzeug fährt gerade + seit {{ live.dauer }} · {{ live.strecke }} km · {{ live.tempo }} km/h + + + + + +
+
+ + +
+
+
{{ modell }}
+
{{ kennzeichen }}
+
+ RS 6 +
+
+ +
+
+
+ +
+ + {{ icons.fuelRange }}Reichweite +
+ +
+ +
+ Tankfüllstand {{ tankPercentLabel }} % + {{ tankLiter }} l von 73 l +
+
+ + + +
+ +
+ + + {{ icons.planRoute }}Letzte Fahrt + {{ lastTrip.title }} + {{ lastTrip.sub }} · {{ lastTrip.value }} + + + + + {{ icons.gasStation }}Letzte Tankung + {{ lastFuel.title }} + {{ lastFuel.sub }} · {{ lastFuel.value }} + + + + + + + +
+
+
+ + +
+
+ + +
+ {{ icons.compass }} + {{ live.ort }} · aktualisiert vor {{ live.alter }} +
+
+
+
+ + {{ icons.topSpeed }}Geschwindigkeit +
+ +
+
Zündung an · {{ live.drehzahl }} 1/min
+
+ + + + + + +
+
+
+ + +
+ +
+ + +
+ RS 6 + Audi Sport +
+
+ + + +
+
+
+ + + + {{ a.icon }}{{ a.label }} + {{ a.value }} + {{ a.sub }} + + + +
+
+
+ +
+ + {{ audiDetail.icon }}{{ audiDetail.label }} +
{{ audiDetail.title }}
+ +
+ + + + + +
+
+
+
+ + + + +
+
{{ icons.planRoute }}
+
Noch keine Fahrten
+

Sobald du das erste Mal losfährst, zeichnet DataMetric360 die Fahrt automatisch auf und sortiert sie hier nach Monat ein.

+
+ Verbindung prüfen +
+
+
+
+ +
+ +
+ + + + + + + + + + + + + +
+
+ +
+ + +
+
+
{{ trip.title }}
+
{{ trip.sub }}
+
+ + {{ trip.artIcon }}{{ trip.art }} + +
+ +
+ + + +
+
+
+
+
+ + +
+ +
+ + +
+
{{ icons.consumption }}
+
Noch nichts auszuwerten
+

Nach der ersten vollständigen Fahrt siehst du hier Strecke, Fahrzeit, Verbrauch und Kosten. Für den Vergleich Tag/Nacht brauchst du etwa eine Woche Daten.

+
+
+
+ +
+
+ + {{ icons.mileage }}{{ stat.label }} +
+ +
+
+
+
+ + {{ icons.time }}Tag und Nacht +
+ +
+
+ + {{ icons.commute }}Privat und Arbeitsweg +
+ +
+
+
+
+ + Im Detail +
+ +
+
+
+
+
+
+ + + + +
+
{{ icons.gasStation }}
+
Noch keine Tankvorgänge
+

Trag deine erste Tankung ein, dann rechnet die App Verbrauch und Kosten automatisch mit. Den Beleg kannst du direkt fotografieren.

+
+ Tankung eintragen +
+
+
+
+ +
+ +
+ + + + + + + + + + + + + +
+ + {{ icons.add }}Tankung eintragen + +
+
+
+ +
+ +
+ + {{ fuel.station }} +
+
{{ fuel.title }}
+ +
+ + {{ icons.camera }}Beleg +
+ +
+ +
+ +
+
+
+
+
+
+
+
+ + +
+
+ + {{ icons.carSettings }}Fahrzeugdaten +
+ + + + + + + + + +
+
+ + Darstellung +
+ + + + + + +
+
+
+
+ + {{ icons.photo }}Fotos +
+ + + + + +
+
+ + {{ icons.add }}Foto hinzufügen + +
+
+ + {{ icons.download }}Daten +
+ Daten exportieren (CSV) + Backup erstellen + Verbindung trennen +
+
Letztes Backup: 03.08.2026, 02:00 Uhr
+
+
+
+
+ +
+ + +
+ +
+
+
+
+
+ +
+ + + diff --git a/design/DataMetric360.dc.html b/design/DataMetric360.dc.html new file mode 100644 index 0000000..b20ab80 --- /dev/null +++ b/design/DataMetric360.dc.html @@ -0,0 +1,103 @@ + + + + + + + + + + + + + + + +
+ +
+
+ Audi + DataMetric360 +
Bildschirme und Zustände
+
+
+ + + +
+
+ + + + +
+
+ +
+
+
+ Smartphone + 402 px · Tab-Leiste unten +
+
+ +
+
+ +
+
+ Großer Bildschirm + 1280 px · Navigation seitlich, Liste und Detail nebeneinander +
+
+ +
+
+
+
+ +
+ + + diff --git a/design/README.md b/design/README.md new file mode 100644 index 0000000..b4c9fe7 --- /dev/null +++ b/design/README.md @@ -0,0 +1,41 @@ +# design/ — Entwurf aus Claude Design + +Export des Claude-Design-Projekts **DataMetric360 App Design** +(https://claude.ai/design/p/c28a8d4d-ec4e-4178-9e49-ab5b90c02097). + +Das ist der **Entwurf**, nicht der lauffähige Code. Umgesetzt wird er später in +`companion-app/` auf Basis der Komponenten aus `design-system/`; die Architektur dahinter steht in +`../COMPANION_APP_ARCHITECTURE.md`, der Auftrag an den Entwurf in `../DESIGN_BRIEF_DATAMETRIC360.md`. + +## Inhalt + +| Pfad | Was | +|---|---| +| `DataMetric360.dc.html` | Einstiegsdatei des Entwurfs | +| `DM360.dc.html` | Die eigentlichen Bildschirme und Zustände | +| `support.js` | Hilfsfunktionen des Entwurfs | +| `assets/` | Icons, Logos, Typenschilder und Schriften, die der Entwurf verwendet | +| `uploads/` | Rohdateien, die ins Design-Projekt hochgeladen wurden (Schriften, Ringe, alle RS-/S-Typenschilder) | +| `_ds/` | Kompiliertes Bündel des Design-Systems `@audi-dash/ui` - erzeugt aus `../design-system/`, hier nur mitgeliefert, damit der Entwurf für sich allein darstellbar ist. **Nicht von Hand ändern**, sondern `../design-system/` anpassen und neu synchronisieren. | + +## Stand dieses Exports + +Heruntergeladen am 2026-08-11. Zwei bekannte Abweichungen, die im Design-Projekt bereits als Korrektur +beauftragt, in *diesem* Export aber noch nicht enthalten sind: + +1. **Falsches Modell:** zeigt „Audi RS 6 Avant" mit RS-6-Typenschild. Richtig ist der + **RS 4 Avant competition** (siehe `../SPECIFICATION.md` §1). +2. **Zu geringer Umfang:** enthält erst die Hauptbildschirme. Es fehlen 16 weitere Seiten, die das + bestehende HA-Panel bereits hat (Fahrzeugstatus, Fahrzeugdaten, Batterieverlauf, Service, + Werkstatt, Servicebuch, Versicherung/Steuer, Beitrag, Vertragsdetails, Schutzbrief, Notruf, + Kfz-Steuer, Reifen, Fahrt-Detail, Tankvorgang-Detail sowie deutlich umfangreichere Einstellungen) + - vollständige Liste in `../SPECIFICATION.md` §3. + +Dieser Ordner wird beim nächsten Export komplett ersetzt. + +## Markenrechtlicher Hinweis + +`assets/` und `uploads/` enthalten die Hausschrift Audi Type, die Ringe und die Typenschilder. Die +sind lizenz- beziehungsweise markenrechtlich geschützt (`../bauauftrag.md` §8/§12) und nur für diese +private Installation freigegeben. Dieses Repository ist deshalb privat zu halten. `../design-system/` +kommt bewusst ohne diese Dateien aus, weil es nach außen (Claude Design) hochgeladen wird. diff --git a/design/_ds/audi-dashboard-ui-27d66fd4-ed86-43b2-b8bf-61e281a5a1a5/README.md b/design/_ds/audi-dashboard-ui-27d66fd4-ed86-43b2-b8bf-61e281a5a1a5/README.md new file mode 100644 index 0000000..e073dc5 --- /dev/null +++ b/design/_ds/audi-dashboard-ui-27d66fd4-ed86-43b2-b8bf-61e281a5a1a5/README.md @@ -0,0 +1,72 @@ +## Usage conventions + +- **Always wrap the tree that uses these components in `
` (or `data-theme="tag"` for the light theme).** Color tokens (`--fg`, `--canvas`, `--tile`, etc.) are defined on `:root` and work anywhere, but text `color` and page `background` are only applied via the `.ads-root` class — content rendered outside it falls back to browser-default black-on-white. +- Default theme is **Nacht** (dark) — this is what `:root` sets without any `data-theme` override. Use `data-theme="tag"` for the light variant. +- No Audi brand assets (font, rings, nameplate) are included in this bundle — it uses a neutral `Helvetica, Arial, sans-serif` fallback stack by design. +- `Popup` renders via a React portal into `document.body` by default (`position: fixed`, centers or anchors relative to the viewport) — it doesn't need to sit inside `.ads-root` itself since its own CSS sets `background`/`color` explicitly rather than inheriting them. +- `SwipeRow` is a controlled/uncontrolled swipe-to-reveal row: swiping (or setting `swiped`) slides content left to reveal a delete action on the right, clipping the row's left edge by design — this is the intended interaction, not a layout bug. + +# AudiDashUI (@audi-dash/ui@0.1.0) + +This design system is the published @audi-dash/ui React library, bundled as a single +browser global. All 20 components are the real upstream code. + +## Where things are + +- `_ds_bundle.js` — the whole-DS bundle at the project root; loads every component to `window.AudiDashUI`. First line is a `/* @ds-bundle: … */` metadata header. +- `styles.css` — the single stylesheet entry: it `@import`s the tokens, fonts, and component styles (`_ds_bundle.css`). Link this one file. +- `components///.prompt.md` (example JSX + variants), `.d.ts` (types), `.html` (variant grid). +- `tokens/*.css` — CSS custom properties, names verbatim from upstream. +- `fonts/` — `@font-face` files + `fonts.css` (when the package ships fonts). + +For a specific component, `read_file("components///.prompt.md")`. + +## Loading + +Add these two lines to your page once (React must be on the page first): + +```html + + +``` + +Components are then available at `window.AudiDashUI.*`. Mount into a dedicated child node (e.g. `
`), not the host page's own React root, so the two trees don't collide: + +```jsx +const { Accordion } = window.AudiDashUI; +ReactDOM.createRoot(document.getElementById('ds-root')).render(); +``` + +## Tokens + +23 CSS custom properties from @audi-dash/ui. Names are +preserved verbatim from upstream. They are declared inside `_ds_bundle.css` (this DS ships one compiled stylesheet rather than separate token files). + +- **typography** (1): `--font-stack` +- **other** (22): `--red`, `--r-tile`, `--r-pill`, … + +## Components + +### general +- `Accordion` +- `ActionButton` +- `Feld` +- `Fig` +- `IconButton` +- `ImagePlaceholder` +- `Pill` +- `Popup` +- `PopupMenuItem` +- `ProgressBar` +- `ProgressRing` +- `RowList` +- `Seg` +- `StatGrid` +- `StatusRow` +- `SwipeRow` +- `Switch` +- `TabBar` +- `Tile` + +### accordion +- `LeafRow` diff --git a/design/_ds/audi-dashboard-ui-27d66fd4-ed86-43b2-b8bf-61e281a5a1a5/_adherence.oxlintrc.json b/design/_ds/audi-dashboard-ui-27d66fd4-ed86-43b2-b8bf-61e281a5a1a5/_adherence.oxlintrc.json new file mode 100644 index 0000000..9f6bcc6 --- /dev/null +++ b/design/_ds/audi-dashboard-ui-27d66fd4-ed86-43b2-b8bf-61e281a5a1a5/_adherence.oxlintrc.json @@ -0,0 +1,290 @@ +{ + "plugins": [ + "react", + "import" + ], + "rules": { + "react/forbid-elements": [ + "warn", + { + "forbid": [] + } + ], + "no-restricted-imports": [ + "warn", + { + "patterns": [ + { + "group": [ + "components/accordion/LeafRow/**", + "components/general/Accordion/**", + "components/general/ActionButton/**", + "components/general/Feld/**", + "components/general/Fig/**", + "components/general/IconButton/**", + "components/general/ImagePlaceholder/**", + "components/general/Pill/**", + "components/general/Popup/**", + "components/general/PopupMenuItem/**", + "components/general/ProgressBar/**", + "components/general/ProgressRing/**", + "components/general/RowList/**", + "components/general/Seg/**", + "components/general/StatGrid/**", + "components/general/StatusRow/**", + "components/general/SwipeRow/**", + "components/general/Switch/**", + "components/general/TabBar/**", + "components/general/Tile/**" + ], + "message": "Import design-system components from 'index.js', not component internals." + } + ] + } + ], + "no-restricted-syntax": [ + "warn", + { + "selector": "Literal[value=/#[0-9a-fA-F]{3,8}\\b/]", + "message": "Raw hex color — use a design-system color token via var()." + }, + { + "selector": "Literal[value=/\\b\\d+px\\b/]", + "message": "Raw px value — use a design-system spacing token via var()." + }, + { + "selector": "JSXOpeningElement[name.name='Accordion'] > JSXAttribute > JSXIdentifier[name!=/^(?:title|summary|open|defaultOpen|onOpenChange|level|children|className|key|ref|className|style|children)$/]", + "message": " doesn't accept that prop. Declared props: title, summary, open, defaultOpen, onOpenChange, level, children, className." + }, + { + "selector": "JSXOpeningElement[name.name='ActionButton'] > JSXAttribute > JSXIdentifier[name!=/^(?:children|onClick|variant|disabled|type|className|key|ref|className|style|children)$/]", + "message": " doesn't accept that prop. Declared props: children, onClick, variant, disabled, type, className." + }, + { + "selector": "JSXOpeningElement[name.name='ActionButton'] > JSXAttribute[name.name='variant'] > Literal[value!=/^(?:default|destructive)$/]", + "message": " variant must be one of 'default' | 'destructive'." + }, + { + "selector": "JSXOpeningElement[name.name='ActionButton'] > JSXAttribute[name.name='type'] > Literal[value!=/^(?:button|submit)$/]", + "message": " type must be one of 'button' | 'submit'." + }, + { + "selector": "JSXOpeningElement[name.name='Feld'] > JSXAttribute > JSXIdentifier[name!=/^(?:label|value|children|unit|last|className|key|ref|className|style|children)$/]", + "message": " doesn't accept that prop. Declared props: label, value, children, unit, last, className." + }, + { + "selector": "JSXOpeningElement[name.name='Fig'] > JSXAttribute > JSXIdentifier[name!=/^(?:value|unit|size|className|key|ref|className|style|children)$/]", + "message": " doesn't accept that prop. Declared props: value, unit, size, className." + }, + { + "selector": "JSXOpeningElement[name.name='IconButton'] > JSXAttribute > JSXIdentifier[name!=/^(?:onClick|children|disabled|className|key|ref|className|style|children)$/]", + "message": " doesn't accept that prop. Declared props: onClick, children, disabled, className." + }, + { + "selector": "JSXOpeningElement[name.name='ImagePlaceholder'] > JSXAttribute > JSXIdentifier[name!=/^(?:src|alt|label|hint|icon|size|className|key|ref|className|style|children)$/]", + "message": " doesn't accept that prop. Declared props: src, alt, label, hint, icon, size, className." + }, + { + "selector": "JSXOpeningElement[name.name='ImagePlaceholder'] > JSXAttribute[name.name='size'] > Literal[value!=/^(?:default|mini|round)$/]", + "message": " size must be one of 'default' | 'mini' | 'round'." + }, + { + "selector": "JSXOpeningElement[name.name='LeafRow'] > JSXAttribute > JSXIdentifier[name!=/^(?:title|subTitle|value|subValue|onClick|className|key|ref|className|style|children)$/]", + "message": " doesn't accept that prop. Declared props: title, subTitle, value, subValue, onClick, className." + }, + { + "selector": "JSXOpeningElement[name.name='Pill'] > JSXAttribute > JSXIdentifier[name!=/^(?:children|variant|className|key|ref|className|style|children)$/]", + "message": " doesn't accept that prop. Declared props: children, variant, className." + }, + { + "selector": "JSXOpeningElement[name.name='Pill'] > JSXAttribute[name.name='variant'] > Literal[value!=/^(?:default|work)$/]", + "message": " variant must be one of 'default' | 'work'." + }, + { + "selector": "JSXOpeningElement[name.name='Popup'] > JSXAttribute > JSXIdentifier[name!=/^(?:open|onClose|variant|anchor|children|className|portalTarget|key|ref|className|style|children)$/]", + "message": " doesn't accept that prop. Declared props: open, onClose, variant, anchor, children, className, portalTarget." + }, + { + "selector": "JSXOpeningElement[name.name='Popup'] > JSXAttribute[name.name='variant'] > Literal[value!=/^(?:menu|form)$/]", + "message": " variant must be one of 'menu' | 'form'." + }, + { + "selector": "JSXOpeningElement[name.name='PopupMenuItem'] > JSXAttribute > JSXIdentifier[name!=/^(?:onClick|destructive|children|key|ref|className|style|children)$/]", + "message": " doesn't accept that prop. Declared props: onClick, destructive, children." + }, + { + "selector": "JSXOpeningElement[name.name='ProgressBar'] > JSXAttribute > JSXIdentifier[name!=/^(?:percent|segments|showLegend|className|key|ref|className|style|children)$/]", + "message": " doesn't accept that prop. Declared props: percent, segments, showLegend, className." + }, + { + "selector": "JSXOpeningElement[name.name='ProgressRing'] > JSXAttribute > JSXIdentifier[name!=/^(?:percent|value|unit|label|size|className|key|ref|className|style|children)$/]", + "message": " doesn't accept that prop. Declared props: percent, value, unit, label, size, className." + }, + { + "selector": "JSXOpeningElement[name.name='RowList'] > JSXAttribute > JSXIdentifier[name!=/^(?:items|className|key|ref|className|style|children)$/]", + "message": " doesn't accept that prop. Declared props: items, className." + }, + { + "selector": "JSXOpeningElement[name.name='Seg'] > JSXAttribute > JSXIdentifier[name!=/^(?:options|value|onChange|className|key|ref|className|style|children)$/]", + "message": " doesn't accept that prop. Declared props: options, value, onChange, className." + }, + { + "selector": "JSXOpeningElement[name.name='StatGrid'] > JSXAttribute > JSXIdentifier[name!=/^(?:items|columns|className|key|ref|className|style|children)$/]", + "message": " doesn't accept that prop. Declared props: items, columns, className." + }, + { + "selector": "JSXOpeningElement[name.name='StatusRow'] > JSXAttribute > JSXIdentifier[name!=/^(?:status|title|subtitle|onClick|className|key|ref|className|style|children)$/]", + "message": " doesn't accept that prop. Declared props: status, title, subtitle, onClick, className." + }, + { + "selector": "JSXOpeningElement[name.name='StatusRow'] > JSXAttribute[name.name='status'] > Literal[value!=/^(?:ok|warn|bad)$/]", + "message": " status must be one of 'ok' | 'warn' | 'bad'." + }, + { + "selector": "JSXOpeningElement[name.name='SwipeRow'] > JSXAttribute > JSXIdentifier[name!=/^(?:children|onDelete|deleteLabel|swiped|onSwipedChange|className|key|ref|className|style|children)$/]", + "message": " doesn't accept that prop. Declared props: children, onDelete, deleteLabel, swiped, onSwipedChange, className." + }, + { + "selector": "JSXOpeningElement[name.name='Switch'] > JSXAttribute > JSXIdentifier[name!=/^(?:checked|onChange|disabled|id|className|key|ref|className|style|children)$/]", + "message": " doesn't accept that prop. Declared props: checked, onChange, disabled, id, className." + }, + { + "selector": "JSXOpeningElement[name.name='TabBar'] > JSXAttribute > JSXIdentifier[name!=/^(?:items|activeKey|onChange|iconOnly|className|key|ref|className|style|children)$/]", + "message": " doesn't accept that prop. Declared props: items, activeKey, onChange, iconOnly, className." + }, + { + "selector": "JSXOpeningElement[name.name='Tile'] > JSXAttribute > JSXIdentifier[name!=/^(?:variant|chevron|onClick|className|children|key|ref|className|style|children)$/]", + "message": " doesn't accept that prop. Declared props: variant, chevron, onClick, className, children." + }, + { + "selector": "JSXOpeningElement[name.name='Tile'] > JSXAttribute[name.name='variant'] > Literal[value!=/^(?:default|button|flat)$/]", + "message": " variant must be one of 'default' | 'button' | 'flat'." + } + ] + }, + "overrides": [ + { + "files": [ + "**/index.js" + ], + "rules": { + "no-restricted-imports": "off" + } + } + ], + "x-omelette": { + "components": { + "Accordion": { + "replaces": [] + }, + "ActionButton": { + "replaces": [] + }, + "Feld": { + "replaces": [] + }, + "Fig": { + "replaces": [] + }, + "IconButton": { + "replaces": [] + }, + "ImagePlaceholder": { + "replaces": [] + }, + "LeafRow": { + "replaces": [] + }, + "Pill": { + "replaces": [] + }, + "Popup": { + "replaces": [] + }, + "PopupMenuItem": { + "replaces": [] + }, + "ProgressBar": { + "replaces": [] + }, + "ProgressRing": { + "replaces": [] + }, + "RowList": { + "replaces": [] + }, + "Seg": { + "replaces": [] + }, + "StatGrid": { + "replaces": [] + }, + "StatusRow": { + "replaces": [] + }, + "SwipeRow": { + "replaces": [] + }, + "Switch": { + "replaces": [] + }, + "TabBar": { + "replaces": [] + }, + "Tile": { + "replaces": [] + } + }, + "tokens": [ + "--bad", + "--canvas", + "--fg", + "--fg2", + "--fg3", + "--font-stack", + "--line", + "--line-strong", + "--ok", + "--r-func", + "--r-pill", + "--r-tile", + "--rahmen-hg", + "--red", + "--shade", + "--sp-1", + "--sp-2", + "--sp-3", + "--sp-4", + "--sp-5", + "--tile", + "--tile-2", + "--warn" + ], + "tokenKinds": { + "--red": "color", + "--r-tile": "spacing", + "--r-pill": "spacing", + "--r-func": "spacing", + "--rahmen-hg": "color", + "--sp-1": "spacing", + "--sp-2": "spacing", + "--sp-3": "spacing", + "--sp-4": "spacing", + "--sp-5": "spacing", + "--canvas": "color", + "--tile": "color", + "--tile-2": "color", + "--line": "color", + "--line-strong": "color", + "--fg": "color", + "--fg2": "color", + "--fg3": "color", + "--ok": "color", + "--warn": "color", + "--bad": "color", + "--shade": "color", + "--font-stack": "font" + }, + "fontFamilies": [] + } +} \ No newline at end of file diff --git a/design/_ds/audi-dashboard-ui-27d66fd4-ed86-43b2-b8bf-61e281a5a1a5/_ds_bundle.css b/design/_ds/audi-dashboard-ui-27d66fd4-ed86-43b2-b8bf-61e281a5a1a5/_ds_bundle.css new file mode 100644 index 0000000..5ba5e7d --- /dev/null +++ b/design/_ds/audi-dashboard-ui-27d66fd4-ed86-43b2-b8bf-61e281a5a1a5/_ds_bundle.css @@ -0,0 +1,733 @@ +/* src/tokens/tokens.css */ +:root { + --red: #F50537; + --r-tile: 20px; + --r-pill: 999px; + --r-func: 8px; + --rahmen-hg: #111; + --sp-1: 4px; + --sp-2: 8px; + --sp-3: 12px; + --sp-4: 16px; + --sp-5: 22px; + --canvas: #161b23; + --tile: #1f2733; + --tile-2: #2a3341; + --line: rgba(255, 255, 255, .10); + --line-strong: rgba(255, 255, 255, .20); + --fg: #FFFFFF; + --fg2: #9aa1ad; + --fg3: #657081; + --ok: #15da15; + --warn: #ffaa00; + --bad: #fd2c4e; + --shade: rgba(255, 255, 255, .05); + --font-stack: + Helvetica, + Arial, + sans-serif; +} +[data-theme=tag] { + --canvas: #FFFFFF; + --tile: #f2f2f2; + --tile-2: #e5e5e5; + --line: rgba(0, 0, 0, .10); + --line-strong: rgba(0, 0, 0, .22); + --fg: #000000; + --fg2: #4c4c4c; + --fg3: #666666; + --ok: #0DA20D; + --warn: #ffaa00; + --bad: #eb0d3f; + --shade: rgba(0, 0, 0, .04); +} +.ads-root { + font-family: var(--font-stack); + font-variant-numeric: tabular-nums; + color: var(--fg); + background: var(--canvas); +} +.ads-eyebrow { + font-size: 10px; + letter-spacing: .2em; + text-transform: uppercase; + color: var(--fg3); + display: block; +} +.ads-title { + font-size: 23px; + letter-spacing: -.015em; + line-height: 1.15; + color: var(--fg); + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} +.ads-label { + font-size: 10px; + letter-spacing: .2em; + text-transform: uppercase; + color: var(--fg3); + display: block; +} +.ads-sport { + font-style: italic; + letter-spacing: .005em; +} + +/* src/components/Pill/Pill.css */ +.ads-pill { + display: inline-flex; + align-items: center; + font-size: 10px; + letter-spacing: .14em; + text-transform: uppercase; + color: var(--fg2); + border: 1px solid var(--line-strong); + border-radius: var(--r-pill); + padding: 6px 12px; +} +.ads-pill--work { + color: var(--red); + border-color: var(--red); +} + +/* src/components/IconButton/IconButton.css */ +.ads-icon-button { + display: inline-flex; + align-items: center; + justify-content: center; + width: 34px; + height: 34px; + border: none; + border-radius: 50%; + background: none; + color: var(--fg3); + cursor: pointer; + padding: 0; +} +.ads-icon-button svg { + width: 18px; + height: 18px; +} +.ads-icon-button:hover:not(:disabled) { + background: var(--tile-2); + color: var(--fg); +} +.ads-icon-button:disabled { + opacity: .4; + cursor: default; +} + +/* src/components/Fig/Fig.css */ +.ads-fig { + font-weight: 300; + letter-spacing: -.02em; + line-height: .95; + color: var(--fg); +} +.ads-fig__unit { + font-size: .32em; + font-weight: 400; + letter-spacing: normal; + color: var(--fg2); + margin-left: .32em; +} + +/* src/components/StatusRow/StatusRow.css */ +.ads-status { + display: flex; + align-items: center; + gap: var(--sp-3); + width: 100%; + background: none; + border: none; + padding: 0; + text-align: left; + font-family: inherit; + cursor: default; +} +button.ads-status { + cursor: pointer; +} +.ads-dot { + width: 11px; + height: 11px; + border-radius: 50%; + flex: 0 0 auto; +} +.ads-dot--ok { + background: var(--ok); +} +.ads-dot--warn { + background: var(--warn); +} +.ads-dot--bad { + background: var(--bad); +} +.ads-status__text { + display: flex; + flex-direction: column; +} +.ads-status__t { + font-size: 14px; + color: var(--fg); +} +.ads-status__s { + font-size: 11px; + color: var(--fg3); +} + +/* src/components/ActionButton/ActionButton.css */ +.ads-action { + display: block; + width: 100%; + font-family: inherit; + font-size: 11px; + letter-spacing: .14em; + text-transform: uppercase; + color: var(--fg); + background: none; + border: 1px solid var(--line-strong); + border-radius: var(--r-pill); + padding: 14px; + cursor: pointer; +} +.ads-action:hover:not(:disabled) { + border-color: var(--red); +} +.ads-action:disabled { + opacity: .4; + cursor: default; +} +.ads-action--destructive { + color: var(--bad); + border-color: var(--bad); +} +.ads-action--destructive:hover:not(:disabled) { + background: var(--bad); + color: var(--fg); + border-color: var(--bad); +} + +/* src/components/Switch/Switch.css */ +.ads-switch { + position: relative; + display: inline-block; + flex-shrink: 0; + width: 46px; + height: 27px; +} +.ads-switch input { + position: absolute; + inset: 0; + opacity: 0; + margin: 0; + cursor: pointer; + min-width: 0; +} +.ads-switch__track { + position: absolute; + inset: 0; + background: var(--tile-2); + border: 1px solid var(--line); + border-radius: var(--r-pill); + transition: background .18s; + pointer-events: none; +} +.ads-switch__track::before { + content: ""; + position: absolute; + left: 2px; + top: 1px; + width: 23px; + height: 23px; + background: #fff; + border-radius: 50%; + transition: transform .18s; +} +.ads-switch input:checked + .ads-switch__track { + background: var(--red); + border-color: var(--red); +} +.ads-switch input:checked + .ads-switch__track::before { + transform: translateX(19px); +} +.ads-switch input:disabled + .ads-switch__track { + opacity: .4; +} + +/* src/components/Seg/Seg.css */ +.ads-seg { + display: flex; + gap: var(--sp-2); +} +.ads-seg button { + flex: 1; + border: 1px solid var(--line-strong); + background: none; + color: var(--fg2); + font-family: inherit; + font-size: 11px; + letter-spacing: .12em; + text-transform: uppercase; + padding: 11px 8px; + border-radius: var(--r-pill); + cursor: pointer; +} +.ads-seg button.ads-seg__on { + border-color: var(--red); + color: var(--fg); +} + +/* src/components/RowList/RowList.css */ +.ads-rows { + margin: 0; +} +.ads-row { + display: flex; + justify-content: space-between; + align-items: baseline; + gap: var(--sp-3); + padding: 13px 0; + border-bottom: 1px solid var(--line); +} +.ads-row:last-child { + border-bottom: 0; +} +.ads-row dt { + font-size: 13px; + color: var(--fg2); +} +.ads-row dd { + margin: 0; + font-size: 14px; + color: var(--fg); + text-align: right; +} +.ads-row dd small { + display: block; + font-size: 11px; + color: var(--fg3); +} + +/* src/components/Accordion/LeafRow.css */ +.ads-leaf { + display: flex; + align-items: center; + justify-content: space-between; + gap: var(--sp-3); + width: 100%; + background: none; + border: none; + font-family: inherit; + text-align: left; + padding: 12px 0 12px 44px; + cursor: default; + border-bottom: 1px solid var(--line); +} +button.ads-leaf { + cursor: pointer; +} +.ads-leaf__k { + font-size: 13.5px; + color: var(--fg); + display: flex; + flex-direction: column; +} +.ads-leaf__k small { + font-size: 11px; + color: var(--fg3); +} +.ads-leaf__v { + font-size: 13px; + color: var(--fg2); + text-align: right; + display: flex; + flex-direction: column; +} +.ads-leaf__v small { + font-size: 11px; + color: var(--fg3); +} +.ads-chev { + width: 6px; + height: 10px; + color: var(--fg3); + flex: 0 0 auto; +} + +/* src/components/Tile/Tile.css */ +.ads-tile { + background: var(--tile); + border-radius: var(--r-tile); + padding: var(--sp-5); + margin-bottom: var(--sp-3); +} +.ads-tile--flat { + background: none; + padding: 0; +} +button.ads-tile--button { + display: flex; + align-items: center; + justify-content: space-between; + width: 100%; + border: none; + font-family: inherit; + text-align: left; + cursor: pointer; + position: relative; +} +button.ads-tile--button:hover { + background: var(--tile-2); +} +.ads-tile__content { + flex: 1; +} +.ads-tile__go { + width: 6px; + height: 10px; + color: var(--fg3); + flex: 0 0 auto; + margin-left: var(--sp-3); +} + +/* src/components/Feld/Feld.css */ +.ads-feld { + display: flex; + justify-content: space-between; + align-items: center; + gap: var(--sp-4); + padding: 12px 0; + border-bottom: 1px solid var(--line); +} +.ads-feld--last { + border-bottom: 0; +} +.ads-feld label { + font-size: 13px; + color: var(--fg2); +} +.ads-feld input, +.ads-feld select { + background: var(--tile-2); + border: 1px solid var(--line); + color: var(--fg); + font-family: inherit; + font-size: 13.5px; + padding: 8px 11px; + border-radius: var(--r-func); + text-align: right; + min-width: 132px; +} +.ads-mit-einheit { + display: inline-flex; + align-items: center; + gap: var(--sp-2); +} +.ads-mit-einheit input { + min-width: 92px; + text-align: right; +} +.ads-mit-einheit span:last-child { + font-size: 13px; + color: var(--fg2); +} + +/* src/components/ProgressRing/ProgressRing.css */ +.ads-ring { + position: relative; + display: inline-block; +} +.ads-ring svg { + transform: rotate(-90deg); +} +.ads-ring__track { + fill: none; + stroke: var(--line); + stroke-width: 10; +} +.ads-ring__arc { + fill: none; + stroke: var(--red); + stroke-width: 10; + stroke-linecap: round; + transition: stroke-dashoffset .3s; +} +.ads-ring__mid { + position: absolute; + inset: 0; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + text-align: center; +} + +/* src/components/ProgressBar/ProgressBar.css */ +.ads-balken { + height: 4px; + border-radius: var(--r-pill); + background: var(--line); + overflow: hidden; +} +.ads-balken i { + display: block; + height: 100%; + background: var(--fg); + border-radius: var(--r-pill); +} +.ads-bar { + display: flex; + height: 4px; + border-radius: var(--r-pill); + overflow: hidden; + gap: 2px; +} +.ads-bar i { + display: block; + border-radius: var(--r-pill); +} +.ads-legend { + display: flex; + flex-wrap: wrap; + gap: var(--sp-3); + margin-top: var(--sp-2); + font-size: 11px; + color: var(--fg2); +} +.ads-legend span { + display: inline-flex; + align-items: center; + gap: 6px; +} +.ads-legend i { + width: 8px; + height: 8px; + border-radius: 50%; + display: inline-block; +} + +/* src/components/StatGrid/StatGrid.css */ +.ads-quad { + display: grid; + gap: var(--sp-4); +} +.ads-quad__n { + display: block; +} +.ads-quad__l { + display: block; + margin-top: 4px; + font-size: 9px; + letter-spacing: .12em; + text-transform: uppercase; + color: var(--fg3); +} + +/* src/components/Accordion/Accordion.css */ +.ads-acc-h { + display: flex; + align-items: center; + gap: var(--sp-2); + width: 100%; + background: none; + border: none; + font-family: inherit; + text-align: left; + padding: 12px 0; + cursor: pointer; + border-bottom: 1px solid var(--line); +} +.ads-acc-h__k { + flex: 1; + font-size: 15px; + color: var(--fg); +} +.ads-acc-h__v { + font-size: 11.5px; + color: var(--fg2); + text-align: right; +} +.ads-mark { + width: 6px; + height: 10px; + border-right: 1.4px solid var(--fg3); + border-bottom: 1.4px solid var(--fg3); + transform: rotate(-45deg) scaleY(1); + transition: transform .15s, border-color .15s; +} +.ads-acc-h[aria-expanded=true] .ads-mark { + border-color: var(--red); + transform: rotate(45deg) scaleY(1); +} +.ads-acc-b { + display: none; +} +.ads-acc-b--on { + display: block; +} +.ads-accordion--lvl2 { + margin-left: 22px; +} +.ads-accordion--lvl2 .ads-acc-h__k { + font-size: 13px; +} + +/* src/components/SwipeRow/SwipeRow.css */ +.ads-swipe-wrap { + position: relative; + overflow: hidden; +} +.ads-swipe-delete { + position: absolute; + inset: 0 0 0 auto; + width: 84px; + background: var(--bad); + color: #fff; + border: none; + font-family: inherit; + font-size: 11px; + letter-spacing: .08em; + text-transform: uppercase; + cursor: pointer; +} +.ads-swipe-content { + position: relative; + background: var(--tile); + touch-action: pan-y; + transition: transform .18s; +} + +/* src/components/TabBar/TabBar.css */ +.ads-tabbar { + display: grid; + border-top: 1px solid var(--line); +} +.ads-tab { + display: flex; + flex-direction: column; + align-items: center; + gap: 4px; + padding: 10px 0 8px; + background: none; + border: none; + border-top: 2px solid transparent; + margin-top: -1px; + color: var(--fg3); + font-family: inherit; + cursor: pointer; +} +.ads-tab--on { + border-top-color: var(--red); + color: var(--fg); +} +.ads-tab__icon svg { + width: 21px; + height: 21px; +} +.ads-tabbar--ohne .ads-tab__icon svg { + width: 26px; + height: 26px; +} +.ads-tab__label { + font-size: 9px; + letter-spacing: .08em; + text-transform: uppercase; +} + +/* src/components/Popup/Popup.css */ +.ads-popup-catcher { + position: fixed; + inset: 0; + z-index: 1000; + background: none; + border: none; +} +.ads-popup { + position: fixed; + z-index: 1001; + background: var(--tile-2); + border-radius: 14px; + padding: var(--sp-4); +} +.ads-popup--menu { + display: flex; + flex-direction: column; + min-width: 180px; +} +.ads-popup--form { + min-width: 260px; +} +.ads-popup-item { + display: block; + width: 100%; + text-align: left; + background: none; + border: none; + color: var(--fg); + font-family: inherit; + font-size: 13.5px; + padding: 10px 4px; + cursor: pointer; +} +.ads-popup-item--destructive { + color: var(--bad); +} + +/* src/components/ImagePlaceholder/ImagePlaceholder.css */ +.ads-bildbox { + position: relative; + width: 100%; + aspect-ratio: 4 / 3; + border-radius: 12px; + overflow: hidden; +} +.ads-bildbox img { + display: block; + width: 100%; + height: 100%; + object-fit: cover; +} +.ads-bildbox--mini { + width: 78px; + height: 78px; + aspect-ratio: auto; + border-radius: 12px; +} +.ads-bildbox--round { + border-radius: 50%; +} +.ads-platzhalter { + width: 100%; + height: 100%; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: 6px; + border: 1px dashed var(--line-strong); + border-radius: inherit; + color: var(--fg3); + text-align: center; + padding: var(--sp-2); +} +.ads-platzhalter__icon svg { + width: 26px; + height: 26px; + color: var(--fg3); +} +.ads-platzhalter__label { + font-size: 10.5px; + letter-spacing: .02em; + color: var(--fg3); +} +.ads-platzhalter__hint { + font-family: ui-monospace, monospace; + font-size: 9px; + color: var(--fg3); +} + +/* src/styles.css */ +/*# sourceMappingURL=styles.css.map */ \ No newline at end of file diff --git a/design/_ds/audi-dashboard-ui-27d66fd4-ed86-43b2-b8bf-61e281a5a1a5/_ds_bundle.js b/design/_ds/audi-dashboard-ui-27d66fd4-ed86-43b2-b8bf-61e281a5a1a5/_ds_bundle.js new file mode 100644 index 0000000..3cc2679 --- /dev/null +++ b/design/_ds/audi-dashboard-ui-27d66fd4-ed86-43b2-b8bf-61e281a5a1a5/_ds_bundle.js @@ -0,0 +1,563 @@ +/* @ds-bundle: {"namespace":"AudiDashUI","components":[{"name":"Accordion","sourcePath":"components/general/Accordion/Accordion.jsx"},{"name":"ActionButton","sourcePath":"components/general/ActionButton/ActionButton.jsx"},{"name":"Feld","sourcePath":"components/general/Feld/Feld.jsx"},{"name":"Fig","sourcePath":"components/general/Fig/Fig.jsx"},{"name":"IconButton","sourcePath":"components/general/IconButton/IconButton.jsx"},{"name":"ImagePlaceholder","sourcePath":"components/general/ImagePlaceholder/ImagePlaceholder.jsx"},{"name":"LeafRow","sourcePath":"components/accordion/LeafRow/LeafRow.jsx"},{"name":"Pill","sourcePath":"components/general/Pill/Pill.jsx"},{"name":"Popup","sourcePath":"components/general/Popup/Popup.jsx"},{"name":"PopupMenuItem","sourcePath":"components/general/PopupMenuItem/PopupMenuItem.jsx"},{"name":"ProgressBar","sourcePath":"components/general/ProgressBar/ProgressBar.jsx"},{"name":"ProgressRing","sourcePath":"components/general/ProgressRing/ProgressRing.jsx"},{"name":"RowList","sourcePath":"components/general/RowList/RowList.jsx"},{"name":"Seg","sourcePath":"components/general/Seg/Seg.jsx"},{"name":"StatGrid","sourcePath":"components/general/StatGrid/StatGrid.jsx"},{"name":"StatusRow","sourcePath":"components/general/StatusRow/StatusRow.jsx"},{"name":"SwipeRow","sourcePath":"components/general/SwipeRow/SwipeRow.jsx"},{"name":"Switch","sourcePath":"components/general/Switch/Switch.jsx"},{"name":"TabBar","sourcePath":"components/general/TabBar/TabBar.jsx"},{"name":"Tile","sourcePath":"components/general/Tile/Tile.jsx"}],"sourceHashes":{"components/general/Accordion/Accordion.jsx":"e451421cbbee","components/general/Accordion/Accordion.d.ts":"0b821f95d8ec","components/general/Accordion/Accordion.prompt.md":"7b4714a7568d","components/general/ActionButton/ActionButton.jsx":"555676a71f72","components/general/ActionButton/ActionButton.d.ts":"faef681772e0","components/general/ActionButton/ActionButton.prompt.md":"1e8fad2d73f9","components/general/Feld/Feld.jsx":"fec8fe89e3b8","components/general/Feld/Feld.d.ts":"263528b0d195","components/general/Feld/Feld.prompt.md":"274cbafb13e5","components/general/Fig/Fig.jsx":"5870842c3cc9","components/general/Fig/Fig.d.ts":"a326dd89b7fd","components/general/Fig/Fig.prompt.md":"c60284795308","components/general/IconButton/IconButton.jsx":"fcd5ddfd2b26","components/general/IconButton/IconButton.d.ts":"e7a8c88afc00","components/general/IconButton/IconButton.prompt.md":"f311ce3928f4","components/general/ImagePlaceholder/ImagePlaceholder.jsx":"8ddcd8dab0a0","components/general/ImagePlaceholder/ImagePlaceholder.d.ts":"d6364f15e9c0","components/general/ImagePlaceholder/ImagePlaceholder.prompt.md":"43ca50be5f77","components/accordion/LeafRow/LeafRow.jsx":"ce900d42927c","components/accordion/LeafRow/LeafRow.d.ts":"85468f327f7a","components/accordion/LeafRow/LeafRow.prompt.md":"237acb37d8e6","components/general/Pill/Pill.jsx":"210d8cf6596a","components/general/Pill/Pill.d.ts":"530c874d26b6","components/general/Pill/Pill.prompt.md":"14374bc5a758","components/general/Popup/Popup.jsx":"bede56d5c4aa","components/general/Popup/Popup.d.ts":"469d967b7416","components/general/Popup/Popup.prompt.md":"6195801e8172","components/general/PopupMenuItem/PopupMenuItem.jsx":"0429937f4520","components/general/PopupMenuItem/PopupMenuItem.d.ts":"d98857eaf3c3","components/general/PopupMenuItem/PopupMenuItem.prompt.md":"8f18bd7e059b","components/general/ProgressBar/ProgressBar.jsx":"9ca1d1ea172a","components/general/ProgressBar/ProgressBar.d.ts":"baaa06ad6859","components/general/ProgressBar/ProgressBar.prompt.md":"039685a8659f","components/general/ProgressRing/ProgressRing.jsx":"78d41740d78b","components/general/ProgressRing/ProgressRing.d.ts":"15839d274511","components/general/ProgressRing/ProgressRing.prompt.md":"32b3e060530f","components/general/RowList/RowList.jsx":"62af0e4a633e","components/general/RowList/RowList.d.ts":"6f76bdb3711d","components/general/RowList/RowList.prompt.md":"2abce7b8d541","components/general/Seg/Seg.jsx":"0ad3d0f3e130","components/general/Seg/Seg.d.ts":"549442e8afad","components/general/Seg/Seg.prompt.md":"a1432f2825f6","components/general/StatGrid/StatGrid.jsx":"218bbd339935","components/general/StatGrid/StatGrid.d.ts":"a1b9d892b1a6","components/general/StatGrid/StatGrid.prompt.md":"0f1df1271fb0","components/general/StatusRow/StatusRow.jsx":"de77b6665985","components/general/StatusRow/StatusRow.d.ts":"3fe225d397b1","components/general/StatusRow/StatusRow.prompt.md":"cd33af1c2e77","components/general/SwipeRow/SwipeRow.jsx":"27451f62cae8","components/general/SwipeRow/SwipeRow.d.ts":"496e2058917a","components/general/SwipeRow/SwipeRow.prompt.md":"d191d8adba8c","components/general/Switch/Switch.jsx":"33ba18bc52cc","components/general/Switch/Switch.d.ts":"e5b2427866a1","components/general/Switch/Switch.prompt.md":"81f49ffeb8a6","components/general/TabBar/TabBar.jsx":"b74b7d431989","components/general/TabBar/TabBar.d.ts":"2e79e7e870c7","components/general/TabBar/TabBar.prompt.md":"dd8948507175","components/general/Tile/Tile.jsx":"b526964c5c96","components/general/Tile/Tile.d.ts":"b37ce97e2658","components/general/Tile/Tile.prompt.md":"e7cc32b1303d"},"inlinedExternals":[],"builtBy":"cc-design-sync"} */ +"use strict"; +var AudiDashUI = (() => { + var __create = Object.create; + var __defProp = Object.defineProperty; + var __getOwnPropDesc = Object.getOwnPropertyDescriptor; + var __getOwnPropNames = Object.getOwnPropertyNames; + var __getProtoOf = Object.getPrototypeOf; + var __hasOwnProp = Object.prototype.hasOwnProperty; + var __esm = (fn, res, err) => function __init() { + if (err) throw err[0]; + try { + return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res; + } catch (e) { + throw err = [e], e; + } + }; + var __commonJS = (cb, mod) => function __require() { + try { + return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; + } catch (e) { + throw mod = 0, e; + } + }; + var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); + }; + var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; + }; + var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( + // If the importer is in node compatibility mode or this is not an ESM + // file that has been converted to a CommonJS file using a Babel- + // compatible transform (i.e. "__esModule" has not been set), then set + // "default" to the CommonJS "module.exports" for node compatibility. + isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, + mod + )); + var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); + + // + var init_define_import_meta_env = __esm({ + ""() { + } + }); + + // shim:react-shim + var require_react_shim = __commonJS({ + "shim:react-shim"(exports, module) { + init_define_import_meta_env(); + var R = window.React; + function np(p, k) { + var o = {}; + for (var x in p) if (x !== "children") o[x] = p[x]; + if (k !== void 0) o.key = k; + return o; + } + function jsx20(t, p, k) { + var c = p && p.children; + return c === void 0 ? R.createElement(t, np(p, k)) : R.createElement(t, np(p, k), c); + } + function jsxs16(t, p, k) { + return R.createElement.apply(R, [t, np(p, k)].concat(p.children)); + } + module.exports = R; + module.exports.jsx = jsx20; + module.exports.jsxs = jsxs16; + module.exports.jsxDEV = function(t, p, k, s) { + return (s ? jsxs16 : jsx20)(t, p, k); + }; + module.exports.Fragment = R.Fragment; + } + }); + + // shim:react-dom-shim + var require_react_dom_shim = __commonJS({ + "shim:react-dom-shim"(exports, module) { + init_define_import_meta_env(); + var D = window.ReactDOM; + var n = function() { + }; + module.exports = Object.assign({ preload: n, preinit: n, preconnect: n, prefetchDNS: n, preloadModule: n, preinitModule: n }, D); + } + }); + + // dist/index.js + var index_exports = {}; + __export(index_exports, { + Accordion: () => Accordion, + ActionButton: () => ActionButton, + Feld: () => Feld, + Fig: () => Fig, + IconButton: () => IconButton, + ImagePlaceholder: () => ImagePlaceholder, + LeafRow: () => LeafRow, + Pill: () => Pill, + Popup: () => Popup, + PopupMenuItem: () => PopupMenuItem, + ProgressBar: () => ProgressBar, + ProgressRing: () => ProgressRing, + RowList: () => RowList, + Seg: () => Seg, + StatGrid: () => StatGrid, + StatusRow: () => StatusRow, + SwipeRow: () => SwipeRow, + Switch: () => Switch, + TabBar: () => TabBar, + Tile: () => Tile + }); + init_define_import_meta_env(); + var import_jsx_runtime = __toESM(require_react_shim(), 1); + var import_jsx_runtime2 = __toESM(require_react_shim(), 1); + var import_jsx_runtime3 = __toESM(require_react_shim(), 1); + var import_jsx_runtime4 = __toESM(require_react_shim(), 1); + var import_jsx_runtime5 = __toESM(require_react_shim(), 1); + var import_jsx_runtime6 = __toESM(require_react_shim(), 1); + var import_jsx_runtime7 = __toESM(require_react_shim(), 1); + var import_jsx_runtime8 = __toESM(require_react_shim(), 1); + var import_jsx_runtime9 = __toESM(require_react_shim(), 1); + var import_jsx_runtime10 = __toESM(require_react_shim(), 1); + var import_jsx_runtime11 = __toESM(require_react_shim(), 1); + var import_jsx_runtime12 = __toESM(require_react_shim(), 1); + var import_jsx_runtime13 = __toESM(require_react_shim(), 1); + var React = __toESM(require_react_shim(), 1); + var import_jsx_runtime14 = __toESM(require_react_shim(), 1); + var import_jsx_runtime15 = __toESM(require_react_shim(), 1); + var React2 = __toESM(require_react_shim(), 1); + var import_jsx_runtime16 = __toESM(require_react_shim(), 1); + var import_jsx_runtime17 = __toESM(require_react_shim(), 1); + var import_react_dom = __toESM(require_react_dom_shim(), 1); + var import_jsx_runtime18 = __toESM(require_react_shim(), 1); + var React3 = __toESM(require_react_shim(), 1); + var import_jsx_runtime19 = __toESM(require_react_shim(), 1); + function Pill({ children, variant = "default", className }) { + const classes = ["ads-pill"]; + if (variant === "work") classes.push("ads-pill--work"); + if (className) classes.push(className); + return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: classes.join(" "), children }); + } + function IconButton({ + onClick, + children, + disabled, + className, + ...rest + }) { + const classes = ["ads-icon-button"]; + if (className) classes.push(className); + return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)( + "button", + { + type: "button", + className: classes.join(" "), + onClick, + disabled, + ...rest, + children + } + ); + } + function Fig({ value, unit, size, className }) { + const classes = ["ads-fig"]; + if (className) classes.push(className); + const style = size !== void 0 ? { fontSize: typeof size === "number" ? `${size}px` : size } : void 0; + return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: classes.join(" "), style, children: [ + value, + unit !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "ads-fig__unit", children: unit }) + ] }); + } + function StatusRow({ status, title, subtitle, onClick, className }) { + const classes = ["ads-status"]; + if (className) classes.push(className); + const Tag = onClick ? "button" : "div"; + return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)( + Tag, + { + type: onClick ? "button" : void 0, + className: classes.join(" "), + onClick, + children: [ + /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: `ads-dot ads-dot--${status}`, "aria-hidden": true }), + /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { className: "ads-status__text", children: [ + /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "ads-status__t", children: title }), + subtitle !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "ads-status__s", children: subtitle }) + ] }) + ] + } + ); + } + function ActionButton({ + children, + onClick, + variant = "default", + disabled, + type = "button", + className + }) { + const classes = ["ads-action"]; + if (variant === "destructive") classes.push("ads-action--destructive"); + if (className) classes.push(className); + return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { type, className: classes.join(" "), onClick, disabled, children }); + } + function Switch({ + checked, + onChange, + disabled, + id, + className, + ...rest + }) { + const classes = ["ads-switch"]; + if (className) classes.push(className); + return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: classes.join(" "), children: [ + /* @__PURE__ */ (0, import_jsx_runtime6.jsx)( + "input", + { + type: "checkbox", + role: "switch", + id, + checked, + disabled, + onChange: (e) => onChange(e.target.checked), + ...rest + } + ), + /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "ads-switch__track", "aria-hidden": true }) + ] }); + } + function Seg({ + options, + value, + onChange, + className + }) { + const classes = ["ads-seg"]; + if (className) classes.push(className); + return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: classes.join(" "), children: options.map((opt) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)( + "button", + { + type: "button", + className: opt.value === value ? "ads-seg__on" : void 0, + onClick: () => onChange(opt.value), + children: opt.label + }, + opt.value + )) }); + } + function RowList({ items, className }) { + const classes = ["ads-rows"]; + if (className) classes.push(className); + return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("dl", { className: classes.join(" "), children: items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "ads-row", children: [ + /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("dt", { children: item.label }), + /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("dd", { children: [ + item.value, + item.subValue !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("small", { children: item.subValue }) + ] }) + ] }, item.key)) }); + } + function Tile({ variant = "default", chevron, onClick, className, children }) { + const classes = ["ads-tile"]; + if (variant === "flat") classes.push("ads-tile--flat"); + if (variant === "button") classes.push("ads-tile--button"); + if (className) classes.push(className); + if (variant === "button") { + return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("button", { type: "button", className: classes.join(" "), onClick, children: [ + /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "ads-tile__content", children }), + chevron && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("svg", { className: "ads-tile__go", viewBox: "0 0 6 10", "aria-hidden": true, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("path", { d: "M1 1l4 4-4 4", fill: "none", stroke: "currentColor", strokeWidth: "1.4" }) }) + ] }); + } + return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: classes.join(" "), children }); + } + function Feld({ label, value, children, unit, last, className }) { + const classes = ["ads-feld"]; + if (last) classes.push("ads-feld--last"); + if (className) classes.push(className); + const control = children ? unit ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { className: "ads-mit-einheit", children: [ + children, + /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { children: unit }) + ] }) : children : /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { children: value }); + return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: classes.join(" "), children: [ + /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("label", { children: label }), + control + ] }); + } + var RADIUS = 64; + var CIRCUMFERENCE = 2 * Math.PI * RADIUS; + function ProgressRing({ + percent, + value, + unit, + label, + size = 150, + className + }) { + const clamped = Math.max(0, Math.min(100, percent)); + const offset = CIRCUMFERENCE * (1 - clamped / 100); + const classes = ["ads-ring"]; + if (className) classes.push(className); + return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: classes.join(" "), style: { width: size, height: size }, children: [ + /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("svg", { viewBox: "0 0 150 150", width: size, height: size, children: [ + /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("circle", { cx: "75", cy: "75", r: RADIUS, className: "ads-ring__track" }), + /* @__PURE__ */ (0, import_jsx_runtime11.jsx)( + "circle", + { + cx: "75", + cy: "75", + r: RADIUS, + className: "ads-ring__arc", + strokeDasharray: CIRCUMFERENCE, + strokeDashoffset: offset + } + ) + ] }), + /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { className: "ads-ring__mid", children: [ + /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Fig, { value: value ?? Math.round(clamped), unit }), + label !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "ads-label", children: label }) + ] }) + ] }); + } + function ProgressBar({ percent, segments, showLegend, className }) { + const classes = ["ads-progress-bar"]; + if (className) classes.push(className); + if (segments && segments.length > 0) { + const total = segments.reduce((sum, s) => sum + s.value, 0) || 1; + const legend = showLegend ?? segments.length > 1; + return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: classes.join(" "), children: [ + /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "ads-bar", children: segments.map((seg, i) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)( + "i", + { + style: { flex: seg.value / total, background: seg.color ?? "var(--fg)" } + }, + i + )) }), + legend && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "ads-legend", children: segments.map((seg, i) => /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { children: [ + /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("i", { style: { background: seg.color ?? "var(--fg)" } }), + seg.label + ] }, i)) }) + ] }); + } + const clamped = Math.max(0, Math.min(100, percent ?? 0)); + return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: classes.join(" "), children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "ads-balken", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("i", { style: { width: `${clamped}%` } }) }) }); + } + function StatGrid({ items, columns = 4, className }) { + const classes = ["ads-quad"]; + if (className) classes.push(className); + return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: classes.join(" "), style: { gridTemplateColumns: `repeat(${columns}, 1fr)` }, children: items.map((item, i) => /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { children: [ + /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Fig, { className: "ads-quad__n", value: item.value, unit: item.unit, size: 17 }), + /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "ads-quad__l", children: item.caption }) + ] }, i)) }); + } + function Accordion({ + title, + summary, + open, + defaultOpen = false, + onOpenChange, + level = 1, + children, + className + }) { + const [internalOpen, setInternalOpen] = React.useState(defaultOpen); + const isControlled = open !== void 0; + const isOpen = isControlled ? open : internalOpen; + const toggle = () => { + const next = !isOpen; + if (!isControlled) setInternalOpen(next); + onOpenChange?.(next); + }; + const classes = ["ads-accordion"]; + if (level === 2) classes.push("ads-accordion--lvl2"); + if (className) classes.push(className); + return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: classes.join(" "), children: [ + /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("button", { type: "button", className: "ads-acc-h", onClick: toggle, "aria-expanded": isOpen, children: [ + /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "ads-acc-h__k", children: title }), + summary !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "ads-acc-h__v", children: summary }), + /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "ads-mark", "aria-hidden": true }) + ] }), + /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: isOpen ? "ads-acc-b ads-acc-b--on" : "ads-acc-b", children }) + ] }); + } + function LeafRow({ title, subTitle, value, subValue, onClick, className }) { + const classes = ["ads-leaf"]; + if (className) classes.push(className); + const Tag = onClick ? "button" : "div"; + return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(Tag, { type: onClick ? "button" : void 0, className: classes.join(" "), onClick, children: [ + /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("span", { className: "ads-leaf__k", children: [ + title, + subTitle !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("small", { children: subTitle }) + ] }), + /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("span", { className: "ads-leaf__v", children: [ + value, + subValue !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("small", { children: subValue }) + ] }), + /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("svg", { className: "ads-chev", viewBox: "0 0 6 10", "aria-hidden": true, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("path", { d: "M1 1l4 4-4 4", fill: "none", stroke: "currentColor", strokeWidth: "1.4" }) }) + ] }); + } + var SWIPE_THRESHOLD = -40; + var SWIPE_OPEN = -84; + var listeners = /* @__PURE__ */ new Set(); + function closeAllExcept(keep) { + for (const close of listeners) { + if (close !== keep) close(); + } + } + function SwipeRow({ + children, + onDelete, + deleteLabel = "Delete", + swiped, + onSwipedChange, + className + }) { + const [internalSwiped, setInternalSwiped] = React2.useState(false); + const isControlled = swiped !== void 0; + const isSwiped = isControlled ? swiped : internalSwiped; + const setSwiped = React2.useCallback( + (next) => { + if (!isControlled) setInternalSwiped(next); + onSwipedChange?.(next); + }, + [isControlled, onSwipedChange] + ); + const close = React2.useCallback(() => setSwiped(false), [setSwiped]); + React2.useEffect(() => { + listeners.add(close); + return () => { + listeners.delete(close); + }; + }, [close]); + const dragStartX = React2.useRef(null); + const onPointerDown = (e) => { + dragStartX.current = e.clientX; + }; + const onPointerMove = (e) => { + if (dragStartX.current === null) return; + const delta = e.clientX - dragStartX.current; + if (delta < SWIPE_THRESHOLD) { + closeAllExcept(close); + setSwiped(true); + dragStartX.current = null; + } else if (delta > -SWIPE_THRESHOLD) { + setSwiped(false); + } + }; + const onPointerUp = () => { + dragStartX.current = null; + }; + const classes = ["ads-swipe-wrap"]; + if (className) classes.push(className); + return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: classes.join(" "), children: [ + /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("button", { type: "button", className: "ads-swipe-delete", onClick: onDelete, children: deleteLabel }), + /* @__PURE__ */ (0, import_jsx_runtime16.jsx)( + "div", + { + className: isSwiped ? "ads-swipe-content ads-swiped" : "ads-swipe-content", + style: { transform: isSwiped ? `translateX(${SWIPE_OPEN}px)` : void 0 }, + onPointerDown, + onPointerMove, + onPointerUp, + onPointerCancel: onPointerUp, + children + } + ) + ] }); + } + function TabBar({ items, activeKey, onChange, iconOnly, className }) { + const classes = ["ads-tabbar"]; + if (iconOnly) classes.push("ads-tabbar--ohne"); + if (className) classes.push(className); + return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)( + "nav", + { + className: classes.join(" "), + style: { gridTemplateColumns: `repeat(${items.length}, 1fr)` }, + children: items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)( + "button", + { + type: "button", + className: item.key === activeKey ? "ads-tab ads-tab--on" : "ads-tab", + onClick: () => onChange(item.key), + children: [ + /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "ads-tab__icon", children: item.icon }), + !iconOnly && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "ads-tab__label", children: item.label }) + ] + }, + item.key + )) + } + ); + } + function Popup({ + open, + onClose, + variant = "menu", + anchor = "center", + children, + className, + portalTarget + }) { + if (!open) return null; + const classes = ["ads-popup", `ads-popup--${variant}`]; + if (className) classes.push(className); + const style = anchor === "center" ? { top: "50%", left: "50%", transform: "translate(-50%, -50%)" } : { ...anchor }; + const content = /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_jsx_runtime18.Fragment, { children: [ + /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "ads-popup-catcher", onClick: onClose }), + /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: classes.join(" "), style, children }) + ] }); + const target = portalTarget ?? (typeof document !== "undefined" ? document.body : null); + return target ? (0, import_react_dom.createPortal)(content, target) : content; + } + function PopupMenuItem({ onClick, destructive, children }) { + return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)( + "button", + { + type: "button", + className: destructive ? "ads-popup-item ads-popup-item--destructive" : "ads-popup-item", + onClick, + children + } + ); + } + var DEFAULT_ICON = /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("svg", { viewBox: "0 0 24 24", width: "26", height: "26", "aria-hidden": true, children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)( + "path", + { + fill: "currentColor", + fillRule: "evenodd", + d: "M4 5a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V5Zm2 0v14h12V5H6Zm3 3a1.5 1.5 0 1 1 0 3 1.5 1.5 0 0 1 0-3Zm-1 8 3-3 2 2 3-4 3 5H8Z", + clipRule: "evenodd" + } + ) }); + function ImagePlaceholder({ + src, + alt, + label, + hint, + icon, + size = "default", + className + }) { + const [failed, setFailed] = React3.useState(false); + const classes = ["ads-bildbox"]; + if (size === "mini") classes.push("ads-bildbox--mini"); + if (size === "round") classes.push("ads-bildbox--round"); + if (className) classes.push(className); + const showPlaceholder = !src || failed; + return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: classes.join(" "), children: [ + !showPlaceholder && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("img", { src, alt, onError: () => setFailed(true) }), + showPlaceholder && /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "ads-platzhalter", children: [ + /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "ads-platzhalter__icon", children: icon ?? DEFAULT_ICON }), + /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "ads-platzhalter__label", children: label }), + hint !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "ads-platzhalter__hint", children: hint }) + ] }) + ] }); + } + return __toCommonJS(index_exports); +})(); +window.AudiDashUI=AudiDashUI.__dsMainNs?Object.assign({},AudiDashUI,AudiDashUI.__dsMainNs,{__dsMainNs:undefined}):AudiDashUI; diff --git a/design/_ds/audi-dashboard-ui-27d66fd4-ed86-43b2-b8bf-61e281a5a1a5/_ds_manifest.json b/design/_ds/audi-dashboard-ui-27d66fd4-ed86-43b2-b8bf-61e281a5a1a5/_ds_manifest.json new file mode 100644 index 0000000..a1dedf9 --- /dev/null +++ b/design/_ds/audi-dashboard-ui-27d66fd4-ed86-43b2-b8bf-61e281a5a1a5/_ds_manifest.json @@ -0,0 +1 @@ +{"namespace":"AudiDashUI","components":[{"name":"Accordion","sourcePath":"components/general/Accordion/Accordion.jsx"},{"name":"ActionButton","sourcePath":"components/general/ActionButton/ActionButton.jsx"},{"name":"Feld","sourcePath":"components/general/Feld/Feld.jsx"},{"name":"Fig","sourcePath":"components/general/Fig/Fig.jsx"},{"name":"IconButton","sourcePath":"components/general/IconButton/IconButton.jsx"},{"name":"ImagePlaceholder","sourcePath":"components/general/ImagePlaceholder/ImagePlaceholder.jsx"},{"name":"LeafRow","sourcePath":"components/accordion/LeafRow/LeafRow.jsx"},{"name":"Pill","sourcePath":"components/general/Pill/Pill.jsx"},{"name":"Popup","sourcePath":"components/general/Popup/Popup.jsx"},{"name":"PopupMenuItem","sourcePath":"components/general/PopupMenuItem/PopupMenuItem.jsx"},{"name":"ProgressBar","sourcePath":"components/general/ProgressBar/ProgressBar.jsx"},{"name":"ProgressRing","sourcePath":"components/general/ProgressRing/ProgressRing.jsx"},{"name":"RowList","sourcePath":"components/general/RowList/RowList.jsx"},{"name":"Seg","sourcePath":"components/general/Seg/Seg.jsx"},{"name":"StatGrid","sourcePath":"components/general/StatGrid/StatGrid.jsx"},{"name":"StatusRow","sourcePath":"components/general/StatusRow/StatusRow.jsx"},{"name":"SwipeRow","sourcePath":"components/general/SwipeRow/SwipeRow.jsx"},{"name":"Switch","sourcePath":"components/general/Switch/Switch.jsx"},{"name":"TabBar","sourcePath":"components/general/TabBar/TabBar.jsx"},{"name":"Tile","sourcePath":"components/general/Tile/Tile.jsx"}],"startingPoints":[],"cards":[{"path":"components/accordion/LeafRow/LeafRow.html","group":"accordion"},{"path":"components/general/Accordion/Accordion.html","group":"general","viewport":"900x700"},{"path":"components/general/ActionButton/ActionButton.html","group":"general"},{"path":"components/general/Feld/Feld.html","group":"general","viewport":"900x700"},{"path":"components/general/Fig/Fig.html","group":"general"},{"path":"components/general/IconButton/IconButton.html","group":"general"},{"path":"components/general/ImagePlaceholder/ImagePlaceholder.html","group":"general"},{"path":"components/general/Pill/Pill.html","group":"general"},{"path":"components/general/Popup/Popup.html","group":"general","viewport":"340x300"},{"path":"components/general/PopupMenuItem/PopupMenuItem.html","group":"general"},{"path":"components/general/ProgressBar/ProgressBar.html","group":"general"},{"path":"components/general/ProgressRing/ProgressRing.html","group":"general"},{"path":"components/general/RowList/RowList.html","group":"general"},{"path":"components/general/Seg/Seg.html","group":"general"},{"path":"components/general/StatGrid/StatGrid.html","group":"general","viewport":"900x700"},{"path":"components/general/StatusRow/StatusRow.html","group":"general"},{"path":"components/general/SwipeRow/SwipeRow.html","group":"general"},{"path":"components/general/Switch/Switch.html","group":"general"},{"path":"components/general/TabBar/TabBar.html","group":"general","viewport":"900x700"},{"path":"components/general/Tile/Tile.html","group":"general"}],"templates":[],"hasThumbnailHtml":false,"globalCssPaths":["_ds_bundle.css","styles.css"],"tokens":[{"name":"--red","value":"#F50537","kind":"color","definedIn":"_ds_bundle.css"},{"name":"--r-tile","value":"20px","kind":"spacing","definedIn":"_ds_bundle.css"},{"name":"--r-pill","value":"999px","kind":"spacing","definedIn":"_ds_bundle.css"},{"name":"--r-func","value":"8px","kind":"spacing","definedIn":"_ds_bundle.css"},{"name":"--rahmen-hg","value":"#111","kind":"color","definedIn":"_ds_bundle.css"},{"name":"--sp-1","value":"4px","kind":"spacing","definedIn":"_ds_bundle.css"},{"name":"--sp-2","value":"8px","kind":"spacing","definedIn":"_ds_bundle.css"},{"name":"--sp-3","value":"12px","kind":"spacing","definedIn":"_ds_bundle.css"},{"name":"--sp-4","value":"16px","kind":"spacing","definedIn":"_ds_bundle.css"},{"name":"--sp-5","value":"22px","kind":"spacing","definedIn":"_ds_bundle.css"},{"name":"--canvas","value":"#161b23","kind":"color","definedIn":"_ds_bundle.css"},{"name":"--tile","value":"#1f2733","kind":"color","definedIn":"_ds_bundle.css"},{"name":"--tile-2","value":"#2a3341","kind":"color","definedIn":"_ds_bundle.css"},{"name":"--line","value":"rgba(255, 255, 255, .10)","kind":"color","definedIn":"_ds_bundle.css"},{"name":"--line-strong","value":"rgba(255, 255, 255, .20)","kind":"color","definedIn":"_ds_bundle.css"},{"name":"--fg","value":"#FFFFFF","kind":"color","definedIn":"_ds_bundle.css"},{"name":"--fg2","value":"#9aa1ad","kind":"color","definedIn":"_ds_bundle.css"},{"name":"--fg3","value":"#657081","kind":"color","definedIn":"_ds_bundle.css"},{"name":"--ok","value":"#15da15","kind":"color","definedIn":"_ds_bundle.css"},{"name":"--warn","value":"#ffaa00","kind":"color","definedIn":"_ds_bundle.css"},{"name":"--bad","value":"#fd2c4e","kind":"color","definedIn":"_ds_bundle.css"},{"name":"--shade","value":"rgba(255, 255, 255, .05)","kind":"color","definedIn":"_ds_bundle.css"},{"name":"--font-stack","value":"Helvetica,\n Arial,\n sans-serif","kind":"font","definedIn":"_ds_bundle.css"},{"name":"--canvas","value":"#FFFFFF","kind":"color","definedIn":"_ds_bundle.css","scope":"[data-theme=tag]"},{"name":"--tile","value":"#f2f2f2","kind":"color","definedIn":"_ds_bundle.css","scope":"[data-theme=tag]"},{"name":"--tile-2","value":"#e5e5e5","kind":"color","definedIn":"_ds_bundle.css","scope":"[data-theme=tag]"},{"name":"--line","value":"rgba(0, 0, 0, .10)","kind":"color","definedIn":"_ds_bundle.css","scope":"[data-theme=tag]"},{"name":"--line-strong","value":"rgba(0, 0, 0, .22)","kind":"color","definedIn":"_ds_bundle.css","scope":"[data-theme=tag]"},{"name":"--fg","value":"#000000","kind":"color","definedIn":"_ds_bundle.css","scope":"[data-theme=tag]"},{"name":"--fg2","value":"#4c4c4c","kind":"color","definedIn":"_ds_bundle.css","scope":"[data-theme=tag]"},{"name":"--fg3","value":"#666666","kind":"color","definedIn":"_ds_bundle.css","scope":"[data-theme=tag]"},{"name":"--ok","value":"#0DA20D","kind":"color","definedIn":"_ds_bundle.css","scope":"[data-theme=tag]"},{"name":"--warn","value":"#ffaa00","kind":"color","definedIn":"_ds_bundle.css","scope":"[data-theme=tag]"},{"name":"--bad","value":"#eb0d3f","kind":"color","definedIn":"_ds_bundle.css","scope":"[data-theme=tag]"},{"name":"--shade","value":"rgba(0, 0, 0, .04)","kind":"color","definedIn":"_ds_bundle.css","scope":"[data-theme=tag]"}],"themes":[{"selector":"[data-theme=tag]","label":"Tag"}],"fonts":[],"brandFonts":[],"source":"design-sync-cli"} \ No newline at end of file diff --git a/design/_ds/audi-dashboard-ui-27d66fd4-ed86-43b2-b8bf-61e281a5a1a5/styles.css b/design/_ds/audi-dashboard-ui-27d66fd4-ed86-43b2-b8bf-61e281a5a1a5/styles.css new file mode 100644 index 0000000..8f6b11b --- /dev/null +++ b/design/_ds/audi-dashboard-ui-27d66fd4-ed86-43b2-b8bf-61e281a5a1a5/styles.css @@ -0,0 +1 @@ +@import "./_ds_bundle.css"; diff --git a/design/assets/audi-rings-black.svg b/design/assets/audi-rings-black.svg new file mode 100644 index 0000000..1c3b009 --- /dev/null +++ b/design/assets/audi-rings-black.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/design/assets/audi-rings-white.svg b/design/assets/audi-rings-white.svg new file mode 100644 index 0000000..83a5ca6 --- /dev/null +++ b/design/assets/audi-rings-white.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/design/assets/audi-sport.svg b/design/assets/audi-sport.svg new file mode 100644 index 0000000..07e5f71 --- /dev/null +++ b/design/assets/audi-sport.svg @@ -0,0 +1 @@ +AS_RGB_pos_red \ No newline at end of file diff --git a/design/assets/badge-rs6-negative.svg b/design/assets/badge-rs6-negative.svg new file mode 100644 index 0000000..506b1a5 --- /dev/null +++ b/design/assets/badge-rs6-negative.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/design/assets/badge-rs6-positive.svg b/design/assets/badge-rs6-positive.svg new file mode 100644 index 0000000..11142fd --- /dev/null +++ b/design/assets/badge-rs6-positive.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/design/assets/fonts/AudiType-Normal.ttf b/design/assets/fonts/AudiType-Normal.ttf new file mode 100644 index 0000000..d026f30 Binary files /dev/null and b/design/assets/fonts/AudiType-Normal.ttf differ diff --git a/design/assets/fonts/AudiType-WideLight.ttf b/design/assets/fonts/AudiType-WideLight.ttf new file mode 100644 index 0000000..5bf7368 Binary files /dev/null and b/design/assets/fonts/AudiType-WideLight.ttf differ diff --git a/design/assets/fonts/AudiType-WideNormal.ttf b/design/assets/fonts/AudiType-WideNormal.ttf new file mode 100644 index 0000000..85a8a32 Binary files /dev/null and b/design/assets/fonts/AudiType-WideNormal.ttf differ diff --git a/design/assets/fonts/AudiTypeVF.ttf b/design/assets/fonts/AudiTypeVF.ttf new file mode 100644 index 0000000..266a488 Binary files /dev/null and b/design/assets/fonts/AudiTypeVF.ttf differ diff --git a/design/assets/icons.js b/design/assets/icons.js new file mode 100644 index 0000000..b4e5eca --- /dev/null +++ b/design/assets/icons.js @@ -0,0 +1 @@ +window.DM360_ICONS = {"add":"","arrow-left":"","camera":"","car-insurance":"","car-settings":"","car":"","caution":"","code":"","commute":"","compass":"","connect-key":"","consumption":"","cubic-capacity":"","dashboard":"","document-taxation":"","download":"","fuel-range":"","gas-station":"","lock":"","mileage":"","over-the-air-car":"","parking":"","photo":"","plan-route":"","poi-home":"","service-package":"","settings":"","time":"","tire":"","top-speed":""}; diff --git a/design/assets/icons.json b/design/assets/icons.json new file mode 100644 index 0000000..0d8a1ed --- /dev/null +++ b/design/assets/icons.json @@ -0,0 +1 @@ +{"add":"","arrow-left":"","camera":"","car-insurance":"","car-settings":"","car":"","caution":"","code":"","commute":"","compass":"","connect-key":"","consumption":"","cubic-capacity":"","dashboard":"","document-taxation":"","download":"","fuel-range":"","gas-station":"","lock":"","mileage":"","over-the-air-car":"","parking":"","photo":"","plan-route":"","poi-home":"","service-package":"","settings":"","time":"","tire":"","top-speed":""} \ No newline at end of file diff --git a/design/assets/icons/add.svg b/design/assets/icons/add.svg new file mode 100644 index 0000000..b334344 --- /dev/null +++ b/design/assets/icons/add.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/design/assets/icons/arrow-left.svg b/design/assets/icons/arrow-left.svg new file mode 100644 index 0000000..8b13354 --- /dev/null +++ b/design/assets/icons/arrow-left.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/design/assets/icons/camera.svg b/design/assets/icons/camera.svg new file mode 100644 index 0000000..c1133ef --- /dev/null +++ b/design/assets/icons/camera.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/design/assets/icons/car-insurance.svg b/design/assets/icons/car-insurance.svg new file mode 100644 index 0000000..b17dbb9 --- /dev/null +++ b/design/assets/icons/car-insurance.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/design/assets/icons/car-settings.svg b/design/assets/icons/car-settings.svg new file mode 100644 index 0000000..9def5d6 --- /dev/null +++ b/design/assets/icons/car-settings.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/design/assets/icons/car.svg b/design/assets/icons/car.svg new file mode 100644 index 0000000..33571db --- /dev/null +++ b/design/assets/icons/car.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/design/assets/icons/caution.svg b/design/assets/icons/caution.svg new file mode 100644 index 0000000..f548a7b --- /dev/null +++ b/design/assets/icons/caution.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/design/assets/icons/code.svg b/design/assets/icons/code.svg new file mode 100644 index 0000000..d8e5085 --- /dev/null +++ b/design/assets/icons/code.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/design/assets/icons/commute.svg b/design/assets/icons/commute.svg new file mode 100644 index 0000000..6d53023 --- /dev/null +++ b/design/assets/icons/commute.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/design/assets/icons/compass.svg b/design/assets/icons/compass.svg new file mode 100644 index 0000000..7711d68 --- /dev/null +++ b/design/assets/icons/compass.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/design/assets/icons/connect-key.svg b/design/assets/icons/connect-key.svg new file mode 100644 index 0000000..41e72a8 --- /dev/null +++ b/design/assets/icons/connect-key.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/design/assets/icons/consumption.svg b/design/assets/icons/consumption.svg new file mode 100644 index 0000000..fc29823 --- /dev/null +++ b/design/assets/icons/consumption.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/design/assets/icons/cubic-capacity.svg b/design/assets/icons/cubic-capacity.svg new file mode 100644 index 0000000..b7be893 --- /dev/null +++ b/design/assets/icons/cubic-capacity.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/design/assets/icons/dashboard.svg b/design/assets/icons/dashboard.svg new file mode 100644 index 0000000..e6f7a78 --- /dev/null +++ b/design/assets/icons/dashboard.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/design/assets/icons/document-taxation.svg b/design/assets/icons/document-taxation.svg new file mode 100644 index 0000000..57d35f4 --- /dev/null +++ b/design/assets/icons/document-taxation.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/design/assets/icons/download.svg b/design/assets/icons/download.svg new file mode 100644 index 0000000..1f3b7f3 --- /dev/null +++ b/design/assets/icons/download.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/design/assets/icons/fuel-range.svg b/design/assets/icons/fuel-range.svg new file mode 100644 index 0000000..ce5a0d7 --- /dev/null +++ b/design/assets/icons/fuel-range.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/design/assets/icons/gas-station.svg b/design/assets/icons/gas-station.svg new file mode 100644 index 0000000..ecb7117 --- /dev/null +++ b/design/assets/icons/gas-station.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/design/assets/icons/lock.svg b/design/assets/icons/lock.svg new file mode 100644 index 0000000..ffde04c --- /dev/null +++ b/design/assets/icons/lock.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/design/assets/icons/mileage.svg b/design/assets/icons/mileage.svg new file mode 100644 index 0000000..ebc5efc --- /dev/null +++ b/design/assets/icons/mileage.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/design/assets/icons/over-the-air-car.svg b/design/assets/icons/over-the-air-car.svg new file mode 100644 index 0000000..2fbdd47 --- /dev/null +++ b/design/assets/icons/over-the-air-car.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/design/assets/icons/parking.svg b/design/assets/icons/parking.svg new file mode 100644 index 0000000..e4b4f3f --- /dev/null +++ b/design/assets/icons/parking.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/design/assets/icons/photo.svg b/design/assets/icons/photo.svg new file mode 100644 index 0000000..dd24633 --- /dev/null +++ b/design/assets/icons/photo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/design/assets/icons/plan-route.svg b/design/assets/icons/plan-route.svg new file mode 100644 index 0000000..da3ac1c --- /dev/null +++ b/design/assets/icons/plan-route.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/design/assets/icons/poi-home.svg b/design/assets/icons/poi-home.svg new file mode 100644 index 0000000..b787f73 --- /dev/null +++ b/design/assets/icons/poi-home.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/design/assets/icons/service-package.svg b/design/assets/icons/service-package.svg new file mode 100644 index 0000000..71fa040 --- /dev/null +++ b/design/assets/icons/service-package.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/design/assets/icons/settings.svg b/design/assets/icons/settings.svg new file mode 100644 index 0000000..28d14e8 --- /dev/null +++ b/design/assets/icons/settings.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/design/assets/icons/time.svg b/design/assets/icons/time.svg new file mode 100644 index 0000000..5bfcda8 --- /dev/null +++ b/design/assets/icons/time.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/design/assets/icons/tire.svg b/design/assets/icons/tire.svg new file mode 100644 index 0000000..3f2adac --- /dev/null +++ b/design/assets/icons/tire.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/design/assets/icons/top-speed.svg b/design/assets/icons/top-speed.svg new file mode 100644 index 0000000..82f546f --- /dev/null +++ b/design/assets/icons/top-speed.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/design/assets/shell.svg b/design/assets/shell.svg new file mode 100644 index 0000000..846e6c4 --- /dev/null +++ b/design/assets/shell.svg @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/design/support.js b/design/support.js new file mode 100644 index 0000000..cb009b6 --- /dev/null +++ b/design/support.js @@ -0,0 +1,1911 @@ +// GENERATED from dc-runtime/src/*.ts — do not edit. Rebuild with `cd dc-runtime && bun run build`. +"use strict"; +(() => { + var __defProp = Object.defineProperty; + var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; + var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value); + + // src/react.ts + function getReact() { + const R = window.React; + if (!R) throw new Error("dc-runtime: window.React is not available yet"); + return R; + } + function getReactDOM() { + const RD = window.ReactDOM; + if (!RD) throw new Error("dc-runtime: window.ReactDOM is not available yet"); + return RD; + } + var h = ((...args) => getReact().createElement( + ...args + )); + + // src/parse.ts + function parseDcDocument(doc) { + const dc = doc.querySelector("x-dc"); + if (!dc) return null; + const scriptEl = doc.querySelector("script[data-dc-script]"); + const { props, preview } = parseDataProps( + scriptEl?.getAttribute("data-props") ?? null + ); + return { + template: dc.innerHTML, + js: scriptEl ? scriptEl.textContent || "" : "", + props, + preview + }; + } + function parseDcText(src) { + const openMatch = /]*)?>/.exec(src); + if (!openMatch) return null; + const close = src.lastIndexOf(""); + if (close === -1 || close < openMatch.index) return null; + const template = src.slice(openMatch.index + openMatch[0].length, close); + const doc = new DOMParser().parseFromString(src, "text/html"); + const scriptEl = doc.querySelector("script[data-dc-script]"); + const { props, preview } = parseDataProps( + scriptEl?.getAttribute("data-props") ?? null + ); + return { + template, + js: scriptEl ? scriptEl.textContent || "" : "", + props, + preview + }; + } + function parseDataProps(raw) { + if (!raw) return { props: null, preview: null }; + let parsed; + try { + parsed = JSON.parse(raw); + } catch { + return { props: null, preview: null }; + } + if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) { + return { props: null, preview: null }; + } + const obj = parsed; + const preview = obj.$preview && typeof obj.$preview === "object" ? obj.$preview : null; + const rest = {}; + for (const k of Object.keys(obj)) { + if (k[0] !== "$") rest[k] = obj[k]; + } + return { props: Object.keys(rest).length ? rest : null, preview }; + } + function dcNameFromPath(pathname) { + let p = pathname || ""; + try { + p = decodeURIComponent(p); + } catch { + } + const base = p.split("/").pop() || "Root"; + return base.replace(/\.dc\.html$/, "").replace(/\.html?$/, "") || "Root"; + } + + // src/boot.ts + var BASE_CSS = ` + .sc-placeholder{background:color-mix(in srgb,currentColor 8%,transparent); + border:1px solid color-mix(in srgb,currentColor 50%,transparent); + border-radius:2px;box-sizing:border-box;overflow:hidden} + @keyframes sc-shine{0%{background-position:100% 50%}100%{background-position:0% 50%}} + html.sc-dc-streaming .sc-placeholder, + html.sc-dc-streaming .sc-interp.sc-missing{position:relative; + background:color-mix(in srgb,currentColor 5%,transparent); + border-color:transparent} + html.sc-dc-streaming .sc-placeholder::before, + html.sc-dc-streaming .sc-interp.sc-missing::before{content:''; + position:absolute;inset:0;pointer-events:none; + background:linear-gradient(90deg,rgba(217,119,87,0) 25%,rgba(247,225,211,.95) 37%,rgba(217,119,87,0) 63%); + background-size:400% 100%;animation:sc-shine 1.4s ease infinite} + html.sc-dc-streaming .sc-placeholder:nth-child(n+9 of .sc-placeholder)::before, + html.sc-dc-streaming .sc-interp.sc-missing:nth-child(n+9 of .sc-interp.sc-missing)::before{animation:none; + background:color-mix(in srgb,currentColor 8%,transparent)} + .sc-placeholder-error{padding:4px 8px;font:11px/1.4 ui-monospace,monospace; + color:color-mix(in srgb,currentColor 70%,transparent);word-break:break-word} + .sc-interp.sc-missing{display:inline-block;width:2em;height:1em;overflow:hidden; + vertical-align:text-bottom;background:rgba(255,255,255,.3);border:1px solid rgba(0,0,0,.5); + border-radius:2px;box-sizing:border-box;color:transparent; + user-select:none} + .sc-interp.sc-unresolved{font-family:ui-monospace,monospace;font-size:.85em; + color:color-mix(in srgb,currentColor 50%,transparent); + background:color-mix(in srgb,currentColor 10%,transparent);border-radius:3px; + padding:0 3px} + .sc-host.sc-has-error{position:relative} + .sc-logic-error{position:absolute;top:8px;left:8px;z-index:2147483647;max-width:60ch; + padding:6px 10px;background:#b00020;color:#fff;font:12px/1.4 ui-monospace,monospace; + border-radius:4px;white-space:pre-wrap;pointer-events:none} + /* Mirrors PRINT_BASELINE_CSS in apps/web deck-stage-export.ts \u2014 keep both + in sync until dc-runtime regains a build step. */ + @media print { + @page { margin: 0.5cm; } + figure, table { break-inside: avoid; } + #dc-root, #dc-root > .sc-host { height: auto; } + *, *::before, *::after { + print-color-adjust: exact; -webkit-print-color-adjust: exact; + backdrop-filter: none !important; -webkit-backdrop-filter: none !important; + animation-delay: -99s !important; animation-duration: .001s !important; + animation-iteration-count: 1 !important; animation-fill-mode: both !important; + animation-play-state: running !important; transition-duration: 0s !important; + } + } + `; + var FULL_PAGE_CSS = "html,body{height:100%;margin:0}#dc-root,#dc-root>.sc-host{height:100%}"; + function rootNameForDocument(doc, loc) { + let bootPath = loc.pathname || ""; + if (!/\.dc\.html?$/i.test(safeDecode(bootPath))) { + try { + bootPath = new URL(doc.baseURI || "/").pathname; + } catch { + } + } + return dcNameFromPath(bootPath); + } + function safeDecode(s) { + try { + return decodeURIComponent(s); + } catch { + return s; + } + } + function boot(runtime, doc = document) { + const parsed = parseDcDocument(doc); + if (!parsed) return null; + const React = getReact(); + const rootName = rootNameForDocument(doc, location); + runtime.markFetched(rootName); + runtime.setRootName(rootName); + runtime.adoptParsed(rootName, parsed); + if (!window.__resources) { + fetch(location.href).then((res) => res.ok ? res.text() : "").then((t) => { + const raw = t ? parseDcText(t) : null; + if (raw?.template) runtime.updateHtml(rootName, raw.template); + }).catch(() => { + }); + } + const dc = doc.querySelector("x-dc"); + const hostEl = doc.createElement("div"); + hostEl.id = "dc-root"; + dc.replaceWith(hostEl); + if (!parsed.preview) { + const s = doc.createElement("style"); + s.textContent = FULL_PAGE_CSS; + doc.head.appendChild(s); + } + const Root = runtime.getDC(rootName); + const entry = runtime.registry.get(rootName); + function StandaloneRoot() { + const [, setTick] = React.useState(0); + React.useEffect(() => { + const sub = () => setTick((n) => n + 1); + entry.subs.add(sub); + return () => { + entry.subs.delete(sub); + }; + }, []); + const defaults = React.useMemo(() => { + const d = {}; + for (const k in entry.propsMeta || {}) { + const v = entry.propsMeta?.[k]?.default; + if (v !== void 0) d[k] = v; + } + return d; + }, [entry.propsMeta]); + return h(Root, { ...defaults, ...entry.propOverrides || {} }); + } + const ReactDOM = getReactDOM(); + if (ReactDOM.createRoot) + ReactDOM.createRoot(hostEl).render(h(StandaloneRoot)); + else ReactDOM.render(h(StandaloneRoot), hostEl); + return rootName; + } + + // src/expr.ts + var IDENT_RE = /^[A-Za-z_$][A-Za-z0-9_$]*/; + var NUMBER_RE = /^-?\d+(\.\d+)?$/; + function resolve(vals, src) { + const expr = String(src).trim(); + if (!expr) return void 0; + if (expr[0] === "(" && expr[expr.length - 1] === ")" && parensWrapWhole(expr)) { + return resolve(vals, expr.slice(1, -1)); + } + const eq = findTopLevelEquality(expr); + if (eq) { + const lv = resolve(vals, expr.slice(0, eq.index)); + const rv = resolve(vals, expr.slice(eq.index + eq.op.length)); + switch (eq.op) { + case "===": + return lv === rv; + case "!==": + return lv !== rv; + case "==": + return lv == rv; + default: + return lv != rv; + } + } + if (expr[0] === "!") return !resolve(vals, expr.slice(1)); + if (expr === "true") return true; + if (expr === "false") return false; + if (expr === "null") return null; + if (expr === "undefined") return void 0; + if (NUMBER_RE.test(expr)) return Number(expr); + if (expr.length >= 2 && (expr[0] === '"' || expr[0] === "'") && expr[expr.length - 1] === expr[0]) { + return expr.slice(1, -1); + } + return resolvePath(vals, expr); + } + function parensWrapWhole(expr) { + let depth = 0; + for (let i = 0; i < expr.length - 1; i++) { + if (expr[i] === "(") depth++; + else if (expr[i] === ")") { + depth--; + if (depth === 0) return false; + } + } + return true; + } + function findTopLevelEquality(expr) { + let depth = 0; + for (let i = 0; i < expr.length; i++) { + const c = expr[i]; + if (c === "[" || c === "(") depth++; + else if (c === "]" || c === ")") depth--; + else if (depth === 0 && (c === "=" || c === "!") && expr[i + 1] === "=") { + if (i > 0 && (expr[i - 1] === "=" || expr[i - 1] === "!")) continue; + if (!expr.slice(0, i).trim()) continue; + const op = expr[i + 2] === "=" ? c + "==" : c + "="; + return { index: i, op }; + } + } + return null; + } + function resolvePath(vals, expr) { + const head = expr.match(IDENT_RE); + if (!head) return void 0; + let cur = vals == null ? void 0 : vals[head[0]]; + let i = head[0].length; + while (i < expr.length) { + if (expr[i] === ".") { + const m = expr.slice(i + 1).match(IDENT_RE) || expr.slice(i + 1).match(/^\d+/); + if (!m) return void 0; + cur = cur == null ? void 0 : cur[m[0]]; + i += 1 + m[0].length; + } else if (expr[i] === "[") { + let depth = 1; + let j = i + 1; + while (j < expr.length && depth > 0) { + if (expr[j] === "[") depth++; + else if (expr[j] === "]") { + depth--; + if (depth === 0) break; + } + j++; + } + if (depth !== 0) return void 0; + const key = resolve(vals, expr.slice(i + 1, j)); + cur = cur == null ? void 0 : cur[key]; + i = j + 1; + } else { + return void 0; + } + } + return cur; + } + + // src/encode.ts + var CAMEL_ATTR = "sc-camel-"; + var INLINE_TEXT_TAGS = new Set( + "a abbr b bdi bdo br cite code del dfn em i ins kbd mark q s samp small span strike strong sub sup u var wbr".split( + " " + ) + ); + var RAW_WRAP = { + select: "sc-raw-select", + table: "sc-raw-table", + tbody: "sc-raw-tbody", + thead: "sc-raw-thead", + tfoot: "sc-raw-tfoot", + tr: "sc-raw-tr", + td: "sc-raw-td", + th: "sc-raw-th", + caption: "sc-raw-caption" + }; + var RAW_UNWRAP = Object.fromEntries( + Object.entries(RAW_WRAP).map(([k, v]) => [v, k]) + ); + var EVENT_MAP = { + onclick: "onClick", + onchange: "onChange", + oninput: "onInput", + onsubmit: "onSubmit", + onkeydown: "onKeyDown", + onkeyup: "onKeyUp", + onkeypress: "onKeyPress", + onmousedown: "onMouseDown", + onmouseup: "onMouseUp", + onmouseenter: "onMouseEnter", + onmouseleave: "onMouseLeave", + onfocus: "onFocus", + onblur: "onBlur", + ondoubleclick: "onDoubleClick", + oncontextmenu: "onContextMenu", + onmousemove: "onMouseMove", + onmouseover: "onMouseOver", + onmouseout: "onMouseOut", + onpointerdown: "onPointerDown", + onpointerup: "onPointerUp", + onpointermove: "onPointerMove", + onpointerenter: "onPointerEnter", + onpointerleave: "onPointerLeave", + onpointercancel: "onPointerCancel", + onpointerover: "onPointerOver", + onpointerout: "onPointerOut", + ongotpointercapture: "onGotPointerCapture", + onlostpointercapture: "onLostPointerCapture", + ontouchstart: "onTouchStart", + ontouchend: "onTouchEnd", + ontouchmove: "onTouchMove", + ontouchcancel: "onTouchCancel", + ondragstart: "onDragStart", + ondragend: "onDragEnd", + ondragenter: "onDragEnter", + ondragleave: "onDragLeave", + ondragover: "onDragOver", + onanimationstart: "onAnimationStart", + onanimationend: "onAnimationEnd", + onanimationiteration: "onAnimationIteration", + ontransitionend: "onTransitionEnd" + }; + var ATTRS = `(?:[^>"']|"[^"]*"|'[^']*')*`; + var IMPORT_SELF_CLOSE_RE = new RegExp( + "<(x-import|dc-import)(" + ATTRS + ")/>", + "gi" + ); + var CAMEL_ATTR_RE = /(\s)([a-z]+[A-Z][A-Za-z0-9]*)(\s*=)/g; + function encodeCamelAttrs(html) { + return html.replace( + CAMEL_ATTR_RE, + (_, sp, name, eq) => sp + CAMEL_ATTR + name.replace(/[A-Z]/g, (c) => "-" + c.toLowerCase()) + eq + ); + } + function encodeCase(html) { + html = html.replace( + IMPORT_SELF_CLOSE_RE, + (_, t, a) => "<" + t + a + ">" + ); + html = html.replace(/)/gi, "/gi, ""); + html = encodeCamelAttrs(html); + for (const [real, alias] of Object.entries(RAW_WRAP)) { + html = html.replace( + new RegExp("(])", "gi"), + "$1" + alias + ); + } + return html; + } + function kebabToCamel(s) { + return s.replace(/-([a-z])/g, (_, c) => c.toUpperCase()); + } + function cssToObj(css) { + const o = {}; + for (const decl of css.split(";")) { + const i = decl.indexOf(":"); + if (i < 0) continue; + const prop = decl.slice(0, i).trim(); + o[prop.startsWith("--") ? prop : kebabToCamel(prop)] = decl.slice(i + 1).trim(); + } + return o; + } + function compileAttr(raw) { + const whole = raw.match(/^\s*\{\{([\s\S]+?)\}\}\s*$/); + if (whole) { + const path = whole[1]; + return (vals) => resolve(vals, path); + } + if (raw.includes("{{")) { + const parts = raw.split(/\{\{([\s\S]+?)\}\}/g); + return (vals) => parts.map((s, i) => i & 1 ? resolve(vals, s) ?? "" : s).join(""); + } + return () => raw; + } + + // src/compile.ts + function collectProps(node, kind, host) { + const propGetters = []; + const pseudoClasses = []; + let hintSize = null; + for (const { name, value } of [...node.attributes]) { + if (name === "sc-name" || name === "data-dc-tpl") continue; + let key = name; + if (key.startsWith(CAMEL_ATTR)) + key = kebabToCamel(key.slice(CAMEL_ATTR.length)); + if (key === "hint-size") { + hintSize = value; + continue; + } + if (key.startsWith("style-")) { + pseudoClasses.push(host.pseudoClass(key.slice(6), value)); + continue; + } + if (kind !== "dom") { + if (key.includes("-") && !(kind === "x-import" && (key.startsWith("aria-") || key.startsWith("data-")))) + key = kebabToCamel(key); + } else { + if (key === "class") key = "className"; + else if (key === "for") key = "htmlFor"; + else if (key.startsWith("on")) + key = EVENT_MAP[key] || "on" + key[2].toUpperCase() + key.slice(3); + } + propGetters.push([key, compileAttr(value)]); + } + return { propGetters, pseudoClasses, hintSize }; + } + var HOST_STYLE_PROPS = /* @__PURE__ */ new Set([ + "position", + "left", + "right", + "top", + "bottom", + "inset", + "width", + "height", + "z-index", + "transform" + ]); + function hostPositionStyle(style) { + const all = typeof style === "string" ? cssToObj(style) : style != null && typeof style === "object" ? style : null; + if (!all) return void 0; + const out = {}; + for (const [k, v] of Object.entries(all)) { + const kebab = k.replace(/[A-Z]/g, (c) => "-" + c.toLowerCase()); + if (HOST_STYLE_PROPS.has(kebab)) out[k] = v; + } + return Object.keys(out).length ? out : void 0; + } + function compileTemplate(html, host) { + const tpl = document.createElement("template"); + //! nosemgrep: direct-inner-html-assignment + tpl.innerHTML = encodeCase(html); + let tplN = 0; + (function stamp(node) { + if (node.nodeType === Node.ELEMENT_NODE) { + node.setAttribute("data-dc-tpl", String(tplN++)); + } + for (const c of node.childNodes) stamp(c); + })(tpl.content); + const builders = walkChildren(tpl.content, host); + const render = ((vals, ctx) => builders.map((b, i) => b(vals || {}, ctx, i))); + render.__annotated = tpl.innerHTML; + return render; + } + function walkChildren(node, host) { + return [...node.childNodes].map((c) => walk(c, host)).filter((b) => b != null); + } + var SLIDE_ID_VALUE_RE = /^[0-9a-f]{8}$/; + var DECK_CONTROL_FLOW_RE = /^(sc-if|sc-for|sc-else|dc-import|x-import)$/; + var DECK_AUX_RE = /^(template|script|style|sc-helmet|helmet)$/; + function isDeckMountTag(el) { + if (el.localName === "deck-stage") return true; + return el.localName === "x-import" && (el.getAttribute("component-from-global-scope") || "") === "deck-stage"; + } + function walkDeckChildren(el, host) { + const pairs = [...el.childNodes].map((c) => ({ c, b: walk(c, host) })).filter((p) => p.b !== null); + const kids = pairs.map((p) => p.b); + const seen = /* @__PURE__ */ new Set(); + const wsSeen = /* @__PURE__ */ new Map(); + const keys = []; + const nextSlideId = new Array(pairs.length); + { + let upcoming = null; + for (let j = pairs.length - 1; j >= 0; j--) { + const n = pairs[j].c; + if (n.nodeType === Node.ELEMENT_NODE) { + const t = n.localName; + upcoming = !DECK_AUX_RE.test(t) && !DECK_CONTROL_FLOW_RE.test(t) ? n.getAttribute("data-om-slide-id") : null; + } + nextSlideId[j] = upcoming; + } + } + for (let j = 0; j < pairs.length; j++) { + const { c } = pairs[j]; + if (c.nodeType === Node.TEXT_NODE) { + if ((c.nodeValue ?? "").trim() === "") { + const base = nextSlideId[j] ? "omid-ws:" + nextSlideId[j] : "omid-ws:aux"; + const n = wsSeen.get(base) ?? 0; + wsSeen.set(base, n + 1); + keys.push(n === 0 ? base : base + ":" + n); + continue; + } + return { kids, keys: null }; + } + if (c.nodeType !== Node.ELEMENT_NODE) { + keys.push(j); + continue; + } + const child = c; + const tag = child.localName; + if (DECK_AUX_RE.test(tag)) { + keys.push(j); + continue; + } + if (DECK_CONTROL_FLOW_RE.test(tag)) return { kids, keys: null }; + const v = child.getAttribute("data-om-slide-id"); + if (!v || !SLIDE_ID_VALUE_RE.test(v) || seen.has(v)) { + return { kids, keys: null }; + } + seen.add(v); + keys.push("omid:" + v); + } + return { kids, keys }; + } + function renderDeckKids(kids, kidKeys, vals, ctx) { + return kids.map((b, j) => { + const k = kidKeys ? kidKeys[j] : j; + const out = b(vals, ctx, k); + return kidKeys != null && typeof out === "string" ? h(getReact().Fragment, { key: k }, out) : out; + }); + } + function walk(node, host) { + if (node.nodeType === Node.TEXT_NODE) return walkText(node); + if (node.nodeType !== Node.ELEMENT_NODE) return null; + const el = node; + const tag = el.tagName.toLowerCase(); + if (tag === "sc-for") return walkFor(el, host); + if (tag === "sc-if") return walkIf(el, host); + if (tag === "x-import") return walkXImport(el, host); + if (tag === "sc-helmet") return host.helmet(el); + if (tag === "dc-import") return walkComponent(el, host); + return walkElement(el, host); + } + var warnedHoles = /* @__PURE__ */ new Set(); + function warnUnresolved(ctx, what) { + const key = (ctx?.__name || "?") + "\0" + what; + if (warnedHoles.has(key)) return; + warnedHoles.add(key); + console.warn("[dc-runtime] " + (ctx?.__name || "template") + ": " + what); + } + function walkText(node) { + const txt = node.nodeValue ?? ""; + if (!txt.includes("{{")) { + if (!txt.trim() && !txt.includes(" ")) return null; + return () => txt; + } + const parts = txt.split(/\{\{([\s\S]+?)\}\}/g); + return (vals, ctx, key) => h( + getReact().Fragment, + { key }, + ...parts.map((p, i) => { + if (!(i & 1)) return p; + const v = resolve(vals, p); + if (v === void 0) { + if (!ctx?.__streamingNow) { + if (document.body?.hasAttribute("data-dc-editor-on")) { + return h( + "span", + { key: i, className: "sc-interp sc-unresolved" }, + "{{ " + p.trim() + " }}" + ); + } + warnUnresolved( + ctx, + "{{ " + p.trim() + " }} never resolved \u2014 rendered as empty" + ); + return null; + } + return h( + "span", + { key: i, className: "sc-interp sc-missing" }, + p.trim() + ); + } + if (getReact().isValidElement(v) || Array.isArray(v)) { + return h(getReact().Fragment, { key: i }, v); + } + if (v === null || typeof v === "boolean") return null; + return h("span", { key: i, className: "sc-interp" }, String(v)); + }) + ); + } + function walkFor(el, host) { + const listGet = compileAttr(el.getAttribute("list") || ""); + const asName = el.getAttribute("as") || "item"; + const hintN = parseInt(el.getAttribute("hint-placeholder-count") || "0", 10); + const kids = walkChildren(el, host); + const listSrc = el.getAttribute("list") || ""; + return (vals, ctx, key) => { + let list = listGet(vals); + if (!Array.isArray(list)) { + if (!ctx?.__streamingNow) { + if (list !== void 0 && list !== null) { + warnUnresolved( + ctx, + 'sc-for list="' + listSrc + '" is not an array (' + typeof list + ")" + ); + } + list = []; + } else { + list = hintN > 0 ? Array(hintN).fill(void 0) : []; + } + } + return h( + getReact().Fragment, + { key }, + list.map((item, i) => { + const sub = { ...vals, [asName]: item, $index: i }; + return h( + getReact().Fragment, + { key: i }, + kids.map((b, j) => b(sub, ctx, j)) + ); + }) + ); + }; + } + function walkIf(el, host) { + const valGet = compileAttr(el.getAttribute("value") || ""); + const hintRaw = el.getAttribute("hint-placeholder-val"); + const hintGet = hintRaw != null ? compileAttr(hintRaw) : null; + const kids = walkChildren(el, host); + return (vals, ctx, key) => { + let v = valGet(vals); + if (v === void 0 && hintGet && ctx?.__streamingNow) v = hintGet(vals); + return v ? h( + getReact().Fragment, + { key }, + kids.map((b, j) => b(vals, ctx, j)) + ) : null; + }; + } + function walkComponent(el, host) { + const name = el.getAttribute("name") || el.getAttribute("component") || ""; + el.removeAttribute("name"); + el.removeAttribute("component"); + const tplId = el.getAttribute("data-dc-tpl"); + const styleRaw = el.getAttribute("style"); + el.removeAttribute("style"); + const styleGet = styleRaw != null ? compileAttr(styleRaw) : null; + const { propGetters, hintSize } = collectProps(el, "dc-import", host); + const kids = walkChildren(el, host); + return (vals, ctx, key) => { + const props = { + key, + __hintSize: hintSize, + __tplId: tplId, + __hostStyle: styleGet ? hostPositionStyle(styleGet(vals)) : void 0 + }; + for (const [k, g] of propGetters) { + const v = g(vals); + if (k === "dcProps") { + if (v && typeof v === "object") Object.assign(props, v); + continue; + } + props[k] = v; + } + if (kids.length) props.children = kids.map((b, j) => b(vals, ctx, j)); + return h(host.component(name), props); + }; + } + function walkXImport(el, host) { + const globalNameGet = compileAttr( + el.getAttribute("component-from-global-scope") || "" + ); + const exportNameGet = compileAttr( + el.getAttribute("component") || el.getAttribute("name") || "" + ); + const fromRaw = el.getAttribute("from") || (el.getAttribute("component-from-global-scope") ? "" : el.getAttribute("src") || el.getAttribute("import") || ""); + const urls = fromRaw.trim() ? fromRaw.trim().split(/\s+/) : []; + const url = urls.length ? urls[urls.length - 1] : ""; + const kindOf = (u) => /\.(jsx|tsx)(\?|#|$)/i.test(u) ? "jsx" : "js"; + const tplId = el.getAttribute("data-dc-tpl"); + const styleRaw = el.getAttribute("style"); + el.removeAttribute("style"); + const styleGet = styleRaw != null ? compileAttr(styleRaw) : null; + const wrap = tplId != null || styleGet != null; + const { propGetters, hintSize } = collectProps(el, "x-import", host); + const hasContent = el.children.length > 0 || !!(el.textContent || "").trim(); + const deckKeyed = hasContent && isDeckMountTag(el) ? walkDeckChildren(el, host) : null; + const kids = deckKeyed ? deckKeyed.kids : hasContent ? walkChildren(el, host) : []; + const kidKeys = deckKeyed?.keys ?? null; + const urlBindable = fromRaw.includes("{{"); + if (urls.length && !urlBindable) { + let prev; + for (const u of urls) prev = host.loadExternal(kindOf(u), u, prev); + } + const evalName = (g, vals) => { + const v = g(vals); + const s = v == null ? "" : String(v); + return s.includes("{{") ? "" : s; + }; + return (vals, ctx, key) => { + const globalName = evalName(globalNameGet, vals); + const name = globalName || evalName(exportNameGet, vals); + const C = !name || urlBindable ? null : globalName ? host.resolveExternalGlobal(url, globalName) : host.resolveExternal(url, name); + const hostStyle = styleGet ? hostPositionStyle(styleGet(vals)) : void 0; + const wrapper = wrap ? { + key, + className: "sc-host-x", + "data-dc-tpl": tplId, + style: hostStyle || { display: "contents" } + } : null; + if (!C) { + const error = urlBindable ? "x-import `from` cannot contain {{ \u2026 }} \u2014 module URLs are resolved at parse time; use a literal URL" : host.resolveExternalError(url, name); + const ph = host.placeholder({ + key: wrapper ? void 0 : key, + name, + hintSize, + error + }); + return wrapper ? h("div", wrapper, ph) : ph; + } + const props = wrapper ? {} : { key }; + let unresolvedHole = false; + for (const [k, g] of propGetters) { + if (k === "component" || k === "componentFromGlobalScope" || k === "from") { + continue; + } + const v = g(vals); + if (v === void 0) unresolvedHole = true; + if (k === "dcProps") { + if (v && typeof v === "object") Object.assign(props, v); + continue; + } + props[k] = v; + } + if (unresolvedHole && ctx?.__htmlStreamingNow) { + const ph = host.placeholder({ + key: wrapper ? void 0 : key, + name, + hintSize, + error: null + }); + return wrapper ? h("div", wrapper, ph) : ph; + } + if (kids.length) { + props.children = renderDeckKids(kids, kidKeys, vals, ctx); + } + return wrapper ? h("div", wrapper, h(C, props)) : h(C, props); + }; + } + function contentKey(el) { + const clone = el.cloneNode(true); + for (const d of clone.querySelectorAll("*")) { + while (d.attributes.length) d.removeAttribute(d.attributes[0].name); + } + const s = clone.innerHTML; + let h2 = 5381; + for (let i = 0; i < s.length; i++) h2 = (h2 << 5) + h2 + s.charCodeAt(i) | 0; + return s.length + "." + (h2 >>> 0).toString(36); + } + var NEVER_CONTENT_KEYED = new Set( + "script style textarea option title select canvas iframe video audio".split( + " " + ) + ); + var NOT_INLINE_SELECTOR = ":not(" + [...INLINE_TEXT_TAGS].join(",") + ")"; + function walkElement(el, host) { + const realTag = RAW_UNWRAP[el.localName] || el.localName; + const tplId = el.getAttribute("data-dc-tpl"); + const inlineOnly = el.childNodes.length > 0 && !NEVER_CONTENT_KEYED.has(realTag) && el.querySelector(NOT_INLINE_SELECTOR) === null; + const keySuffix = inlineOnly ? "|" + contentKey(el) : ""; + const { propGetters, pseudoClasses } = collectProps(el, "dom", host); + const deckKeyed = isDeckMountTag(el) ? walkDeckChildren(el, host) : null; + const kids = deckKeyed ? deckKeyed.kids : walkChildren(el, host); + const kidKeys = deckKeyed?.keys ?? null; + return (vals, ctx, key) => { + const props = { + key: key + keySuffix, + "data-dc-tpl": tplId + }; + for (const [k, g] of propGetters) { + let v = g(vals); + if (k === "style" && typeof v === "string") v = cssToObj(v); + if ((k === "value" || k === "checked") && v === void 0) { + v = k === "checked" ? false : ""; + } + props[k] = v; + } + if (pseudoClasses.length) { + props.className = [props.className, ...pseudoClasses].filter(Boolean).join(" "); + } + return h(realTag, props, ...renderDeckKids(kids, kidKeys, vals, ctx)); + }; + } + + // src/logic.ts + var StreamableLogic = class { + constructor(props) { + __publicField(this, "props"); + __publicField(this, "state", {}); + /** Back-pointer to the wrapper component, installed after construction. */ + __publicField(this, "__host"); + this.props = props || {}; + } + setState(update, cb) { + this.__host && this.__host.__setLogicState(update, cb); + } + forceUpdate() { + this.__host && this.__host.forceUpdate(); + } + componentDidMount() { + } + componentDidUpdate(_prevProps) { + } + componentWillUnmount() { + } + /** The flat object the template renders against (merged over props). */ + renderVals() { + return {}; + } + }; + function evalDcLogic(src) { + //! nosemgrep: eval-and-function-constructor + const fn = new Function( + "DCLogic", + "StreamableLogic", + "React", + src + '\n;return (typeof Component!=="undefined"&&Component)||undefined;' + ); + return fn(StreamableLogic, StreamableLogic, getReact()); + } + + // src/component.ts + function shallowEqual(a, b) { + if (!b) return false; + const ak = Object.keys(a).filter((k) => k !== "children"); + const bk = Object.keys(b).filter((k) => k !== "children"); + if (ak.length !== bk.length) return false; + for (const k of ak) if (a[k] !== b[k]) return false; + return true; + } + function Placeholder({ + name, + hintSize, + streaming, + error + }) { + const [w, hgt] = (hintSize || "100%,60px").split(","); + return h( + "div", + { + className: "sc-placeholder" + (streaming ? " sc-streaming" : ""), + style: { width: w.trim(), height: hgt && hgt.trim() }, + title: name + }, + error ? h( + "div", + { className: "sc-placeholder-error" }, + (name ? name + ": " : "") + error + ) : null + ); + } + function hintToMin(hint) { + if (!hint) return void 0; + const [w, hgt] = hint.split(","); + return { minWidth: w.trim(), minHeight: hgt && hgt.trim() }; + } + function createComponentFactory(registry, ensureFetched) { + const React = getReact(); + const AncestorContext = React.createContext([]); + class StreamableComponent extends React.Component { + constructor(props) { + super(props); + __publicField(this, "__name"); + __publicField(this, "__sub"); + __publicField(this, "__needsDidMount", false); + /** Snapshot of the registry's streaming flags taken at render time — + * builders read it off the RenderCtx (this) to pick placeholder vs + * render-nothing for unresolved values. */ + __publicField(this, "__streamingNow", false); + __publicField(this, "__htmlStreamingNow", false); + /** When a construct throws, remember the (class, registry.ver, props) + * triple so render-time reconcile doesn't re-attempt it on every parent + * re-render. A registry bump (new class, template, external module + * resolving via bumpAll) changes `ver` and breaks the memo so an + * env-dependent constructor can self-heal. */ + __publicField(this, "__failedLogic", null); + __publicField(this, "__failedUserProps", null); + __publicField(this, "__failedVer", -1); + /** Per-instance constructor error — kept here (not on the registry entry) + * so one instance's successful construct can't hide a sibling's failure, + * and a construct can never wipe an eval error `updateJs` recorded on + * `r.logicError`. */ + __publicField(this, "__ctorError", null); + __publicField(this, "logic"); + this.__name = props.__name; + this.state = { __v: 0, __err: null }; + this.__sub = () => { + if (this.state.__err) this.setState({ __err: null }); + this.forceUpdate(); + }; + this.__makeLogic(registry.get(this.__name).Logic, null); + ensureFetched(this.__name); + } + /** Error-boundary hook: a render crash anywhere in this DC's subtree + * (its own template, an x-import'd component, a child DC without its + * own deeper boundary) lands here instead of unmounting the page. */ + static getDerivedStateFromError(e) { + return { __err: e instanceof Error && e.message ? e.message : String(e) }; + } + componentDidCatch(e, info) { + console.error( + "[dc-runtime] render error in <" + this.__name + ">:", + e, + info?.componentStack || "" + ); + } + /** Instantiate the logic class (or the no-op base) and adopt `prevState` + * over its initial state — used both at mount and on hot-swap. */ + __makeLogic(Logic, prevState) { + const L = Logic || StreamableLogic; + try { + this.logic = new L(this.__userProps()); + this.__failedLogic = null; + this.__failedUserProps = null; + this.__ctorError = null; + } catch (e) { + console.error(e); + this.__failedLogic = Logic; + this.__failedUserProps = this.__userProps(); + this.__failedVer = registry.get(this.__name).ver; + this.__ctorError = this.__name + ": " + (e instanceof Error && e.message ? e.message : String(e)); + this.logic = new StreamableLogic( + this.__userProps() + ); + } + this.logic.__host = this; + if (prevState) + this.logic.state = { ...this.logic.state || {}, ...prevState }; + } + /** The props the author's logic + template see — internal __-prefixed + * wiring stripped. */ + __userProps() { + const { __name, __hintSize, __tplId, __hostStyle, ...rest } = this.props; + return rest; + } + __setLogicState(update, cb) { + const prev = this.logic.state; + const patch = typeof update === "function" ? update(prev) : update; + this.logic.state = { ...prev, ...patch }; + this.setState((s) => ({ __v: s.__v + 1 }), cb); + } + /** Swap the logic instance when the registry's Logic class changed + * (streaming completion, hot reload). State carries over; didMount + * re-fires after the swap commits so refs exist. */ + __reconcileLogic() { + const r = registry.get(this.__name); + const Next = r.Logic; + const Cur = this.logic.constructor; + if (Next === Cur || !Next && Cur === StreamableLogic || Next === this.__failedLogic && r.ver === this.__failedVer && shallowEqual(this.__userProps(), this.__failedUserProps)) { + return; + } + if (!this.__needsDidMount) { + try { + this.logic.componentWillUnmount(); + } catch (e) { + console.error(e); + } + } + this.__makeLogic(Next, this.logic.state); + this.__needsDidMount = true; + } + componentDidMount() { + registry.get(this.__name).subs.add(this.__sub); + try { + this.logic.componentDidMount(); + } catch (e) { + console.error(e); + } + } + componentDidUpdate(prevProps) { + this.logic.props = this.__userProps(); + if (this.__needsDidMount) { + if (this.state.__err || !registry.get(this.__name).tpl) return; + this.__needsDidMount = false; + try { + this.logic.componentDidMount(); + } catch (e) { + console.error(e); + } + } else { + try { + this.logic.componentDidUpdate(prevProps); + } catch (e) { + console.error(e); + } + } + } + componentWillUnmount() { + registry.get(this.__name).subs.delete(this.__sub); + if (!this.__needsDidMount) { + try { + this.logic.componentWillUnmount(); + } catch (e) { + console.error(e); + } + } + } + render() { + const r = registry.get(this.__name); + const cls = "sc-host" + (r.htmlStreaming ? " sc-streaming-html" : "") + (r.jsStreaming ? " sc-streaming-js" : ""); + const hintStyle = r.htmlStreaming ? hintToMin(this.props.__hintSize) : void 0; + const hostStyle = this.props.__hostStyle || hintStyle ? { ...hintStyle || {}, ...this.props.__hostStyle || {} } : void 0; + const hostBase = { + className: cls, + style: hostStyle, + "data-sc-name": this.__name, + "data-dc-tpl": this.props.__tplId + }; + const chain = Array.isArray(this.context) ? this.context : []; + if (chain.includes(this.__name)) { + const cycle = [ + ...chain.slice(chain.indexOf(this.__name)), + this.__name + ].join(" \u2192 "); + return h( + "div", + { ...hostBase, className: cls + " sc-has-error" }, + h(Placeholder, { + name: this.__name, + hintSize: this.props.__hintSize, + error: "circular import: " + cycle + }) + ); + } + if (this.state.__err) { + return h( + "div", + { ...hostBase, className: cls + " sc-has-error" }, + h( + "div", + { className: "sc-logic-error", "data-omelette-chrome": "" }, + this.__name + ": " + this.state.__err + ), + h(Placeholder, { + name: this.__name, + hintSize: this.props.__hintSize, + error: this.state.__err + }) + ); + } + this.__reconcileLogic(); + if (!r.tpl) { + return h( + "div", + hostBase, + h(Placeholder, { name: this.__name, hintSize: this.props.__hintSize }) + ); + } + const userProps = this.__userProps(); + this.logic.props = userProps; + let vals = userProps; + let renderErr = r.logicError || this.__ctorError; + try { + vals = { ...userProps, ...this.logic.renderVals() || {} }; + } catch (e) { + console.error(e); + renderErr = this.__name + ".renderVals(): " + (e instanceof Error && e.message ? e.message : String(e)); + } + this.__streamingNow = !!(r.htmlStreaming || r.jsStreaming); + this.__htmlStreamingNow = !!r.htmlStreaming; + return h( + "div", + { ...hostBase, className: cls + (renderErr ? " sc-has-error" : "") }, + renderErr && h( + "div", + { className: "sc-logic-error", "data-omelette-chrome": "" }, + renderErr + ), + h( + AncestorContext.Provider, + { value: [...chain, this.__name] }, + r.tpl(vals, this) + ) + ); + } + } + __publicField(StreamableComponent, "contextType", AncestorContext); + const named = /* @__PURE__ */ new Map(); + function getDC(name) { + const hit = named.get(name); + if (hit) return hit; + function Dispatcher(p) { + const [, setTick] = React.useState(0); + React.useEffect(() => { + const sub = () => setTick((n) => n + 1); + registry.get(name).subs.add(sub); + return () => { + registry.get(name).subs.delete(sub); + }; + }, []); + ensureFetched(name); + return h(StreamableComponent, { ...p, __name: name }); + } + Dispatcher.displayName = name; + named.set(name, Dispatcher); + return Dispatcher; + } + return { + getDC, + StreamableComponent + }; + } + + // src/bundled.ts + function bundledBlob(url) { + const blobs = window.__resourceBlobs; + const b = blobs ? blobs[url.split("#")[0]] : void 0; + return b instanceof Blob ? b : null; + } + + // src/cdn.ts + var REACT_URL = "https://unpkg.com/react@18.3.1/umd/react.production.min.js"; + var REACT_SRI = "sha384-DGyLxAyjq0f9SPpVevD6IgztCFlnMF6oW/XQGmfe+IsZ8TqEiDrcHkMLKI6fiB/Z"; + var REACT_DOM_URL = "https://unpkg.com/react-dom@18.3.1/umd/react-dom.production.min.js"; + var REACT_DOM_SRI = "sha384-gTGxhz21lVGYNMcdJOyq01Edg0jhn/c22nsx0kyqP0TxaV5WVdsSH1fSDUf5YJj1"; + var BABEL_URL = "https://unpkg.com/@babel/standalone@7.29.0/babel.min.js"; + var BABEL_SRI = "sha384-m08KidiNqLdpJqLq95G/LEi8Qvjl/xUYll3QILypMoQ65QorJ9Lvtp2RXYGBFj1y"; + function cdnScriptFor(url, sri) { + const res = window.__resources; + const v = res ? res[url] : void 0; + return typeof v === "string" && v ? { src: v } : { src: url, integrity: sri }; + } + + // src/external.ts + var isCustomElementName = (n) => !n.includes(".") && n.includes("-"); + function isRenderableType(g) { + if (typeof g === "function") return !isElementClass(g); + return typeof g === "object" && g !== null && typeof g.$$typeof === "symbol"; + } + function resolveDottedPath(root, name) { + let cur = root; + for (const seg of name.split(".")) { + if (cur == null) return void 0; + cur = cur[seg]; + } + return cur; + } + var GLOBAL_POLL_INTERVAL_MS = 50; + var GLOBAL_POLL_TIMEOUT_MS = 3e4; + function createExternalModules(onResolved) { + const cache = /* @__PURE__ */ new Map(); + let babelLoading = null; + const reportedMissing = /* @__PURE__ */ new Map(); + const polling = /* @__PURE__ */ new Set(); + function ensureBabel() { + if (window.Babel) return Promise.resolve(); + if (babelLoading) return babelLoading; + const babel = cdnScriptFor(BABEL_URL, BABEL_SRI); + babelLoading = new Promise((res, rej) => { + const s = document.createElement("script"); + s.src = babel.src; + if (babel.integrity) { + s.integrity = babel.integrity; + s.crossOrigin = "anonymous"; + } + s.onload = () => res(); + s.onerror = rej; + document.head.appendChild(s); + }); + return babelLoading; + } + const pending = /* @__PURE__ */ new Map(); + function load(kind, url, after) { + const existing = pending.get(url); + if (existing) return existing; + cache.set(url, null); + console.info("[dc-runtime] x-import: loading", url, "(" + kind + ")"); + const ready = Promise.all([ + kind === "jsx" ? ensureBabel() : Promise.resolve(), + after ?? Promise.resolve() + ]); + const p = ready.then(() => { + const pre = bundledBlob(url); + if (pre) return pre.text(); + return fetch(url).then((r) => { + if (!r.ok) throw new Error("HTTP " + r.status); + return r.text(); + }); + }).then((src) => { + const code = kind === "jsx" ? window.Babel.transform(src, { + filename: url, + presets: ["react", "typescript"] + }).code : src; + const module = { exports: {} }; + const before = new Set(Object.keys(window)); + //! nosemgrep: eval-and-function-constructor + new Function("React", "module", "exports", "require", code)( + getReact(), + module, + module.exports, + () => ({}) + ); + const globals = {}; + for (const k of Object.keys(window)) { + if (!before.has(k) && typeof window[k] === "function") { + globals[k] = window[k]; + } + } + cache.set(url, { mod: module.exports, globals }); + console.info( + "[dc-runtime] x-import: loaded", + url, + "\u2014 exports:", + Object.keys(module.exports), + "window globals:", + Object.keys(globals) + ); + onResolved(); + }).catch((e) => { + cache.set(url, { + mod: {}, + globals: {}, + error: "failed to load: " + (e instanceof Error && e.message ? e.message : String(e)) + }); + console.error( + "[dc-runtime] x-import: FAILED to load", + url, + "(" + kind + ")", + e + ); + onResolved(); + }); + pending.set(url, p); + return p; + } + function resolve2(url, name) { + const entry = cache.get(url); + if (!entry) return null; + const { mod, globals } = entry; + const C = mod && mod[name] || globals && globals[name] || typeof window !== "undefined" && window[name] || mod && mod.default; + if (typeof C === "function") return C; + const key = url + "\0" + name; + if (!reportedMissing.has(key)) { + reportedMissing.set( + key, + entry.error || 'no export named "' + name + '" (has: ' + Object.keys(mod).join(", ") + ")" + ); + console.error( + "[dc-runtime] x-import: module", + url, + "loaded but has no component named", + JSON.stringify(name), + "\u2014 available exports:", + Object.keys(mod), + "window globals:", + Object.keys(globals), + ". The module must `module.exports = {" + name + "}` or set `window." + name + "`." + ); + } + return null; + } + function waitForGlobal(name) { + if (polling.has(name)) return; + polling.add(name); + const started = Date.now(); + const isCE = isCustomElementName(name); + const tick = () => { + const found = isCE ? customElements.get(name) : isRenderableType(resolveDottedPath(window, name)); + if (found) { + polling.delete(name); + onResolved(); + return; + } + if (Date.now() - started >= GLOBAL_POLL_TIMEOUT_MS) { + console.warn( + "[dc-runtime] x-import: global", + JSON.stringify(name), + "never appeared on window after " + GLOBAL_POLL_TIMEOUT_MS + "ms" + ); + return; + } + setTimeout(tick, GLOBAL_POLL_INTERVAL_MS); + }; + setTimeout(tick, GLOBAL_POLL_INTERVAL_MS); + } + function resolveGlobal(url, name) { + const isCE = isCustomElementName(name); + if (!url) { + if (isCE) { + if (customElements.get(name)) return name; + waitForGlobal(name); + return null; + } + const g2 = resolveDottedPath(window, name); + if (isRenderableType(g2)) return g2; + waitForGlobal(name); + return null; + } + const entry = cache.get(url); + if (!entry) return null; + if (isCE && customElements.get(name)) return name; + const g = entry.globals[name] ?? resolveDottedPath(window, name); + if (isRenderableType(g)) return g; + if (name.includes(".")) return null; + const key = url + "\0global\0" + name; + if (!reportedMissing.has(key)) { + reportedMissing.set(key, null); + if (isCE && !customElements.get(name)) { + console.warn( + "[dc-runtime] x-import:", + url, + "loaded but no custom element", + JSON.stringify(name), + "is registered and window." + name + " is not a function \u2014 rendering <" + name + "> as an unknown element." + ); + } + } + return name; + } + function getError(url, name) { + const entry = cache.get(url); + if (entry?.error) return entry.error; + return reportedMissing.get(url + "\0" + name) || null; + } + return { load, resolve: resolve2, resolveGlobal, getError }; + } + function isElementClass(g) { + try { + return typeof g === "function" && typeof HTMLElement !== "undefined" && g.prototype instanceof HTMLElement; + } catch { + return false; + } + } + + // src/atomics.ts + var ATOMIC_CSS = ( + // layout + ".fx{display:flex}.col{display:flex;flex-direction:column}.grid{display:grid}.ac{align-items:center}.jc{justify-content:center}.jb{justify-content:space-between}.f1{flex:1}.noshrink{flex-shrink:0}.wrap{flex-wrap:wrap}.fw5{font-weight:500}.fw6{font-weight:600}.fw7{font-weight:700}.fw8{font-weight:800}.fs11{font-size:11px}.fs12{font-size:12px}.fs13{font-size:13px}.fs14{font-size:14px}.fs15{font-size:15px}.fs16{font-size:16px}.fs20{font-size:20px}.fs22{font-size:22px}.upper{text-transform:uppercase}.tc{text-align:center}.nowrap{white-space:nowrap}.gap8{gap:8px}.gap10{gap:10px}.gap12{gap:12px}.gap16{gap:16px}.gap24{gap:24px}.m0{margin:0}.mt8{margin-top:8px}.mt12{margin-top:12px}.mt16{margin-top:16px}.mb8{margin-bottom:8px}.mb12{margin-bottom:12px}.mb16{margin-bottom:16px}.posrel{position:relative}.posabs{position:absolute}.round{border-radius:50%}.ohide{overflow:hidden}.bbox{box-sizing:border-box}.pointer{cursor:pointer}.w100{width:100%}.b0{border:none}" + ); + + // src/helmet.ts + var DESIGN_DOC_MODE_RE = /]*\bname\s*=\s*["']design_doc_mode["'][^>]*\b(?:content|value)\s*=\s*["'](\w+)["']/i; + var CANVAS_BG_LIGHT = "#f0eee6"; + var CANVAS_BG_DARK = "#2e2c26"; + function createHelmetManager(doc, isStreaming) { + const mounted = /* @__PURE__ */ new Set(); + const live = /* @__PURE__ */ new Map(); + let designDocMode = null; + let canvasStyleEl = null; + let appTheme = "light"; + try { + const ds = doc.documentElement.dataset.theme; + appTheme = ds === "dark" || ds === "light" ? ds : new URLSearchParams(doc.defaultView?.location.search ?? "").get( + "theme" + ) === "dark" ? "dark" : "light"; + } catch { + } + function applyCanvasBg() { + if (!canvasStyleEl) return; + const bg = appTheme === "dark" ? CANVAS_BG_DARK : CANVAS_BG_LIGHT; + canvasStyleEl.textContent = `html,body{background:${bg}}#dc-root>.sc-host{position:relative}`; + } + function postDesignMode(mode) { + if (window.parent === window) return; + try { + window.parent.postMessage({ type: "__dc_design_mode", mode }, "*"); + } catch { + } + } + function setDesignDocMode(mode) { + if (mode === designDocMode) return; + designDocMode = mode; + postDesignMode(mode); + if (mode === "canvas") { + doc.documentElement.setAttribute("data-dc-canvas", ""); + canvasStyleEl = doc.createElement("style"); + canvasStyleEl.setAttribute("data-dc-canvas", ""); + applyCanvasBg(); + doc.head.appendChild(canvasStyleEl); + } else { + doc.documentElement.removeAttribute("data-dc-canvas"); + canvasStyleEl?.remove(); + canvasStyleEl = null; + } + } + window.addEventListener("message", (e) => { + const type = e.data && e.data.type; + if (type === "__dc_theme") { + const t = e.data.theme; + if (t === "light" || t === "dark") { + appTheme = t; + applyCanvasBg(); + } + return; + } + if (!designDocMode || type !== "__dc_probe") return; + postDesignMode(designDocMode); + }); + function compile(node) { + const raw = [...node.children]; + const helmetClosed = node.nextSibling != null || node.parentNode?.nextSibling != null; + if (node.hasAttribute("data-dc-atomics") && !mounted.has("__dc-atomics")) { + mounted.add("__dc-atomics"); + const el = doc.createElement("style"); + el.id = "__dc-atomics"; + el.textContent = ATOMIC_CSS; + doc.head.appendChild(el); + } + return (_vals, ctx) => { + const name = ctx && ctx.__name || ""; + const streaming = !!(name && isStreaming(name)); + for (let i = 0; i < raw.length; i++) { + const child = raw[i]; + const tag = child.tagName; + const mayBePartial = streaming && !helmetClosed && i === raw.length - 1; + if (tag === "SCRIPT") { + if (mayBePartial) continue; + const key = "SCRIPT|" + (child.getAttribute("src") || child.textContent || ""); + if (mounted.has(key)) continue; + mounted.add(key); + const el = doc.createElement("script"); + for (const { name: an, value } of [...child.attributes]) + el.setAttribute(an, value); + if (child.textContent) el.textContent = child.textContent; + doc.head.appendChild(el); + } else if (tag === "LINK" || tag === "META") { + if (mayBePartial) continue; + const key = tag + "|" + (child.getAttribute("href") || child.getAttribute("src") || child.outerHTML); + if (mounted.has(key)) continue; + mounted.add(key); + if (tag === "LINK") { + const rel = (child.getAttribute("rel") || "").toLowerCase().split(/\s+/); + const href = (child.getAttribute("href") || "").trim(); + const res = window.__resources; + const pre = res && rel.includes("stylesheet") && !rel.includes("alternate") ? res[href] : void 0; + const blob = typeof pre === "string" && pre ? bundledBlob(pre) : null; + if (blob) { + const el = doc.createElement("style"); + if (child.hasAttribute("disabled")) { + el.setAttribute("media", "not all"); + } else if (child.getAttribute("media")) { + el.setAttribute("media", child.getAttribute("media")); + } + if (child.getAttribute("title")) + el.setAttribute("title", child.getAttribute("title")); + void blob.text().then((css) => { + el.textContent = css; + }); + doc.head.appendChild(el); + continue; + } + } + doc.head.appendChild(child.cloneNode(true)); + } else { + const key = name + "|" + i; + let el = live.get(key); + if (!el || el.tagName !== tag) { + if (el) el.remove(); + el = doc.createElement(tag.toLowerCase()); + live.set(key, el); + doc.head.appendChild(el); + } + for (const { name: an, value } of [...child.attributes]) { + if (el.getAttribute(an) !== value) el.setAttribute(an, value); + } + if (el.textContent !== child.textContent) + el.textContent = child.textContent; + } + } + return null; + }; + } + return { compile, setDesignDocMode }; + } + + // src/pseudo.ts + function scanUnquotedUrl(css, i) { + if (css[i] !== "u" && css[i] !== "U" || css.slice(i, i + 4).toLowerCase() !== "url(" || /[a-z0-9_-]/i.test(css[i - 1] ?? "")) { + return -1; + } + let j = i + 4; + while (j < css.length && /\s/.test(css[j])) j++; + if (css[j] === '"' || css[j] === "'") return -1; + while (j < css.length && css[j] !== ")") { + if (css[j] === "\\") j++; + j++; + } + return j < css.length ? j + 1 : css.length; + } + function stripComments(css) { + let out = ""; + let quote = ""; + for (let i = 0; i < css.length; i++) { + const c = css[i]; + if (quote) { + if (c === "\\") { + out += c + (css[i + 1] ?? ""); + i++; + continue; + } + if (c === quote) quote = ""; + out += c; + } else if (c === "'" || c === '"') { + quote = c; + out += c; + } else if (c === "/" && css[i + 1] === "*") { + const end = css.indexOf("*/", i + 2); + i = end === -1 ? css.length : end + 1; + out += " "; + } else { + const end = scanUnquotedUrl(css, i); + if (end === -1) out += c; + else { + out += css.slice(i, end); + i = end - 1; + } + } + } + return out; + } + function importantify(css) { + css = stripComments(css); + const decls = []; + let start = 0; + let depth = 0; + let quote = ""; + for (let i = 0; i < css.length; i++) { + const c = css[i]; + if (quote) { + if (c === "\\") i++; + else if (c === quote) quote = ""; + } else if (c === "'" || c === '"') quote = c; + else if (c === "(") depth++; + else if (c === ")") depth = Math.max(0, depth - 1); + else if (c === ";" && depth === 0) { + decls.push(css.slice(start, i)); + start = i + 1; + } else { + const end = scanUnquotedUrl(css, i); + if (end !== -1) i = end - 1; + } + } + decls.push(css.slice(start)); + return decls.map((d) => d.trim()).filter(Boolean).map((d) => /!\s*important$/i.test(d) ? d : d + " !important").join(";"); + } + function createPseudoSheet(doc) { + let el = null; + const cache = /* @__PURE__ */ new Map(); + let n = 0; + return (pseudo, css) => { + const k = pseudo + "|" + css; + const hit = cache.get(k); + if (hit) return hit; + if (!el) { + el = doc.createElement("style"); + doc.head.appendChild(el); + } + const cls = "scp" + (n++).toString(36); + const isPseudoElement = pseudo === "before" || pseudo === "after"; + const sel = isPseudoElement ? "." + cls + "::" + pseudo : "." + cls + ":" + pseudo; + el.sheet.insertRule( + sel + "{" + (isPseudoElement ? css : importantify(css)) + "}", + el.sheet.cssRules.length + ); + cache.set(k, cls); + return cls; + }; + } + + // src/registry.ts + function createRegistry() { + const entries = /* @__PURE__ */ Object.create(null); + function get(name) { + return entries[name] || (entries[name] = { + html: "", + tpl: null, + Logic: null, + jsStreaming: false, + htmlStreaming: false, + ver: 0, + subs: /* @__PURE__ */ new Set(), + fetched: false + }); + } + function bump(name) { + const r = get(name); + r.ver++; + for (const fn of r.subs) fn(); + } + return { + entries, + get, + bump, + bumpAll() { + for (const n in entries) bump(n); + } + }; + } + + // src/runtime.ts + var COMPONENT_DIR = "."; + function createRuntime(doc = document) { + const registry = createRegistry(); + const pseudoClass = createPseudoSheet(doc); + const helmet = createHelmetManager( + doc, + (name) => registry.get(name).htmlStreaming + ); + const external = createExternalModules(() => registry.bumpAll()); + const factory = createComponentFactory(registry, ensureFetched); + const host = { + component: (name) => factory.getDC(name), + placeholder: (props) => h(Placeholder, props), + helmet: (node) => helmet.compile(node), + loadExternal: (kind, url, after) => external.load(kind, url, after), + resolveExternal: (url, name) => external.resolve(url, name), + resolveExternalGlobal: (url, name) => external.resolveGlobal(url, name), + resolveExternalError: (url, name) => external.getError(url, name), + pseudoClass + }; + function ensureFetched(name) { + const r = registry.get(name); + if (r.fetched) return; + r.fetched = true; + const url = COMPONENT_DIR + "/" + encodeURIComponent(name) + ".dc.html"; + const res = window.__resources; + const pre = res ? res[url] : void 0; + const target = typeof pre === "string" && pre ? pre : url; + const blob = bundledBlob(target); + (blob ? blob.text() : fetch(target).then((res2) => { + if (!res2.ok) { + console.error( + '[dc-runtime] sibling fetch for "' + name + '" failed:', + url, + "returned", + res2.status, + "\u2014 the reference renders as an empty placeholder." + ); + return ""; + } + return res2.text(); + })).then((t) => { + if (!t) return; + const parsed = parseDcText(t); + if (!parsed) { + console.error( + '[dc-runtime] sibling fetch for "' + name + '":', + url, + "has no block \u2014 not a Design Component." + ); + return; + } + if (parsed.props) r.propsMeta = parsed.props; + if (parsed.preview) r.preview = parsed.preview; + if (parsed.template && !r.html) updateHtml(name, parsed.template); + if (parsed.js && !r.Logic) updateJs(name, parsed.js); + }).catch( + (e) => console.error( + '[dc-runtime] sibling fetch for "' + name + '" threw:', + url, + e + ) + ); + } + let rootName = null; + function updateHtml(name, html) { + const r = registry.get(name); + r.html = html; + if (name === rootName) { + const mode = DESIGN_DOC_MODE_RE.exec(html)?.[1] ?? null; + if (mode || !r.htmlStreaming) helmet.setDesignDocMode(mode); + } + try { + r.tpl = compileTemplate(html, host); + } catch (e) { + console.error("[dc-runtime] template compile FAILED for", name, e); + } + registry.bump(name); + } + function updateJs(name, src) { + const r = registry.get(name); + const seq = r.jsSeq = (r.jsSeq || 0) + 1; + try { + const Cls = evalDcLogic(src); + if (r.jsSeq !== seq) return; + if (typeof Cls !== "function") { + r.logicError = name + ".dc.html: