@temporeum/timeline-vue 0.0.0-stage → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md ADDED
@@ -0,0 +1,12 @@
1
+ # Changelog
2
+
3
+ ## 1.0.0 — 2026-11-07
4
+
5
+ The first release, on 1.0.0 of `@temporeum/timeline-element`. From here on the package follows [semantic versioning](https://horakdani.github.io/Temporeum_timeline_SDK/stability.html).
6
+
7
+ - `<Timeline>` and `useTimelineState` for Vue 3: every `TimelineConfig` field as a declared, typed prop (`TimelineProps<T>`, generic over the items' data; a bare boolean attribute is `true`, a reactive value reaches the instance as the plain object), every instance event as an emit (`TIMELINE_EVENTS` of the element), `ready` with the instance.
8
+ - `registerPlugin` and `hasPlugin` (and the `TimelinePlugin` type) are handed on from `@temporeum/timeline-element`, so an app that installs only the adapter registers the plugins it needs; the element is a `^1.0.0` dependency.
9
+ - The view and the selection are defaults — `defaultDomain` and `defaultSelectedIds` — and stay where the reader moved them on a re-render; the instance's `zoomTo` and `select` move them. Every other field is compared by what it says: an option object written anew on each render is no change, and a drag in progress goes on.
10
+ - Server-rendered by Vue's own renderer (Nuxt included) and hydrated without a second drawing.
11
+ - Options that need a plugin of the element (`gantt`, `resources`, the time tools, `groups`, the item kinds, `strings`, `calendar`, `direction`) need it registered once for the page, with `registerPlugin` from `@temporeum/timeline-element` — in the app's entry, before the first timeline, and where the server renders too. Without it the configuration throws, naming the import.
12
+ - The `#item` slot: each item's content as Vue, teleported into the box over the item — it keeps its state while the item is drawn, and is unmounted when it leaves the view. Needs the element's `/items` plugin, registered once.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Daniel Horak and contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,135 @@
1
- # Temporary Holding Version
1
+ # @temporeum/timeline-vue
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ The timeline as a Vue component, built on the shared instance of
4
+ [`@temporeum/timeline-element`](https://github.com/horakdani/Temporeum_timeline_SDK/tree/main/packages/web-component#readme).
5
+
6
+ ```bash
7
+ npm install @temporeum/timeline-vue @temporeum/timeline-element
8
+ ```
9
+
10
+ The element is the adapter's own dependency; list it beside the adapter, as
11
+ above, to import its plugins (`@temporeum/timeline-element/items`, `/gantt`,
12
+ `/resources` …): pnpm and Yarn PnP let an app import only what it lists. The
13
+ types an app writes — `Item`, `Lane`, `Group`, `TimeMs` and every event's
14
+ payload (`ItemMovedPayload`, `SelectionChangedPayload` …) — come from
15
+ `@temporeum/timeline-vue` itself.
16
+
17
+ The peer range is `vue ^3.5.0` (`useId` is new in 3.5). The suite runs on
18
+ the newest Vue 3 and, in CI, on 3.5.0, the lowest the range admits.
19
+
20
+ ```vue excerpt:template/vue/src/App.vue
21
+ <script setup>
22
+ import { Timeline, useTimelineState } from "@temporeum/timeline-vue";
23
+ import { ref, shallowRef } from "vue";
24
+
25
+ const DAY = 86_400_000;
26
+ const t = Date.UTC(2026, 2, 2);
27
+ const items = [
28
+ { id: "design", label: "Design", laneId: "work", start: t, end: t + 7 * DAY, data: { owner: "Ana" } },
29
+ { id: "launch", label: "Launch", laneId: "ship", start: t + 25 * DAY, end: t + 32 * DAY, data: { owner: "Dev" } },
30
+ ];
31
+ const lanes = [
32
+ { id: "work", label: "Work" },
33
+ { id: "ship", label: "Shipping" },
34
+ ];
35
+
36
+ const timeline = shallowRef(null);
37
+ const selected = useTimelineState(timeline, (state) => state.selectedIds);
38
+ const log = ref("Drag an item.");
39
+ const onMoved = ({ item, to }) => {
40
+ log.value = `${item.label} moved to ${new Date(to.start ?? item.start).toDateString()}`;
41
+ };
42
+ </script>
43
+
44
+ <template>
45
+ <main style="padding: 16px">
46
+ <Timeline
47
+ :items="items"
48
+ :lanes="lanes"
49
+ :height="320"
50
+ aria-label="Release plan"
51
+ :editing="{ enabled: true, snapMs: DAY }"
52
+ @item-moved="onMoved"
53
+ @ready="timeline = $event"
54
+ >
55
+ <!-- An item's content as Vue: a picture of the item, its label still its name. -->
56
+ <template #item="{ item }">
57
+ <b>{{ item.label }}</b> · {{ item.data.owner }}
58
+ </template>
59
+ </Timeline>
60
+ <p aria-live="polite">{{ log }} {{ selected?.length ?? 0 }} selected.</p>
61
+ </main>
62
+ </template>
63
+ ```
64
+
65
+ The `#item` slot needs the element's `/items` plugin, as `template` does:
66
+ register it once, before the first timeline — without it the timeline
67
+ throws on mount, naming the import.
68
+
69
+ ```js excerpt:template/vue/src/main.js
70
+ import { registerPlugin } from "@temporeum/timeline-element";
71
+ import { itemsPlugin } from "@temporeum/timeline-element/items";
72
+ // …
73
+ registerPlugin(itemsPlugin);
74
+ ```
75
+
76
+ The whole project, with Vite, is the [Vue template](https://github.com/horakdani/Temporeum_timeline_SDK/tree/main/packages/docs/templates/vue); a
77
+ [Nuxt one](https://github.com/horakdani/Temporeum_timeline_SDK/tree/main/packages/docs/templates/nuxt) is beside it.
78
+
79
+ Every [`TimelineConfig`](https://horakdani.github.io/Temporeum_timeline_SDK/reference/api.html#configuration) field is a typed
80
+ prop — in camelCase or kebab-case, `:time-zone` is `timeZone`, and a bare
81
+ `lane-headers` is `true`; `class`, `style`, `id` and other attributes go on
82
+ the box —
83
+ and every instance event an emit by its own name (`@item-moved`,
84
+ `@selection-changed`, `@viewport-changed`, …). `@ready` hands over the live
85
+ instance, and `null` on unmount; a template ref's `timeline` is the same
86
+ instance.
87
+
88
+ The view and the selection are where the timeline starts:
89
+ `:default-domain` and `:default-selected-ids`. A re-render does not move
90
+ them back; the instance's `zoomTo` and `select` do. Every other attribute
91
+ is compared by what it says, so an `:editing="{ enabled: true }"` object
92
+ written anew on each render is no change.
93
+
94
+ ## It does not re-render to draw
95
+
96
+ The component creates the instance once, on mount, and hands it the
97
+ attributes that changed — the same `items` array is not new data. A pan, a
98
+ pinch, a drag are drawn by the instance, imperatively; Vue does not hear of
99
+ them. What a component renders from is the instance's store:
100
+ `useTimelineState(timeline, selector, isEqual?)` gives a shallow ref that
101
+ changes when the selected part does, and at most once per drawn frame,
102
+ however many pointer events the frame held. `timeline` may be a ref, a
103
+ getter (`() => view.value?.timeline`) or the instance.
104
+
105
+ ## Server rendering
106
+
107
+ On the server — Nuxt, or `renderToString` of your own — the component prints
108
+ the drawing the browser would draw, at `ssr-width` (960 px by default), and
109
+ on hydration the instance takes those nodes over instead of drawing again.
110
+ Nothing else is needed: no client plugin, no compiler option.
111
+
112
+ ```vue excerpt:template/nuxt/app/app.vue
113
+ <template>
114
+ <main>
115
+ <Timeline :items="items" :lanes="lanes" :height="320" aria-label="Release plan" :ssr-width="960" />
116
+ </main>
117
+ </template>
118
+ ```
119
+
120
+ The drawing goes into the server's markup only. Vue 3.5 writes a dynamic
121
+ `innerHTML` again while hydrating, and an `innerHTML` written by script is a
122
+ second drawing, not the parser's first; on the client the component's node
123
+ has no children for Vue to compare, so Vue leaves alone what the parser
124
+ built.
125
+
126
+ ## Documentation
127
+
128
+ Guides, recipes and the API reference with live examples are on the
129
+ [docs site](https://horakdani.github.io/Temporeum_timeline_SDK/) — the Vue page is [Frameworks](https://horakdani.github.io/Temporeum_timeline_SDK/frameworks.html). Every
130
+ code block in this README is checked against a running template in CI
131
+ (`npm run test:examples -w @temporeum/timeline-docs`).
132
+
133
+ ## Licence
134
+
135
+ MIT
package/dist/index.cjs ADDED
@@ -0,0 +1,266 @@
1
+ /*! @temporeum/timeline-vue | MIT */
2
+ 'use strict';
3
+
4
+ var timelineElement = require('@temporeum/timeline-element');
5
+ var vue = require('vue');
6
+
7
+ /**
8
+ * `@temporeum/timeline-vue` — the timeline as a Vue component.
9
+ *
10
+ * The component is a shell around the shared instance (`createTimeline`,
11
+ * from `@temporeum/timeline-element`), as the React one is: it creates the
12
+ * instance once, on mount, hands it every attribute that changed, and lets
13
+ * go of it on unmount. It does not re-render to draw. A pan of a hundred
14
+ * pointer events is drawn by the instance, imperatively, and Vue does not
15
+ * hear of it — its reactivity is the wrong tool for sixty frames a second of
16
+ * SVG attributes.
17
+ *
18
+ * What a component *does* render from is the instance's store.
19
+ * `useTimelineState` subscribes to it with a selector and gives a shallow
20
+ * ref: one that shows the selection changes when the selection changes and
21
+ * at no other time; one that shows the visible range changes once per drawn
22
+ * frame at most, however many events the frame held.
23
+ *
24
+ * **Server rendering.** On the server the component prints the same drawing
25
+ * the browser would draw (the core is DOM-free), so the page shows a
26
+ * timeline before the bundle loads; on hydration the instance takes those
27
+ * nodes over. The drawing goes into the server's markup only: Vue 3.5
28
+ * writes a dynamic `innerHTML` again while hydrating, and an `innerHTML`
29
+ * written by script is not the parser's — the instance would draw a second
30
+ * timeline. On the client the node has no children for Vue to compare, so
31
+ * Vue leaves alone what the parser built.
32
+ */
33
+ /**
34
+ * A prop that may be written as a bare attribute (`<Timeline lane-headers />`)
35
+ * is a boolean first: Vue reads the empty string as `true` for it. The rest
36
+ * take any value, and an absent one is `undefined` — not in the
37
+ * configuration, so the instance's default holds.
38
+ */
39
+ const ANY = { type: null, default: undefined };
40
+ const FLAG = { type: Boolean, default: undefined };
41
+ const PROPS = {
42
+ items: ANY,
43
+ lanes: ANY,
44
+ groups: ANY,
45
+ template: ANY,
46
+ templateOptions: ANY,
47
+ slots: { type: [Boolean, Function], default: undefined },
48
+ gantt: ANY,
49
+ resources: ANY,
50
+ resourceOptions: ANY,
51
+ defaultDomain: ANY,
52
+ limits: ANY,
53
+ orientation: ANY,
54
+ breakpoint: ANY,
55
+ density: ANY,
56
+ metrics: ANY,
57
+ packMode: ANY,
58
+ theme: ANY,
59
+ locale: ANY,
60
+ timeZone: ANY,
61
+ formatTick: ANY,
62
+ axisContext: FLAG,
63
+ touchAction: ANY,
64
+ maxLabels: ANY,
65
+ labelOverflow: ANY,
66
+ ariaLabel: ANY,
67
+ decorations: ANY,
68
+ cluster: { type: [Boolean, Object], default: undefined },
69
+ hooks: ANY,
70
+ height: ANY,
71
+ interactions: ANY,
72
+ editing: ANY,
73
+ defaultSelectedIds: ANY,
74
+ instanceId: ANY,
75
+ nonce: ANY,
76
+ measureText: ANY,
77
+ sceneSpace: { type: [Boolean, String], default: undefined },
78
+ hiddenDates: ANY,
79
+ timeBars: ANY,
80
+ timeBarOptions: ANY,
81
+ rolling: { type: [Boolean, Object], default: undefined },
82
+ zoomPresets: { type: [Boolean, Array], default: undefined },
83
+ minimap: { type: [Boolean, Object], default: undefined },
84
+ rangeSelect: { type: [Boolean, Object], default: undefined },
85
+ laneHeaders: FLAG,
86
+ tooltip: { type: [Boolean, Function], default: undefined },
87
+ direction: ANY,
88
+ strings: ANY,
89
+ calendar: ANY,
90
+ ssrWidth: { type: Number, default: undefined },
91
+ };
92
+ /** Where the view and the selection start, and the server's width: said once, not configuration that changes. */
93
+ const OWN = new Set(["ssrWidth", "defaultDomain", "defaultSelectedIds"]);
94
+ /** `useId` gives `v-0` or `v:0`; a stylesheet scope wants a plain name. */
95
+ const scopeOf = (id) => `tl${id.replace(/[^a-zA-Z0-9_-]/g, "")}`;
96
+ /**
97
+ * The configuration part of the props: the ones given, as plain values. A
98
+ * reactive array or object the host passes is Vue's proxy of it; the
99
+ * instance holds the object itself, so its identity is the host's and the
100
+ * frames do not go through the proxy.
101
+ */
102
+ function configOf(props, scope) {
103
+ const config = {};
104
+ for (const key of Object.keys(PROPS)) {
105
+ const value = props[key];
106
+ if (!OWN.has(key) && value !== undefined)
107
+ config[key] = vue.toRaw(value);
108
+ }
109
+ // Light DOM: two timelines on one page must not share one stylesheet.
110
+ if (config.instanceId === undefined)
111
+ config.instanceId = scope;
112
+ return config;
113
+ }
114
+ /** The keys whose values are not the same object: an unchanged `items` array must not look like new data. */
115
+ function changedOf(before, next) {
116
+ const changed = {};
117
+ let any = false;
118
+ for (const key of new Set([...Object.keys(before), ...Object.keys(next)])) {
119
+ if (key !== "__proto__" && before[key] !== next[key]) {
120
+ changed[key] = next[key];
121
+ any = true;
122
+ }
123
+ }
124
+ return any ? changed : undefined;
125
+ }
126
+ /**
127
+ * The timeline. Every {@link TimelineConfig} field is a prop (`:items`,
128
+ * `:time-zone` or `:timeZone`, a bare `lane-headers`), every instance event
129
+ * an emit (`@item-moved`, `@selection-changed`, …), and `ready` hands over
130
+ * the live instance; a template ref's `timeline` is the same instance.
131
+ * `class`, `style`, `id` and the rest of the attributes go on the box.
132
+ *
133
+ * The `#item` slot (`<template #item="{ item }">`) is each item's content
134
+ * as Vue, teleported into the box over the item (`slots`): only the items
135
+ * drawn have one. The content is a picture — the pointer and the keyboard
136
+ * act on the item, and its `label` stays its accessible name. Needs the
137
+ * `/items` plugin, as `template` does.
138
+ */
139
+ const Timeline = vue.defineComponent((props, { emit, expose, slots }) => {
140
+ // Vue 3.5.0 types useId() as possibly undefined (outside a setup); here it is in one.
141
+ const scope = scopeOf(vue.useId() ?? "");
142
+ const container = vue.ref(null);
143
+ const timeline = vue.shallowRef(null);
144
+ const drawn = vue.shallowRef(new Map());
145
+ // With an `#item` slot every item has a box, unless `slots` picks.
146
+ const configNow = () => {
147
+ const config = configOf(props, scope);
148
+ if (slots.item !== undefined && config.slots === undefined)
149
+ config.slots = true;
150
+ return config;
151
+ };
152
+ let applied = configNow();
153
+ const initial = {
154
+ ...applied,
155
+ ...(props.defaultDomain === undefined ? {} : { domain: vue.toRaw(props.defaultDomain) }),
156
+ ...(props.defaultSelectedIds === undefined ? {} : { selectedIds: vue.toRaw(props.defaultSelectedIds) }),
157
+ };
158
+ // The server's drawing, computed once — on the server only: Vue's
159
+ // server renderer is what provides an SSR context.
160
+ const html = vue.inject(vue.ssrContextKey, null) !== null
161
+ ? (() => {
162
+ const frame = timelineElement.renderTimelineSvg(initial, props.ssrWidth === undefined ? {} : { width: props.ssrWidth });
163
+ return frame.svg + frame.groups;
164
+ })()
165
+ : undefined;
166
+ let stops = [];
167
+ vue.onMounted(() => {
168
+ const instance = timelineElement.createTimeline(container.value, { ...initial, ...applied }, { hydrate: true });
169
+ stops = timelineElement.TIMELINE_EVENTS.map((type) => instance.on(type, (payload) => forward(emit, type, payload)));
170
+ // Vue renders the teleports in its own flush, a microtask after the
171
+ // frame that drew the boxes: before the browser paints it.
172
+ stops.push(instance.on("slotsChanged", ({ slots: next }) => (drawn.value = next)));
173
+ drawn.value = instance.slots;
174
+ timeline.value = instance;
175
+ emit("ready", instance);
176
+ });
177
+ // Hand the instance what changed, and only that.
178
+ vue.onUpdated(() => {
179
+ const next = configNow();
180
+ const changed = changedOf(applied, next);
181
+ applied = next;
182
+ if (changed !== undefined)
183
+ timeline.value?.update(changed);
184
+ });
185
+ vue.onBeforeUnmount(() => {
186
+ for (const stop of stops)
187
+ stop();
188
+ stops = [];
189
+ timeline.value?.destroy();
190
+ timeline.value = null;
191
+ emit("ready", null);
192
+ });
193
+ expose({ timeline });
194
+ return () => {
195
+ const height = props.height ?? timelineElement.DEFAULT_HEIGHT;
196
+ const item = slots.item;
197
+ const teleports = item === undefined ? [] : [...drawn.value].map(([id, slot]) => vue.h(vue.Teleport, { key: id, to: slot.element }, item({ item: slot.item })));
198
+ // The teleports are the box's children, as anchors: one root, so the
199
+ // server's markup stays the box alone. Without a teleport the box has
200
+ // no children for Vue — on the server it has the drawing, and while
201
+ // hydrating Vue must not compare the instance's nodes with any. The
202
+ // host's class, style and attributes fall through onto the box.
203
+ return vue.h("div", {
204
+ ref: container,
205
+ style: { position: "relative", overflow: "hidden", height: `${String(height)}px` },
206
+ "data-tl-vue": "",
207
+ ...(html === undefined ? {} : { innerHTML: html }),
208
+ }, html === undefined && teleports.length > 0 ? teleports : undefined);
209
+ };
210
+ }, {
211
+ name: "TemporeumTimeline",
212
+ // The runtime declaration; the types are the setup function's, generic over the items' data.
213
+ props: PROPS,
214
+ emits: [...timelineElement.TIMELINE_EVENTS, "ready"],
215
+ slots: Object,
216
+ });
217
+ /** One instance event, emitted under its own name: the payload is that event's. */
218
+ function forward(emit, type, payload) {
219
+ emit(type, payload);
220
+ }
221
+ /**
222
+ * Subscribe to the part of the instance's state a component renders.
223
+ *
224
+ * The ref changes when `selector`'s result changes (by `isEqual`,
225
+ * `Object.is` by default) — and at most once per drawn frame, because the
226
+ * store notifies at most once per frame. `undefined` until there is an
227
+ * instance; `timeline` may be a ref, a getter (`() => view.value?.timeline`)
228
+ * or the instance itself.
229
+ */
230
+ function useTimelineState(timeline, selector, isEqual = Object.is) {
231
+ const state = vue.shallowRef(undefined);
232
+ vue.watch(() => vue.toValue(timeline), (instance, _, onCleanup) => {
233
+ if (instance === null || instance === undefined) {
234
+ state.value = undefined;
235
+ return;
236
+ }
237
+ let seen;
238
+ const read = () => {
239
+ const snapshot = instance.getSnapshot();
240
+ if (seen !== undefined && seen.snapshot === snapshot)
241
+ return;
242
+ const selected = selector(snapshot);
243
+ if (seen !== undefined && isEqual(seen.selected, selected)) {
244
+ seen = { snapshot, selected: seen.selected };
245
+ return;
246
+ }
247
+ seen = { snapshot, selected };
248
+ state.value = selected;
249
+ };
250
+ read();
251
+ onCleanup(instance.subscribe(read));
252
+ }, { immediate: true });
253
+ return state;
254
+ }
255
+
256
+ Object.defineProperty(exports, "hasPlugin", {
257
+ enumerable: true,
258
+ get: function () { return timelineElement.hasPlugin; }
259
+ });
260
+ Object.defineProperty(exports, "registerPlugin", {
261
+ enumerable: true,
262
+ get: function () { return timelineElement.registerPlugin; }
263
+ });
264
+ exports.Timeline = Timeline;
265
+ exports.useTimelineState = useTimelineState;
266
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs","sources":["../src/index.ts"],"sourcesContent":["/**\n * `@temporeum/timeline-vue` — the timeline as a Vue component.\n *\n * The component is a shell around the shared instance (`createTimeline`,\n * from `@temporeum/timeline-element`), as the React one is: it creates the\n * instance once, on mount, hands it every attribute that changed, and lets\n * go of it on unmount. It does not re-render to draw. A pan of a hundred\n * pointer events is drawn by the instance, imperatively, and Vue does not\n * hear of it — its reactivity is the wrong tool for sixty frames a second of\n * SVG attributes.\n *\n * What a component *does* render from is the instance's store.\n * `useTimelineState` subscribes to it with a selector and gives a shallow\n * ref: one that shows the selection changes when the selection changes and\n * at no other time; one that shows the visible range changes once per drawn\n * frame at most, however many events the frame held.\n *\n * **Server rendering.** On the server the component prints the same drawing\n * the browser would draw (the core is DOM-free), so the page shows a\n * timeline before the bundle loads; on hydration the instance takes those\n * nodes over. The drawing goes into the server's markup only: Vue 3.5\n * writes a dynamic `innerHTML` again while hydrating, and an `innerHTML`\n * written by script is not the parser's — the instance would draw a second\n * timeline. On the client the node has no children for Vue to compare, so\n * Vue leaves alone what the parser built.\n */\n\nimport { createTimeline, DEFAULT_HEIGHT, renderTimelineSvg, TIMELINE_EVENTS } from \"@temporeum/timeline-element\";\nimport type {\n ItemSlot,\n Timeline as TimelineInstance,\n TimelineComponentConfig,\n TimelineConfig,\n TimelineInstanceEventMap,\n TimelineInstanceEventName,\n TimelineSnapshot,\n TimelineUpdate,\n} from \"@temporeum/timeline-element\";\nimport { defineComponent, h, inject, onBeforeUnmount, onMounted, onUpdated, ref, shallowRef, ssrContextKey, Teleport, toRaw, toValue, useId, watch } from \"vue\";\nimport type {\n AllowedComponentProps,\n ComponentCustomProps,\n ComponentOptionsMixin,\n CreateComponentPublicInstanceWithMixins,\n MaybeRefOrGetter,\n PublicProps,\n SetupContext,\n ShallowRef,\n SlotsType,\n VNodeProps,\n} from \"vue\";\n\nexport type { TimelineComponentConfig, TimelineConfig, TimelineSnapshot } from \"@temporeum/timeline-element\";\n/** The element's plugin registry, from the adapter too: an app that installs only the adapter still registers the plugins its configuration needs. */\n// The data and the event payloads, handed on: one install types an app.\nexport type {\n ClusterOpenedPayload,\n Command,\n CommandPayload,\n DensityChangedPayload,\n Domain,\n Group,\n GroupMovedPayload,\n GroupToggledPayload,\n HoverPayload,\n InputSkippedPayload,\n Item,\n ItemEventPayload,\n ItemMovedPayload,\n ItemPatch,\n ItemResizedPayload,\n ItemsAddedPayload,\n ItemsChangedPayload,\n ItemsRemovedPayload,\n JumpRequestPayload,\n Lane,\n LayoutChangedPayload,\n OrientationChangedPayload,\n SelectionChangedPayload,\n SlotsChangedPayload,\n TimeBar,\n TimeBarMovedPayload,\n TimelineInstanceEventMap,\n TimelineInstanceEventName,\n TimeMs,\n TimeRange,\n ViewportChangedPayload,\n} from \"@temporeum/timeline-element\";\nexport { hasPlugin, registerPlugin } from \"@temporeum/timeline-element\";\nexport type { PluginName, TimelinePlugin } from \"@temporeum/timeline-element\";\nexport type { TimelineInstance };\n\n/** What the component emits: every instance event, by its own name, and `ready` with the instance (`null` on unmount). */\nexport type TimelineEmits<T = unknown> = { readonly [K in TimelineInstanceEventName]: (payload: TimelineInstanceEventMap<T>[K]) => void } & {\n readonly ready: (timeline: TimelineInstance<T> | null) => void;\n};\n\n/** The component's props: every {@link TimelineComponentConfig} field, and the width the server draws at. */\nexport type TimelineProps<T = unknown> = TimelineComponentConfig<T> & {\n /** Width the server draws at; the client redraws at the real one. */\n readonly ssrWidth?: number | undefined;\n};\n\n/** The `#item` slot: each drawn item's content. */\nexport type TimelineSlots<T = unknown> = SlotsType<{ readonly item: { readonly item: Item<T> } }>;\n\n/** A handler prop for every event — `onItemMoved`, `onReady`, … — its payload typed by the items' data. */\nexport type TimelineListeners<T = unknown> = { readonly [K in keyof TimelineEmits<T> & string as `on${Capitalize<K>}`]?: TimelineEmits<T>[K] };\n\n/**\n * The component's type, generic over the items' data: every prop, every\n * handler and the `#item` slot typed by it, and a template ref's `timeline`.\n * Written out because Vue types the runtime `emits` list — the names — as\n * handlers of `(...args: any[]) => any`, and the options' slots as `unknown`.\n */\nexport type TimelineComponent = new <T = unknown>(\n props: TimelineProps<T> & TimelineListeners<T> & VNodeProps & AllowedComponentProps & ComponentCustomProps,\n) => CreateComponentPublicInstanceWithMixins<\n TimelineProps<T> & TimelineListeners<T>,\n { readonly timeline: TimelineInstance<T> | null },\n Record<never, never>,\n Record<never, never>,\n Record<never, never>,\n ComponentOptionsMixin,\n ComponentOptionsMixin,\n TimelineEmits<T>,\n PublicProps,\n Record<never, never>,\n false,\n Record<never, never>,\n TimelineSlots<T>\n>;\n\n/** An item, as the element's types name it (the adapter depends on the element alone). */\ntype Item<T> = ItemSlot<T>[\"item\"];\n\n/**\n * A prop that may be written as a bare attribute (`<Timeline lane-headers />`)\n * is a boolean first: Vue reads the empty string as `true` for it. The rest\n * take any value, and an absent one is `undefined` — not in the\n * configuration, so the instance's default holds.\n */\nconst ANY = { type: null, default: undefined } as const;\nconst FLAG = { type: Boolean, default: undefined } as const;\nconst PROPS: { readonly [K in keyof TimelineProps]-?: { readonly type: unknown; readonly default: undefined } } = {\n items: ANY,\n lanes: ANY,\n groups: ANY,\n template: ANY,\n templateOptions: ANY,\n slots: { type: [Boolean, Function], default: undefined },\n gantt: ANY,\n resources: ANY,\n resourceOptions: ANY,\n defaultDomain: ANY,\n limits: ANY,\n orientation: ANY,\n breakpoint: ANY,\n density: ANY,\n metrics: ANY,\n packMode: ANY,\n theme: ANY,\n locale: ANY,\n timeZone: ANY,\n formatTick: ANY,\n axisContext: FLAG,\n touchAction: ANY,\n maxLabels: ANY,\n labelOverflow: ANY,\n ariaLabel: ANY,\n decorations: ANY,\n cluster: { type: [Boolean, Object], default: undefined },\n hooks: ANY,\n height: ANY,\n interactions: ANY,\n editing: ANY,\n defaultSelectedIds: ANY,\n instanceId: ANY,\n nonce: ANY,\n measureText: ANY,\n sceneSpace: { type: [Boolean, String], default: undefined },\n hiddenDates: ANY,\n timeBars: ANY,\n timeBarOptions: ANY,\n rolling: { type: [Boolean, Object], default: undefined },\n zoomPresets: { type: [Boolean, Array], default: undefined },\n minimap: { type: [Boolean, Object], default: undefined },\n rangeSelect: { type: [Boolean, Object], default: undefined },\n laneHeaders: FLAG,\n tooltip: { type: [Boolean, Function], default: undefined },\n direction: ANY,\n strings: ANY,\n calendar: ANY,\n ssrWidth: { type: Number, default: undefined },\n};\n\n/** Where the view and the selection start, and the server's width: said once, not configuration that changes. */\nconst OWN = new Set([\"ssrWidth\", \"defaultDomain\", \"defaultSelectedIds\"]);\n\n/** `useId` gives `v-0` or `v:0`; a stylesheet scope wants a plain name. */\nconst scopeOf = (id: string): string => `tl${id.replace(/[^a-zA-Z0-9_-]/g, \"\")}`;\n\n/**\n * The configuration part of the props: the ones given, as plain values. A\n * reactive array or object the host passes is Vue's proxy of it; the\n * instance holds the object itself, so its identity is the host's and the\n * frames do not go through the proxy.\n */\nfunction configOf(props: Record<string, unknown>, scope: string): Record<string, unknown> {\n const config: Record<string, unknown> = {};\n for (const key of Object.keys(PROPS)) {\n const value = props[key];\n if (!OWN.has(key) && value !== undefined) config[key] = toRaw(value);\n }\n // Light DOM: two timelines on one page must not share one stylesheet.\n if (config.instanceId === undefined) config.instanceId = scope;\n return config;\n}\n\n/** The keys whose values are not the same object: an unchanged `items` array must not look like new data. */\nfunction changedOf(before: Record<string, unknown>, next: Record<string, unknown>): Record<string, unknown> | undefined {\n const changed: Record<string, unknown> = {};\n let any = false;\n for (const key of new Set([...Object.keys(before), ...Object.keys(next)])) {\n if (key !== \"__proto__\" && before[key] !== next[key]) {\n changed[key] = next[key];\n any = true;\n }\n }\n return any ? changed : undefined;\n}\n\n/**\n * The timeline. Every {@link TimelineConfig} field is a prop (`:items`,\n * `:time-zone` or `:timeZone`, a bare `lane-headers`), every instance event\n * an emit (`@item-moved`, `@selection-changed`, …), and `ready` hands over\n * the live instance; a template ref's `timeline` is the same instance.\n * `class`, `style`, `id` and the rest of the attributes go on the box.\n *\n * The `#item` slot (`<template #item=\"{ item }\">`) is each item's content\n * as Vue, teleported into the box over the item (`slots`): only the items\n * drawn have one. The content is a picture — the pointer and the keyboard\n * act on the item, and its `label` stays its accessible name. Needs the\n * `/items` plugin, as `template` does.\n */\nexport const Timeline: TimelineComponent = defineComponent(\n <T = unknown>(props: TimelineProps<T>, { emit, expose, slots }: SetupContext<TimelineEmits<T>, TimelineSlots>) => {\n // Vue 3.5.0 types useId() as possibly undefined (outside a setup); here it is in one.\n const scope = scopeOf(useId() ?? \"\");\n const container = ref<HTMLDivElement | null>(null);\n const timeline = shallowRef<TimelineInstance<T> | null>(null);\n const drawn = shallowRef<ReadonlyMap<string, ItemSlot<T>>>(new Map());\n // With an `#item` slot every item has a box, unless `slots` picks.\n const configNow = (): Record<string, unknown> => {\n const config = configOf(props as Record<string, unknown>, scope);\n if (slots.item !== undefined && config.slots === undefined) config.slots = true;\n return config;\n };\n let applied = configNow();\n const initial: Record<string, unknown> = {\n ...applied,\n ...(props.defaultDomain === undefined ? {} : { domain: toRaw(props.defaultDomain) }),\n ...(props.defaultSelectedIds === undefined ? {} : { selectedIds: toRaw(props.defaultSelectedIds) }),\n };\n // The server's drawing, computed once — on the server only: Vue's\n // server renderer is what provides an SSR context.\n const html =\n inject(ssrContextKey, null) !== null\n ? (() => {\n const frame = renderTimelineSvg(initial as TimelineConfig<T>, props.ssrWidth === undefined ? {} : { width: props.ssrWidth });\n return frame.svg + frame.groups;\n })()\n : undefined;\n let stops: (() => void)[] = [];\n\n onMounted(() => {\n const instance = createTimeline<T>(container.value as HTMLDivElement, { ...initial, ...applied } as TimelineConfig<T>, { hydrate: true });\n stops = TIMELINE_EVENTS.map((type) => instance.on(type, (payload) => forward(emit, type, payload)));\n // Vue renders the teleports in its own flush, a microtask after the\n // frame that drew the boxes: before the browser paints it.\n stops.push(instance.on(\"slotsChanged\", ({ slots: next }) => (drawn.value = next)));\n drawn.value = instance.slots;\n timeline.value = instance;\n emit(\"ready\", instance);\n });\n\n // Hand the instance what changed, and only that.\n onUpdated(() => {\n const next = configNow();\n const changed = changedOf(applied, next);\n applied = next;\n if (changed !== undefined) timeline.value?.update(changed as TimelineUpdate<T>);\n });\n\n onBeforeUnmount(() => {\n for (const stop of stops) stop();\n stops = [];\n timeline.value?.destroy();\n timeline.value = null;\n emit(\"ready\", null);\n });\n\n expose({ timeline });\n\n return () => {\n const height = props.height ?? DEFAULT_HEIGHT;\n const item = slots.item;\n const teleports = item === undefined ? [] : [...drawn.value].map(([id, slot]) => h(Teleport, { key: id, to: slot.element }, item({ item: slot.item })));\n // The teleports are the box's children, as anchors: one root, so the\n // server's markup stays the box alone. Without a teleport the box has\n // no children for Vue — on the server it has the drawing, and while\n // hydrating Vue must not compare the instance's nodes with any. The\n // host's class, style and attributes fall through onto the box.\n return h(\n \"div\",\n {\n ref: container,\n style: { position: \"relative\", overflow: \"hidden\", height: `${String(height)}px` },\n \"data-tl-vue\": \"\",\n ...(html === undefined ? {} : { innerHTML: html }),\n },\n html === undefined && teleports.length > 0 ? teleports : undefined,\n );\n };\n },\n {\n name: \"TemporeumTimeline\",\n // The runtime declaration; the types are the setup function's, generic over the items' data.\n props: PROPS as never,\n emits: [...TIMELINE_EVENTS, \"ready\"],\n slots: Object as TimelineSlots,\n },\n) as unknown as TimelineComponent;\n\n/** One instance event, emitted under its own name: the payload is that event's. */\nfunction forward<T, K extends TimelineInstanceEventName>(emit: SetupContext<TimelineEmits<T>>[\"emit\"], type: K, payload: TimelineInstanceEventMap<T>[K]): void {\n (emit as (type: K, payload: TimelineInstanceEventMap<T>[K]) => void)(type, payload);\n}\n\n/**\n * Subscribe to the part of the instance's state a component renders.\n *\n * The ref changes when `selector`'s result changes (by `isEqual`,\n * `Object.is` by default) — and at most once per drawn frame, because the\n * store notifies at most once per frame. `undefined` until there is an\n * instance; `timeline` may be a ref, a getter (`() => view.value?.timeline`)\n * or the instance itself.\n */\nexport function useTimelineState<T, S>(\n timeline: MaybeRefOrGetter<TimelineInstance<T> | null | undefined>,\n selector: (snapshot: TimelineSnapshot) => S,\n isEqual: (a: S, b: S) => boolean = Object.is,\n): Readonly<ShallowRef<S | undefined>> {\n const state = shallowRef<S | undefined>(undefined);\n watch(\n () => toValue(timeline),\n (instance, _, onCleanup) => {\n if (instance === null || instance === undefined) {\n state.value = undefined;\n return;\n }\n let seen: { snapshot: TimelineSnapshot; selected: S } | undefined;\n const read = (): void => {\n const snapshot = instance.getSnapshot();\n if (seen !== undefined && seen.snapshot === snapshot) return;\n const selected = selector(snapshot);\n if (seen !== undefined && isEqual(seen.selected, selected)) {\n seen = { snapshot, selected: seen.selected };\n return;\n }\n seen = { snapshot, selected };\n state.value = selected;\n };\n read();\n onCleanup(instance.subscribe(read));\n },\n { immediate: true },\n );\n return state;\n}\n"],"names":["toRaw","defineComponent","useId","ref","shallowRef","inject","ssrContextKey","renderTimelineSvg","onMounted","createTimeline","TIMELINE_EVENTS","onUpdated","onBeforeUnmount","DEFAULT_HEIGHT","h","Teleport","watch","toValue"],"mappings":"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"}
@@ -0,0 +1,90 @@
1
+ /**
2
+ * `@temporeum/timeline-vue` — the timeline as a Vue component.
3
+ *
4
+ * The component is a shell around the shared instance (`createTimeline`,
5
+ * from `@temporeum/timeline-element`), as the React one is: it creates the
6
+ * instance once, on mount, hands it every attribute that changed, and lets
7
+ * go of it on unmount. It does not re-render to draw. A pan of a hundred
8
+ * pointer events is drawn by the instance, imperatively, and Vue does not
9
+ * hear of it — its reactivity is the wrong tool for sixty frames a second of
10
+ * SVG attributes.
11
+ *
12
+ * What a component *does* render from is the instance's store.
13
+ * `useTimelineState` subscribes to it with a selector and gives a shallow
14
+ * ref: one that shows the selection changes when the selection changes and
15
+ * at no other time; one that shows the visible range changes once per drawn
16
+ * frame at most, however many events the frame held.
17
+ *
18
+ * **Server rendering.** On the server the component prints the same drawing
19
+ * the browser would draw (the core is DOM-free), so the page shows a
20
+ * timeline before the bundle loads; on hydration the instance takes those
21
+ * nodes over. The drawing goes into the server's markup only: Vue 3.5
22
+ * writes a dynamic `innerHTML` again while hydrating, and an `innerHTML`
23
+ * written by script is not the parser's — the instance would draw a second
24
+ * timeline. On the client the node has no children for Vue to compare, so
25
+ * Vue leaves alone what the parser built.
26
+ */
27
+ import type { ItemSlot, Timeline as TimelineInstance, TimelineComponentConfig, TimelineInstanceEventMap, TimelineInstanceEventName, TimelineSnapshot } from "@temporeum/timeline-element";
28
+ import type { AllowedComponentProps, ComponentCustomProps, ComponentOptionsMixin, CreateComponentPublicInstanceWithMixins, MaybeRefOrGetter, PublicProps, ShallowRef, SlotsType, VNodeProps } from "vue";
29
+ export type { TimelineComponentConfig, TimelineConfig, TimelineSnapshot } from "@temporeum/timeline-element";
30
+ /** The element's plugin registry, from the adapter too: an app that installs only the adapter still registers the plugins its configuration needs. */
31
+ export type { ClusterOpenedPayload, Command, CommandPayload, DensityChangedPayload, Domain, Group, GroupMovedPayload, GroupToggledPayload, HoverPayload, InputSkippedPayload, Item, ItemEventPayload, ItemMovedPayload, ItemPatch, ItemResizedPayload, ItemsAddedPayload, ItemsChangedPayload, ItemsRemovedPayload, JumpRequestPayload, Lane, LayoutChangedPayload, OrientationChangedPayload, SelectionChangedPayload, SlotsChangedPayload, TimeBar, TimeBarMovedPayload, TimelineInstanceEventMap, TimelineInstanceEventName, TimeMs, TimeRange, ViewportChangedPayload, } from "@temporeum/timeline-element";
32
+ export { hasPlugin, registerPlugin } from "@temporeum/timeline-element";
33
+ export type { PluginName, TimelinePlugin } from "@temporeum/timeline-element";
34
+ export type { TimelineInstance };
35
+ /** What the component emits: every instance event, by its own name, and `ready` with the instance (`null` on unmount). */
36
+ export type TimelineEmits<T = unknown> = {
37
+ readonly [K in TimelineInstanceEventName]: (payload: TimelineInstanceEventMap<T>[K]) => void;
38
+ } & {
39
+ readonly ready: (timeline: TimelineInstance<T> | null) => void;
40
+ };
41
+ /** The component's props: every {@link TimelineComponentConfig} field, and the width the server draws at. */
42
+ export type TimelineProps<T = unknown> = TimelineComponentConfig<T> & {
43
+ /** Width the server draws at; the client redraws at the real one. */
44
+ readonly ssrWidth?: number | undefined;
45
+ };
46
+ /** The `#item` slot: each drawn item's content. */
47
+ export type TimelineSlots<T = unknown> = SlotsType<{
48
+ readonly item: {
49
+ readonly item: Item<T>;
50
+ };
51
+ }>;
52
+ /** A handler prop for every event — `onItemMoved`, `onReady`, … — its payload typed by the items' data. */
53
+ export type TimelineListeners<T = unknown> = {
54
+ readonly [K in keyof TimelineEmits<T> & string as `on${Capitalize<K>}`]?: TimelineEmits<T>[K];
55
+ };
56
+ /**
57
+ * The component's type, generic over the items' data: every prop, every
58
+ * handler and the `#item` slot typed by it, and a template ref's `timeline`.
59
+ * Written out because Vue types the runtime `emits` list — the names — as
60
+ * handlers of `(...args: any[]) => any`, and the options' slots as `unknown`.
61
+ */
62
+ export type TimelineComponent = new <T = unknown>(props: TimelineProps<T> & TimelineListeners<T> & VNodeProps & AllowedComponentProps & ComponentCustomProps) => CreateComponentPublicInstanceWithMixins<TimelineProps<T> & TimelineListeners<T>, {
63
+ readonly timeline: TimelineInstance<T> | null;
64
+ }, Record<never, never>, Record<never, never>, Record<never, never>, ComponentOptionsMixin, ComponentOptionsMixin, TimelineEmits<T>, PublicProps, Record<never, never>, false, Record<never, never>, TimelineSlots<T>>;
65
+ /** An item, as the element's types name it (the adapter depends on the element alone). */
66
+ type Item<T> = ItemSlot<T>["item"];
67
+ /**
68
+ * The timeline. Every {@link TimelineConfig} field is a prop (`:items`,
69
+ * `:time-zone` or `:timeZone`, a bare `lane-headers`), every instance event
70
+ * an emit (`@item-moved`, `@selection-changed`, …), and `ready` hands over
71
+ * the live instance; a template ref's `timeline` is the same instance.
72
+ * `class`, `style`, `id` and the rest of the attributes go on the box.
73
+ *
74
+ * The `#item` slot (`<template #item="{ item }">`) is each item's content
75
+ * as Vue, teleported into the box over the item (`slots`): only the items
76
+ * drawn have one. The content is a picture — the pointer and the keyboard
77
+ * act on the item, and its `label` stays its accessible name. Needs the
78
+ * `/items` plugin, as `template` does.
79
+ */
80
+ export declare const Timeline: TimelineComponent;
81
+ /**
82
+ * Subscribe to the part of the instance's state a component renders.
83
+ *
84
+ * The ref changes when `selector`'s result changes (by `isEqual`,
85
+ * `Object.is` by default) — and at most once per drawn frame, because the
86
+ * store notifies at most once per frame. `undefined` until there is an
87
+ * instance; `timeline` may be a ref, a getter (`() => view.value?.timeline`)
88
+ * or the instance itself.
89
+ */
90
+ export declare function useTimelineState<T, S>(timeline: MaybeRefOrGetter<TimelineInstance<T> | null | undefined>, selector: (snapshot: TimelineSnapshot) => S, isEqual?: (a: S, b: S) => boolean): Readonly<ShallowRef<S | undefined>>;
@@ -0,0 +1,90 @@
1
+ /**
2
+ * `@temporeum/timeline-vue` — the timeline as a Vue component.
3
+ *
4
+ * The component is a shell around the shared instance (`createTimeline`,
5
+ * from `@temporeum/timeline-element`), as the React one is: it creates the
6
+ * instance once, on mount, hands it every attribute that changed, and lets
7
+ * go of it on unmount. It does not re-render to draw. A pan of a hundred
8
+ * pointer events is drawn by the instance, imperatively, and Vue does not
9
+ * hear of it — its reactivity is the wrong tool for sixty frames a second of
10
+ * SVG attributes.
11
+ *
12
+ * What a component *does* render from is the instance's store.
13
+ * `useTimelineState` subscribes to it with a selector and gives a shallow
14
+ * ref: one that shows the selection changes when the selection changes and
15
+ * at no other time; one that shows the visible range changes once per drawn
16
+ * frame at most, however many events the frame held.
17
+ *
18
+ * **Server rendering.** On the server the component prints the same drawing
19
+ * the browser would draw (the core is DOM-free), so the page shows a
20
+ * timeline before the bundle loads; on hydration the instance takes those
21
+ * nodes over. The drawing goes into the server's markup only: Vue 3.5
22
+ * writes a dynamic `innerHTML` again while hydrating, and an `innerHTML`
23
+ * written by script is not the parser's — the instance would draw a second
24
+ * timeline. On the client the node has no children for Vue to compare, so
25
+ * Vue leaves alone what the parser built.
26
+ */
27
+ import type { ItemSlot, Timeline as TimelineInstance, TimelineComponentConfig, TimelineInstanceEventMap, TimelineInstanceEventName, TimelineSnapshot } from "@temporeum/timeline-element";
28
+ import type { AllowedComponentProps, ComponentCustomProps, ComponentOptionsMixin, CreateComponentPublicInstanceWithMixins, MaybeRefOrGetter, PublicProps, ShallowRef, SlotsType, VNodeProps } from "vue";
29
+ export type { TimelineComponentConfig, TimelineConfig, TimelineSnapshot } from "@temporeum/timeline-element";
30
+ /** The element's plugin registry, from the adapter too: an app that installs only the adapter still registers the plugins its configuration needs. */
31
+ export type { ClusterOpenedPayload, Command, CommandPayload, DensityChangedPayload, Domain, Group, GroupMovedPayload, GroupToggledPayload, HoverPayload, InputSkippedPayload, Item, ItemEventPayload, ItemMovedPayload, ItemPatch, ItemResizedPayload, ItemsAddedPayload, ItemsChangedPayload, ItemsRemovedPayload, JumpRequestPayload, Lane, LayoutChangedPayload, OrientationChangedPayload, SelectionChangedPayload, SlotsChangedPayload, TimeBar, TimeBarMovedPayload, TimelineInstanceEventMap, TimelineInstanceEventName, TimeMs, TimeRange, ViewportChangedPayload, } from "@temporeum/timeline-element";
32
+ export { hasPlugin, registerPlugin } from "@temporeum/timeline-element";
33
+ export type { PluginName, TimelinePlugin } from "@temporeum/timeline-element";
34
+ export type { TimelineInstance };
35
+ /** What the component emits: every instance event, by its own name, and `ready` with the instance (`null` on unmount). */
36
+ export type TimelineEmits<T = unknown> = {
37
+ readonly [K in TimelineInstanceEventName]: (payload: TimelineInstanceEventMap<T>[K]) => void;
38
+ } & {
39
+ readonly ready: (timeline: TimelineInstance<T> | null) => void;
40
+ };
41
+ /** The component's props: every {@link TimelineComponentConfig} field, and the width the server draws at. */
42
+ export type TimelineProps<T = unknown> = TimelineComponentConfig<T> & {
43
+ /** Width the server draws at; the client redraws at the real one. */
44
+ readonly ssrWidth?: number | undefined;
45
+ };
46
+ /** The `#item` slot: each drawn item's content. */
47
+ export type TimelineSlots<T = unknown> = SlotsType<{
48
+ readonly item: {
49
+ readonly item: Item<T>;
50
+ };
51
+ }>;
52
+ /** A handler prop for every event — `onItemMoved`, `onReady`, … — its payload typed by the items' data. */
53
+ export type TimelineListeners<T = unknown> = {
54
+ readonly [K in keyof TimelineEmits<T> & string as `on${Capitalize<K>}`]?: TimelineEmits<T>[K];
55
+ };
56
+ /**
57
+ * The component's type, generic over the items' data: every prop, every
58
+ * handler and the `#item` slot typed by it, and a template ref's `timeline`.
59
+ * Written out because Vue types the runtime `emits` list — the names — as
60
+ * handlers of `(...args: any[]) => any`, and the options' slots as `unknown`.
61
+ */
62
+ export type TimelineComponent = new <T = unknown>(props: TimelineProps<T> & TimelineListeners<T> & VNodeProps & AllowedComponentProps & ComponentCustomProps) => CreateComponentPublicInstanceWithMixins<TimelineProps<T> & TimelineListeners<T>, {
63
+ readonly timeline: TimelineInstance<T> | null;
64
+ }, Record<never, never>, Record<never, never>, Record<never, never>, ComponentOptionsMixin, ComponentOptionsMixin, TimelineEmits<T>, PublicProps, Record<never, never>, false, Record<never, never>, TimelineSlots<T>>;
65
+ /** An item, as the element's types name it (the adapter depends on the element alone). */
66
+ type Item<T> = ItemSlot<T>["item"];
67
+ /**
68
+ * The timeline. Every {@link TimelineConfig} field is a prop (`:items`,
69
+ * `:time-zone` or `:timeZone`, a bare `lane-headers`), every instance event
70
+ * an emit (`@item-moved`, `@selection-changed`, …), and `ready` hands over
71
+ * the live instance; a template ref's `timeline` is the same instance.
72
+ * `class`, `style`, `id` and the rest of the attributes go on the box.
73
+ *
74
+ * The `#item` slot (`<template #item="{ item }">`) is each item's content
75
+ * as Vue, teleported into the box over the item (`slots`): only the items
76
+ * drawn have one. The content is a picture — the pointer and the keyboard
77
+ * act on the item, and its `label` stays its accessible name. Needs the
78
+ * `/items` plugin, as `template` does.
79
+ */
80
+ export declare const Timeline: TimelineComponent;
81
+ /**
82
+ * Subscribe to the part of the instance's state a component renders.
83
+ *
84
+ * The ref changes when `selector`'s result changes (by `isEqual`,
85
+ * `Object.is` by default) — and at most once per drawn frame, because the
86
+ * store notifies at most once per frame. `undefined` until there is an
87
+ * instance; `timeline` may be a ref, a getter (`() => view.value?.timeline`)
88
+ * or the instance itself.
89
+ */
90
+ export declare function useTimelineState<T, S>(timeline: MaybeRefOrGetter<TimelineInstance<T> | null | undefined>, selector: (snapshot: TimelineSnapshot) => S, isEqual?: (a: S, b: S) => boolean): Readonly<ShallowRef<S | undefined>>;
package/dist/index.mjs ADDED
@@ -0,0 +1,256 @@
1
+ /*! @temporeum/timeline-vue | MIT */
2
+ import { renderTimelineSvg, createTimeline, TIMELINE_EVENTS, DEFAULT_HEIGHT } from '@temporeum/timeline-element';
3
+ export { hasPlugin, registerPlugin } from '@temporeum/timeline-element';
4
+ import { defineComponent, useId, ref, shallowRef, toRaw, inject, ssrContextKey, onMounted, onUpdated, onBeforeUnmount, h, Teleport, watch, toValue } from 'vue';
5
+
6
+ /**
7
+ * `@temporeum/timeline-vue` — the timeline as a Vue component.
8
+ *
9
+ * The component is a shell around the shared instance (`createTimeline`,
10
+ * from `@temporeum/timeline-element`), as the React one is: it creates the
11
+ * instance once, on mount, hands it every attribute that changed, and lets
12
+ * go of it on unmount. It does not re-render to draw. A pan of a hundred
13
+ * pointer events is drawn by the instance, imperatively, and Vue does not
14
+ * hear of it — its reactivity is the wrong tool for sixty frames a second of
15
+ * SVG attributes.
16
+ *
17
+ * What a component *does* render from is the instance's store.
18
+ * `useTimelineState` subscribes to it with a selector and gives a shallow
19
+ * ref: one that shows the selection changes when the selection changes and
20
+ * at no other time; one that shows the visible range changes once per drawn
21
+ * frame at most, however many events the frame held.
22
+ *
23
+ * **Server rendering.** On the server the component prints the same drawing
24
+ * the browser would draw (the core is DOM-free), so the page shows a
25
+ * timeline before the bundle loads; on hydration the instance takes those
26
+ * nodes over. The drawing goes into the server's markup only: Vue 3.5
27
+ * writes a dynamic `innerHTML` again while hydrating, and an `innerHTML`
28
+ * written by script is not the parser's — the instance would draw a second
29
+ * timeline. On the client the node has no children for Vue to compare, so
30
+ * Vue leaves alone what the parser built.
31
+ */
32
+ /**
33
+ * A prop that may be written as a bare attribute (`<Timeline lane-headers />`)
34
+ * is a boolean first: Vue reads the empty string as `true` for it. The rest
35
+ * take any value, and an absent one is `undefined` — not in the
36
+ * configuration, so the instance's default holds.
37
+ */
38
+ const ANY = { type: null, default: undefined };
39
+ const FLAG = { type: Boolean, default: undefined };
40
+ const PROPS = {
41
+ items: ANY,
42
+ lanes: ANY,
43
+ groups: ANY,
44
+ template: ANY,
45
+ templateOptions: ANY,
46
+ slots: { type: [Boolean, Function], default: undefined },
47
+ gantt: ANY,
48
+ resources: ANY,
49
+ resourceOptions: ANY,
50
+ defaultDomain: ANY,
51
+ limits: ANY,
52
+ orientation: ANY,
53
+ breakpoint: ANY,
54
+ density: ANY,
55
+ metrics: ANY,
56
+ packMode: ANY,
57
+ theme: ANY,
58
+ locale: ANY,
59
+ timeZone: ANY,
60
+ formatTick: ANY,
61
+ axisContext: FLAG,
62
+ touchAction: ANY,
63
+ maxLabels: ANY,
64
+ labelOverflow: ANY,
65
+ ariaLabel: ANY,
66
+ decorations: ANY,
67
+ cluster: { type: [Boolean, Object], default: undefined },
68
+ hooks: ANY,
69
+ height: ANY,
70
+ interactions: ANY,
71
+ editing: ANY,
72
+ defaultSelectedIds: ANY,
73
+ instanceId: ANY,
74
+ nonce: ANY,
75
+ measureText: ANY,
76
+ sceneSpace: { type: [Boolean, String], default: undefined },
77
+ hiddenDates: ANY,
78
+ timeBars: ANY,
79
+ timeBarOptions: ANY,
80
+ rolling: { type: [Boolean, Object], default: undefined },
81
+ zoomPresets: { type: [Boolean, Array], default: undefined },
82
+ minimap: { type: [Boolean, Object], default: undefined },
83
+ rangeSelect: { type: [Boolean, Object], default: undefined },
84
+ laneHeaders: FLAG,
85
+ tooltip: { type: [Boolean, Function], default: undefined },
86
+ direction: ANY,
87
+ strings: ANY,
88
+ calendar: ANY,
89
+ ssrWidth: { type: Number, default: undefined },
90
+ };
91
+ /** Where the view and the selection start, and the server's width: said once, not configuration that changes. */
92
+ const OWN = new Set(["ssrWidth", "defaultDomain", "defaultSelectedIds"]);
93
+ /** `useId` gives `v-0` or `v:0`; a stylesheet scope wants a plain name. */
94
+ const scopeOf = (id) => `tl${id.replace(/[^a-zA-Z0-9_-]/g, "")}`;
95
+ /**
96
+ * The configuration part of the props: the ones given, as plain values. A
97
+ * reactive array or object the host passes is Vue's proxy of it; the
98
+ * instance holds the object itself, so its identity is the host's and the
99
+ * frames do not go through the proxy.
100
+ */
101
+ function configOf(props, scope) {
102
+ const config = {};
103
+ for (const key of Object.keys(PROPS)) {
104
+ const value = props[key];
105
+ if (!OWN.has(key) && value !== undefined)
106
+ config[key] = toRaw(value);
107
+ }
108
+ // Light DOM: two timelines on one page must not share one stylesheet.
109
+ if (config.instanceId === undefined)
110
+ config.instanceId = scope;
111
+ return config;
112
+ }
113
+ /** The keys whose values are not the same object: an unchanged `items` array must not look like new data. */
114
+ function changedOf(before, next) {
115
+ const changed = {};
116
+ let any = false;
117
+ for (const key of new Set([...Object.keys(before), ...Object.keys(next)])) {
118
+ if (key !== "__proto__" && before[key] !== next[key]) {
119
+ changed[key] = next[key];
120
+ any = true;
121
+ }
122
+ }
123
+ return any ? changed : undefined;
124
+ }
125
+ /**
126
+ * The timeline. Every {@link TimelineConfig} field is a prop (`:items`,
127
+ * `:time-zone` or `:timeZone`, a bare `lane-headers`), every instance event
128
+ * an emit (`@item-moved`, `@selection-changed`, …), and `ready` hands over
129
+ * the live instance; a template ref's `timeline` is the same instance.
130
+ * `class`, `style`, `id` and the rest of the attributes go on the box.
131
+ *
132
+ * The `#item` slot (`<template #item="{ item }">`) is each item's content
133
+ * as Vue, teleported into the box over the item (`slots`): only the items
134
+ * drawn have one. The content is a picture — the pointer and the keyboard
135
+ * act on the item, and its `label` stays its accessible name. Needs the
136
+ * `/items` plugin, as `template` does.
137
+ */
138
+ const Timeline = defineComponent((props, { emit, expose, slots }) => {
139
+ // Vue 3.5.0 types useId() as possibly undefined (outside a setup); here it is in one.
140
+ const scope = scopeOf(useId() ?? "");
141
+ const container = ref(null);
142
+ const timeline = shallowRef(null);
143
+ const drawn = shallowRef(new Map());
144
+ // With an `#item` slot every item has a box, unless `slots` picks.
145
+ const configNow = () => {
146
+ const config = configOf(props, scope);
147
+ if (slots.item !== undefined && config.slots === undefined)
148
+ config.slots = true;
149
+ return config;
150
+ };
151
+ let applied = configNow();
152
+ const initial = {
153
+ ...applied,
154
+ ...(props.defaultDomain === undefined ? {} : { domain: toRaw(props.defaultDomain) }),
155
+ ...(props.defaultSelectedIds === undefined ? {} : { selectedIds: toRaw(props.defaultSelectedIds) }),
156
+ };
157
+ // The server's drawing, computed once — on the server only: Vue's
158
+ // server renderer is what provides an SSR context.
159
+ const html = inject(ssrContextKey, null) !== null
160
+ ? (() => {
161
+ const frame = renderTimelineSvg(initial, props.ssrWidth === undefined ? {} : { width: props.ssrWidth });
162
+ return frame.svg + frame.groups;
163
+ })()
164
+ : undefined;
165
+ let stops = [];
166
+ onMounted(() => {
167
+ const instance = createTimeline(container.value, { ...initial, ...applied }, { hydrate: true });
168
+ stops = TIMELINE_EVENTS.map((type) => instance.on(type, (payload) => forward(emit, type, payload)));
169
+ // Vue renders the teleports in its own flush, a microtask after the
170
+ // frame that drew the boxes: before the browser paints it.
171
+ stops.push(instance.on("slotsChanged", ({ slots: next }) => (drawn.value = next)));
172
+ drawn.value = instance.slots;
173
+ timeline.value = instance;
174
+ emit("ready", instance);
175
+ });
176
+ // Hand the instance what changed, and only that.
177
+ onUpdated(() => {
178
+ const next = configNow();
179
+ const changed = changedOf(applied, next);
180
+ applied = next;
181
+ if (changed !== undefined)
182
+ timeline.value?.update(changed);
183
+ });
184
+ onBeforeUnmount(() => {
185
+ for (const stop of stops)
186
+ stop();
187
+ stops = [];
188
+ timeline.value?.destroy();
189
+ timeline.value = null;
190
+ emit("ready", null);
191
+ });
192
+ expose({ timeline });
193
+ return () => {
194
+ const height = props.height ?? DEFAULT_HEIGHT;
195
+ const item = slots.item;
196
+ const teleports = item === undefined ? [] : [...drawn.value].map(([id, slot]) => h(Teleport, { key: id, to: slot.element }, item({ item: slot.item })));
197
+ // The teleports are the box's children, as anchors: one root, so the
198
+ // server's markup stays the box alone. Without a teleport the box has
199
+ // no children for Vue — on the server it has the drawing, and while
200
+ // hydrating Vue must not compare the instance's nodes with any. The
201
+ // host's class, style and attributes fall through onto the box.
202
+ return h("div", {
203
+ ref: container,
204
+ style: { position: "relative", overflow: "hidden", height: `${String(height)}px` },
205
+ "data-tl-vue": "",
206
+ ...(html === undefined ? {} : { innerHTML: html }),
207
+ }, html === undefined && teleports.length > 0 ? teleports : undefined);
208
+ };
209
+ }, {
210
+ name: "TemporeumTimeline",
211
+ // The runtime declaration; the types are the setup function's, generic over the items' data.
212
+ props: PROPS,
213
+ emits: [...TIMELINE_EVENTS, "ready"],
214
+ slots: Object,
215
+ });
216
+ /** One instance event, emitted under its own name: the payload is that event's. */
217
+ function forward(emit, type, payload) {
218
+ emit(type, payload);
219
+ }
220
+ /**
221
+ * Subscribe to the part of the instance's state a component renders.
222
+ *
223
+ * The ref changes when `selector`'s result changes (by `isEqual`,
224
+ * `Object.is` by default) — and at most once per drawn frame, because the
225
+ * store notifies at most once per frame. `undefined` until there is an
226
+ * instance; `timeline` may be a ref, a getter (`() => view.value?.timeline`)
227
+ * or the instance itself.
228
+ */
229
+ function useTimelineState(timeline, selector, isEqual = Object.is) {
230
+ const state = shallowRef(undefined);
231
+ watch(() => toValue(timeline), (instance, _, onCleanup) => {
232
+ if (instance === null || instance === undefined) {
233
+ state.value = undefined;
234
+ return;
235
+ }
236
+ let seen;
237
+ const read = () => {
238
+ const snapshot = instance.getSnapshot();
239
+ if (seen !== undefined && seen.snapshot === snapshot)
240
+ return;
241
+ const selected = selector(snapshot);
242
+ if (seen !== undefined && isEqual(seen.selected, selected)) {
243
+ seen = { snapshot, selected: seen.selected };
244
+ return;
245
+ }
246
+ seen = { snapshot, selected };
247
+ state.value = selected;
248
+ };
249
+ read();
250
+ onCleanup(instance.subscribe(read));
251
+ }, { immediate: true });
252
+ return state;
253
+ }
254
+
255
+ export { Timeline, useTimelineState };
256
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","sources":["../src/index.ts"],"sourcesContent":["/**\n * `@temporeum/timeline-vue` — the timeline as a Vue component.\n *\n * The component is a shell around the shared instance (`createTimeline`,\n * from `@temporeum/timeline-element`), as the React one is: it creates the\n * instance once, on mount, hands it every attribute that changed, and lets\n * go of it on unmount. It does not re-render to draw. A pan of a hundred\n * pointer events is drawn by the instance, imperatively, and Vue does not\n * hear of it — its reactivity is the wrong tool for sixty frames a second of\n * SVG attributes.\n *\n * What a component *does* render from is the instance's store.\n * `useTimelineState` subscribes to it with a selector and gives a shallow\n * ref: one that shows the selection changes when the selection changes and\n * at no other time; one that shows the visible range changes once per drawn\n * frame at most, however many events the frame held.\n *\n * **Server rendering.** On the server the component prints the same drawing\n * the browser would draw (the core is DOM-free), so the page shows a\n * timeline before the bundle loads; on hydration the instance takes those\n * nodes over. The drawing goes into the server's markup only: Vue 3.5\n * writes a dynamic `innerHTML` again while hydrating, and an `innerHTML`\n * written by script is not the parser's — the instance would draw a second\n * timeline. On the client the node has no children for Vue to compare, so\n * Vue leaves alone what the parser built.\n */\n\nimport { createTimeline, DEFAULT_HEIGHT, renderTimelineSvg, TIMELINE_EVENTS } from \"@temporeum/timeline-element\";\nimport type {\n ItemSlot,\n Timeline as TimelineInstance,\n TimelineComponentConfig,\n TimelineConfig,\n TimelineInstanceEventMap,\n TimelineInstanceEventName,\n TimelineSnapshot,\n TimelineUpdate,\n} from \"@temporeum/timeline-element\";\nimport { defineComponent, h, inject, onBeforeUnmount, onMounted, onUpdated, ref, shallowRef, ssrContextKey, Teleport, toRaw, toValue, useId, watch } from \"vue\";\nimport type {\n AllowedComponentProps,\n ComponentCustomProps,\n ComponentOptionsMixin,\n CreateComponentPublicInstanceWithMixins,\n MaybeRefOrGetter,\n PublicProps,\n SetupContext,\n ShallowRef,\n SlotsType,\n VNodeProps,\n} from \"vue\";\n\nexport type { TimelineComponentConfig, TimelineConfig, TimelineSnapshot } from \"@temporeum/timeline-element\";\n/** The element's plugin registry, from the adapter too: an app that installs only the adapter still registers the plugins its configuration needs. */\n// The data and the event payloads, handed on: one install types an app.\nexport type {\n ClusterOpenedPayload,\n Command,\n CommandPayload,\n DensityChangedPayload,\n Domain,\n Group,\n GroupMovedPayload,\n GroupToggledPayload,\n HoverPayload,\n InputSkippedPayload,\n Item,\n ItemEventPayload,\n ItemMovedPayload,\n ItemPatch,\n ItemResizedPayload,\n ItemsAddedPayload,\n ItemsChangedPayload,\n ItemsRemovedPayload,\n JumpRequestPayload,\n Lane,\n LayoutChangedPayload,\n OrientationChangedPayload,\n SelectionChangedPayload,\n SlotsChangedPayload,\n TimeBar,\n TimeBarMovedPayload,\n TimelineInstanceEventMap,\n TimelineInstanceEventName,\n TimeMs,\n TimeRange,\n ViewportChangedPayload,\n} from \"@temporeum/timeline-element\";\nexport { hasPlugin, registerPlugin } from \"@temporeum/timeline-element\";\nexport type { PluginName, TimelinePlugin } from \"@temporeum/timeline-element\";\nexport type { TimelineInstance };\n\n/** What the component emits: every instance event, by its own name, and `ready` with the instance (`null` on unmount). */\nexport type TimelineEmits<T = unknown> = { readonly [K in TimelineInstanceEventName]: (payload: TimelineInstanceEventMap<T>[K]) => void } & {\n readonly ready: (timeline: TimelineInstance<T> | null) => void;\n};\n\n/** The component's props: every {@link TimelineComponentConfig} field, and the width the server draws at. */\nexport type TimelineProps<T = unknown> = TimelineComponentConfig<T> & {\n /** Width the server draws at; the client redraws at the real one. */\n readonly ssrWidth?: number | undefined;\n};\n\n/** The `#item` slot: each drawn item's content. */\nexport type TimelineSlots<T = unknown> = SlotsType<{ readonly item: { readonly item: Item<T> } }>;\n\n/** A handler prop for every event — `onItemMoved`, `onReady`, … — its payload typed by the items' data. */\nexport type TimelineListeners<T = unknown> = { readonly [K in keyof TimelineEmits<T> & string as `on${Capitalize<K>}`]?: TimelineEmits<T>[K] };\n\n/**\n * The component's type, generic over the items' data: every prop, every\n * handler and the `#item` slot typed by it, and a template ref's `timeline`.\n * Written out because Vue types the runtime `emits` list — the names — as\n * handlers of `(...args: any[]) => any`, and the options' slots as `unknown`.\n */\nexport type TimelineComponent = new <T = unknown>(\n props: TimelineProps<T> & TimelineListeners<T> & VNodeProps & AllowedComponentProps & ComponentCustomProps,\n) => CreateComponentPublicInstanceWithMixins<\n TimelineProps<T> & TimelineListeners<T>,\n { readonly timeline: TimelineInstance<T> | null },\n Record<never, never>,\n Record<never, never>,\n Record<never, never>,\n ComponentOptionsMixin,\n ComponentOptionsMixin,\n TimelineEmits<T>,\n PublicProps,\n Record<never, never>,\n false,\n Record<never, never>,\n TimelineSlots<T>\n>;\n\n/** An item, as the element's types name it (the adapter depends on the element alone). */\ntype Item<T> = ItemSlot<T>[\"item\"];\n\n/**\n * A prop that may be written as a bare attribute (`<Timeline lane-headers />`)\n * is a boolean first: Vue reads the empty string as `true` for it. The rest\n * take any value, and an absent one is `undefined` — not in the\n * configuration, so the instance's default holds.\n */\nconst ANY = { type: null, default: undefined } as const;\nconst FLAG = { type: Boolean, default: undefined } as const;\nconst PROPS: { readonly [K in keyof TimelineProps]-?: { readonly type: unknown; readonly default: undefined } } = {\n items: ANY,\n lanes: ANY,\n groups: ANY,\n template: ANY,\n templateOptions: ANY,\n slots: { type: [Boolean, Function], default: undefined },\n gantt: ANY,\n resources: ANY,\n resourceOptions: ANY,\n defaultDomain: ANY,\n limits: ANY,\n orientation: ANY,\n breakpoint: ANY,\n density: ANY,\n metrics: ANY,\n packMode: ANY,\n theme: ANY,\n locale: ANY,\n timeZone: ANY,\n formatTick: ANY,\n axisContext: FLAG,\n touchAction: ANY,\n maxLabels: ANY,\n labelOverflow: ANY,\n ariaLabel: ANY,\n decorations: ANY,\n cluster: { type: [Boolean, Object], default: undefined },\n hooks: ANY,\n height: ANY,\n interactions: ANY,\n editing: ANY,\n defaultSelectedIds: ANY,\n instanceId: ANY,\n nonce: ANY,\n measureText: ANY,\n sceneSpace: { type: [Boolean, String], default: undefined },\n hiddenDates: ANY,\n timeBars: ANY,\n timeBarOptions: ANY,\n rolling: { type: [Boolean, Object], default: undefined },\n zoomPresets: { type: [Boolean, Array], default: undefined },\n minimap: { type: [Boolean, Object], default: undefined },\n rangeSelect: { type: [Boolean, Object], default: undefined },\n laneHeaders: FLAG,\n tooltip: { type: [Boolean, Function], default: undefined },\n direction: ANY,\n strings: ANY,\n calendar: ANY,\n ssrWidth: { type: Number, default: undefined },\n};\n\n/** Where the view and the selection start, and the server's width: said once, not configuration that changes. */\nconst OWN = new Set([\"ssrWidth\", \"defaultDomain\", \"defaultSelectedIds\"]);\n\n/** `useId` gives `v-0` or `v:0`; a stylesheet scope wants a plain name. */\nconst scopeOf = (id: string): string => `tl${id.replace(/[^a-zA-Z0-9_-]/g, \"\")}`;\n\n/**\n * The configuration part of the props: the ones given, as plain values. A\n * reactive array or object the host passes is Vue's proxy of it; the\n * instance holds the object itself, so its identity is the host's and the\n * frames do not go through the proxy.\n */\nfunction configOf(props: Record<string, unknown>, scope: string): Record<string, unknown> {\n const config: Record<string, unknown> = {};\n for (const key of Object.keys(PROPS)) {\n const value = props[key];\n if (!OWN.has(key) && value !== undefined) config[key] = toRaw(value);\n }\n // Light DOM: two timelines on one page must not share one stylesheet.\n if (config.instanceId === undefined) config.instanceId = scope;\n return config;\n}\n\n/** The keys whose values are not the same object: an unchanged `items` array must not look like new data. */\nfunction changedOf(before: Record<string, unknown>, next: Record<string, unknown>): Record<string, unknown> | undefined {\n const changed: Record<string, unknown> = {};\n let any = false;\n for (const key of new Set([...Object.keys(before), ...Object.keys(next)])) {\n if (key !== \"__proto__\" && before[key] !== next[key]) {\n changed[key] = next[key];\n any = true;\n }\n }\n return any ? changed : undefined;\n}\n\n/**\n * The timeline. Every {@link TimelineConfig} field is a prop (`:items`,\n * `:time-zone` or `:timeZone`, a bare `lane-headers`), every instance event\n * an emit (`@item-moved`, `@selection-changed`, …), and `ready` hands over\n * the live instance; a template ref's `timeline` is the same instance.\n * `class`, `style`, `id` and the rest of the attributes go on the box.\n *\n * The `#item` slot (`<template #item=\"{ item }\">`) is each item's content\n * as Vue, teleported into the box over the item (`slots`): only the items\n * drawn have one. The content is a picture — the pointer and the keyboard\n * act on the item, and its `label` stays its accessible name. Needs the\n * `/items` plugin, as `template` does.\n */\nexport const Timeline: TimelineComponent = defineComponent(\n <T = unknown>(props: TimelineProps<T>, { emit, expose, slots }: SetupContext<TimelineEmits<T>, TimelineSlots>) => {\n // Vue 3.5.0 types useId() as possibly undefined (outside a setup); here it is in one.\n const scope = scopeOf(useId() ?? \"\");\n const container = ref<HTMLDivElement | null>(null);\n const timeline = shallowRef<TimelineInstance<T> | null>(null);\n const drawn = shallowRef<ReadonlyMap<string, ItemSlot<T>>>(new Map());\n // With an `#item` slot every item has a box, unless `slots` picks.\n const configNow = (): Record<string, unknown> => {\n const config = configOf(props as Record<string, unknown>, scope);\n if (slots.item !== undefined && config.slots === undefined) config.slots = true;\n return config;\n };\n let applied = configNow();\n const initial: Record<string, unknown> = {\n ...applied,\n ...(props.defaultDomain === undefined ? {} : { domain: toRaw(props.defaultDomain) }),\n ...(props.defaultSelectedIds === undefined ? {} : { selectedIds: toRaw(props.defaultSelectedIds) }),\n };\n // The server's drawing, computed once — on the server only: Vue's\n // server renderer is what provides an SSR context.\n const html =\n inject(ssrContextKey, null) !== null\n ? (() => {\n const frame = renderTimelineSvg(initial as TimelineConfig<T>, props.ssrWidth === undefined ? {} : { width: props.ssrWidth });\n return frame.svg + frame.groups;\n })()\n : undefined;\n let stops: (() => void)[] = [];\n\n onMounted(() => {\n const instance = createTimeline<T>(container.value as HTMLDivElement, { ...initial, ...applied } as TimelineConfig<T>, { hydrate: true });\n stops = TIMELINE_EVENTS.map((type) => instance.on(type, (payload) => forward(emit, type, payload)));\n // Vue renders the teleports in its own flush, a microtask after the\n // frame that drew the boxes: before the browser paints it.\n stops.push(instance.on(\"slotsChanged\", ({ slots: next }) => (drawn.value = next)));\n drawn.value = instance.slots;\n timeline.value = instance;\n emit(\"ready\", instance);\n });\n\n // Hand the instance what changed, and only that.\n onUpdated(() => {\n const next = configNow();\n const changed = changedOf(applied, next);\n applied = next;\n if (changed !== undefined) timeline.value?.update(changed as TimelineUpdate<T>);\n });\n\n onBeforeUnmount(() => {\n for (const stop of stops) stop();\n stops = [];\n timeline.value?.destroy();\n timeline.value = null;\n emit(\"ready\", null);\n });\n\n expose({ timeline });\n\n return () => {\n const height = props.height ?? DEFAULT_HEIGHT;\n const item = slots.item;\n const teleports = item === undefined ? [] : [...drawn.value].map(([id, slot]) => h(Teleport, { key: id, to: slot.element }, item({ item: slot.item })));\n // The teleports are the box's children, as anchors: one root, so the\n // server's markup stays the box alone. Without a teleport the box has\n // no children for Vue — on the server it has the drawing, and while\n // hydrating Vue must not compare the instance's nodes with any. The\n // host's class, style and attributes fall through onto the box.\n return h(\n \"div\",\n {\n ref: container,\n style: { position: \"relative\", overflow: \"hidden\", height: `${String(height)}px` },\n \"data-tl-vue\": \"\",\n ...(html === undefined ? {} : { innerHTML: html }),\n },\n html === undefined && teleports.length > 0 ? teleports : undefined,\n );\n };\n },\n {\n name: \"TemporeumTimeline\",\n // The runtime declaration; the types are the setup function's, generic over the items' data.\n props: PROPS as never,\n emits: [...TIMELINE_EVENTS, \"ready\"],\n slots: Object as TimelineSlots,\n },\n) as unknown as TimelineComponent;\n\n/** One instance event, emitted under its own name: the payload is that event's. */\nfunction forward<T, K extends TimelineInstanceEventName>(emit: SetupContext<TimelineEmits<T>>[\"emit\"], type: K, payload: TimelineInstanceEventMap<T>[K]): void {\n (emit as (type: K, payload: TimelineInstanceEventMap<T>[K]) => void)(type, payload);\n}\n\n/**\n * Subscribe to the part of the instance's state a component renders.\n *\n * The ref changes when `selector`'s result changes (by `isEqual`,\n * `Object.is` by default) — and at most once per drawn frame, because the\n * store notifies at most once per frame. `undefined` until there is an\n * instance; `timeline` may be a ref, a getter (`() => view.value?.timeline`)\n * or the instance itself.\n */\nexport function useTimelineState<T, S>(\n timeline: MaybeRefOrGetter<TimelineInstance<T> | null | undefined>,\n selector: (snapshot: TimelineSnapshot) => S,\n isEqual: (a: S, b: S) => boolean = Object.is,\n): Readonly<ShallowRef<S | undefined>> {\n const state = shallowRef<S | undefined>(undefined);\n watch(\n () => toValue(timeline),\n (instance, _, onCleanup) => {\n if (instance === null || instance === undefined) {\n state.value = undefined;\n return;\n }\n let seen: { snapshot: TimelineSnapshot; selected: S } | undefined;\n const read = (): void => {\n const snapshot = instance.getSnapshot();\n if (seen !== undefined && seen.snapshot === snapshot) return;\n const selected = selector(snapshot);\n if (seen !== undefined && isEqual(seen.selected, selected)) {\n seen = { snapshot, selected: seen.selected };\n return;\n }\n seen = { snapshot, selected };\n state.value = selected;\n };\n read();\n onCleanup(instance.subscribe(read));\n },\n { immediate: true },\n );\n return state;\n}\n"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,74 @@
1
1
  {
2
2
  "name": "@temporeum/timeline-vue",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "1.0.0",
4
+ "description": "The Temporeum timeline as a Vue component: editable, accessible, server-rendered and hydrated.",
5
+ "license": "MIT",
6
+ "author": "Daniel Horak",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/horakdani/Temporeum_timeline_SDK.git",
10
+ "directory": "packages/vue"
11
+ },
12
+ "homepage": "https://horakdani.github.io/Temporeum_timeline_SDK/",
13
+ "bugs": {
14
+ "url": "https://github.com/horakdani/Temporeum_timeline_SDK/issues"
15
+ },
16
+ "keywords": [
17
+ "timeline",
18
+ "vue",
19
+ "nuxt",
20
+ "gantt",
21
+ "editable",
22
+ "accessible",
23
+ "ssr"
24
+ ],
25
+ "publishConfig": {
26
+ "access": "public",
27
+ "provenance": true
28
+ },
29
+ "type": "module",
30
+ "sideEffects": false,
31
+ "main": "./dist/index.cjs",
32
+ "module": "./dist/index.mjs",
33
+ "types": "./dist/index.d.cts",
34
+ "exports": {
35
+ ".": {
36
+ "import": {
37
+ "types": "./dist/index.d.ts",
38
+ "default": "./dist/index.mjs"
39
+ },
40
+ "require": {
41
+ "types": "./dist/index.d.cts",
42
+ "default": "./dist/index.cjs"
43
+ }
44
+ },
45
+ "./package.json": "./package.json"
46
+ },
47
+ "files": [
48
+ "dist",
49
+ "README.md",
50
+ "CHANGELOG.md"
51
+ ],
52
+ "engines": {
53
+ "node": ">=22.12.0"
54
+ },
55
+ "dependencies": {
56
+ "@temporeum/timeline-element": "^1.0.0"
57
+ },
58
+ "peerDependencies": {
59
+ "vue": "^3.5.0"
60
+ },
61
+ "scripts": {
62
+ "build": "node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\" && tsc -p tsconfig.build.json --emitDeclarationOnly && rollup -c && node ../../scripts/sdk_cjs_types.mjs",
63
+ "typecheck": "tsc -p tsconfig.json --noEmit",
64
+ "test": "npm run --silent build -w @temporeum/timeline-core && npm run --silent build -w @temporeum/timeline-element && npm run --silent build && npm run --silent typecheck && vitest run --coverage"
65
+ },
66
+ "devDependencies": {
67
+ "@vue/compiler-dom": "^3.5.44",
68
+ "@vitest/browser-playwright": "^5.1.0",
69
+ "@vitest/coverage-v8": "^5.1.0",
70
+ "typescript": "^6.0.3",
71
+ "vitest": "^5.1.0",
72
+ "vue": "^3.5.44"
73
+ }
74
+ }