@grida/svg-editor 1.0.0-alpha.2 → 1.0.0-alpha.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +213 -5
- package/dist/chunk-CfYAbeIz.mjs +13 -0
- package/dist/{dom-kA8NDuVh.mjs → dom-CmOu0HvI.mjs} +701 -7
- package/dist/dom-Cn-RtjRL.d.ts +48 -0
- package/dist/{dom-CfP_ZURh.js → dom-CoVZzFqy.js} +716 -7
- package/dist/dom-DJnZhtOd.d.mts +48 -0
- package/dist/dom.d.mts +2 -16
- package/dist/dom.d.ts +2 -16
- package/dist/dom.js +1 -1
- package/dist/dom.mjs +1 -1
- package/dist/{editor-M6j8XGO5.mjs → editor-CjK56cgb.mjs} +11 -11
- package/dist/{editor-BryibVvr.d.mts → editor-D2l_CDr0.d.ts} +314 -108
- package/dist/{editor-DllAMsDu.js → editor-D2zZAyny.js} +13 -13
- package/dist/{editor-klT8wu-x.d.ts → editor-Uu6dZX4y.d.mts} +314 -108
- package/dist/index-CHiXYO9-.d.ts +1 -0
- package/dist/index-ThDLM4Am.d.mts +1 -0
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/index.mjs +1 -1
- package/dist/{paint-DuCg6Y-K.mjs → paint-Cfiw4g_J.mjs} +17 -1
- package/dist/{paint-DHq_3iwU.js → paint-dDV-Trt9.js} +23 -1
- package/dist/presets.d.mts +46 -0
- package/dist/presets.d.ts +46 -0
- package/dist/presets.js +55 -0
- package/dist/presets.mjs +50 -0
- package/dist/react.d.mts +49 -6
- package/dist/react.d.ts +49 -6
- package/dist/react.js +49 -9
- package/dist/react.mjs +49 -10
- package/package.json +9 -4
package/README.md
CHANGED
|
@@ -123,6 +123,108 @@ A few scenarios this is designed to handle well.
|
|
|
123
123
|
>
|
|
124
124
|
> The editor freezes the animation at `t=0` for editing, applies the position change to the static `cx` attribute, and preserves the `<animate>` block verbatim. The inspector shows a clear "animated property" badge so the user understands what they're editing.
|
|
125
125
|
|
|
126
|
+
### Free-form canvas (Figma-style infinite canvas)
|
|
127
|
+
|
|
128
|
+
Identity camera, default gestures, no auto-fit. Pan with the wheel, Cmd+wheel to zoom at cursor, space-drag for hand-tool, `Shift+1` to fit, `Shift+0` to reset.
|
|
129
|
+
|
|
130
|
+
```tsx
|
|
131
|
+
import {
|
|
132
|
+
SvgEditorCanvas,
|
|
133
|
+
SvgEditorProvider,
|
|
134
|
+
useCameraSnapshot,
|
|
135
|
+
} from "@grida/svg-editor/react";
|
|
136
|
+
import type { DomSurfaceHandle } from "@grida/svg-editor/dom";
|
|
137
|
+
import { useState } from "react";
|
|
138
|
+
|
|
139
|
+
export function FreeFormCanvas({ svg }: { svg: string }) {
|
|
140
|
+
const [handle, setHandle] = useState<DomSurfaceHandle | null>(null);
|
|
141
|
+
const zoom = useCameraSnapshot(handle, (c) => c.zoom, 1);
|
|
142
|
+
return (
|
|
143
|
+
<SvgEditorProvider svg={svg}>
|
|
144
|
+
<div style={{ position: "relative", width: "100%", height: "100vh" }}>
|
|
145
|
+
<SvgEditorCanvas
|
|
146
|
+
onAttach={setHandle}
|
|
147
|
+
style={{ width: "100%", height: "100%" }}
|
|
148
|
+
/>
|
|
149
|
+
<div style={{ position: "absolute", bottom: 12, right: 12 }}>
|
|
150
|
+
<button onClick={() => handle?.camera.fit("<root>")}>Fit</button>
|
|
151
|
+
<button onClick={() => handle?.camera.reset()}>100%</button>
|
|
152
|
+
<span>{Math.round(zoom * 100)}%</span>
|
|
153
|
+
</div>
|
|
154
|
+
</div>
|
|
155
|
+
</SvgEditorProvider>
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### Keynote-like canvas (fixed-viewBox slide with bounded camera)
|
|
161
|
+
|
|
162
|
+
The keynote case wants more than "fit on load" — it wants **"the slide is the world"**: no zooming out past fit, no panning when the slide already fills the viewport, and clamped panning when zoomed in so the slide always covers the viewport edge-to-edge.
|
|
163
|
+
|
|
164
|
+
This bundle ships as a one-import preset at the **`@grida/svg-editor/presets`** subpath. The preset composes the public primitives:
|
|
165
|
+
|
|
166
|
+
1. `attach_dom_surface` with `fit: true` — slide visible on first frame.
|
|
167
|
+
2. `camera.constraints = { type: 'cover', bounds: '<root>', padding }` — typed [camera constraint](#camera-constraints) that clamps zoom + pan.
|
|
168
|
+
3. `editor.subscribe_with_selector(s => s.load_version, () => camera.fit('<root>'))` — refit only on fresh document loads, not on edits.
|
|
169
|
+
|
|
170
|
+
The preset is opt-in by import: the main `@grida/svg-editor` entry never touches `presets/`, so hosts that don't want the bundle aren't paying for it.
|
|
171
|
+
|
|
172
|
+
```tsx
|
|
173
|
+
import { useEffect, useRef, useState } from "react";
|
|
174
|
+
import { SvgEditorProvider, useSvgEditor } from "@grida/svg-editor/react";
|
|
175
|
+
import { keynote, type KeynoteSurfaceHandle } from "@grida/svg-editor/presets";
|
|
176
|
+
|
|
177
|
+
export function KeynoteCanvas({ svg }: { svg: string }) {
|
|
178
|
+
return (
|
|
179
|
+
<SvgEditorProvider svg={svg}>
|
|
180
|
+
<KeynoteHost />
|
|
181
|
+
</SvgEditorProvider>
|
|
182
|
+
);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
function KeynoteHost() {
|
|
186
|
+
const editor = useSvgEditor();
|
|
187
|
+
const container_ref = useRef<HTMLDivElement | null>(null);
|
|
188
|
+
const [handle, setHandle] = useState<KeynoteSurfaceHandle | null>(null);
|
|
189
|
+
|
|
190
|
+
// Mount the preset on first render; dispose on unmount. The preset
|
|
191
|
+
// owns fit-on-attach, the cover constraint, and the load-version refit
|
|
192
|
+
// subscription — the host writes ~10 lines of React lifecycle, no math.
|
|
193
|
+
useEffect(() => {
|
|
194
|
+
const container = container_ref.current;
|
|
195
|
+
if (!container) return;
|
|
196
|
+
const h = keynote.attach(editor, { container, padding: 80 });
|
|
197
|
+
setHandle(h);
|
|
198
|
+
return () => {
|
|
199
|
+
setHandle(null);
|
|
200
|
+
h.detach();
|
|
201
|
+
};
|
|
202
|
+
}, [editor]);
|
|
203
|
+
|
|
204
|
+
return (
|
|
205
|
+
<div style={{ padding: 24, background: "#1f2937", height: "100vh" }}>
|
|
206
|
+
<div
|
|
207
|
+
ref={container_ref}
|
|
208
|
+
style={{
|
|
209
|
+
width: "100%",
|
|
210
|
+
height: "100%",
|
|
211
|
+
background: "#fff",
|
|
212
|
+
boxShadow: "0 10px 40px rgba(0,0,0,0.3)",
|
|
213
|
+
}}
|
|
214
|
+
/>
|
|
215
|
+
{/* Use `handle` for chrome — `useCameraSnapshot(handle, c => c.zoom, 1)`
|
|
216
|
+
for a zoom badge, `handle.set_padding(0)` for a Present-mode toggle, etc. */}
|
|
217
|
+
</div>
|
|
218
|
+
);
|
|
219
|
+
}
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
The handle is `KeynoteSurfaceHandle = DomSurfaceHandle & { set_padding(p: number): void }`. `set_padding` is preset-specific sugar for "I want a present-mode toggle that varies padding at runtime"; it mutates the live constraint and refits in one call.
|
|
223
|
+
|
|
224
|
+
Both examples ship as live demos at `/canvas/svg` (free-form, no preset) and `/canvas/svg/keynote` (preset) in the dogfood app. Their diff is the spec for what the SDK owes its users: same editor, same camera, same gestures — the keynote demo opts into the preset; the free-form demo doesn't.
|
|
225
|
+
|
|
226
|
+
> **Going deeper.** If you need to compose the building blocks differently — different constraint shape, conditional refit, host-managed bounds — read [`src/presets/keynote.ts`](https://github.com/gridaco/grida/blob/main/packages/grida-svg-editor/src/presets/keynote.ts) (≤ 70 lines of pure composition over public API) as the canonical reference.
|
|
227
|
+
|
|
126
228
|
## Install
|
|
127
229
|
|
|
128
230
|
```sh
|
|
@@ -164,13 +266,90 @@ A surface is the editor's attachment seam — it mounts the SVG into a host envi
|
|
|
164
266
|
```ts
|
|
165
267
|
import { attach_dom_surface } from "@grida/svg-editor/dom";
|
|
166
268
|
|
|
167
|
-
const handle = attach_dom_surface(editor, {
|
|
168
|
-
|
|
269
|
+
const handle = attach_dom_surface(editor, {
|
|
270
|
+
container,
|
|
271
|
+
gestures: true, // default — install the bundled gesture set (see "Camera")
|
|
272
|
+
fit: false, // default — start with identity camera (no auto-fit)
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
handle.camera; // surface-scoped pan/zoom (see "Camera")
|
|
276
|
+
handle.gestures; // surface-scoped wheel/pointer/keyboard layer
|
|
169
277
|
handle.detach();
|
|
170
278
|
```
|
|
171
279
|
|
|
172
280
|
`@grida/svg-editor/dom` is the only place in this package that imports DOM types. The internal `Surface` type exists for tests and future work; it is not a documented extension point at v1.
|
|
173
281
|
|
|
282
|
+
### Camera
|
|
283
|
+
|
|
284
|
+
The camera is a **surface-scoped** pan/zoom: it lives on `handle.camera`, never on `editor.state`. View state and document state are disjoint — pan/zoom doesn't bump `state.version`, doesn't serialize, and isn't undoable. A second `attach_dom_surface(...)` gets its own camera.
|
|
285
|
+
|
|
286
|
+
```ts
|
|
287
|
+
handle.camera.center; // world-space point at viewport center (Vec2)
|
|
288
|
+
handle.camera.zoom; // uniform scale; 1 = 100 %
|
|
289
|
+
handle.camera.bounds; // world Rect visible in the viewport
|
|
290
|
+
handle.camera.viewport_size; // { width, height } in screen px
|
|
291
|
+
handle.camera.transform; // underlying cmath.Transform (advanced read)
|
|
292
|
+
|
|
293
|
+
handle.camera.pan({ x, y }); // translate by a screen-space delta
|
|
294
|
+
handle.camera.zoom_at(factor, origin_screen); // pinch / wheel-at-cursor
|
|
295
|
+
handle.camera.set_center({ x, y });
|
|
296
|
+
handle.camera.set_zoom(z, pivot_screen?);
|
|
297
|
+
handle.camera.set_transform(t); // idempotent — no notify when t === current
|
|
298
|
+
|
|
299
|
+
handle.camera.fit("<root>"); // fit the document into the viewport
|
|
300
|
+
handle.camera.fit("<selection>"); // fit current selection
|
|
301
|
+
handle.camera.fit(nodeId);
|
|
302
|
+
handle.camera.fit(rect, { margin: 64 });
|
|
303
|
+
handle.camera.reset(); // identity
|
|
304
|
+
|
|
305
|
+
handle.camera.subscribe(cb): Unsubscribe; // transient channel — no state.version bump
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
`set_transform` is **idempotent by contract**: when the new transform is element-wise equal to the current, the call is a no-op (no notification fires). This is what makes constraints terminate in finite steps and what lets host-side "subscribe → derive → set" loops converge without recursion.
|
|
309
|
+
|
|
310
|
+
Default behavior: **identity on attach**. Pass `fit: true` to `attach_dom_surface(...)` and the camera fits `"<root>"` on the first frame — Excalidraw's `initialData.scrollToContent: true`, but on the surface. Subsequent `editor.load()` calls do **not** re-fit; that's a host concern. Use `editor.state.load_version` (the "fresh document" signal, [see State](#observation--state)) as the trigger — it bumps once per `editor.load()` and is stable across edits:
|
|
311
|
+
|
|
312
|
+
```ts
|
|
313
|
+
editor.subscribe_with_selector(
|
|
314
|
+
(s) => s.load_version,
|
|
315
|
+
() => handle.camera.fit("<root>")
|
|
316
|
+
);
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
#### Constraints
|
|
320
|
+
|
|
321
|
+
```ts
|
|
322
|
+
handle.camera.constraints = {
|
|
323
|
+
type: "cover", // bounds cover viewport (keynote / slide UX)
|
|
324
|
+
bounds: "<root>", // or an explicit Rect
|
|
325
|
+
padding: 80, // screen-pixel breathing room
|
|
326
|
+
};
|
|
327
|
+
handle.camera.constraints = null; // clear
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
A typed viewport clamp, evaluated synchronously inside every `set_transform` call. v1.1 ships one variant, `type: 'cover'`: bounds cover the viewport edge-to-edge — zoom lower-bounded at fit-with-padding, pan clamped so the user can't see past the bounds. CSS analogy: `object-fit: cover` applied to the bounds rect.
|
|
331
|
+
|
|
332
|
+
The discriminator (`type`) is a tagged union for forward compatibility — future variants (`'contain'`, `'pan-region'`) will be addable without breaking existing call sites. The [keynote preset](#keynote-like-canvas-fixed-viewbox-slide-with-bounded-camera) is built on this primitive.
|
|
333
|
+
|
|
334
|
+
#### Gestures
|
|
335
|
+
|
|
336
|
+
`handle.gestures` is sibling to `editor.keymap` — a layer of installable bindings. The default set is bundled on attach:
|
|
337
|
+
|
|
338
|
+
| `id` | trigger | effect |
|
|
339
|
+
| ------------------ | --------------------------------- | -------------------------------- |
|
|
340
|
+
| `wheel-pan-zoom` | plain wheel | `camera.pan(delta)` |
|
|
341
|
+
| `wheel-pan-zoom` | Ctrl/Cmd + wheel, native pinch | `camera.zoom_at(...)` at cursor |
|
|
342
|
+
| `space-drag-pan` | Space-down + drag | hand-tool pan |
|
|
343
|
+
| `middle-mouse-pan` | middle-button drag | pan |
|
|
344
|
+
| `keyboard-zoom` | `Shift+0` / `Shift+1` / `Shift+2` | reset / fit root / fit selection |
|
|
345
|
+
| `keyboard-zoom` | `Cmd/Ctrl + =` / `Cmd/Ctrl + -` | zoom in / out |
|
|
346
|
+
|
|
347
|
+
Swap as a unit (`attach_dom_surface(editor, { container, gestures: false })`) then call `handle.gestures.bind({ id, install: ctx => uninstall })` à la carte. **No per-gesture options bag** — if you disagree with a default, unbind it and bind your own. Same discipline as `editor.keymap`.
|
|
348
|
+
|
|
349
|
+
#### `svg-boundary ≠ editor boundary`
|
|
350
|
+
|
|
351
|
+
The SVG's intrinsic `width` / `height` / `viewBox` are _content_, not viewport. The camera frames space; the SVG sits in that space. A 1920×1080 attachment is fully serviced by `camera.fit("<root>")` + container CSS for the unbounded case, or by `camera.constraints = { type: 'cover', bounds: '<root>', padding }` for the slide case. There is no first-class "stage" concept; the constraint is the layer where bounded-canvas UX is expressed.
|
|
352
|
+
|
|
174
353
|
### Lifecycle
|
|
175
354
|
|
|
176
355
|
```ts
|
|
@@ -202,6 +381,8 @@ editor.state: {
|
|
|
202
381
|
readonly version: number; // bumps on every emit (selection, mutation, history)
|
|
203
382
|
readonly structure_version: number; // bumps only on tree-shape / display-label changes;
|
|
204
383
|
// stable across pure attribute writes
|
|
384
|
+
readonly load_version: number; // bumps once per editor.load(svg) call; starts at 0;
|
|
385
|
+
// the right "fresh document" signal — stable across edits
|
|
205
386
|
};
|
|
206
387
|
|
|
207
388
|
editor.subscribe(fn: (state: EditorState) => void): Unsubscribe;
|
|
@@ -597,16 +778,18 @@ import {
|
|
|
597
778
|
useSvgEditor,
|
|
598
779
|
useEditorState,
|
|
599
780
|
useCommands,
|
|
781
|
+
useCameraSnapshot,
|
|
600
782
|
} from "@grida/svg-editor/react";
|
|
601
783
|
```
|
|
602
784
|
|
|
603
785
|
That's the whole public surface.
|
|
604
786
|
|
|
605
787
|
- `SvgEditorProvider` — owns the headless editor, puts it in context.
|
|
606
|
-
- `SvgEditorCanvas` — the only UI component we ship; internally calls `attach_dom_surface(editor, { container: div })` on mount and `detach()` on unmount.
|
|
788
|
+
- `SvgEditorCanvas` — the only UI component we ship; internally calls `attach_dom_surface(editor, { container: div, gestures, fit, initial_camera })` on mount and `detach()` on unmount. Pass `onAttach={setHandle}` to receive the `DomSurfaceHandle` (for `handle.camera` / `handle.gestures`).
|
|
607
789
|
- `useSvgEditor()` — returns the editor instance from context.
|
|
608
|
-
- `useEditorState(selector, equals?)` — subscribes to a slice of `editor.state` and re-renders on change.
|
|
790
|
+
- `useEditorState(selector, equals?)` — subscribes to a slice of `editor.state` and re-renders on change.
|
|
609
791
|
- `useCommands()` — sugar for `useSvgEditor().commands`.
|
|
792
|
+
- `useCameraSnapshot(handle, selector, fallback)` — sibling to `useEditorState`, for the camera channel. Returns the selected value and re-renders on camera mutation; uses `fallback` while `handle` is null. The recipe lives in the package because both demos wrote it identically (see `/canvas/svg` and `/canvas/svg/keynote`).
|
|
610
793
|
|
|
611
794
|
Top-level wiring:
|
|
612
795
|
|
|
@@ -790,6 +973,28 @@ The `@grida/keybinding` package provides the `Keybinding` type, `kb()` / `seq()`
|
|
|
790
973
|
|
|
791
974
|
Anything that earns enough use to be a stable primitive graduates out of this section into the high-level API. Anything we add but later regret stays here under a deprecation marker until it can be removed.
|
|
792
975
|
|
|
976
|
+
## Presets
|
|
977
|
+
|
|
978
|
+
```ts
|
|
979
|
+
import { keynote } from "@grida/svg-editor/presets";
|
|
980
|
+
|
|
981
|
+
const handle = keynote.attach(editor, { container, padding: 80 });
|
|
982
|
+
// later: handle.set_padding(0); // present-mode toggle
|
|
983
|
+
// handle.detach();
|
|
984
|
+
```
|
|
985
|
+
|
|
986
|
+
Presets are **opinionated bundles** that compose the public primitives (`attach_dom_surface`, `camera.constraints`, `load_version`, etc.) into one-import setups for common UX shapes. They live at the **`@grida/svg-editor/presets`** subpath — an explicit opt-in. The main `@grida/svg-editor` entry never references this subpath, so hosts that don't want a preset don't pay for it.
|
|
987
|
+
|
|
988
|
+
**v1.1 ships one preset:**
|
|
989
|
+
|
|
990
|
+
- **`keynote`** — slide-shaped canvas. Attaches the DOM surface with `fit: true`, installs `camera.constraints = { type: 'cover', bounds: '<root>', padding }`, subscribes to `editor.state.load_version` for refit-on-load. Returns a `KeynoteSurfaceHandle = DomSurfaceHandle & { set_padding(p): void }` — the `set_padding` method swaps the constraint padding at runtime (use for "Present mode" toggles).
|
|
991
|
+
|
|
992
|
+
The preset's source ([`src/presets/keynote.ts`](https://github.com/gridaco/grida/blob/main/packages/grida-svg-editor/src/presets/keynote.ts)) is ≤ 70 lines of pure composition over the public package surface — no `_internal` reach, no private coupling. If you need a different shape, copy the file and modify.
|
|
993
|
+
|
|
994
|
+
**Discipline.** Code in `src/presets/` is allowed to import only from `@grida/svg-editor` / `@grida/svg-editor/dom` / `@grida/svg-editor/react` and third-party packages — never from `src/core/`, `src/commands/`, `src/keymap/`, or `src/gestures/`. This means every preset is composable against what an external consumer has access to: if a preset works, the same composition works for any host.
|
|
995
|
+
|
|
996
|
+
A second preset graduates when a second use case asks for one (`slidedeck`, `sticker`, `canvas`, …) — discovery-loop discipline.
|
|
997
|
+
|
|
793
998
|
## Deferred for v1
|
|
794
999
|
|
|
795
1000
|
What v1 explicitly doesn't ship. Each is documented elsewhere with the v1 workaround.
|
|
@@ -803,6 +1008,9 @@ What v1 explicitly doesn't ship. Each is documented elsewhere with the v1 workar
|
|
|
803
1008
|
- **Non-DOM surfaces** (worker, React Native, headless test harness).
|
|
804
1009
|
- **Paint-server validity warnings** (dangling `url(#id)` references).
|
|
805
1010
|
- **Rotation gesture in the HUD.**
|
|
1011
|
+
- **Persisted camera state.** Camera is surface-scoped and never enters `editor.state` / `editor.serialize()` / history. Hosts that want view bookmarks persist `handle.camera.transform` themselves.
|
|
1012
|
+
- **Gesture momentum / inertia / animated `fit`.** The `animate` shape isn't reserved in the type — it'll be added when delivered, not before.
|
|
1013
|
+
- **`CameraConstraints` variants beyond `'cover'`.** v1.1 ships `type: 'cover'` only (bounds cover viewport — slide / keynote UX). The discriminator is a tagged union so future variants land as additive arms: `type: 'contain'` (bounds always fully visible inside viewport — bounded artwork) and `type: 'pan-region'` (d3-zoom `translateExtent` style — pan clamped to a region with free zoom) are reserved names but not yet implemented. Peer-validated direction: tldraw's `TLCameraConstraints.behavior: 'inside' | 'outside'`, mapped to CSS-style `'cover'` / `'contain'` naming.
|
|
806
1014
|
|
|
807
1015
|
## Anti-goals
|
|
808
1016
|
|
|
@@ -820,7 +1028,7 @@ If a consumer needs any of the above, the right answer is "this is the wrong too
|
|
|
820
1028
|
|
|
821
1029
|
## Status
|
|
822
1030
|
|
|
823
|
-
`v1.0.0-alpha.
|
|
1031
|
+
`v1.0.0-alpha.4` — selection, translate, paint editing (solid + gradient), gradient defs, history, reorder, remove, set_text, keyboard shortcuts, **surface-scoped camera** (pan / zoom / fit with idempotent `set_transform`), **gestures layer** sibling to `editor.keymap` (wheel-pan-zoom, space-drag, middle-mouse-drag, keyboard zoom), **typed `camera.constraints`** (`'cover'` variant, peer-validated tagged union), **`editor.state.load_version`** (fresh-document signal distinct from `structure_version`), and the **`@grida/svg-editor/presets`** subpath shipping `keynote.attach` for slide-shaped SVGs.
|
|
824
1032
|
|
|
825
1033
|
Round-trip fidelity (P1) is the design invariant; the v1 surface is deliberately minimal and the [Low-level API](#low-level-api) is the escape hatch when the high-level API doesn't yet cover what you need.
|
|
826
1034
|
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
//#region \0rolldown/runtime.js
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __exportAll = (all, no_symbols) => {
|
|
4
|
+
let target = {};
|
|
5
|
+
for (var name in all) __defProp(target, name, {
|
|
6
|
+
get: all[name],
|
|
7
|
+
enumerable: true
|
|
8
|
+
});
|
|
9
|
+
if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
|
|
10
|
+
return target;
|
|
11
|
+
};
|
|
12
|
+
//#endregion
|
|
13
|
+
export { __exportAll as t };
|