histropediajs 1.6.1 → 1.7.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/README.md CHANGED
@@ -108,7 +108,7 @@ Each article (event) uses the following minimal shape. Short property aliases ar
108
108
  hidePeriodLine?: boolean,
109
109
  hiddenByFilter?: boolean,
110
110
  imageUrl?: string,
111
- cardLayout?: 'portrait' | 'landscape',
111
+ cardLayout?: 'portrait' | 'landscape' | 'title-only' | 'title-subtitle' | 'label' | 'image-text' | 'image-only' | 'pill' | string,
112
112
  style?: object,
113
113
  hoverStyle?: object,
114
114
  activeStyle?: object
@@ -167,6 +167,81 @@ the base indicator settings. Within `activeStyle`, `color: 'article'` uses the c
167
167
  colour; the same value in the base or hidden style uses its resolved normal colour. Indicator
168
168
  `opacity` accepts values from `0` to `1`.
169
169
 
170
+ ## Connector line styling
171
+
172
+ Set `connectorLine` in an article style to control the line and its filled arrow independently.
173
+ The normal defaults preserve the existing appearance:
174
+
175
+ ```js
176
+ connectorLine: {
177
+ visible: true,
178
+ color: 'article',
179
+ dash: [],
180
+ lineCap: 'butt',
181
+ offsetX: 18,
182
+ offsetY: -20,
183
+ thickness: 1,
184
+ arrow: {
185
+ visible: true,
186
+ color: 'inherit',
187
+ width: 16,
188
+ height: 45,
189
+ },
190
+ }
191
+ ```
192
+
193
+ `connectorLine.color` accepts a CSS colour string or `'article'`, which follows the article's
194
+ resolved colour in its current normal, hover, active, or active-hover state. `arrow.color` also
195
+ accepts `'inherit'` to follow the resolved connector-line colour. Keywords are resolved during
196
+ drawing and remain unchanged in the stored styles, including those returned by `getCurrentStyle()`.
197
+ Explicit colours remain fixed across states unless another style layer overrides them.
198
+
199
+ For a grey dashed line with an arrow that follows the current article colour:
200
+
201
+ ```js
202
+ const timeline = new Timeline(container, {
203
+ article: {
204
+ defaultStyle: {
205
+ connectorLine: {
206
+ color: '#aaa',
207
+ dash: [4, 3],
208
+ lineCap: 'round',
209
+ arrow: { color: 'article' },
210
+ },
211
+ },
212
+ defaultHoverStyle: {
213
+ connectorLine: { dash: [] }, // Solid while hovered.
214
+ },
215
+ },
216
+ });
217
+ ```
218
+
219
+ | Option | Behaviour |
220
+ | ---------------------- | --------------------------------------------------------------------------------------------------------------------- |
221
+ | `visible: false` | Hides both the connector stroke and arrow. |
222
+ | `arrow.visible: false` | Hides only the arrow; the line still reaches its configured card attachment point, including `offsetX` and `offsetY`. |
223
+ | `thickness: 0` | Hides only the line stroke, allowing an arrow-only appearance. |
224
+ | `dash` | Canvas dash/gap lengths in CSS pixels, applied only to the stroke; `[]` is solid and `[4, 3]` is dashed. |
225
+ | `lineCap` | Stroke end shape: `'butt'` (default), `'round'`, or `'square'`. |
226
+
227
+ All settings support sparse overrides through the existing style cascade: library defaults,
228
+ registered card-layout defaults, timeline defaults, timeline layout overrides, lane defaults,
229
+ lane layout overrides, then article styles. Hover and active overrides use the same cascade;
230
+ when both states apply, active values win conflicts and hover-only values remain. Arrays such as
231
+ `dash` are replaced by an override, so `[]` resets a dashed style to solid.
232
+
233
+ The existing active style sets `thickness: 2`. For an arrow-only connector in every state, override
234
+ both the normal and active thickness:
235
+
236
+ ```js
237
+ article.setStyle({ connectorLine: { thickness: 0 } });
238
+ article.setActiveStyle({ connectorLine: { thickness: 0 } });
239
+ ```
240
+
241
+ Connector settings do not change the period bar or date indicators. The period bar continues to
242
+ use the current article colour and its existing period-line options. Date indicators retain the
243
+ normal/active colour rules described above, including ignoring hover colours.
244
+
170
245
  ## Parent context date labels
171
246
 
172
247
  Set `style.dateLabel.parent.visible` to `true` to add a persistent calendar-parent row beneath the
@@ -238,6 +313,19 @@ import Histropedia from 'histropediajs';
238
313
  - **Logger**: centralized console logger with `setEnabled(boolean)`
239
314
  - **Constants**: zoom levels, precisions, density controls, etc.
240
315
 
316
+ ### Removing configuration overrides
317
+
318
+ Use `Histropedia.UNSET` (also a named export) to clear an override and return to its default or inherited style:
319
+
320
+ ```js
321
+ timeline.setOption('zoom.wheelSpeed', Histropedia.UNSET);
322
+ article.setStyle({ header: { color: Histropedia.UNSET, height: 'auto' } });
323
+ article.setHoverStyle('border.width', Histropedia.UNSET);
324
+ article.setActiveStyle('border.width', Histropedia.UNSET);
325
+ ```
326
+
327
+ An explicit value stays an override; removing it lets the value follow the lower configuration layers. `null` and `undefined` retain their existing meanings. See [clearing configuration overrides](docs/unset.md) for lane/timeline styles, optional properties, and layout extensions.
328
+
241
329
  ### Timeline constructor
242
330
 
243
331
  ```ts
@@ -262,6 +350,8 @@ If `container` is an element, the timeline creates and appends its own `<canvas>
262
350
  - `on(event: string, handler)` / `off(event, handler)` / `trigger(event, ...args)`: event system.
263
351
  - `select(articleId)`: bring to the front and trigger the `article-select` event.
264
352
 
353
+ See [viewport navigation completion](docs/navigation.md) for `options.onComplete`, asynchronous timing, cancellation, and legacy callback compatibility.
354
+
265
355
  ### Events
266
356
 
267
357
  Register handlers using `timeline.on(name, callback)` or pass `options.on = { [name]: handler }`.
@@ -387,6 +477,113 @@ TimelineOptions tunes layout, interaction, article rendering, and image loading.
387
477
 
388
478
  Find the full option reference, defaults, and advanced patterns in the hosted docs: https://js.histropedia.com/documentation.
389
479
 
480
+ ### Article auto width
481
+
482
+ Set `width: 'auto'` to size article cards from their content, with an optional `maxWidth` cap:
483
+
484
+ ```js
485
+ const timeline = new Timeline(container, {
486
+ article: {
487
+ defaultStyle: { width: 'auto', maxWidth: 320 },
488
+ },
489
+ });
490
+
491
+ // The same styles work on individual articles and in lane/layout style overrides.
492
+ timeline.getArticleById('example')?.setStyle({ width: 'auto', maxWidth: 280 });
493
+ ```
494
+
495
+ Cards use their content width up to the cap, then use the existing wrapping and layout rules.
496
+ Numeric `width` values keep their existing behaviour and ignore `maxWidth`. Without a cap,
497
+ auto width can grow to fit the content.
498
+ Auto width is driven by text and layout spacing, not image resolution. Portrait images fit
499
+ the measured card width; landscape cards reserve their existing image slot. Cached bitmaps
500
+ are sized for that drawing area.
501
+
502
+ The [`image-only` preset](docs/custom-card-layouts.md#image-only) uses a filled
503
+ `backgroundColor` placeholder for missing, loading or failed images. Automatic
504
+ dimensions assume a square until loading succeeds, then follow the image aspect
505
+ ratio; fixed dimensions remain fixed.
506
+
507
+ Custom layouts use the same size cache and cap. An omitted `getWidth` hook measures standard
508
+ title/subtitle text, block padding, margins, and border; a custom hook can supply its own content width.
509
+ Use `this.getWidth()` in drawing code for the resolved numeric width. See
510
+ [custom card measurements](docs/custom-card-layouts.md#auto-width) for details.
511
+
512
+ ### Article heights, text blocks and images
513
+
514
+ Both portrait and landscape support numeric or automatic card and text-block heights,
515
+ multi-line subtitles, block background colours, uniform or per-side block `padding`, and `image.visible`. Padding
516
+ defaults to zero, adds to automatic block height, and sits inside numeric block heights. Automatic blocks allocate
517
+ complete lines; numeric blocks retain their text placement and may overflow. Numeric total card heights clip
518
+ that overflow. `image.maxHeight` caps all image shapes in both layouts, with automatic
519
+ or numeric card heights, without changing an explicitly set card height.
520
+ Fixed portrait images keep their normal width and crop vertically at
521
+ the smaller of `image.maxHeight` and the remaining card height. Automatic landscape height keeps a stable thumbnail
522
+ while text grows. Both layouts accept numeric or per-side `image.margin`, such as
523
+ `{ top: 4, right: 12, bottom: 4, left: 4 }`. Landscape margins surround the thumbnail, including the gap
524
+ before header/subheader backgrounds; automatic width includes both horizontal margins.
525
+ See [article sizing](docs/article-sizing.md) for defaults, overflow priority,
526
+ style migration notes and examples, or open the **Article sizing** demo.
527
+
528
+ ### Pan and pinch momentum
529
+
530
+ Touchscreen pinches continue both zooming and panning after release, using recent finger
531
+ spacing and midpoint movement. Zoom stays anchored to the moving pinch midpoint. Configure
532
+ zoom inertia under `zoom.pinchMomentum`; its pan component uses `pan.momentum`:
533
+
534
+ ```js
535
+ const timeline = new Timeline(container, {
536
+ zoom: {
537
+ pinchMomentum: {
538
+ active: true,
539
+ sampleWindow: 50,
540
+ minVelocity: 0.001,
541
+ stopVelocity: 0.0001,
542
+ friction: 0.005,
543
+ maxDuration: 1200,
544
+ },
545
+ },
546
+ pan: {
547
+ momentum: {
548
+ active: true,
549
+ sampleWindow: 100,
550
+ minVelocity: 0.01,
551
+ stopVelocity: 0.005,
552
+ friction: 0.005,
553
+ maxDuration: 5600,
554
+ },
555
+ },
556
+ });
557
+ ```
558
+
559
+ These are the defaults. Each component can be disabled independently with `active: false`.
560
+ `sampleWindow` and `maxDuration` are milliseconds. Zoom velocities are zoom levels per
561
+ millisecond; pan velocities are pixels per millisecond. Lower `friction` means a longer glide.
562
+ Numeric momentum settings must be positive finite numbers; other values use the defaults.
563
+
564
+ Zoom velocity uses the last 50 ms of input by default, including a baseline for sparse
565
+ gestures. Input timestamps determine speed; there is no launch-speed cap or multiplier.
566
+ Friction and maximum duration control the glide after launch, independently of that speed.
567
+
568
+ Momentum begins after both fingers lift. Release velocity is measured at the first lift;
569
+ a staggered release under 100 ms preserves it. Holding still or continuing a one-finger
570
+ drag discards the old pinch velocity. A single release-tail movement must exceed 16 CSS
571
+ pixels to become a pan; sustained movement uses 8 pixels. The threshold is consumed
572
+ without a jump, and pan inertia requires genuine movement history.
573
+
574
+ During a repeated pinch, zoom can coast for up to 80 ms while the next fingers land.
575
+ The first pinch movement takes over at the current scale without a jump or extra gain.
576
+ A tap, hold, one-finger drag, wheel input, or `setZoom()` stops that coast. Pan momentum
577
+ stops on contact. Zoom and date bounds remain enforced.
578
+
579
+ For physical-device checks, the development demo includes **Record pinch** and
580
+ **Save pinch data** controls. See [touchscreen testing](docs/pinch-momentum.md).
581
+
582
+ Smooth touchpad zoom already follows the browser's continuous wheel events, including any
583
+ device/OS momentum. No additional inertia is added to that stream. Trackpad pinch events
584
+ reported as Ctrl+wheel continue to follow `zoom.allowCtrlWheel` (default `false`). Notched
585
+ mouse wheels retain `zoom.discreteWheelAnimation` and have no release momentum.
586
+
390
587
  ### Sub-day zoom
391
588
 
392
589
  Sub-day zoom is opt-in, so existing timelines keep exactly the same minimum scale. The default
@@ -435,6 +632,7 @@ negative or longer than four digits, and fractional seconds contain one to three
435
632
  ```js
436
633
  timeline.setStartDate('2026-08-13T12:30:15.250', {
437
634
  animation: { active: true, duration: 500 },
635
+ onComplete: () => console.log('Viewport navigation finished'),
438
636
  });
439
637
 
440
638
  timeline.setCentreDate('-44-03-15 09:01');
@@ -448,7 +646,7 @@ period.
448
646
 
449
647
  ### Card layouts
450
648
 
451
- Two built-in layouts are registered: `portrait` and `landscape`. By default the timeline falls back to `article.defaultCardLayout: 'portrait'`, while ordered `article.cardLayoutBreakpoints` can override that fallback using the currently available vertical space for article cards.
649
+ The two base layouts are `portrait` (vertical) and `landscape` (horizontal). Six built-in presets provide common content and shape options: `title-only`, `title-subtitle`, `label`, `image-text` and `image-only` extend portrait, while `pill` extends landscape with a circular thumbnail and rounded ends. See [preset descriptions and examples](docs/custom-card-layouts.md#built-in-presets), or try the **Built-in card presets** demo scenario. By default the timeline falls back to `article.defaultCardLayout: 'portrait'`, while ordered `article.cardLayoutBreakpoints` can override that fallback using the currently available vertical space for article cards.
452
650
 
453
651
  ```js
454
652
  const timeline = new Timeline(container, {
@@ -552,6 +750,11 @@ npm run dev
552
750
 
553
751
  Then open the served URL (Vite dev server). Switch scenarios via the toolbar.
554
752
 
753
+ Choose **Card layout inheritance** (or add `?scenario=card-layout-inheritance&metrics=0`)
754
+ to compare built-in cards with custom layouts created using `extends`. The scenario
755
+ includes style-only presets, an extension of a custom layout, and a drawing-hook
756
+ override. Hover, select and star the cards to check their inherited behaviour.
757
+
555
758
  ## Browser support / Build targets
556
759
 
557
760
  ### Build targets