Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions .changeset/6170-timeline-schema-declared-keys.md
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
---
'@object-ui/plugin-timeline': minor
'@object-ui/types': minor
---

`TimelineSchema` now declares the presentational keys the timeline renderer actually reads
(objectui#6170, maintainer ruling 2026-08-25 — the same family rule adopted on
objectui#6172: the exported type aligns to the measured authored + read set).

Before this, `TimelineSchema` declared `events` (required), `orientation` and `position`,
and nothing else. `TimelineRenderer` is annotated `schema: TimelineSchema` and reads nine
keys off that node — `variant`, `items`, `dateFormat`, `onItemClick`, `minDate`, `maxDate`,
`rowLabel`, `scale`, `timeScale` — and **none** of the three that were declared. The docs
property table and the registration's own designer `inputs` had agreed with the renderer
all along; only the exported type disagreed. It was invisible to `tsc` because `BaseSchema`
carries `[key: string]: any`, so every undeclared key resolved as `any` and the annotation
constrained nothing.

The most visible casualty was the docs page's own TypeScript example, which did not
compile: `Property 'events' is missing in type '{ type: "timeline"; variant: string; items:
… }' but required in type 'TimelineSchema'`. The page taught an authoring form its own
published type refused.

**Declared now** (TS interface and the `@object-ui/types/zod` mirror together): `variant`,
`items`, `dateFormat`, `scale`, `timeScale`, `rowLabel`, `minDate`, `maxDate`. `onItemClick`
is deliberately left undeclared — it is a runtime slot `ObjectTimeline` installs, and this
package keeps callback-shaped keys off the authored surface.

**`scale` is the canonical axis key.** It is `@objectstack/spec`'s `ui/TimelineConfig.json`
spelling and the one `resolveTimelineScale` reads first (`scale ?? timeScale`). The designer
now offers it, with all six buckets: `hour` / `quarter` / `year` have rendered correctly
since objectui#2942 but were offered by neither the designer (which listed three) nor the
exported type (which listed none), so they were authorable and undiscoverable. `timeScale`
stays as a deprecated alias so stored JSON keeps working; retiring it is routed separately.

**`events` is now optional.** It was required, which is why the documented authoring form
did not type-check. That widening is the only non-additive change here — strictly more
programs compile and strictly more input parses than before. `events`, `orientation` and
`position` remain declared and remain read by nothing; a timeline authored with `events`
still renders an empty rail. Their removal is a breaking narrowing of a published type and
is routed through ADR-0049 enforce-or-remove as its own change, not smuggled into this one.

Accept-set note for consumers: keys that previously resolved as `any` are now typed, so a
value the renderer never implemented — `variant: 'diagonal'`, `dateFormat: 'medieval'`,
`scale: 'fortnight'` — is a type error and a Zod rejection where it used to pass silently.
Nothing that renders today stops rendering. `BaseSchema`'s index signature is untouched, so
an undeclared key is still accepted by both halves (objectui#5155 / objectui#6269 own that
ceiling).
19 changes: 16 additions & 3 deletions content/docs/plugins/plugin-timeline.mdx
Original file line numberDiff line numberDiff line change
Expand Up@@ -58,7 +58,7 @@ const schema = {
- **Customizable Markers**: Color-coded markers with icon support
- **Date Formatting**: Multiple date format options
- **Gantt Charts**: Project timeline visualization with task bars
- **Time Scales**: Day, week, or month scales for Gantt view
- **Time Scales**: Hour, day, week, month, quarter, or year scales for Gantt view
- **Lightweight**: Pure CSS and React components

## Schema API
Expand All@@ -72,7 +72,8 @@ const schema = {
items?: TimelineItem[],
dateFormat?: 'short' | 'long' | 'iso',
// Gantt-specific
timeScale?: 'day' | 'week' | 'month',
scale?: 'hour' | 'day' | 'week' | 'month' | 'quarter' | 'year',
timeScale?: 'hour' | 'day' | 'week' | 'month' | 'quarter' | 'year', // deprecated alias of `scale`
rowLabel?: string,
minDate?: string,
maxDate?: string,
Expand DownExpand Up@@ -115,12 +116,24 @@ const schema = {
| `variant` | string | `'vertical'` | Timeline layout: vertical, horizontal, or gantt |
| `items` | array | `[]` | Array of timeline items |
| `dateFormat` | string | `'short'` | Date formatting: short, long, or iso |
| `timeScale` | string | `'month'` | Gantt time scale: day, week, or month |
| `scale` | string | `'month'` | Gantt axis bucket: hour, day, week, month, quarter, or year |
| `timeScale` | string | — | **Deprecated** — the pre-spec spelling of `scale`, still read as a fallback |
| `rowLabel` | string | `'Items'` | Label for Gantt rows |
| `minDate` | string | auto | Override min date for Gantt (YYYY-MM-DD) |
| `maxDate` | string | auto | Override max date for Gantt (YYYY-MM-DD) |
| `className` | string | `''` | Additional Tailwind CSS classes |

Every key above is declared on the exported `TimelineSchema`, so an editor
completes them and a wrong value is a type error. `scale` is the canonical axis
key — it is `@objectstack/spec`'s `ui/TimelineConfig.json` spelling and the one
the renderer reads first (`scale ?? timeScale`).

<Callout type="warn">
`events`, `orientation` and `position` are also declared on `TimelineSchema`
and are **read by nothing**. A timeline authored with `events` renders an empty
rail — use `items`. They are deprecated and scheduled for removal.
</Callout>

## Variants

### Marker Variants
Expand Down
24 changes: 22 additions & 2 deletions packages/plugin-timeline/src/renderer.tsx
Original file line numberDiff line numberDiff line change
Expand Up@@ -524,13 +524,33 @@ ComponentRegistry.register(
label: 'Date Format',
defaultValue: 'short',
},
// The designer's axis key is `scale` — the spec's spelling
// (`ui/TimelineConfig.json`) and the one `resolveTimelineScale` prefers.
// It offers all six buckets: `hour` / `quarter` / `year` have rendered
// correctly since #2942 but were offered by neither the designer nor the
// exported type, so they were authorable and undiscoverable (objectui#6170).
{
name: 'timeScale',
name: 'scale',
type: 'enum',
enum: ['day', 'week', 'month'],
enum: [...TIMELINE_SCALES],
label: 'Time Scale (Gantt only)',
defaultValue: 'month',
},
// Kept so a stored `timeScale` still round-trips through the designer.
// Deprecated in favour of `scale`; retiring the alias is routed separately
// (objectui#6170 maintainer ruling 2026-08-25). `ComponentInput` has no
// `deprecated` slot and no index signature, so the notice lives in
// `description` — this package's stated ceiling for anything the coarse
// `type` cannot express.
{
name: 'timeScale',
type: 'enum',
enum: [...TIMELINE_SCALES],
label: 'Time Scale (Gantt only)',
description:
'DEPRECATED — use `scale`, which @objectstack/spec owns and this renderer reads first. Kept so stored JSON keeps working.',
advanced: true,
},
{
name: 'rowLabel',
type: 'string',
Expand Down
Loading
Loading