@nowline/layout 0.8.6 → 0.9.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/dist/axis-columns.d.ts +70 -0
- package/dist/axis-columns.d.ts.map +1 -0
- package/dist/axis-columns.js +104 -0
- package/dist/axis-columns.js.map +1 -0
- package/dist/calendar-resolver.d.ts +27 -0
- package/dist/calendar-resolver.d.ts.map +1 -0
- package/dist/calendar-resolver.js +132 -0
- package/dist/calendar-resolver.js.map +1 -0
- package/dist/calendar.d.ts +0 -19
- package/dist/calendar.d.ts.map +1 -1
- package/dist/calendar.js +4 -44
- package/dist/calendar.js.map +1 -1
- package/dist/canvas-width.d.ts +23 -0
- package/dist/canvas-width.d.ts.map +1 -0
- package/dist/canvas-width.js +26 -0
- package/dist/canvas-width.js.map +1 -0
- package/dist/capacity.d.ts +28 -0
- package/dist/capacity.d.ts.map +1 -1
- package/dist/capacity.js +64 -29
- package/dist/capacity.js.map +1 -1
- package/dist/chart-translation.d.ts +22 -0
- package/dist/chart-translation.d.ts.map +1 -0
- package/dist/chart-translation.js +83 -0
- package/dist/chart-translation.js.map +1 -0
- package/dist/container-header-geometry.d.ts +64 -0
- package/dist/container-header-geometry.d.ts.map +1 -0
- package/dist/container-header-geometry.js +89 -0
- package/dist/container-header-geometry.js.map +1 -0
- package/dist/dsl-utils.d.ts +3 -4
- package/dist/dsl-utils.d.ts.map +1 -1
- package/dist/dsl-utils.js +8 -25
- package/dist/dsl-utils.js.map +1 -1
- package/dist/edge-routing.d.ts +69 -78
- package/dist/edge-routing.d.ts.map +1 -1
- package/dist/edge-routing.js +271 -401
- package/dist/edge-routing.js.map +1 -1
- package/dist/frame-tab-geometry.d.ts +24 -14
- package/dist/frame-tab-geometry.d.ts.map +1 -1
- package/dist/frame-tab-geometry.js +69 -23
- package/dist/frame-tab-geometry.js.map +1 -1
- package/dist/header-card-geometry.d.ts +12 -0
- package/dist/header-card-geometry.d.ts.map +1 -1
- package/dist/header-card-geometry.js +14 -2
- package/dist/header-card-geometry.js.map +1 -1
- package/dist/header-logo.d.ts +28 -0
- package/dist/header-logo.d.ts.map +1 -0
- package/dist/header-logo.js +51 -0
- package/dist/header-logo.js.map +1 -0
- package/dist/i18n.d.ts +11 -0
- package/dist/i18n.d.ts.map +1 -1
- package/dist/i18n.js +11 -1
- package/dist/i18n.js.map +1 -1
- package/dist/index.d.ts +20 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +17 -7
- package/dist/index.js.map +1 -1
- package/dist/inline-date-pin-geometry.d.ts +19 -11
- package/dist/inline-date-pin-geometry.d.ts.map +1 -1
- package/dist/inline-date-pin-geometry.js +45 -46
- package/dist/inline-date-pin-geometry.js.map +1 -1
- package/dist/item-bar-geometry.d.ts +192 -4
- package/dist/item-bar-geometry.d.ts.map +1 -1
- package/dist/item-bar-geometry.js +258 -5
- package/dist/item-bar-geometry.js.map +1 -1
- package/dist/item-port-geometry.d.ts +13 -0
- package/dist/item-port-geometry.d.ts.map +1 -0
- package/dist/item-port-geometry.js +63 -0
- package/dist/item-port-geometry.js.map +1 -0
- package/dist/layout-context.d.ts +115 -51
- package/dist/layout-context.d.ts.map +1 -1
- package/dist/layout-context.js +96 -5
- package/dist/layout-context.js.map +1 -1
- package/dist/layout-insights.d.ts.map +1 -1
- package/dist/layout-insights.js +73 -1
- package/dist/layout-insights.js.map +1 -1
- package/dist/layout.d.ts +35 -0
- package/dist/layout.d.ts.map +1 -1
- package/dist/layout.js +18 -1315
- package/dist/layout.js.map +1 -1
- package/dist/nodes/anchor-node.d.ts.map +1 -1
- package/dist/nodes/anchor-node.js +11 -4
- package/dist/nodes/anchor-node.js.map +1 -1
- package/dist/nodes/content-extent.d.ts +24 -0
- package/dist/nodes/content-extent.d.ts.map +1 -0
- package/dist/nodes/content-extent.js +100 -0
- package/dist/nodes/content-extent.js.map +1 -0
- package/dist/nodes/dependency-edges.d.ts +6 -0
- package/dist/nodes/dependency-edges.d.ts.map +1 -0
- package/dist/nodes/dependency-edges.js +148 -0
- package/dist/nodes/dependency-edges.js.map +1 -0
- package/dist/nodes/footnote-node.d.ts +24 -3
- package/dist/nodes/footnote-node.d.ts.map +1 -1
- package/dist/nodes/footnote-node.js +129 -25
- package/dist/nodes/footnote-node.js.map +1 -1
- package/dist/nodes/group-node.d.ts +10 -21
- package/dist/nodes/group-node.d.ts.map +1 -1
- package/dist/nodes/group-node.js +79 -152
- package/dist/nodes/group-node.js.map +1 -1
- package/dist/nodes/header-node.d.ts +56 -0
- package/dist/nodes/header-node.d.ts.map +1 -0
- package/dist/nodes/header-node.js +163 -0
- package/dist/nodes/header-node.js.map +1 -0
- package/dist/nodes/include-node.d.ts +22 -12
- package/dist/nodes/include-node.d.ts.map +1 -1
- package/dist/nodes/include-node.js +95 -62
- package/dist/nodes/include-node.js.map +1 -1
- package/dist/nodes/item-measure.d.ts +135 -0
- package/dist/nodes/item-measure.d.ts.map +1 -0
- package/dist/nodes/item-measure.js +514 -0
- package/dist/nodes/item-measure.js.map +1 -0
- package/dist/nodes/item-node.d.ts +162 -9
- package/dist/nodes/item-node.d.ts.map +1 -1
- package/dist/nodes/item-node.js +256 -69
- package/dist/nodes/item-node.js.map +1 -1
- package/dist/nodes/marker-band.d.ts +118 -0
- package/dist/nodes/marker-band.d.ts.map +1 -0
- package/dist/nodes/marker-band.js +303 -0
- package/dist/nodes/marker-band.js.map +1 -0
- package/dist/nodes/marker-geometry.js +1 -1
- package/dist/nodes/marker-geometry.js.map +1 -1
- package/dist/nodes/milestone-node.d.ts +112 -15
- package/dist/nodes/milestone-node.d.ts.map +1 -1
- package/dist/nodes/milestone-node.js +246 -95
- package/dist/nodes/milestone-node.js.map +1 -1
- package/dist/nodes/nowline-node.d.ts +8 -0
- package/dist/nodes/nowline-node.d.ts.map +1 -0
- package/dist/nodes/nowline-node.js +74 -0
- package/dist/nodes/nowline-node.js.map +1 -0
- package/dist/nodes/parallel-node.d.ts +7 -12
- package/dist/nodes/parallel-node.d.ts.map +1 -1
- package/dist/nodes/parallel-node.js +66 -30
- package/dist/nodes/parallel-node.js.map +1 -1
- package/dist/nodes/region-markers.d.ts +41 -0
- package/dist/nodes/region-markers.d.ts.map +1 -0
- package/dist/nodes/region-markers.js +130 -0
- package/dist/nodes/region-markers.js.map +1 -0
- package/dist/nodes/roadmap-node.d.ts +9 -72
- package/dist/nodes/roadmap-node.d.ts.map +1 -1
- package/dist/nodes/roadmap-node.js +38 -788
- package/dist/nodes/roadmap-node.js.map +1 -1
- package/dist/nodes/row-track.d.ts +33 -0
- package/dist/nodes/row-track.d.ts.map +1 -0
- package/dist/nodes/row-track.js +170 -0
- package/dist/nodes/row-track.js.map +1 -0
- package/dist/nodes/sequence-item.d.ts +25 -0
- package/dist/nodes/sequence-item.d.ts.map +1 -0
- package/dist/nodes/sequence-item.js +396 -0
- package/dist/nodes/sequence-item.js.map +1 -0
- package/dist/nodes/sequence-one.d.ts +5 -0
- package/dist/nodes/sequence-one.d.ts.map +1 -0
- package/dist/nodes/sequence-one.js +26 -0
- package/dist/nodes/sequence-one.js.map +1 -0
- package/dist/nodes/swimlane-node.d.ts +5 -17
- package/dist/nodes/swimlane-node.d.ts.map +1 -1
- package/dist/nodes/swimlane-node.js +62 -145
- package/dist/nodes/swimlane-node.js.map +1 -1
- package/dist/nodes/wave-node.d.ts +52 -0
- package/dist/nodes/wave-node.d.ts.map +1 -0
- package/dist/nodes/wave-node.js +483 -0
- package/dist/nodes/wave-node.js.map +1 -0
- package/dist/non-working-display.d.ts +14 -0
- package/dist/non-working-display.d.ts.map +1 -0
- package/dist/non-working-display.js +28 -0
- package/dist/non-working-display.js.map +1 -0
- package/dist/phases/date-window.d.ts +48 -0
- package/dist/phases/date-window.d.ts.map +1 -0
- package/dist/phases/date-window.js +130 -0
- package/dist/phases/date-window.js.map +1 -0
- package/dist/phases/finalize.d.ts +198 -0
- package/dist/phases/finalize.d.ts.map +1 -0
- package/dist/phases/finalize.js +1058 -0
- package/dist/phases/finalize.js.map +1 -0
- package/dist/phases/measure.d.ts +77 -0
- package/dist/phases/measure.d.ts.map +1 -0
- package/dist/phases/measure.js +222 -0
- package/dist/phases/measure.js.map +1 -0
- package/dist/phases/place.d.ts +28 -0
- package/dist/phases/place.d.ts.map +1 -0
- package/dist/phases/place.js +225 -0
- package/dist/phases/place.js.map +1 -0
- package/dist/renderable.d.ts.map +1 -1
- package/dist/renderable.js +23 -3
- package/dist/renderable.js.map +1 -1
- package/dist/resolve-today.d.ts +11 -1
- package/dist/resolve-today.d.ts.map +1 -1
- package/dist/resolve-today.js +26 -12
- package/dist/resolve-today.js.map +1 -1
- package/dist/row-packer.d.ts +42 -16
- package/dist/row-packer.d.ts.map +1 -1
- package/dist/row-packer.js +51 -78
- package/dist/row-packer.js.map +1 -1
- package/dist/schedule.d.ts +58 -1
- package/dist/schedule.d.ts.map +1 -1
- package/dist/schedule.js +280 -106
- package/dist/schedule.js.map +1 -1
- package/dist/start-rules.d.ts +27 -0
- package/dist/start-rules.d.ts.map +1 -0
- package/dist/start-rules.js +91 -0
- package/dist/start-rules.js.map +1 -0
- package/dist/start-terms.d.ts +23 -0
- package/dist/start-terms.d.ts.map +1 -0
- package/dist/start-terms.js +27 -0
- package/dist/start-terms.js.map +1 -0
- package/dist/status-dot.d.ts +46 -0
- package/dist/status-dot.d.ts.map +1 -0
- package/dist/status-dot.js +78 -0
- package/dist/status-dot.js.map +1 -0
- package/dist/style-resolution.d.ts.map +1 -1
- package/dist/style-resolution.js +23 -43
- package/dist/style-resolution.js.map +1 -1
- package/dist/text-measure.d.ts +28 -0
- package/dist/text-measure.d.ts.map +1 -0
- package/dist/text-measure.js +70 -0
- package/dist/text-measure.js.map +1 -0
- package/dist/themes/contrast.d.ts +4 -0
- package/dist/themes/contrast.d.ts.map +1 -0
- package/dist/themes/contrast.js +32 -0
- package/dist/themes/contrast.js.map +1 -0
- package/dist/themes/dark.d.ts.map +1 -1
- package/dist/themes/dark.js +28 -1
- package/dist/themes/dark.js.map +1 -1
- package/dist/themes/grayscale.d.ts.map +1 -1
- package/dist/themes/grayscale.js +28 -1
- package/dist/themes/grayscale.js.map +1 -1
- package/dist/themes/index.d.ts +4 -11
- package/dist/themes/index.d.ts.map +1 -1
- package/dist/themes/index.js +6 -4
- package/dist/themes/index.js.map +1 -1
- package/dist/themes/light.d.ts.map +1 -1
- package/dist/themes/light.js +28 -1
- package/dist/themes/light.js.map +1 -1
- package/dist/themes/shape.d.ts +31 -0
- package/dist/themes/shape.d.ts.map +1 -1
- package/dist/themes/shared.d.ts +44 -50
- package/dist/themes/shared.d.ts.map +1 -1
- package/dist/themes/shared.js +79 -83
- package/dist/themes/shared.js.map +1 -1
- package/dist/time-scale.d.ts +42 -6
- package/dist/time-scale.d.ts.map +1 -1
- package/dist/time-scale.js +109 -17
- package/dist/time-scale.js.map +1 -1
- package/dist/types.d.ts +528 -11
- package/dist/types.d.ts.map +1 -1
- package/dist/view-preset.d.ts +61 -6
- package/dist/view-preset.d.ts.map +1 -1
- package/dist/view-preset.js +439 -24
- package/dist/view-preset.js.map +1 -1
- package/dist/wave-barrier.d.ts +107 -0
- package/dist/wave-barrier.d.ts.map +1 -0
- package/dist/wave-barrier.js +174 -0
- package/dist/wave-barrier.js.map +1 -0
- package/dist/wave-hatch.d.ts +4 -0
- package/dist/wave-hatch.d.ts.map +1 -0
- package/dist/wave-hatch.js +21 -0
- package/dist/wave-hatch.js.map +1 -0
- package/dist/wave-layout.d.ts +99 -0
- package/dist/wave-layout.d.ts.map +1 -0
- package/dist/wave-layout.js +130 -0
- package/dist/wave-layout.js.map +1 -0
- package/dist/working-calendar.d.ts +128 -4
- package/dist/working-calendar.d.ts.map +1 -1
- package/dist/working-calendar.js +725 -51
- package/dist/working-calendar.js.map +1 -1
- package/dist/working-span.d.ts +11 -0
- package/dist/working-span.d.ts.map +1 -0
- package/dist/working-span.js +18 -0
- package/dist/working-span.js.map +1 -0
- package/package.json +4 -4
- package/src/axis-columns.ts +140 -0
- package/src/calendar-resolver.ts +161 -0
- package/src/calendar.ts +4 -45
- package/src/canvas-width.ts +36 -0
- package/src/capacity.ts +71 -30
- package/src/chart-translation.ts +88 -0
- package/src/container-header-geometry.ts +116 -0
- package/src/dsl-utils.ts +8 -26
- package/src/edge-routing.ts +347 -491
- package/src/frame-tab-geometry.ts +78 -25
- package/src/header-card-geometry.ts +17 -2
- package/src/header-logo.ts +67 -0
- package/src/i18n.ts +22 -1
- package/src/index.ts +97 -12
- package/src/inline-date-pin-geometry.ts +55 -58
- package/src/item-bar-geometry.ts +341 -5
- package/src/item-port-geometry.ts +69 -0
- package/src/layout-context.ts +210 -72
- package/src/layout-insights.ts +109 -2
- package/src/layout.ts +57 -1530
- package/src/nodes/anchor-node.ts +11 -4
- package/src/nodes/content-extent.ts +107 -0
- package/src/nodes/dependency-edges.ts +171 -0
- package/src/nodes/footnote-node.ts +171 -31
- package/src/nodes/group-node.ts +92 -214
- package/src/nodes/header-node.ts +255 -0
- package/src/nodes/include-node.ts +124 -110
- package/src/nodes/item-measure.ts +723 -0
- package/src/nodes/item-node.ts +358 -80
- package/src/nodes/marker-band.ts +406 -0
- package/src/nodes/marker-geometry.ts +1 -1
- package/src/nodes/milestone-node.ts +321 -136
- package/src/nodes/nowline-node.ts +87 -0
- package/src/nodes/parallel-node.ts +69 -38
- package/src/nodes/region-markers.ts +194 -0
- package/src/nodes/roadmap-node.ts +46 -950
- package/src/nodes/row-track.ts +217 -0
- package/src/nodes/sequence-item.ts +433 -0
- package/src/nodes/sequence-one.ts +40 -0
- package/src/nodes/swimlane-node.ts +66 -205
- package/src/nodes/wave-node.ts +609 -0
- package/src/non-working-display.ts +32 -0
- package/src/phases/date-window.ts +191 -0
- package/src/phases/finalize.ts +1303 -0
- package/src/phases/measure.ts +329 -0
- package/src/phases/place.ts +318 -0
- package/src/renderable.ts +23 -3
- package/src/resolve-today.ts +28 -25
- package/src/row-packer.ts +85 -84
- package/src/schedule.ts +362 -114
- package/src/start-rules.ts +113 -0
- package/src/start-terms.ts +38 -0
- package/src/status-dot.ts +81 -0
- package/src/style-resolution.ts +27 -57
- package/src/text-measure.ts +71 -0
- package/src/themes/contrast.ts +34 -0
- package/src/themes/dark.ts +28 -1
- package/src/themes/grayscale.ts +28 -1
- package/src/themes/index.ts +10 -7
- package/src/themes/light.ts +28 -1
- package/src/themes/shape.ts +38 -0
- package/src/themes/shared.ts +85 -93
- package/src/time-scale.ts +117 -19
- package/src/types.ts +529 -20
- package/src/view-preset.ts +520 -27
- package/src/wave-barrier.ts +242 -0
- package/src/wave-hatch.ts +25 -0
- package/src/wave-layout.ts +203 -0
- package/src/working-calendar.ts +875 -57
- package/src/working-span.ts +19 -0
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
// Phase 1, the date window (specs/layout-phases.md §3.2): the roadmap's
|
|
2
|
+
// scope (theme, locale, style context, `default roadmap` style) and the
|
|
3
|
+
// natural date window, a projection of the day schedule
|
|
4
|
+
// (specs/scheduler-unification.md §3.3). Nothing here knows about pixels.
|
|
5
|
+
|
|
6
|
+
import type { NowlineFile, ResolveResult } from '@nowline/core';
|
|
7
|
+
import { findProp } from '@nowline/core/internal';
|
|
8
|
+
import { type CalendarConfig, daysBetween, literalToDays } from '../calendar.js';
|
|
9
|
+
import { resolveWorkingCalendar } from '../calendar-resolver.js';
|
|
10
|
+
import { propValue } from '../dsl-utils.js';
|
|
11
|
+
import { resolveLocale } from '../i18n.js';
|
|
12
|
+
import type { LayoutOptions } from '../layout.js';
|
|
13
|
+
import { isNonWorkingDisplay, type NonWorkingDisplay } from '../non-working-display.js';
|
|
14
|
+
import type { RoadmapSchedule } from '../schedule.js';
|
|
15
|
+
import { resolveStyle, type StyleContext } from '../style-resolution.js';
|
|
16
|
+
import { type Theme, type ThemeName, themes } from '../themes/index.js';
|
|
17
|
+
import type { ResolvedStyle } from '../types.js';
|
|
18
|
+
import { resolveScale, tickBoundaryAtOrAfter, type ViewPreset } from '../view-preset.js';
|
|
19
|
+
import { daysPerUnit, type WorkingCalendar } from '../working-calendar.js';
|
|
20
|
+
|
|
21
|
+
/** What every later phase reads about the roadmap as a whole. */
|
|
22
|
+
export interface RoadmapScope {
|
|
23
|
+
themeName: ThemeName;
|
|
24
|
+
theme: Theme;
|
|
25
|
+
/** The resolved locale: the surface option, then the directive, then `en-US`. */
|
|
26
|
+
locale: string;
|
|
27
|
+
styleCtx: StyleContext;
|
|
28
|
+
/** `default roadmap`: header position and height, timeline position, minor grid, non-working. */
|
|
29
|
+
roadmapStyle: ResolvedStyle;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* The natural date window and the calendar it is counted in. Item sizes
|
|
34
|
+
* are not part of it: `createLayoutContext` resolves each file's own sizes
|
|
35
|
+
* under `cal`, because an isolated region declares its own.
|
|
36
|
+
*/
|
|
37
|
+
export interface DateWindow {
|
|
38
|
+
cal: CalendarConfig;
|
|
39
|
+
calendar: WorkingCalendar;
|
|
40
|
+
/** The view preset (`scale:` block): tick unit, pixels per unit, labels. */
|
|
41
|
+
preset: ViewPreset;
|
|
42
|
+
schedule: RoadmapSchedule;
|
|
43
|
+
startDate: Date;
|
|
44
|
+
/** The natural end. Finalize step f2 may extend the axis past it; nothing else moves it. */
|
|
45
|
+
naturalEndDate: Date;
|
|
46
|
+
/** Working days in the natural window. */
|
|
47
|
+
spanDays: number;
|
|
48
|
+
/** Calendar days under `non-working:show`, else `spanDays`. */
|
|
49
|
+
timelineDays: number;
|
|
50
|
+
/** How non-working days are drawn: the surface option, then `default roadmap`. */
|
|
51
|
+
nonWorking: NonWorkingDisplay;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export function resolveScope(
|
|
55
|
+
file: NowlineFile,
|
|
56
|
+
resolved: ResolveResult,
|
|
57
|
+
options: LayoutOptions,
|
|
58
|
+
): RoadmapScope {
|
|
59
|
+
const themeName: ThemeName = options.theme ?? 'light';
|
|
60
|
+
const theme: Theme = themes[themeName];
|
|
61
|
+
const locale = resolveLocale(options.locale, directiveLocale(file));
|
|
62
|
+
const styleCtx: StyleContext = {
|
|
63
|
+
theme,
|
|
64
|
+
styles: resolved.config.styles,
|
|
65
|
+
defaults: resolved.config.defaults,
|
|
66
|
+
labels: resolved.content.labels,
|
|
67
|
+
};
|
|
68
|
+
// Raw style props (including `timeline-position` and `minor-grid`) are
|
|
69
|
+
// banned on the roadmap declaration itself, so the values come from the
|
|
70
|
+
// level-2 `default roadmap` line in config.
|
|
71
|
+
const roadmapStyle = resolveStyle('roadmap', file.roadmapDecl?.properties ?? [], styleCtx);
|
|
72
|
+
return { themeName, theme, locale, styleCtx, roadmapStyle };
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export function resolveDateWindow(
|
|
76
|
+
file: NowlineFile,
|
|
77
|
+
resolved: ResolveResult,
|
|
78
|
+
options: LayoutOptions,
|
|
79
|
+
scope: RoadmapScope,
|
|
80
|
+
schedule: RoadmapSchedule,
|
|
81
|
+
): DateWindow {
|
|
82
|
+
// The working calendar maps dates to working-day indices for the
|
|
83
|
+
// window, the axis and every placement (specs/working-calendar.md
|
|
84
|
+
// §5, §7.1).
|
|
85
|
+
const { config: cal, working: calendar } = resolveWorkingCalendar(file, resolved);
|
|
86
|
+
const preset = resolveScale(file, resolved.config.scale);
|
|
87
|
+
// Window is content-aware: when `length:` is omitted we derive the end
|
|
88
|
+
// day from the latest dated/sequenced entity (item, anchor, milestone,
|
|
89
|
+
// today's now-line) instead of defaulting to a 180-day desert.
|
|
90
|
+
const { startDate, endDate } = computeDateWindow(file, schedule, options.today, preset);
|
|
91
|
+
// How non-working days are drawn: the surface option, then the file's
|
|
92
|
+
// `default roadmap non-working:` key (resolved to `hide` when absent).
|
|
93
|
+
// It reaches every placement through the time scale.
|
|
94
|
+
const nonWorking = isNonWorkingDisplay(options.nonWorking)
|
|
95
|
+
? options.nonWorking
|
|
96
|
+
: scope.roadmapStyle.nonWorking;
|
|
97
|
+
// `TimeScale.showsNonWorking`, needed here to size the scale's range.
|
|
98
|
+
const showsNonWorking = nonWorking === 'show' && calendar.hasNonWorkingDays;
|
|
99
|
+
const spanDays = Math.max(1, calendar.workingIndexOf(startDate, endDate));
|
|
100
|
+
// Under `show` every calendar day takes a pixel width of its own, so
|
|
101
|
+
// the chart widens by the non-working days in the window.
|
|
102
|
+
const timelineDays = showsNonWorking ? Math.max(1, daysBetween(startDate, endDate)) : spanDays;
|
|
103
|
+
return {
|
|
104
|
+
cal,
|
|
105
|
+
calendar,
|
|
106
|
+
preset,
|
|
107
|
+
schedule,
|
|
108
|
+
startDate,
|
|
109
|
+
naturalEndDate: endDate,
|
|
110
|
+
spanDays,
|
|
111
|
+
timelineDays,
|
|
112
|
+
nonWorking,
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Compute a sensible [startDate, endDate] window from the roadmap's day
|
|
117
|
+
// schedule (`scheduleRoadmap`, specs/scheduler-unification.md §3.3).
|
|
118
|
+
//
|
|
119
|
+
// Precedence:
|
|
120
|
+
// 1. An explicit `length:` is a minimum span; content (including wave
|
|
121
|
+
// barriers E_n and every S_k) past it grows the window to the next
|
|
122
|
+
// tick boundary.
|
|
123
|
+
// 2. Otherwise we derive the end day from the actual content extent
|
|
124
|
+
// (`schedule.extent.contentEndDay`: latest lane cursor, anchor date,
|
|
125
|
+
// milestone date/after, wave edge) and today's now-line if it falls
|
|
126
|
+
// past the content. This keeps the rendered chart from defaulting to
|
|
127
|
+
// a 180-day desert when the content only spans a few weeks.
|
|
128
|
+
// 3. As a last resort (no content + no length), fall back to a small
|
|
129
|
+
// 4-week placeholder so an empty roadmap still draws a sensible axis.
|
|
130
|
+
//
|
|
131
|
+
// The start is `schedule.startDate`: the roadmap's `start:`, else `today`
|
|
132
|
+
// (see `scheduleRoadmap`). Every day count is a working-day index from the
|
|
133
|
+
// start (specs/working-calendar.md §5) under the schedule's calendar. A
|
|
134
|
+
// calendar with no non-working day keeps calendar-day arithmetic.
|
|
135
|
+
//
|
|
136
|
+
// Exported for tests; not part of the package surface.
|
|
137
|
+
export function computeDateWindow(
|
|
138
|
+
file: NowlineFile,
|
|
139
|
+
schedule: RoadmapSchedule,
|
|
140
|
+
today: Date | undefined,
|
|
141
|
+
scale: ViewPreset,
|
|
142
|
+
): { startDate: Date; endDate: Date } {
|
|
143
|
+
const props = file.roadmapDecl?.properties ?? [];
|
|
144
|
+
const { config: cal, working: calendar } = schedule.calendar;
|
|
145
|
+
const { startDate } = schedule;
|
|
146
|
+
const lengthRaw = propValue(props, 'length');
|
|
147
|
+
let minDays = 0;
|
|
148
|
+
if (lengthRaw) {
|
|
149
|
+
const days = literalToDays(lengthRaw, cal);
|
|
150
|
+
if (days > 0) {
|
|
151
|
+
minDays = days;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
// An explicit `length:` bounds the now-line: a far-future `today` must
|
|
155
|
+
// not stretch a deliberately-sized roadmap (that case stays out of range
|
|
156
|
+
// and surfaces as an NL.W1000 insight). Content overflow — items,
|
|
157
|
+
// anchors, milestones — still grows the window below via `padded`, with
|
|
158
|
+
// `length:` acting purely as the floor. Without `length:`, `today`
|
|
159
|
+
// extends the window so the now-line is always in range.
|
|
160
|
+
let contentDays = schedule.extent.contentEndDay;
|
|
161
|
+
if (today && !(minDays > 0)) {
|
|
162
|
+
const t = calendar.workingIndexOf(startDate, today);
|
|
163
|
+
if (t > 0) contentDays = Math.max(contentDays, t);
|
|
164
|
+
}
|
|
165
|
+
const tickDays = daysPerUnit(scale.unit, cal);
|
|
166
|
+
// Round up to the smallest tick boundary that is `>= contentDays`. When
|
|
167
|
+
// the latest content lands exactly on a tick boundary the chart ends
|
|
168
|
+
// exactly there (no extra trailing tick); otherwise we extend to the
|
|
169
|
+
// next tick so the right edge always sits on a labelled column. For
|
|
170
|
+
// month / quarter / year scales the boundary is a real month /
|
|
171
|
+
// quarter / year start, not a multiple of `days-per-month` etc.
|
|
172
|
+
const padded = tickBoundaryAtOrAfter(
|
|
173
|
+
startDate,
|
|
174
|
+
contentDays > 0 ? contentDays : 4 * cal.daysPerWeek,
|
|
175
|
+
scale.unit,
|
|
176
|
+
tickDays,
|
|
177
|
+
calendar,
|
|
178
|
+
);
|
|
179
|
+
const finalDays = Math.max(minDays, padded);
|
|
180
|
+
return {
|
|
181
|
+
startDate,
|
|
182
|
+
endDate: calendar.dateAtWorkingIndex(startDate, Math.max(1, finalDays)),
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// Read the optional `locale:` property from the file's `nowline` directive.
|
|
187
|
+
// Layout receives an already-parsed AST, so this is a cheap lookup with no
|
|
188
|
+
// validation work — that's the validator's job in `@nowline/core`.
|
|
189
|
+
function directiveLocale(file: NowlineFile): string | undefined {
|
|
190
|
+
return findProp(file.directive?.properties ?? [], 'locale')?.value;
|
|
191
|
+
}
|