From 1308bb1a1e97f2ee152b7f2cf15fd397767647ab Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 4 Sep 2026 16:56:33 +0000 Subject: [PATCH] docs(spec): colorField describes a field to derive a colour FROM MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `TimelineConfigSchema`, `CalendarConfigSchema` and `GanttConfigSchema` each declare a `colorField`, and all three `.describe()` strings said only that the named field "determines" / "drives" the colour. That reads as "point this at a field that holds a colour" — the case the renderers need least. The common author intent is `colorField: 'status'`, a select field whose options already carry the colours. The renderers resolve it as a ladder (objectui#7243, shared as `createFieldColorResolver` in `@object-ui/core`, present at the console pin 00d3f09c): the option colour the field declares for the record's stored value, else the value itself when it already is a colour literal, else each renderer's own last rung — a semantic colour token (gantt), a theme-aware palette hash (calendar), the default marker (timeline). The three strings now say that, each naming its own last rung. No accept-set change: all three keys stay `z.string().optional()`, and `check:authorable-surface` needed no regeneration. The only regenerated follower is `content/docs/references/ui/view.mdx`. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01G4138K1EG7kQ81FNba5Kp4 --- .changeset/colorfield-derive-describe.md | 15 +++++++++++++++ content/docs/references/ui/view.mdx | 18 +++++++++--------- packages/spec/src/ui/view.zod.ts | 6 +++--- 3 files changed, 27 insertions(+), 12 deletions(-) create mode 100644 .changeset/colorfield-derive-describe.md diff --git a/.changeset/colorfield-derive-describe.md b/.changeset/colorfield-derive-describe.md new file mode 100644 index 0000000000..099854c9e0 --- /dev/null +++ b/.changeset/colorfield-derive-describe.md @@ -0,0 +1,15 @@ +--- +"@objectstack/spec": patch +--- + +`colorField` now documents what it means: a field to DERIVE a colour from, not a field holding one. + +`TimelineConfigSchema`, `CalendarConfigSchema` and `GanttConfigSchema` each declare a `colorField`, and all three `.describe()` strings said only that the field "determines"/"drives" the colour — `'Field to determine item color'`, `'Field whose value determines the event color'`, `'Field that drives the bar color'`. Read literally, that invites pointing the key at a field whose stored value *is* a colour, which is the one case the renderers need the least: the common author intent is `colorField: 'status'`, a select field whose options already carry the colours. + +The renderers resolve it as a derivation ladder (objectui#7243, shared as `createFieldColorResolver` in `@object-ui/core`): + +1. the option `color` the field declares for the record's stored value; +2. else the value itself, when it already is a colour literal (hex 3/6/8-digit, `rgb(...)`, `hsl(...)`); +3. else each renderer's own last rung — the gantt derives a semantic colour token, the calendar hashes onto its theme-aware palette, the timeline draws its default marker. + +The three strings now say that, each naming its own last rung. **Nothing in the accept set moves**: all three keys stay `z.string().optional()`, and a config pointing `colorField` at a plain hex field is still exactly as valid as before — that is rung 2. This is prose on a declared key, so the only regenerated follower is `content/docs/references/ui/view.mdx`. diff --git a/content/docs/references/ui/view.mdx b/content/docs/references/ui/view.mdx index e1349f86e0..1dd3275c86 100644 --- a/content/docs/references/ui/view.mdx +++ b/content/docs/references/ui/view.mdx @@ -106,7 +106,7 @@ Appearance and visualization configuration | **startDateField** | `string` | ✅ | Field providing the event start date/time | | **endDateField** | `string` | optional | Field providing the event end date/time (defaults to a single-day event) | | **titleField** | `string` | optional | Field displayed as the event title. Omit to fall back to the record display name (ADR-0079 resolver chain) | -| **colorField** | `string` | optional | Field whose value determines the event color | +| **colorField** | `string` | optional | Field to derive each event color from (it names a field, not a color): the option color declared on that field for the record value, else the value itself when it already is a color literal (hex, rgb() or hsl()), else the calendar theme-aware palette color hashed from the value | --- @@ -559,7 +559,7 @@ Gallery/card view configuration | **titleField** | `string` | ✅ | Field displayed as the task title | | **progressField** | `string` | optional | Field providing the task completion percentage | | **dependenciesField** | `string` | optional | Field listing the task's predecessor (dependency) record ids | -| **colorField** | `string` | optional | Field that drives the bar color | +| **colorField** | `string` | optional | Field to derive each bar color from (it names a field, not a color): the option color declared on that field for the record value, else the value itself when it already is a color literal (hex, rgb() or hsl()), else a semantic color token derived from the value | | **parentField** | `string` | optional | Field holding the parent task id (builds the summary → step tree) | | **typeField** | `string` | optional | Field whose value maps to task/summary/milestone | | **baselineStartField** | `string` | optional | Baseline (planned) start field | @@ -915,7 +915,7 @@ View filter rule | **startDateField** | `string` | ✅ | Field providing the event start date/time | | **endDateField** | `string` | optional | Field providing the event end date/time (defaults to a single-day event) | | **titleField** | `string` | optional | Field displayed as the event title. Omit to fall back to the record display name (ADR-0079 resolver chain) | -| **colorField** | `string` | optional | Field whose value determines the event color | +| **colorField** | `string` | optional | Field to derive each event color from (it names a field, not a color): the option color declared on that field for the record value, else the value itself when it already is a color literal (hex, rgb() or hsl()), else the calendar theme-aware palette color hashed from the value | ### Nested Shape: `ListView.gantt` @@ -926,7 +926,7 @@ View filter rule | **titleField** | `string` | ✅ | Field displayed as the task title | | **progressField** | `string` | optional | Field providing the task completion percentage | | **dependenciesField** | `string` | optional | Field listing the task's predecessor (dependency) record ids | -| **colorField** | `string` | optional | Field that drives the bar color | +| **colorField** | `string` | optional | Field to derive each bar color from (it names a field, not a color): the option color declared on that field for the record value, else the value itself when it already is a color literal (hex, rgb() or hsl()), else a semantic color token derived from the value | | **parentField** | `string` | optional | Field holding the parent task id (builds the summary → step tree) | | **typeField** | `string` | optional | Field whose value maps to task/summary/milestone | | **baselineStartField** | `string` | optional | Baseline (planned) start field | @@ -959,7 +959,7 @@ View filter rule | **endDateField** | `string` | optional | Field for timeline item end date | | **titleField** | `string` | ✅ | Field to display as timeline item title | | **groupByField** | `string` | optional | Field to group timeline rows | -| **colorField** | `string` | optional | Field to determine item color | +| **colorField** | `string` | optional | Field to derive each item color from (it names a field, not a color): the option color declared on that field for the record value, else the value itself when it already is a color literal (hex, rgb() or hsl()), else the timeline default marker color | | **scale** | `Enum<'hour' \| 'day' \| 'week' \| 'month' \| 'quarter' \| 'year'>` | optional (default: `"week"`) | Default timeline scale | ### Nested Shape: `ListView.chart` @@ -1301,7 +1301,7 @@ View filter rule | **startDateField** | `string` | ✅ | Field providing the event start date/time | | **endDateField** | `string` | optional | Field providing the event end date/time (defaults to a single-day event) | | **titleField** | `string` | optional | Field displayed as the event title. Omit to fall back to the record display name (ADR-0079 resolver chain) | -| **colorField** | `string` | optional | Field whose value determines the event color | +| **colorField** | `string` | optional | Field to derive each event color from (it names a field, not a color): the option color declared on that field for the record value, else the value itself when it already is a color literal (hex, rgb() or hsl()), else the calendar theme-aware palette color hashed from the value | ### Nested Shape: `ObjectListView.gantt` @@ -1312,7 +1312,7 @@ View filter rule | **titleField** | `string` | ✅ | Field displayed as the task title | | **progressField** | `string` | optional | Field providing the task completion percentage | | **dependenciesField** | `string` | optional | Field listing the task's predecessor (dependency) record ids | -| **colorField** | `string` | optional | Field that drives the bar color | +| **colorField** | `string` | optional | Field to derive each bar color from (it names a field, not a color): the option color declared on that field for the record value, else the value itself when it already is a color literal (hex, rgb() or hsl()), else a semantic color token derived from the value | | **parentField** | `string` | optional | Field holding the parent task id (builds the summary → step tree) | | **typeField** | `string` | optional | Field whose value maps to task/summary/milestone | | **baselineStartField** | `string` | optional | Baseline (planned) start field | @@ -1345,7 +1345,7 @@ View filter rule | **endDateField** | `string` | optional | Field for timeline item end date | | **titleField** | `string` | ✅ | Field to display as timeline item title | | **groupByField** | `string` | optional | Field to group timeline rows | -| **colorField** | `string` | optional | Field to determine item color | +| **colorField** | `string` | optional | Field to derive each item color from (it names a field, not a color): the option color declared on that field for the record value, else the value itself when it already is a color literal (hex, rgb() or hsl()), else the timeline default marker color | | **scale** | `Enum<'hour' \| 'day' \| 'week' \| 'month' \| 'quarter' \| 'year'>` | optional (default: `"week"`) | Default timeline scale | ### Nested Shape: `ObjectListView.chart` @@ -1597,7 +1597,7 @@ Timeline view configuration | **endDateField** | `string` | optional | Field for timeline item end date | | **titleField** | `string` | ✅ | Field to display as timeline item title | | **groupByField** | `string` | optional | Field to group timeline rows | -| **colorField** | `string` | optional | Field to determine item color | +| **colorField** | `string` | optional | Field to derive each item color from (it names a field, not a color): the option color declared on that field for the record value, else the value itself when it already is a color literal (hex, rgb() or hsl()), else the timeline default marker color | | **scale** | `Enum<'hour' \| 'day' \| 'week' \| 'month' \| 'quarter' \| 'year'>` | optional (default: `"week"`) | Default timeline scale | diff --git a/packages/spec/src/ui/view.zod.ts b/packages/spec/src/ui/view.zod.ts index 70fd82a854..5d8f1dd3a3 100644 --- a/packages/spec/src/ui/view.zod.ts +++ b/packages/spec/src/ui/view.zod.ts @@ -965,7 +965,7 @@ export const TimelineConfigSchema = lazySchema(() => strictObject({ endDateField: z.string().optional().describe('Field for timeline item end date'), titleField: z.string().describe('Field to display as timeline item title'), groupByField: z.string().optional().describe('Field to group timeline rows'), - colorField: z.string().optional().describe('Field to determine item color'), + colorField: z.string().optional().describe('Field to derive each item color from (it names a field, not a color): the option color declared on that field for the record value, else the value itself when it already is a color literal (hex, rgb() or hsl()), else the timeline default marker color'), scale: z.enum(['hour', 'day', 'week', 'month', 'quarter', 'year']).default('week').describe('Default timeline scale'), }).describe('Timeline view configuration')); @@ -1300,7 +1300,7 @@ export const CalendarConfigSchema = lazySchema(() => strictObject({ startDateField: z.string().describe('Field providing the event start date/time'), endDateField: z.string().optional().describe('Field providing the event end date/time (defaults to a single-day event)'), titleField: z.string().optional().describe('Field displayed as the event title. Omit to fall back to the record display name (ADR-0079 resolver chain)'), - colorField: z.string().optional().describe('Field whose value determines the event color'), + colorField: z.string().optional().describe('Field to derive each event color from (it names a field, not a color): the option color declared on that field for the record value, else the value itself when it already is a color literal (hex, rgb() or hsl()), else the calendar theme-aware palette color hashed from the value'), })); /** @@ -1344,7 +1344,7 @@ export const GanttConfigSchema = lazySchema(() => strictObject({ titleField: z.string().describe('Field displayed as the task title'), progressField: z.string().optional().describe('Field providing the task completion percentage'), dependenciesField: z.string().optional().describe("Field listing the task's predecessor (dependency) record ids"), - colorField: z.string().optional().describe('Field that drives the bar color'), + colorField: z.string().optional().describe('Field to derive each bar color from (it names a field, not a color): the option color declared on that field for the record value, else the value itself when it already is a color literal (hex, rgb() or hsl()), else a semantic color token derived from the value'), // Two-level hierarchy: a parent task id (summary bar) and a row type. parentField: z.string().optional().describe('Field holding the parent task id (builds the summary → step tree)'), typeField: z.string().optional().describe('Field whose value maps to task/summary/milestone'),