openpencil/packages/docs/de/programmable/cli/exporting.md
Danila Poyarkov e17f74991b
feat(storybook): generate Radix UI components for React stories (#971)
* refactor(dom-css): share the generated component's markup and bindings

The component model now holds the element tree every framework writes: each layer's behaviour part, design tag, state class, and attributes, and the root's typed bindings (the two-way value, disabled, and each variant prop as a data attribute). The Vue generator only maps parts to Reka components and writes each binding its way, so another framework is a mapping table and a printer.

* feat(emit): print TSX modules with namespaced tags and spreads

jsx.printModule prints an es template filled with JSX as one TSX module, quoting every string the same way. Dotted tags such as Switch.Root print as JSX member expressions, and jsx.spread passes an object on as attributes. fill now fills holes inside the annotation it keeps on a filled identifier, which left $Props unfilled in a parameter's type.

* feat(storybook): generate Radix UI components for React stories

With --framework react, a component set whose behaviour is a Button, Switch, Checkbox, Toggle, or Collapsible exports as a component on the radix-ui package with its state styles in a CSS module. Its props extend the Radix root's, so checked, defaultChecked, onCheckedChange, and disabled come from Radix, and each other variant property is a prop set as a data attribute. Its stories use Radix's uncontrolled value so a play function can operate it. The browser spec now runs the same Switch and Collapsible checks for Vue and React.

* refactor(storybook): let generators say how stories import their component

The stories printer named each framework to know its Storybook package, how to import the component, and which prop sets its value. A generator now returns its files with the import path, whether the export is named, and the value's arg, and the Storybook packages come from the one table static stories use, so the printer is framework-neutral and exportStorybook looks generators up instead of branching.

* fix(storybook): keep a caller's class on React roots and run stories' play functions

The generated class came after the spread props, so a className passed to a generated React component was dropped. The root now joins its classes with the caller's. The browser spec mounts each framework's Default story and runs its exported play function with Storybook's own within and userEvent, checking the switch ends up on, and checks a caller's class stays on the root. emit shares one isNode guard.
2026-10-08 10:13:52 +00:00

8.1 KiB
Raw Permalink Blame History

title description
Export mit der CLI PNG, JPG, WEBP, SVG, `.fig`, JSX, HTML und Storybook-Stories exportieren oder Dokumentformate umwandeln.

Export mit der CLI

Die CLI exportiert Rasterbilder, SVG, Teile eines Dokuments als .fig, JSX, HTML und Storybook-Stories.

Formate

openpencil export design.fig                           # PNG
openpencil export design.fig -f jpg -s 2 -q 90        # JPG mit 2×
openpencil export design.fig -f svg                   # SVG
openpencil export design.fig -f fig --page "Page 1"   # Seite als .fig
openpencil export design.fig -f html --css tailwind    # HTML mit Tailwind-Klassen

-f wählt das Format (png, jpg, webp, svg, pdf, pptx, jsx, html, fig, storybook), -s den Maßstab, -q die Qualität und -o den Ausgabepfad. --page und --node begrenzen den Export.

JSX

openpencil export design.fig -f tailwind-jsx    # oder: -f jsx --style tailwind

--style openpencil erzeugt das native JSX-Format des JSX-Renderers.

HTML

openpencil export design.fig -f html
openpencil export design.fig -f html --css tailwind
openpencil export design.fig -f html --html standalone --assets external

Der eigenständige HTML-Export wird sofort mit Tailwind kompiliert und benötigt keine Browser-Laufzeit. --assets external schreibt CSS und Bilder neben die HTML-Datei. --fonts assets speichert aufgelöste Webschriften als lokale @font-face-Dateien.

Der HTML-Export dient Übergabe und Weiterverarbeitung, nicht als pixelgenauer Ersatz für die Darstellung auf der Arbeitsfläche.

Storybook

Erzeugt pro Komponentensatz oder Komponente eine CSF3-Datei .stories.ts:

openpencil export design.fig -f storybook                      # React-Stories in ./design-stories/
openpencil export design.fig -f storybook --framework vue -o src/stories
openpencil export design.fig -f storybook --framework html --page "Components"
openpencil export design.pen -f storybook -o src/stories --watch  # bei jedem Speichern neu exportieren
openpencil export 'src/**/*.pen' -f storybook --beside --watch    # Stories neben jedem Design

Designs neben ihren Stories

Legen Sie die Designdatei jeder Komponente in den Ordner der Komponente und exportieren Sie mit --beside: Die Stories, Designbilder und das Manifest .openpencil-stories.json jedes Dokuments landen im eigenen Ordner dieses Dokuments, neben dem Code der Komponente. Ein Storybook-stories-Glob wie ../src/**/*.stories.ts in .storybook/main.ts erfasst sie dann ohne weitere Konfiguration.

Sie können mehrere Dokumente übergeben oder einen Glob in Anführungszeichen wie 'src/**/*.pen', den OpenPencil selbst auflöst (Node.js 22 oder neuer). Mehrere Dokumente erfordern --beside oder --output; --page funktioniert nur mit einem Dokument. Die Dokumente werden nacheinander exportiert, und schlägt eines fehl, werden die übrigen trotzdem exportiert, bevor der Befehl mit einem Fehler endet. --watch beobachtet jedes passende Dokument; ein Dokument, das nach dem Start der Beobachtung entsteht, erfordert einen neuen Lauf.

Jede Variante eines Komponentensatzes wird zu einer Story, und ihre Variantenmerkmale werden zu select-Controls, sodass das Umschalten eines Controls die passende Variante zeigt. Ein Satz mit Verhalten erhält stattdessen die Props des Controls: ein Switch oder eine Checkbox ein boolesches checked, ein Toggle pressed, ein Collapsible open und disabled, wenn der Satz einen deaktivierten Zustand zeichnet; Hover, Pressed und Fokus bleiben eigene Storys. Eigenständige Komponenten mit Schrägstrich im Namen, etwa Button/Primary und Button/Secondary, werden in einer Button-Datei mit einem Variant-Control zusammengefasst. Eine Kombination, für die das Design keine Variante hat, löst in Storybook einen benannten Fehler aus, statt eine andere Variante zu zeigen.

Die Stories rendern die Komponente wie -f html als HTML mit Inline-Stilen und benötigen daher keine OpenPencil-Laufzeit; --framework (react, vue oder html) ändert nur den Wrapper und den Import von Meta/StoryObj aus @storybook/react-vite, @storybook/vue3-vite oder @storybook/html-vite. Text verwendet die Schriftfamilien des Dokuments, die Storybook selbst laden muss. Text-, Boolean- und Instanztausch-Eigenschaften werden noch nicht exportiert.

Mit --framework vue oder --framework react wird ein Komponentensatz, dessen Verhalten ein Button, Switch, Checkbox, Toggle oder Collapsible ist, stattdessen zu einer echten Komponente: <Name>.vue auf Basis von Reka UI oder <Name>.tsx mit <Name>.module.css auf Basis des Pakets radix-ui von Radix UI. Seine Varianten werden zu einem Stylesheet kompiliert, das auf die von Reka und Radix gesetzten Zustände reagiert (data-state, data-disabled, Hover und Fokus), und jedes weitere Variantenmerkmal ist ein Prop, das die Komponente als data-*-Attribut setzt. In Vue ist sein Wert ein v-model wie checked oder open; in React nimmt die Komponente die Props der Radix-Wurzel an, etwa checked, defaultChecked und onCheckedChange. Die Storys rendern die Komponente, und eine Play-Funktion klickt das Control an und prüft seinen Zustand; das Storybook-Projekt braucht daher reka-ui oder radix-ui.

Die Stories enthalten parameters.design-Einträge für @storybook/addon-designs:

  • OpenPencil: Liegt der Dokumentpfad im aktuellen Verzeichnis, ein openpencil://-Link, der das Dokument in der Desktop-Anwendung öffnet und die Variante auswählt, oder ihren Komponentensatz, wenn eine andere Ebene den Namen der Variante trägt. Das Schema adressiert Ebenen über ihren Namen; eine Story, deren Varianten- und Komponentenname beide von anderen Ebenen geteilt werden, erhält keinen Link.
  • Design: ein PNG der Variante in 2×, das neben der Story in <Name>.design/ abgelegt und mit new URL(…, import.meta.url) referenziert wird, sodass Vite es bündelt. Kopieren Sie den Parameter in die Story Ihrer eigenen Komponente, um die Implementierung mit dem Design zu vergleichen. --no-design-images überspringt das Rendern; die Schriftersetzung folgt wie beim Rasterexport --font-policy.

-o benennt das Ausgabeverzeichnis. Ein dortiges Manifest .openpencil-stories.json hält fest, welches Dokument (als Pfad relativ zum Ausgabeverzeichnis) und welche Seite jede Story und jedes Designbild erzeugt hat; checken Sie es zusammen mit den Stories ein. Ein Export ersetzt die Dateien, die ein früherer Export desselben Dokuments dort erzeugt hat, auch die inzwischen gelöschter oder umbenannter Komponenten; mit --page nur die dieser Seite. Er weigert sich, bevor etwas geändert wird, jede andere Datei zu überschreiben – eine handgeschriebene Story, die eines anderen Dokuments oder ein verirrtes Bild. Ein Export einer einzelnen Seite, dessen Dateinamen auf die Stories einer anderen Seite verschoben wurden, verlangt stattdessen einen vollständigen Export. Ohne das Manifest gelten vorhandene Stories als fremd, entfernen Sie sie daher vor einem erneuten Export. --watch hält den Befehl am Laufen und exportiert bei jedem Speichern des Dokuments neu, sodass das Hot Reload von Storybook dem Design folgt; ein Speicherstand, der nicht gelesen werden kann, wird gemeldet, und die Beobachtung läuft weiter. Ein fehlendes --page oder eine Ersetzung bei --font-policy strict beendet den Befehl dennoch.

Laufende Anwendung

Ohne Dateiargument exportiert die CLI aus der laufenden Anwendung:

openpencil export -f png                       # Auswahl im aktiven Dokument exportieren
openpencil export --page "Components" -f png   # alle Ebenen einer Seite exportieren
openpencil export --node 1:23 -f png           # eine Ebene auf einer beliebigen Seite exportieren

--page nimmt einen Seitennamen und --page-id eine Seiten-ID aus openpencil documents list; beide exportieren diese Seite, ohne die Anwendung zu ihr zu wechseln. Mit --document-id exportieren Sie aus einem anderen als dem aktiven Dokument.

Dieser Modus unterstützt PNG, JPG, WEBP, SVG und PDF. PowerPoint, JSX, HTML, Storybook und .fig erfordern ein Dateiargument.