@nowline/layout 0.6.0 → 0.8.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/index.d.ts CHANGED
@@ -5,6 +5,7 @@ export { INCLUDE_CHROME_BADGE_GAP_PX, INCLUDE_CHROME_BADGE_SIZE_PX, INCLUDE_CHRO
5
5
  export { ITEM_CAPTION_INSET_X_PX, ITEM_CAPTION_META_BASELINE_OFFSET_PX, ITEM_CAPTION_META_FONT_SIZE_PX, ITEM_CAPTION_SPILL_GAP_PX, ITEM_CAPTION_TITLE_BASELINE_OFFSET_PX, ITEM_CAPTION_TITLE_FONT_SIZE_PX, ITEM_DECORATION_SPILL_GAP_PX, ITEM_FOOTNOTE_INDICATOR_BASELINE_OFFSET_PX, ITEM_FOOTNOTE_INDICATOR_INSET_RIGHT_PX, ITEM_FOOTNOTE_INDICATOR_STEP_PX, ITEM_LINK_ICON_INSET_PX, ITEM_LINK_ICON_TILE_SIZE_PX, ITEM_STATUS_DOT_INSET_RIGHT_PX, ITEM_STATUS_DOT_INSET_TOP_PX, ITEM_STATUS_DOT_RADIUS_PX, LABEL_CHIP_GAP_ABOVE_PROGRESS_STRIP_PX, LABEL_CHIP_GAP_BETWEEN_PX, LABEL_CHIP_HEIGHT_PX, MIN_BAR_WIDTH_FOR_DOT_PX, MIN_BAR_WIDTH_FOR_FOOTNOTE_PX, MIN_BAR_WIDTH_FOR_LINK_AND_DOT_PX, } from './item-bar-geometry.js';
6
6
  export type { LayoutOptions, LayoutResult } from './layout.js';
7
7
  export { layoutRoadmap } from './layout.js';
8
+ export { collectLayoutInsights, type LayoutInsight, type LayoutInsightContext, type LayoutInsightSeverity, } from './layout-insights.js';
8
9
  export { civilDateInZone, type NormalizedZone, normalizeZone, type ResolveTodayOptions, resolveToday, TimezoneError, } from './resolve-today.js';
9
10
  export type { RoadmapSchedule, ScheduledItem, ScheduleOptions } from './schedule.js';
10
11
  export { scheduleRoadmap } from './schedule.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,2BAA2B,EAC3B,oBAAoB,EACpB,kBAAkB,EAClB,KAAK,oBAAoB,EACzB,mBAAmB,GACtB,MAAM,eAAe,CAAC;AACvB,OAAO,EACH,sBAAsB,EACtB,uBAAuB,EACvB,sBAAsB,EACtB,4BAA4B,EAC5B,2BAA2B,EAC3B,wBAAwB,EACxB,2BAA2B,EAC3B,KAAK,gBAAgB,EACrB,gBAAgB,GACnB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EACH,0BAA0B,EAC1B,4BAA4B,EAC5B,0BAA0B,EAC1B,uBAAuB,EACvB,qBAAqB,EACrB,yBAAyB,EACzB,2BAA2B,EAC3B,6BAA6B,GAChC,MAAM,2BAA2B,CAAC;AACnC,OAAO,EACH,2BAA2B,EAC3B,4BAA4B,EAC5B,iCAAiC,EACjC,4BAA4B,EAC5B,iCAAiC,EACjC,iCAAiC,EACjC,oCAAoC,EACpC,gCAAgC,EAChC,+BAA+B,EAC/B,iCAAiC,EACjC,KAAK,qBAAqB,EAC1B,qBAAqB,GACxB,MAAM,8BAA8B,CAAC;AACtC,OAAO,EACH,uBAAuB,EACvB,oCAAoC,EACpC,8BAA8B,EAC9B,yBAAyB,EACzB,qCAAqC,EACrC,+BAA+B,EAC/B,4BAA4B,EAC5B,0CAA0C,EAC1C,sCAAsC,EACtC,+BAA+B,EAC/B,uBAAuB,EACvB,2BAA2B,EAC3B,8BAA8B,EAC9B,4BAA4B,EAC5B,yBAAyB,EACzB,sCAAsC,EACtC,yBAAyB,EACzB,oBAAoB,EACpB,wBAAwB,EACxB,6BAA6B,EAC7B,iCAAiC,GACpC,MAAM,wBAAwB,CAAC;AAChC,YAAY,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC/D,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EACH,eAAe,EACf,KAAK,cAAc,EACnB,aAAa,EACb,KAAK,mBAAmB,EACxB,YAAY,EACZ,aAAa,GAChB,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EAAE,eAAe,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AACrF,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EACH,SAAS,EACT,cAAc,EACd,UAAU,EACV,kBAAkB,EAClB,KAAK,KAAK,EACV,KAAK,SAAS,EACd,MAAM,GACT,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACH,mBAAmB,EACnB,6BAA6B,EAC7B,yBAAyB,EACzB,yBAAyB,EACzB,gBAAgB,EAChB,yBAAyB,EACzB,4BAA4B,EAC5B,iBAAiB,EACjB,gBAAgB,EAChB,8BAA8B,EAC9B,gBAAgB,EAChB,kBAAkB,EAClB,UAAU,EACV,kCAAkC,EAClC,yBAAyB,EACzB,yBAAyB,EACzB,mBAAmB,EACnB,mBAAmB,EACnB,kCAAkC,EAClC,mBAAmB,EACnB,+BAA+B,EAC/B,6BAA6B,EAC7B,yBAAyB,EACzB,yBAAyB,EACzB,wCAAwC,EACxC,kCAAkC,EAClC,wBAAwB,EACxB,yBAAyB,EACzB,kBAAkB,EAClB,iCAAiC,EACjC,2BAA2B,EAC3B,yBAAyB,EACzB,iBAAiB,EACjB,uBAAuB,EACvB,wBAAwB,EACxB,YAAY,EACZ,sCAAsC,EACtC,6BAA6B,EAC7B,0BAA0B,GAC7B,MAAM,oBAAoB,CAAC;AAC5B,cAAc,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,2BAA2B,EAC3B,oBAAoB,EACpB,kBAAkB,EAClB,KAAK,oBAAoB,EACzB,mBAAmB,GACtB,MAAM,eAAe,CAAC;AACvB,OAAO,EACH,sBAAsB,EACtB,uBAAuB,EACvB,sBAAsB,EACtB,4BAA4B,EAC5B,2BAA2B,EAC3B,wBAAwB,EACxB,2BAA2B,EAC3B,KAAK,gBAAgB,EACrB,gBAAgB,GACnB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EACH,0BAA0B,EAC1B,4BAA4B,EAC5B,0BAA0B,EAC1B,uBAAuB,EACvB,qBAAqB,EACrB,yBAAyB,EACzB,2BAA2B,EAC3B,6BAA6B,GAChC,MAAM,2BAA2B,CAAC;AACnC,OAAO,EACH,2BAA2B,EAC3B,4BAA4B,EAC5B,iCAAiC,EACjC,4BAA4B,EAC5B,iCAAiC,EACjC,iCAAiC,EACjC,oCAAoC,EACpC,gCAAgC,EAChC,+BAA+B,EAC/B,iCAAiC,EACjC,KAAK,qBAAqB,EAC1B,qBAAqB,GACxB,MAAM,8BAA8B,CAAC;AACtC,OAAO,EACH,uBAAuB,EACvB,oCAAoC,EACpC,8BAA8B,EAC9B,yBAAyB,EACzB,qCAAqC,EACrC,+BAA+B,EAC/B,4BAA4B,EAC5B,0CAA0C,EAC1C,sCAAsC,EACtC,+BAA+B,EAC/B,uBAAuB,EACvB,2BAA2B,EAC3B,8BAA8B,EAC9B,4BAA4B,EAC5B,yBAAyB,EACzB,sCAAsC,EACtC,yBAAyB,EACzB,oBAAoB,EACpB,wBAAwB,EACxB,6BAA6B,EAC7B,iCAAiC,GACpC,MAAM,wBAAwB,CAAC;AAChC,YAAY,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC/D,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EACH,qBAAqB,EACrB,KAAK,aAAa,EAClB,KAAK,oBAAoB,EACzB,KAAK,qBAAqB,GAC7B,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACH,eAAe,EACf,KAAK,cAAc,EACnB,aAAa,EACb,KAAK,mBAAmB,EACxB,YAAY,EACZ,aAAa,GAChB,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EAAE,eAAe,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AACrF,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EACH,SAAS,EACT,cAAc,EACd,UAAU,EACV,kBAAkB,EAClB,KAAK,KAAK,EACV,KAAK,SAAS,EACd,MAAM,GACT,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACH,mBAAmB,EACnB,6BAA6B,EAC7B,yBAAyB,EACzB,yBAAyB,EACzB,gBAAgB,EAChB,yBAAyB,EACzB,4BAA4B,EAC5B,iBAAiB,EACjB,gBAAgB,EAChB,8BAA8B,EAC9B,gBAAgB,EAChB,kBAAkB,EAClB,UAAU,EACV,kCAAkC,EAClC,yBAAyB,EACzB,yBAAyB,EACzB,mBAAmB,EACnB,mBAAmB,EACnB,kCAAkC,EAClC,mBAAmB,EACnB,+BAA+B,EAC/B,6BAA6B,EAC7B,yBAAyB,EACzB,yBAAyB,EACzB,wCAAwC,EACxC,kCAAkC,EAClC,wBAAwB,EACxB,yBAAyB,EACzB,kBAAkB,EAClB,iCAAiC,EACjC,2BAA2B,EAC3B,yBAAyB,EACzB,iBAAiB,EACjB,uBAAuB,EACvB,wBAAwB,EACxB,YAAY,EACZ,sCAAsC,EACtC,6BAA6B,EAC7B,0BAA0B,GAC7B,MAAM,oBAAoB,CAAC;AAC5B,cAAc,YAAY,CAAC"}
package/dist/index.js CHANGED
@@ -4,6 +4,7 @@ export { HEADER_AUTHOR_FONT_SIZE_PX, HEADER_AUTHOR_LINE_HEIGHT_PX, HEADER_CARD_P
4
4
  export { INCLUDE_CHROME_BADGE_GAP_PX, INCLUDE_CHROME_BADGE_SIZE_PX, INCLUDE_CHROME_OFFSET_FROM_BOX_PX, INCLUDE_CHROME_SOURCE_GAP_PX, INCLUDE_CHROME_SOURCE_HALO_PAD_PX, INCLUDE_CHROME_SOURCE_PER_CHAR_PX, INCLUDE_CHROME_TAB_LABEL_PER_CHAR_PX, INCLUDE_CHROME_TAB_LEFT_INSET_PX, INCLUDE_CHROME_TAB_MIN_WIDTH_PX, INCLUDE_CHROME_TAB_RIGHT_INSET_PX, includeChromeGeometry, } from './include-chrome-geometry.js';
5
5
  export { ITEM_CAPTION_INSET_X_PX, ITEM_CAPTION_META_BASELINE_OFFSET_PX, ITEM_CAPTION_META_FONT_SIZE_PX, ITEM_CAPTION_SPILL_GAP_PX, ITEM_CAPTION_TITLE_BASELINE_OFFSET_PX, ITEM_CAPTION_TITLE_FONT_SIZE_PX, ITEM_DECORATION_SPILL_GAP_PX, ITEM_FOOTNOTE_INDICATOR_BASELINE_OFFSET_PX, ITEM_FOOTNOTE_INDICATOR_INSET_RIGHT_PX, ITEM_FOOTNOTE_INDICATOR_STEP_PX, ITEM_LINK_ICON_INSET_PX, ITEM_LINK_ICON_TILE_SIZE_PX, ITEM_STATUS_DOT_INSET_RIGHT_PX, ITEM_STATUS_DOT_INSET_TOP_PX, ITEM_STATUS_DOT_RADIUS_PX, LABEL_CHIP_GAP_ABOVE_PROGRESS_STRIP_PX, LABEL_CHIP_GAP_BETWEEN_PX, LABEL_CHIP_HEIGHT_PX, MIN_BAR_WIDTH_FOR_DOT_PX, MIN_BAR_WIDTH_FOR_FOOTNOTE_PX, MIN_BAR_WIDTH_FOR_LINK_AND_DOT_PX, } from './item-bar-geometry.js';
6
6
  export { layoutRoadmap } from './layout.js';
7
+ export { collectLayoutInsights, } from './layout-insights.js';
7
8
  export { civilDateInZone, normalizeZone, resolveToday, TimezoneError, } from './resolve-today.js';
8
9
  export { scheduleRoadmap } from './schedule.js';
9
10
  export { darkTheme, grayscaleTheme, lightTheme, normalizeThemeName, themes, } from './themes/index.js';
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,2BAA2B,EAC3B,oBAAoB,EACpB,kBAAkB,EAElB,mBAAmB,GACtB,MAAM,eAAe,CAAC;AACvB,OAAO,EACH,sBAAsB,EACtB,uBAAuB,EACvB,sBAAsB,EACtB,4BAA4B,EAC5B,2BAA2B,EAC3B,wBAAwB,EACxB,2BAA2B,EAE3B,gBAAgB,GACnB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EACH,0BAA0B,EAC1B,4BAA4B,EAC5B,0BAA0B,EAC1B,uBAAuB,EACvB,qBAAqB,EACrB,yBAAyB,EACzB,2BAA2B,EAC3B,6BAA6B,GAChC,MAAM,2BAA2B,CAAC;AACnC,OAAO,EACH,2BAA2B,EAC3B,4BAA4B,EAC5B,iCAAiC,EACjC,4BAA4B,EAC5B,iCAAiC,EACjC,iCAAiC,EACjC,oCAAoC,EACpC,gCAAgC,EAChC,+BAA+B,EAC/B,iCAAiC,EAEjC,qBAAqB,GACxB,MAAM,8BAA8B,CAAC;AACtC,OAAO,EACH,uBAAuB,EACvB,oCAAoC,EACpC,8BAA8B,EAC9B,yBAAyB,EACzB,qCAAqC,EACrC,+BAA+B,EAC/B,4BAA4B,EAC5B,0CAA0C,EAC1C,sCAAsC,EACtC,+BAA+B,EAC/B,uBAAuB,EACvB,2BAA2B,EAC3B,8BAA8B,EAC9B,4BAA4B,EAC5B,yBAAyB,EACzB,sCAAsC,EACtC,yBAAyB,EACzB,oBAAoB,EACpB,wBAAwB,EACxB,6BAA6B,EAC7B,iCAAiC,GACpC,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EACH,eAAe,EAEf,aAAa,EAEb,YAAY,EACZ,aAAa,GAChB,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EACH,SAAS,EACT,cAAc,EACd,UAAU,EACV,kBAAkB,EAGlB,MAAM,GACT,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACH,mBAAmB,EACnB,6BAA6B,EAC7B,yBAAyB,EACzB,yBAAyB,EACzB,gBAAgB,EAChB,yBAAyB,EACzB,4BAA4B,EAC5B,iBAAiB,EACjB,gBAAgB,EAChB,8BAA8B,EAC9B,gBAAgB,EAChB,kBAAkB,EAClB,UAAU,EACV,kCAAkC,EAClC,yBAAyB,EACzB,yBAAyB,EACzB,mBAAmB,EACnB,mBAAmB,EACnB,kCAAkC,EAClC,mBAAmB,EACnB,+BAA+B,EAC/B,6BAA6B,EAC7B,yBAAyB,EACzB,yBAAyB,EACzB,wCAAwC,EACxC,kCAAkC,EAClC,wBAAwB,EACxB,yBAAyB,EACzB,kBAAkB,EAClB,iCAAiC,EACjC,2BAA2B,EAC3B,yBAAyB,EACzB,iBAAiB,EACjB,uBAAuB,EACvB,wBAAwB,EACxB,YAAY,EACZ,sCAAsC,EACtC,6BAA6B,EAC7B,0BAA0B,GAC7B,MAAM,oBAAoB,CAAC;AAC5B,cAAc,YAAY,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,2BAA2B,EAC3B,oBAAoB,EACpB,kBAAkB,EAElB,mBAAmB,GACtB,MAAM,eAAe,CAAC;AACvB,OAAO,EACH,sBAAsB,EACtB,uBAAuB,EACvB,sBAAsB,EACtB,4BAA4B,EAC5B,2BAA2B,EAC3B,wBAAwB,EACxB,2BAA2B,EAE3B,gBAAgB,GACnB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EACH,0BAA0B,EAC1B,4BAA4B,EAC5B,0BAA0B,EAC1B,uBAAuB,EACvB,qBAAqB,EACrB,yBAAyB,EACzB,2BAA2B,EAC3B,6BAA6B,GAChC,MAAM,2BAA2B,CAAC;AACnC,OAAO,EACH,2BAA2B,EAC3B,4BAA4B,EAC5B,iCAAiC,EACjC,4BAA4B,EAC5B,iCAAiC,EACjC,iCAAiC,EACjC,oCAAoC,EACpC,gCAAgC,EAChC,+BAA+B,EAC/B,iCAAiC,EAEjC,qBAAqB,GACxB,MAAM,8BAA8B,CAAC;AACtC,OAAO,EACH,uBAAuB,EACvB,oCAAoC,EACpC,8BAA8B,EAC9B,yBAAyB,EACzB,qCAAqC,EACrC,+BAA+B,EAC/B,4BAA4B,EAC5B,0CAA0C,EAC1C,sCAAsC,EACtC,+BAA+B,EAC/B,uBAAuB,EACvB,2BAA2B,EAC3B,8BAA8B,EAC9B,4BAA4B,EAC5B,yBAAyB,EACzB,sCAAsC,EACtC,yBAAyB,EACzB,oBAAoB,EACpB,wBAAwB,EACxB,6BAA6B,EAC7B,iCAAiC,GACpC,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EACH,qBAAqB,GAIxB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACH,eAAe,EAEf,aAAa,EAEb,YAAY,EACZ,aAAa,GAChB,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EACH,SAAS,EACT,cAAc,EACd,UAAU,EACV,kBAAkB,EAGlB,MAAM,GACT,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACH,mBAAmB,EACnB,6BAA6B,EAC7B,yBAAyB,EACzB,yBAAyB,EACzB,gBAAgB,EAChB,yBAAyB,EACzB,4BAA4B,EAC5B,iBAAiB,EACjB,gBAAgB,EAChB,8BAA8B,EAC9B,gBAAgB,EAChB,kBAAkB,EAClB,UAAU,EACV,kCAAkC,EAClC,yBAAyB,EACzB,yBAAyB,EACzB,mBAAmB,EACnB,mBAAmB,EACnB,kCAAkC,EAClC,mBAAmB,EACnB,+BAA+B,EAC/B,6BAA6B,EAC7B,yBAAyB,EACzB,yBAAyB,EACzB,wCAAwC,EACxC,kCAAkC,EAClC,wBAAwB,EACxB,yBAAyB,EACzB,kBAAkB,EAClB,iCAAiC,EACjC,2BAA2B,EAC3B,yBAAyB,EACzB,iBAAiB,EACjB,uBAAuB,EACvB,wBAAwB,EACxB,YAAY,EACZ,sCAAsC,EACtC,6BAA6B,EAC7B,0BAA0B,GAC7B,MAAM,oBAAoB,CAAC;AAC5B,cAAc,YAAY,CAAC"}
@@ -0,0 +1,26 @@
1
+ import { type MessageCode } from '@nowline/core';
2
+ import type { PositionedRoadmap } from './types.js';
3
+ export type LayoutInsightSeverity = 'info' | 'warning';
4
+ export interface LayoutInsight {
5
+ message: string;
6
+ severity: LayoutInsightSeverity;
7
+ code: MessageCode;
8
+ entityId?: string;
9
+ /** LSP severity: 2 = warning, 3 = information */
10
+ lspSeverity: 2 | 3;
11
+ data: {
12
+ code: MessageCode;
13
+ args: Record<string, unknown>;
14
+ };
15
+ }
16
+ export interface LayoutInsightContext {
17
+ today?: Date;
18
+ locale?: string;
19
+ }
20
+ /**
21
+ * Collect layout-derived insights from a positioned roadmap. These describe
22
+ * observable reflow consequences (caption spill, lane packing, etc.), not
23
+ * parse/validation errors.
24
+ */
25
+ export declare function collectLayoutInsights(layout: PositionedRoadmap, context?: LayoutInsightContext): LayoutInsight[];
26
+ //# sourceMappingURL=layout-insights.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"layout-insights.d.ts","sourceRoot":"","sources":["../src/layout-insights.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,WAAW,EAAM,MAAM,eAAe,CAAC;AAErD,OAAO,KAAK,EAER,iBAAiB,EAGpB,MAAM,YAAY,CAAC;AAEpB,MAAM,MAAM,qBAAqB,GAAG,MAAM,GAAG,SAAS,CAAC;AAEvD,MAAM,WAAW,aAAa;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,qBAAqB,CAAC;IAChC,IAAI,EAAE,WAAW,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,iDAAiD;IACjD,WAAW,EAAE,CAAC,GAAG,CAAC,CAAC;IACnB,IAAI,EAAE;QAAE,IAAI,EAAE,WAAW,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,CAAC;CAC9D;AAED,MAAM,WAAW,oBAAoB;IACjC,KAAK,CAAC,EAAE,IAAI,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;CACnB;AAmGD;;;;GAIG;AACH,wBAAgB,qBAAqB,CACjC,MAAM,EAAE,iBAAiB,EACzB,OAAO,GAAE,oBAAyB,GACnC,aAAa,EAAE,CAwBjB"}
@@ -0,0 +1,100 @@
1
+ // Layout-time insights — observable reflow consequences from the positioned
2
+ // model. Informational by default; warnings only when author intent is lost
3
+ // (e.g. now-line outside the date window).
4
+ import { tr } from '@nowline/core';
5
+ import { MIN_BAR_WIDTH_FOR_DOT_PX } from './item-bar-geometry.js';
6
+ function formatIsoDate(d) {
7
+ return d.toISOString().slice(0, 10);
8
+ }
9
+ function itemLabel(item) {
10
+ return item.id ?? item.title;
11
+ }
12
+ function walkTrackChildren(children, visit) {
13
+ for (const child of children) {
14
+ if (child.kind === 'item') {
15
+ visit(child);
16
+ }
17
+ else {
18
+ walkTrackChildren(child.children, visit);
19
+ }
20
+ }
21
+ }
22
+ function collectItemInsights(item, locale, out) {
23
+ const name = itemLabel(item);
24
+ if (item.textSpills) {
25
+ out.push(makeInsight(locale, 'NL.I1000', 'info', { name }, name));
26
+ }
27
+ if (item.chipsOutside) {
28
+ out.push(makeInsight(locale, 'NL.I1001', 'info', { name }, name));
29
+ }
30
+ // The status dot is always present, so a bar narrower than the dot's
31
+ // inset is genuinely too small to host its marker. The other cases are
32
+ // already captured by the layout's actual spill flags — using those
33
+ // avoids flagging "decorations spilled" on items that have no link or
34
+ // footnote and nothing actually spilled.
35
+ const tooNarrow = item.box.width < MIN_BAR_WIDTH_FOR_DOT_PX ||
36
+ item.dotSpills ||
37
+ item.iconSpills ||
38
+ item.footnoteSpills;
39
+ if (tooNarrow) {
40
+ out.push(makeInsight(locale, 'NL.I1002', 'info', { name }, name));
41
+ }
42
+ if (item.hasOverflow) {
43
+ out.push(makeInsight(locale, 'NL.I1003', 'info', { name, anchor: item.overflowAnchorId }, name));
44
+ }
45
+ }
46
+ function makeInsight(locale, code, severity, args, entityId) {
47
+ return {
48
+ message: tr(locale, code, args),
49
+ severity,
50
+ code,
51
+ entityId,
52
+ lspSeverity: severity === 'warning' ? 2 : 3,
53
+ data: { code, args },
54
+ };
55
+ }
56
+ function collectSwimlaneInsights(lane, locale, out) {
57
+ const laneName = lane.id ?? lane.title;
58
+ const items = [];
59
+ walkTrackChildren(lane.children, (item) => items.push(item));
60
+ for (const item of items) {
61
+ collectItemInsights(item, locale, out);
62
+ }
63
+ const rowYs = new Set(items.map((i) => i.box.y));
64
+ if (rowYs.size > 1) {
65
+ out.push(makeInsight(locale, 'NL.I1004', 'info', { lane: laneName, rows: rowYs.size }, laneName));
66
+ }
67
+ const hasRed = lane.utilization?.segments.some((s) => s.classification === 'red') ?? false;
68
+ if (hasRed) {
69
+ out.push(makeInsight(locale, 'NL.I1005', 'info', { lane: laneName }, laneName));
70
+ }
71
+ for (const nested of lane.nested) {
72
+ collectSwimlaneInsights(nested, locale, out);
73
+ }
74
+ }
75
+ /**
76
+ * Collect layout-derived insights from a positioned roadmap. These describe
77
+ * observable reflow consequences (caption spill, lane packing, etc.), not
78
+ * parse/validation errors.
79
+ */
80
+ export function collectLayoutInsights(layout, context = {}) {
81
+ const locale = context.locale ?? 'en-US';
82
+ const out = [];
83
+ for (const lane of layout.swimlanes) {
84
+ collectSwimlaneInsights(lane, locale, out);
85
+ }
86
+ if (context.today) {
87
+ const today = context.today;
88
+ const start = layout.timeline.startDate;
89
+ const end = layout.timeline.endDate;
90
+ if (today < start || today > end) {
91
+ out.push(makeInsight(locale, 'NL.W1000', 'warning', {
92
+ date: formatIsoDate(today),
93
+ start: formatIsoDate(start),
94
+ end: formatIsoDate(end),
95
+ }));
96
+ }
97
+ }
98
+ return out;
99
+ }
100
+ //# sourceMappingURL=layout-insights.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"layout-insights.js","sourceRoot":"","sources":["../src/layout-insights.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@nowline/layout",
3
- "version": "0.6.0",
4
- "description": "Nowline layout engine — AST → positioned model for rendering",
3
+ "version": "0.8.0",
4
+ "description": "Nowline layout engine — works out where everything goes on the page before it's drawn.",
5
5
  "license": "Apache-2.0",
6
6
  "engines": {
7
7
  "node": ">=22",
@@ -24,7 +24,7 @@
24
24
  "dependencies": {
25
25
  "d3-scale": "^4.0.2",
26
26
  "d3-time": "^3.1.0",
27
- "@nowline/core": "0.6.0"
27
+ "@nowline/core": "0.8.0"
28
28
  },
29
29
  "devDependencies": {
30
30
  "@types/d3-scale": "^4.0.9",
package/src/index.ts CHANGED
@@ -65,6 +65,12 @@ export {
65
65
  } from './item-bar-geometry.js';
66
66
  export type { LayoutOptions, LayoutResult } from './layout.js';
67
67
  export { layoutRoadmap } from './layout.js';
68
+ export {
69
+ collectLayoutInsights,
70
+ type LayoutInsight,
71
+ type LayoutInsightContext,
72
+ type LayoutInsightSeverity,
73
+ } from './layout-insights.js';
68
74
  export {
69
75
  civilDateInZone,
70
76
  type NormalizedZone,
@@ -0,0 +1,160 @@
1
+ // Layout-time insights — observable reflow consequences from the positioned
2
+ // model. Informational by default; warnings only when author intent is lost
3
+ // (e.g. now-line outside the date window).
4
+
5
+ import { type MessageCode, tr } from '@nowline/core';
6
+ import { MIN_BAR_WIDTH_FOR_DOT_PX } from './item-bar-geometry.js';
7
+ import type {
8
+ PositionedItem,
9
+ PositionedRoadmap,
10
+ PositionedSwimlane,
11
+ PositionedTrackChild,
12
+ } from './types.js';
13
+
14
+ export type LayoutInsightSeverity = 'info' | 'warning';
15
+
16
+ export interface LayoutInsight {
17
+ message: string;
18
+ severity: LayoutInsightSeverity;
19
+ code: MessageCode;
20
+ entityId?: string;
21
+ /** LSP severity: 2 = warning, 3 = information */
22
+ lspSeverity: 2 | 3;
23
+ data: { code: MessageCode; args: Record<string, unknown> };
24
+ }
25
+
26
+ export interface LayoutInsightContext {
27
+ today?: Date;
28
+ locale?: string;
29
+ }
30
+
31
+ function formatIsoDate(d: Date): string {
32
+ return d.toISOString().slice(0, 10);
33
+ }
34
+
35
+ function itemLabel(item: PositionedItem): string {
36
+ return item.id ?? item.title;
37
+ }
38
+
39
+ function walkTrackChildren(
40
+ children: PositionedTrackChild[],
41
+ visit: (item: PositionedItem) => void,
42
+ ): void {
43
+ for (const child of children) {
44
+ if (child.kind === 'item') {
45
+ visit(child);
46
+ } else {
47
+ walkTrackChildren(child.children, visit);
48
+ }
49
+ }
50
+ }
51
+
52
+ function collectItemInsights(item: PositionedItem, locale: string, out: LayoutInsight[]): void {
53
+ const name = itemLabel(item);
54
+
55
+ if (item.textSpills) {
56
+ out.push(makeInsight(locale, 'NL.I1000', 'info', { name }, name));
57
+ }
58
+ if (item.chipsOutside) {
59
+ out.push(makeInsight(locale, 'NL.I1001', 'info', { name }, name));
60
+ }
61
+ // The status dot is always present, so a bar narrower than the dot's
62
+ // inset is genuinely too small to host its marker. The other cases are
63
+ // already captured by the layout's actual spill flags — using those
64
+ // avoids flagging "decorations spilled" on items that have no link or
65
+ // footnote and nothing actually spilled.
66
+ const tooNarrow =
67
+ item.box.width < MIN_BAR_WIDTH_FOR_DOT_PX ||
68
+ item.dotSpills ||
69
+ item.iconSpills ||
70
+ item.footnoteSpills;
71
+ if (tooNarrow) {
72
+ out.push(makeInsight(locale, 'NL.I1002', 'info', { name }, name));
73
+ }
74
+ if (item.hasOverflow) {
75
+ out.push(
76
+ makeInsight(locale, 'NL.I1003', 'info', { name, anchor: item.overflowAnchorId }, name),
77
+ );
78
+ }
79
+ }
80
+
81
+ function makeInsight(
82
+ locale: string,
83
+ code: MessageCode,
84
+ severity: LayoutInsightSeverity,
85
+ args: Record<string, unknown>,
86
+ entityId?: string,
87
+ ): LayoutInsight {
88
+ return {
89
+ message: tr(locale, code, args as never),
90
+ severity,
91
+ code,
92
+ entityId,
93
+ lspSeverity: severity === 'warning' ? 2 : 3,
94
+ data: { code, args },
95
+ };
96
+ }
97
+
98
+ function collectSwimlaneInsights(
99
+ lane: PositionedSwimlane,
100
+ locale: string,
101
+ out: LayoutInsight[],
102
+ ): void {
103
+ const laneName = lane.id ?? lane.title;
104
+ const items: PositionedItem[] = [];
105
+ walkTrackChildren(lane.children, (item) => items.push(item));
106
+
107
+ for (const item of items) {
108
+ collectItemInsights(item, locale, out);
109
+ }
110
+
111
+ const rowYs = new Set(items.map((i) => i.box.y));
112
+ if (rowYs.size > 1) {
113
+ out.push(
114
+ makeInsight(locale, 'NL.I1004', 'info', { lane: laneName, rows: rowYs.size }, laneName),
115
+ );
116
+ }
117
+
118
+ const hasRed = lane.utilization?.segments.some((s) => s.classification === 'red') ?? false;
119
+ if (hasRed) {
120
+ out.push(makeInsight(locale, 'NL.I1005', 'info', { lane: laneName }, laneName));
121
+ }
122
+
123
+ for (const nested of lane.nested) {
124
+ collectSwimlaneInsights(nested, locale, out);
125
+ }
126
+ }
127
+
128
+ /**
129
+ * Collect layout-derived insights from a positioned roadmap. These describe
130
+ * observable reflow consequences (caption spill, lane packing, etc.), not
131
+ * parse/validation errors.
132
+ */
133
+ export function collectLayoutInsights(
134
+ layout: PositionedRoadmap,
135
+ context: LayoutInsightContext = {},
136
+ ): LayoutInsight[] {
137
+ const locale = context.locale ?? 'en-US';
138
+ const out: LayoutInsight[] = [];
139
+
140
+ for (const lane of layout.swimlanes) {
141
+ collectSwimlaneInsights(lane, locale, out);
142
+ }
143
+
144
+ if (context.today) {
145
+ const today = context.today;
146
+ const start = layout.timeline.startDate;
147
+ const end = layout.timeline.endDate;
148
+ if (today < start || today > end) {
149
+ out.push(
150
+ makeInsight(locale, 'NL.W1000', 'warning', {
151
+ date: formatIsoDate(today),
152
+ start: formatIsoDate(start),
153
+ end: formatIsoDate(end),
154
+ }),
155
+ );
156
+ }
157
+ }
158
+
159
+ return out;
160
+ }