@cfasim-ui/docs 0.4.11 → 0.4.13

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.
@@ -29,8 +29,8 @@ const props = withDefaults(
29
29
  const DEFAULT_FONT_SIZE = 13;
30
30
  const DEFAULT_FONT_WEIGHT = "normal";
31
31
  const BOLD_FONT_WEIGHT = 700;
32
- const DEFAULT_HALO_COLOR = "var(--color-bg-0, #fff)";
33
- const DEFAULT_HALO_WIDTH = 3;
32
+ const DEFAULT_OUTLINE_COLOR = "var(--color-bg-0, #fff)";
33
+ const DEFAULT_OUTLINE_WIDTH = 3;
34
34
  const DEFAULT_LINE_WIDTH = 1;
35
35
  const ANCHOR_GAP_PX = 4;
36
36
  const LABEL_GAP_PX = 6;
@@ -55,8 +55,8 @@ interface RenderedAnnotation {
55
55
  fontSize: number;
56
56
  fontWeight: string | number;
57
57
  color: string;
58
- haloColor: string;
59
- haloWidth: number;
58
+ outlineColor: string;
59
+ outlineWidth: number;
60
60
  pointerPath: string;
61
61
  lineColor: string;
62
62
  lineWidth: number;
@@ -66,6 +66,7 @@ interface RenderedAnnotation {
66
66
  // renders correctly in Safari (which doesn't support `context-stroke` on
67
67
  // SVG markers). Present only when an arrow should be drawn.
68
68
  arrowTip?: { x: number; y: number; angle: number };
69
+ arrowTransform: string;
69
70
  rule?: { x1: number; y1: number; x2: number; y2: number };
70
71
  }
71
72
 
@@ -128,13 +129,15 @@ const items = computed<RenderedAnnotation[]>(() => {
128
129
  const color = a.color ?? "currentColor";
129
130
  const fontSize = a.fontSize ?? DEFAULT_FONT_SIZE;
130
131
  const fontWeight = a.fontWeight ?? DEFAULT_FONT_WEIGHT;
131
- const haloColor = a.haloColor ?? DEFAULT_HALO_COLOR;
132
- const haloWidth = a.haloWidth ?? DEFAULT_HALO_WIDTH;
132
+ const outlineColor = a.outlineColor ?? DEFAULT_OUTLINE_COLOR;
133
+ const outlineWidth = a.outlineWidth ?? DEFAULT_OUTLINE_WIDTH;
133
134
  const lineColor = a.lineColor ?? color;
134
135
  const lineWidth = a.lineWidth ?? DEFAULT_LINE_WIDTH;
135
136
  const lineDash = resolveDash(a.lineDash);
136
- const textAnchor =
137
- a.textAnchor ?? (offsetX > 0 ? "start" : offsetX < 0 ? "end" : "middle");
137
+ const alignMap = { left: "start", center: "middle", right: "end" } as const;
138
+ const align =
139
+ a.align ?? (offsetX > 0 ? "left" : offsetX < 0 ? "right" : "center");
140
+ const textAnchor = alignMap[align];
138
141
 
139
142
  let rule: RenderedAnnotation["rule"];
140
143
  let pointerPath = "";
@@ -164,14 +167,17 @@ const items = computed<RenderedAnnotation[]>(() => {
164
167
  fontSize,
165
168
  fontWeight,
166
169
  color,
167
- haloColor,
168
- haloWidth,
170
+ outlineColor,
171
+ outlineWidth,
169
172
  pointerPath,
170
173
  lineColor,
171
174
  lineWidth,
172
175
  lineDash,
173
176
  arrow: wantArrow,
174
177
  arrowTip,
178
+ arrowTransform: arrowTip
179
+ ? `translate(${arrowTip.x} ${arrowTip.y}) rotate(${arrowTip.angle})`
180
+ : "",
175
181
  rule,
176
182
  });
177
183
  }
@@ -302,12 +308,45 @@ function buildPointerPath(
302
308
  <template>
303
309
  <g class="chart-annotations" pointer-events="none">
304
310
  <template v-for="(item, i) in items" :key="i">
311
+ <!--
312
+ Outline pass. Each shape is rendered first in `outlineColor` at a
313
+ wider stroke so the rule line, pointer, and arrow tip stay legible
314
+ over busy series. Outline elements carry `class="annotation-outline"`
315
+ so consumers (and tests) can target the "real" shape directly.
316
+ Outlines deliberately drop `stroke-dasharray` — a dashed outline
317
+ would expose gaps where legibility matters most.
318
+ -->
319
+ <line
320
+ v-if="item.rule && item.outlineWidth > 0"
321
+ v-bind="item.rule"
322
+ class="annotation-outline"
323
+ :stroke="item.outlineColor"
324
+ :stroke-width="item.lineWidth + item.outlineWidth"
325
+ stroke-linecap="round"
326
+ />
327
+ <path
328
+ v-if="item.pointerPath && item.outlineWidth > 0"
329
+ :d="item.pointerPath"
330
+ class="annotation-outline"
331
+ fill="none"
332
+ :stroke="item.outlineColor"
333
+ :stroke-width="item.lineWidth + item.outlineWidth"
334
+ stroke-linecap="round"
335
+ />
336
+ <polygon
337
+ v-if="item.arrowTip && item.outlineWidth > 0"
338
+ points="0,0 -6,-3 -6,3"
339
+ class="annotation-outline"
340
+ :fill="item.outlineColor"
341
+ :stroke="item.outlineColor"
342
+ :stroke-width="item.outlineWidth"
343
+ stroke-linejoin="round"
344
+ :transform="item.arrowTransform"
345
+ />
346
+ <!-- Actual shapes. -->
305
347
  <line
306
348
  v-if="item.rule"
307
- :x1="item.rule.x1"
308
- :y1="item.rule.y1"
309
- :x2="item.rule.x2"
310
- :y2="item.rule.y2"
349
+ v-bind="item.rule"
311
350
  :stroke="item.lineColor"
312
351
  :stroke-width="item.lineWidth"
313
352
  :stroke-dasharray="item.lineDash"
@@ -332,7 +371,7 @@ function buildPointerPath(
332
371
  v-if="item.arrowTip"
333
372
  points="0,0 -6,-3 -6,3"
334
373
  :fill="item.lineColor"
335
- :transform="`translate(${item.arrowTip.x} ${item.arrowTip.y}) rotate(${item.arrowTip.angle})`"
374
+ :transform="item.arrowTransform"
336
375
  />
337
376
  <text
338
377
  :x="item.textX"
@@ -341,8 +380,8 @@ function buildPointerPath(
341
380
  :font-size="item.fontSize"
342
381
  :font-weight="item.fontWeight"
343
382
  :fill="item.color"
344
- :stroke="item.haloColor"
345
- :stroke-width="item.haloWidth"
383
+ :stroke="item.outlineColor"
384
+ :stroke-width="item.outlineWidth"
346
385
  stroke-linejoin="round"
347
386
  paint-order="stroke fill"
348
387
  >
@@ -37,18 +37,23 @@ export interface ChartAnnotation {
37
37
  */
38
38
  fontWeight?: string | number;
39
39
  /**
40
- * Halo (stroke) color drawn behind the text so the label stays legible
41
- * against busy chart elements. Defaults to `var(--color-bg-0, #fff)` so
42
- * it matches the page background out of the box.
40
+ * Color of the legibility outline drawn behind the text, pointer/rule
41
+ * line, and arrow tip. Defaults to `var(--color-bg-0, #fff)` so it
42
+ * matches the page background out of the box.
43
43
  */
44
- haloColor?: string;
45
- /** Halo stroke width in pixels. Default: 3. */
46
- haloWidth?: number;
44
+ outlineColor?: string;
47
45
  /**
48
- * SVG text-anchor for the label. When omitted, derived from the sign of
49
- * `offset.x`: positive `start`, negative `end`, zero → `middle`.
46
+ * Outline stroke width in pixels. Applied to the text (via paint-order
47
+ * stroke), and added to `lineWidth` for the pointer/rule line and
48
+ * arrow tip outline pass. Set to `0` to disable the outline. Default: 3.
50
49
  */
51
- textAnchor?: "start" | "middle" | "end";
50
+ outlineWidth?: number;
51
+ /**
52
+ * Horizontal alignment of the label relative to its anchor position.
53
+ * When omitted, derived from the sign of `offset.x`: positive →
54
+ * `"left"`, negative → `"right"`, zero → `"center"`.
55
+ */
56
+ align?: "left" | "center" | "right";
52
57
  /** Pointer- or rule-line color override. Defaults to `color`. */
53
58
  lineColor?: string;
54
59
  /** Pointer- or rule-line width in pixels. Default: 1. */
@@ -8,6 +8,33 @@ import type { NumberFormat } from "@cfasim-ui/shared";
8
8
  import type { ChartAnnotation } from "./annotations.js";
9
9
  import type { ChartPadding } from "./useChartPadding.js";
10
10
 
11
+ /**
12
+ * Visual styling for the chart title. All fields optional; unspecified
13
+ * fields fall back to the chart's defaults (font-size 14, line-height 18,
14
+ * font-weight 600, currentColor, align "left"). `lineHeight` is in pixels
15
+ * and controls spacing between lines when the title contains `\n`.
16
+ */
17
+ export interface TitleStyle {
18
+ fontSize?: number;
19
+ lineHeight?: number;
20
+ color?: string;
21
+ fontWeight?: number | string;
22
+ /** Horizontal alignment of the title. Default: `"left"`. */
23
+ align?: "left" | "center" | "right";
24
+ }
25
+
26
+ /**
27
+ * Visual styling for axis labels, tick labels, and legend text. Each
28
+ * field is optional; unspecified fields fall back to that element's
29
+ * default. When `color` is set, the default fill-opacity (used by tick
30
+ * labels) is dropped so the exact color is rendered.
31
+ */
32
+ export interface LabelStyle {
33
+ fontSize?: number;
34
+ color?: string;
35
+ fontWeight?: number | string;
36
+ }
37
+
11
38
  /**
12
39
  * Props common to every cartesian chart component. Anything specific to
13
40
  * the chart type (series shape, layout, value-axis details) lives on the
@@ -16,7 +43,19 @@ import type { ChartPadding } from "./useChartPadding.js";
16
43
  export interface ChartCommonProps {
17
44
  width?: number;
18
45
  height?: number;
46
+ /**
47
+ * Chart title. `\n` in the string creates additional lines, each
48
+ * adding `titleStyle.lineHeight` (default 18px) of vertical space.
49
+ */
19
50
  title?: string;
51
+ /** Styling for the chart title. See `TitleStyle`. */
52
+ titleStyle?: TitleStyle;
53
+ /** Styling for axis labels (the `xLabel` / `yLabel` text). */
54
+ axisLabelStyle?: LabelStyle;
55
+ /** Styling for axis tick labels (the numbers/categories on each axis). */
56
+ tickLabelStyle?: LabelStyle;
57
+ /** Styling for the inline legend item labels. */
58
+ legendStyle?: LabelStyle;
20
59
  xLabel?: string;
21
60
  yLabel?: string;
22
61
  debounce?: number;